aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jonas Gunz <himself@jonasgunz.de> 2020-05-25 20:09:04 +0200
committerGravatar Jonas Gunz <himself@jonasgunz.de> 2020-05-25 20:09:04 +0200
commit4440a86cfa359b8e40a484a2cd46d33db5455d8a (patch)
treef5c0c59aebf0058ae97e7ef8b5fb8017f459a05a
downloadircd-4440a86cfa359b8e40a484a2cd46d33db5455d8a.tar.gz
Initial
-rw-r--r--common/bsd.c192
-rw-r--r--common/bsd_ext.h41
-rw-r--r--common/class_def.h58
-rw-r--r--common/common_def.h88
-rw-r--r--common/dbuf.c532
-rw-r--r--common/dbuf_def.h96
-rw-r--r--common/dbuf_ext.h49
-rw-r--r--common/match.c314
-rw-r--r--common/match_ext.h43
-rw-r--r--common/msg_def.h77
-rw-r--r--common/numeric_def.h337
-rw-r--r--common/os.h765
-rw-r--r--common/packet.c197
-rw-r--r--common/packet_ext.h32
-rw-r--r--common/parse.c786
-rw-r--r--common/parse_ext.h56
-rw-r--r--common/patchlevel.h22
-rw-r--r--common/send.c1555
-rw-r--r--common/send_ext.h82
-rw-r--r--common/struct_def.h832
-rw-r--r--common/support.c1190
-rw-r--r--common/support_def.h28
-rw-r--r--common/support_ext.h80
-rwxr-xr-xconfigure50
-rw-r--r--contrib/README21
-rw-r--r--contrib/RULES24
-rw-r--r--contrib/antispoof.README56
-rw-r--r--contrib/antispoof.diff484
-rw-r--r--contrib/ircdwatch/README56
-rw-r--r--contrib/ircdwatch/ircdwatch.850
-rw-r--r--contrib/ircdwatch/ircdwatch.c499
-rw-r--r--contrib/mkpasswd/README64
-rwxr-xr-xcontrib/mkpasswd/crypter55
-rw-r--r--contrib/mkpasswd/mkpasswd.c44
-rw-r--r--contrib/mod_passwd/README30
-rw-r--r--contrib/mod_passwd/mod_passwd.c171
-rw-r--r--contrib/tkserv/CHANGES37
-rw-r--r--contrib/tkserv/CREDITS60
-rw-r--r--contrib/tkserv/INSTALL20
-rw-r--r--contrib/tkserv/README290
-rw-r--r--contrib/tkserv/proto.h24
-rw-r--r--contrib/tkserv/tkserv.access.example10
-rw-r--r--contrib/tkserv/tkserv.c1022
-rw-r--r--doc/2.10-New18
-rw-r--r--doc/2.9-New60
-rw-r--r--doc/Authors180
-rw-r--r--doc/BUGS13
-rw-r--r--doc/ChangeLog1956
-rw-r--r--doc/Etiquette84
-rw-r--r--doc/INSTALL.appendix86
-rw-r--r--doc/INSTALL.info1759
-rw-r--r--doc/INSTALL.sgml1388
-rw-r--r--doc/INSTALL.txt1716
-rw-r--r--doc/Juped/Advertisement39
-rw-r--r--doc/Juped/ChangeLog.common91
-rw-r--r--doc/Juped/ChangeLog.doc90
-rw-r--r--doc/Juped/ChangeLog.include85
-rw-r--r--doc/Juped/ChangeLog.irc77
-rw-r--r--doc/Juped/ChangeLog.ircd458
-rw-r--r--doc/Juped/INSTALL1167
-rw-r--r--doc/Juped/US-Admin/Networking156
-rw-r--r--doc/LICENSE249
-rw-r--r--doc/Makefile39
-rw-r--r--doc/Nets/Europe/CoordEBIC86
-rw-r--r--doc/Nets/Europe/IRCNO171
-rw-r--r--doc/Nets/Europe/InfoEBIC48
-rw-r--r--doc/Nets/Europe/RulesEBIC90
-rw-r--r--doc/Nets/Europe/links.eu70
-rw-r--r--doc/Nets/Europe/rules55
-rw-r--r--doc/Nets/IRCNet17
-rw-r--r--doc/README40
-rw-r--r--doc/RELEASE_LOG23
-rw-r--r--doc/RELEASE_NOTES120
-rw-r--r--doc/SERVICE.sgml285
-rw-r--r--doc/SERVICE.txt330
-rw-r--r--doc/alt-irc-faq293
-rw-r--r--doc/example.conf531
-rw-r--r--doc/iauth-internals.txt350
-rw-r--r--doc/iauth.854
-rw-r--r--doc/iauth.conf.5159
-rw-r--r--doc/irc.185
-rw-r--r--doc/ircd.8202
-rw-r--r--doc/m4macros48
-rw-r--r--iauth/a_conf.c548
-rw-r--r--iauth/a_conf_def.h56
-rw-r--r--iauth/a_conf_ext.h43
-rw-r--r--iauth/a_defines.h39
-rw-r--r--iauth/a_externs.h34
-rw-r--r--iauth/a_io.c831
-rw-r--r--iauth/a_io_ext.h50
-rw-r--r--iauth/a_log.c123
-rw-r--r--iauth/a_log_def.h41
-rw-r--r--iauth/a_log_ext.h46
-rw-r--r--iauth/a_struct_def.h72
-rw-r--r--iauth/iauth.c226
-rw-r--r--iauth/mod_lhex.c318
-rw-r--r--iauth/mod_lhex_ext.h28
-rw-r--r--iauth/mod_pipe.c217
-rw-r--r--iauth/mod_pipe_ext.h28
-rw-r--r--iauth/mod_rfc931.c368
-rw-r--r--iauth/mod_rfc931_ext.h45
-rw-r--r--iauth/mod_socks.c632
-rw-r--r--iauth/mod_socks_ext.h28
-rw-r--r--irc/c_bsd.c149
-rw-r--r--irc/c_bsd_ext.h39
-rw-r--r--irc/c_conf.c95
-rw-r--r--irc/c_conf_ext.h38
-rw-r--r--irc/c_debug.c61
-rw-r--r--irc/c_debug_ext.h49
-rw-r--r--irc/c_defines.h35
-rw-r--r--irc/c_externs.h44
-rw-r--r--irc/c_msg.c407
-rw-r--r--irc/c_msg_ext.h76
-rw-r--r--irc/c_numeric.c413
-rw-r--r--irc/c_numeric_ext.h39
-rw-r--r--irc/c_version.c46
-rw-r--r--irc/c_version_ext.h32
-rw-r--r--irc/ctcp.c50
-rw-r--r--irc/ctcp_ext.h33
-rw-r--r--irc/edit.c411
-rw-r--r--irc/edit_ext.h55
-rw-r--r--irc/help.c228
-rw-r--r--irc/help_def.h23
-rw-r--r--irc/help_ext.h40
-rw-r--r--irc/ignore.c141
-rw-r--r--irc/ignore_ext.h43
-rw-r--r--irc/irc.c908
-rw-r--r--irc/irc_def.h29
-rw-r--r--irc/irc_ext.h84
-rw-r--r--irc/screen.c287
-rw-r--r--irc/screen_ext.h56
-rw-r--r--irc/str.c84
-rw-r--r--irc/str_ext.h39
-rw-r--r--irc/swear.c216
-rw-r--r--irc/swear_ext.h53
-rwxr-xr-xircd/buildm498
-rw-r--r--ircd/channel.c3396
-rw-r--r--ircd/channel_def.h29
-rw-r--r--ircd/channel_ext.h64
-rw-r--r--ircd/chkconf.c745
-rw-r--r--ircd/class.c256
-rw-r--r--ircd/class_ext.h49
-rw-r--r--ircd/hash.c940
-rw-r--r--ircd/hash_def.h32
-rw-r--r--ircd/hash_ext.h52
-rw-r--r--ircd/ircd.c1287
-rw-r--r--ircd/ircd_ext.h62
-rw-r--r--ircd/list.c685
-rw-r--r--ircd/list2.c515
-rw-r--r--ircd/list_ext.h66
-rw-r--r--ircd/nameser_def.h330
-rw-r--r--ircd/res.c1697
-rw-r--r--ircd/res_comp.c929
-rw-r--r--ircd/res_comp_ext.h44
-rw-r--r--ircd/res_def.h59
-rw-r--r--ircd/res_ext.h41
-rw-r--r--ircd/res_init.c642
-rw-r--r--ircd/res_init_ext.h39
-rw-r--r--ircd/res_mkquery.c178
-rw-r--r--ircd/res_mkquery_ext.h35
-rw-r--r--ircd/resolv_def.h220
-rw-r--r--ircd/s_auth.c804
-rw-r--r--ircd/s_auth_ext.h52
-rw-r--r--ircd/s_bsd.c3243
-rw-r--r--ircd/s_bsd_ext.h77
-rw-r--r--ircd/s_conf.c1684
-rw-r--r--ircd/s_conf_ext.h66
-rw-r--r--ircd/s_debug.c668
-rw-r--r--ircd/s_debug_ext.h45
-rw-r--r--ircd/s_defines.h41
-rw-r--r--ircd/s_err.c436
-rw-r--r--ircd/s_err_ext.h33
-rw-r--r--ircd/s_externs.h53
-rw-r--r--ircd/s_id.c208
-rw-r--r--ircd/s_id_ext.h43
-rw-r--r--ircd/s_misc.c998
-rw-r--r--ircd/s_misc_ext.h58
-rw-r--r--ircd/s_numeric.c127
-rw-r--r--ircd/s_numeric_ext.h33
-rw-r--r--ircd/s_serv.c2489
-rw-r--r--ircd/s_serv_ext.h72
-rw-r--r--ircd/s_service.c708
-rw-r--r--ircd/s_service_ext.h58
-rw-r--r--ircd/s_user.c2869
-rw-r--r--ircd/s_user_ext.h60
-rw-r--r--ircd/s_zip.c261
-rw-r--r--ircd/s_zip_ext.h38
-rw-r--r--ircd/service_def.h54
-rw-r--r--ircd/sys_def.h31
-rw-r--r--ircd/version.c.SH.in113
-rw-r--r--ircd/version_ext.h32
-rw-r--r--ircd/whowas.c464
-rw-r--r--ircd/whowas_def.h34
-rw-r--r--ircd/whowas_ext.h47
-rw-r--r--support/Makefile.in488
-rw-r--r--support/acconfig.h101
-rwxr-xr-xsupport/config.guess954
-rw-r--r--support/config.h.dist555
-rw-r--r--support/config.sub955
-rwxr-xr-xsupport/configure4671
-rw-r--r--support/configure.in1519
-rw-r--r--support/iauth.conf18
-rwxr-xr-xsupport/install-sh253
-rwxr-xr-xsupport/mkdirhier70
-rw-r--r--support/setup.h.in413
-rw-r--r--support/sums.in39
-rw-r--r--support/tkconf.h.dist35
207 files changed, 69923 insertions, 0 deletions
diff --git a/common/bsd.c b/common/bsd.c
new file mode 100644
index 0000000..69b66e7
--- /dev/null
+++ b/common/bsd.c
@@ -0,0 +1,192 @@
+/************************************************************************
+ * 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: bsd.c,v 1.3 1998/12/13 00:02:33 kalt Exp $";
+#endif
+
+#include "os.h"
+#ifndef CLIENT_COMPILE
+# include "s_defines.h"
+#else
+# include "c_defines.h"
+#endif
+#define BSD_C
+#ifndef CLIENT_COMPILE
+# include "s_externs.h"
+#else
+# include "c_externs.h"
+#endif
+#undef BSD_C
+
+#ifdef DEBUGMODE
+int writecalls = 0, writeb[10] = {0,0,0,0,0,0,0,0,0,0};
+#endif
+RETSIGTYPE dummy(s)
+int s;
+{
+#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
+# if 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...
+*/
+int deliver_it(cptr, str, len)
+aClient *cptr;
+int len;
+char *str;
+ {
+ int retval;
+ aClient *acpt = cptr->acpt;
+
+#ifdef DEBUGMODE
+ writecalls++;
+#endif
+#ifndef NOWRITEALARM
+ (void)alarm(WRITEWAITDELAY);
+#endif
+#ifdef INET6
+ retval = sendto(cptr->fd, str, len, 0, 0, 0);
+#else
+ retval = send(cptr->fd, str, len, 0);
+#endif
+ /*
+ ** Convert WOULDBLOCK to a return of "0 bytes moved". This
+ ** should occur only if socket was non-blocking. Note, that
+ ** all is Ok, if the 'write' just returns '0' instead of an
+ ** error and errno=EWOULDBLOCK.
+ **
+ ** ...now, would this work on VMS too? --msa
+ */
+ if (retval < 0 && (errno == EWOULDBLOCK || errno == EAGAIN ||
+#ifdef EMSGSIZE
+ errno == EMSGSIZE ||
+#endif
+ errno == ENOBUFS))
+ {
+ retval = 0;
+ cptr->flags |= FLAGS_BLOCKED;
+ }
+ else if (retval > 0)
+ cptr->flags &= ~FLAGS_BLOCKED;
+
+#ifndef NOWRITEALARM
+ (void )alarm(0);
+#endif
+#ifdef DEBUGMODE
+ if (retval < 0) {
+ writeb[0]++;
+ Debug((DEBUG_ERROR,"write error (%s) to %s",
+ sys_errlist[errno], cptr->name));
+#ifndef CLIENT_COMPILE
+ hold_server(cptr);
+#endif
+ } else if (retval == 0)
+ writeb[1]++;
+ else if (retval < 16)
+ writeb[2]++;
+ else if (retval < 32)
+ writeb[3]++;
+ else if (retval < 64)
+ writeb[4]++;
+ else if (retval < 128)
+ writeb[5]++;
+ else if (retval < 256)
+ writeb[6]++;
+ else if (retval < 512)
+ writeb[7]++;
+ else if (retval < 1024)
+ writeb[8]++;
+ else
+ writeb[9]++;
+#endif
+ if (retval > 0)
+ {
+#if defined(DEBUGMODE) && defined(DEBUG_WRITE)
+ Debug((DEBUG_WRITE, "send = %d bytes to %d[%s]:[%*.*s]\n",
+ retval, cptr->fd, cptr->name, retval, retval, str));
+#endif
+ cptr->sendB += retval;
+ me.sendB += retval;
+ if (cptr->sendB > 1023)
+ {
+ cptr->sendK += (cptr->sendB >> 10);
+ cptr->sendB &= 0x03ff; /* 2^10 = 1024, 3ff = 1023 */
+ }
+ if (acpt != &me)
+ {
+ acpt->sendB += retval;
+ if (acpt->sendB > 1023)
+ {
+ acpt->sendK += (acpt->sendB >> 10);
+ acpt->sendB &= 0x03ff;
+ }
+ }
+ else if (me.sendB > 1023)
+ {
+ me.sendK += (me.sendB >> 10);
+ me.sendB &= 0x03ff;
+ }
+ }
+ return(retval);
+}
diff --git a/common/bsd_ext.h b/common/bsd_ext.h
new file mode 100644
index 0000000..e1ec689
--- /dev/null
+++ b/common/bsd_ext.h
@@ -0,0 +1,41 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, common/bsd_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in common/bsd.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef BSD_C
+#ifdef DEBUGMODE
+extern int writecalls, writeb[];
+#endif /* DEBUGMODE */
+#endif /* BSD_C */
+
+/* External definitions for global functions.
+ */
+#ifndef BSD_C
+#define EXTERN extern
+#else /* BSD_C */
+#define EXTERN
+#endif /* BSD_C */
+EXTERN RETSIGTYPE dummy __P((int s));
+EXTERN int deliver_it __P((aClient *cptr, char *str, int len));
+#undef EXTERN
diff --git a/common/class_def.h b/common/class_def.h
new file mode 100644
index 0000000..743b672
--- /dev/null
+++ b/common/class_def.h
@@ -0,0 +1,58 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, common/class_def.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.
+ */
+
+typedef struct Class {
+ int class;
+ int conFreq;
+ int pingFreq;
+ int maxLinks;
+ long maxSendq;
+ int maxHLocal;
+ int maxUHLocal;
+ int maxHGlobal;
+ int maxUHGlobal;
+ 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 MaxHLocal(x) ((x)->maxHLocal)
+#define MaxUHLocal(x) ((x)->maxUHLocal)
+#define MaxHGlobal(x) ((x)->maxHGlobal)
+#define MaxUHGlobal(x) ((x)->maxUHGlobal)
+#define Links(x) ((x)->links)
+#define IncSendq(x) MaxSendq(x) = (int)((float)MaxSendq(x) * 1.1)
+
+#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 ConfMaxHLocal(x) (Class(x)->maxHLocal)
+#define ConfMaxUHLocal(x) (Class(x)->maxUHLocal)
+#define ConfMaxHGlobal(x) (Class(x)->maxHGlobal)
+#define ConfMaxUHGlobal(x) (Class(x)->maxUHGlobal)
+
+#define FirstClass() classes
+#define NextClass(x) ((x)->next)
diff --git a/common/common_def.h b/common/common_def.h
new file mode 100644
index 0000000..dff2150
--- /dev/null
+++ b/common/common_def.h
@@ -0,0 +1,88 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, common/common_def.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.
+ */
+
+#ifdef SPRINTF
+#undef SPRINTF
+#endif
+#if ! USE_STDARG
+#define SPRINTF (void) irc_sprintf
+#else
+#define SPRINTF (void) sprintf
+#endif
+
+#define DupString(x,y) do {x = (char *)MyMalloc(strlen((char *)y) + 1);\
+ (void)strcpy((char *)x, (char *)y);\
+ } while(0)
+
+#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
+
+#define PRINT 1
+#define CNTRL 2
+#define ALPHA 4
+#define PUNCT 8
+#define DIGIT 16
+#define SPACE 32
+
+#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) > (u_char)0x5f))
+#define isupper(c) ((char_atribs[(u_char)(c)]&ALPHA) && \
+ ((u_char)(c) < (u_char)0x60))
+#define isdigit(c) (char_atribs[(u_char)(c)]&DIGIT)
+#define isxdigit(c) (isdigit(c) || \
+ ((u_char)'a' <= (u_char)(c) && \
+ (u_char)(c) <= (u_char)'f') || \
+ ((u_char)'A' <= (u_char)(c) && \
+ (u_char)(c) <= (u_char)'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) >= (u_char)'\0') &&*/ \
+ ((u_char)(c) <= (u_char)0x7f))
+#define isgraph(c) ((char_atribs[(u_char)(c)]&PRINT) && \
+ ((u_char)(c) != (u_char)0x20))
+#define ispunct(c) (!(char_atribs[(u_char)(c)]&(CNTRL|ALPHA|DIGIT)))
+
+#ifdef DEBUGMODE
+# define Debug(x) debug x
+# define DO_DEBUG_MALLOC
+#else
+# define Debug(x) ;
+# define LOGFILE "/dev/null"
+#endif
+
+#if defined(CHKCONF_COMPILE) || defined(CLIENT_COMPILE)
+#undef ZIP_LINKS
+#endif
diff --git a/common/dbuf.c b/common/dbuf.c
new file mode 100644
index 0000000..fbb8d97
--- /dev/null
+++ b/common/dbuf.c
@@ -0,0 +1,532 @@
+/************************************************************************
+ * 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: dbuf.c,v 1.8 1997/09/03 17:45:13 kalt Exp $";
+#endif
+
+/*
+** For documentation of the *global* functions implemented here,
+** see the header file (dbuf.h).
+**
+*/
+
+#include "os.h"
+#ifndef CLIENT_COMPILE
+# include "s_defines.h"
+#else
+# include "c_defines.h"
+#endif
+#define DBUF_C
+#ifndef CLIENT_COMPILE
+# include "s_externs.h"
+#else
+# include "c_externs.h"
+#endif
+#undef DBUF_C
+
+#undef VALLOC
+
+#if !defined(VALLOC) && !defined(valloc)
+#define valloc malloc
+#endif
+
+#ifdef CLIENT_COMPILE
+/* kind of ugly, eh? */
+u_int dbufalloc = 0;
+#endif
+
+u_int poolsize = (BUFFERPOOL > 1500000) ? BUFFERPOOL : 1500000;
+dbufbuf *freelist = NULL;
+
+/* dbuf_init--initialize a stretch of memory as dbufs.
+ Doing this early on should save virtual memory if not real memory..
+ at the very least, we get more control over what the server is doing
+
+ mika@cs.caltech.edu 6/24/95
+*/
+
+void dbuf_init()
+{
+ dbufbuf *dbp;
+ int i = 0, nb;
+
+ nb = poolsize / sizeof(dbufbuf);
+ freelist = (dbufbuf *)valloc(nb * sizeof(dbufbuf));
+ if (!freelist)
+ return; /* screw this if it doesn't work */
+ dbp = freelist;
+#ifndef CLIENT_COMPILE
+ for( ; i < (nb - 1); i++, dbp++, istat.is_dbufnow++)
+#else
+ for( ; i < (nb - 1); i++, dbp++)
+#endif
+ dbp->next = (dbp + 1);
+ dbp->next = NULL;
+#ifndef CLIENT_COMPILE
+ istat.is_dbufnow++;
+ istat.is_dbuf = istat.is_dbufnow;
+#endif
+}
+
+/*
+** dbuf_alloc - allocates a dbufbuf structure either from freelist or
+** creates a new one.
+** Return: 0 on success, -1 on fatal alloc error, -2 on pool exceeding
+*/
+static int dbuf_alloc(dbptr)
+dbufbuf **dbptr;
+{
+#if defined(VALLOC) && !defined(DEBUGMODE)
+ Reg dbufbuf *db2ptr;
+ Reg int num;
+#endif
+
+#ifndef CLIENT_COMPILE
+ if (istat.is_dbufuse++ == istat.is_dbufmax)
+ istat.is_dbufmax = istat.is_dbufuse;
+#else
+ dbufalloc++;
+#endif
+ if ((*dbptr = freelist))
+ {
+ freelist = freelist->next;
+ return 0;
+ }
+#ifndef CLIENT_COMPILE
+ if (istat.is_dbufuse * DBUFSIZ > poolsize)
+#else
+ if (dbufalloc * DBUFSIZ > poolsize)
+#endif
+ {
+#ifndef CLIENT_COMPILE
+ istat.is_dbufuse--;
+#else
+ dbufalloc--;
+#endif
+ return -2; /* Not fatal, go back and increase poolsize */
+ }
+
+#if defined(_SC_PAGE_SIZE) && !defined(_SC_PAGESIZE)
+#define _SC_PAGESIZE _SC_PAGE_SIZE
+#endif
+#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;
+
+#ifndef CLIENT_COMPILE
+ istat.is_dbufnow += num;
+#endif
+
+ *dbptr = (dbufbuf *)valloc(num*sizeof(dbufbuf));
+ if (!*dbptr)
+ return -1;
+
+ num--;
+ for (db2ptr = *dbptr; num; num--)
+ {
+ db2ptr = (dbufbuf *)((char *)db2ptr + sizeof(dbufbuf));
+ db2ptr->next = freelist;
+ freelist = db2ptr;
+ }
+ return 0;
+#else
+#ifndef CLIENT_COMPILE
+ istat.is_dbufnow++;
+#endif
+ if (!(*dbptr = (dbufbuf *)MyMalloc(sizeof(dbufbuf))))
+ return -1;
+ return 0;
+#endif
+}
+/*
+** dbuf_free - return a dbufbuf structure to the freelist
+*/
+static void dbuf_free(ptr)
+Reg dbufbuf *ptr;
+{
+#ifndef CLIENT_COMPILE
+ istat.is_dbufuse--;
+#else
+ dbufalloc--;
+#endif
+ 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... ;)
+*/
+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);
+ }
+#ifdef DBUF_TAIL
+ dyn->tail = dyn->head;
+#endif
+ return -1;
+ }
+
+
+/*
+** 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(dyn, buf, length)
+dbuf *dyn; /* Dynamic buffer header */
+char *buf; /* Pointer to data to be stored */
+int length; /* Number of bytes to store */
+{
+ Reg dbufbuf **h;
+ dbufbuf *d;
+#ifdef DBUF_TAIL
+ dbufbuf *dtail;
+ Reg int off;
+#else
+ Reg int nbr, off;
+#endif
+ Reg int chunk, i, dlength;
+
+ dlength = dyn->length;
+
+ off = (dyn->offset + dyn->length) % DBUFSIZ;
+#ifdef DBUF_TAIL
+ dtail = dyn->tail;
+ if (!dyn->length)
+ h = &(dyn->head);
+ else
+ {
+ if (off)
+ h = &(dyn->tail);
+ else
+ h = &(dyn->tail->next);
+ }
+#else
+ /*
+ ** 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.
+ */
+ nbr = (dyn->offset + dyn->length) / DBUFSIZ;
+ for (h = &(dyn->head); (d = *h) && --nbr >= 0; h = &(d->next));
+#endif
+ /*
+ ** 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 ((i = dbuf_alloc(&d)))
+ {
+ if (i == -1) /* out of memory, cleanup */
+ /* modifies dyn->tail */
+ dbuf_malloc_error(dyn);
+ else
+ /* If we run out of bufferpool, visit upper
+ * level to increase it and retry. -Vesa
+ */
+ {
+ /*
+ ** Cancel this dbuf_put as well,
+ ** since it is incomplete. -krys
+ */
+ dyn->length = dlength;
+#ifdef DBUF_TAIL
+ dyn->tail = dtail;
+#endif
+ }
+ return i;
+ }
+#ifdef DBUF_TAIL
+ dyn->tail = d;
+#endif
+ *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;
+ }
+
+
+/*
+** 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(dyn,length)
+dbuf *dyn; /* Dynamic buffer header */
+int *length; /* Return number of bytes accessible */
+ {
+ if (dyn->head == NULL)
+ {
+#ifdef DBUF_TAIL
+ dyn->tail = NULL;
+#endif
+ *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; /* Dynamic buffer header */
+int length; /* Number of bytes to delete */
+ {
+ 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)
+ {
+ if ((d = dyn->head))
+ { /* What did I do? A memory leak.. ? */
+ dyn->head = d->next;
+ dbuf_free(d);
+ }
+ dyn->offset = 0;
+ }
+ chunk = DBUFSIZ;
+ }
+ if (dyn->head == (dbufbuf *)NULL)
+#ifdef DBUF_TAIL
+ {
+ dyn->tail = NULL;
+#endif
+ dyn->length = 0;
+#ifdef DBUF_TAIL
+ }
+#endif
+ return 0;
+ }
+
+/*
+** 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(dyn, buf, length)
+dbuf *dyn; /* Dynamic buffer header */
+char *buf; /* Pointer to buffer to receive the data */
+int length; /* Max amount of bytes that can be received */
+ {
+ 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;
+ }
+
+/*
+int dbuf_copy(dyn, buf, length)
+dbuf *dyn;
+register char *buf;
+int length;
+{
+ register dbufbuf *d = dyn->head;
+ register char *s;
+ register int chunk, len = length, dlen = dyn->length;
+
+ s = d->data + dyn->offset;
+ chunk = MIN(DBUFSIZ - dyn->offset, dlen);
+
+ while (len > 0)
+ {
+ if (chunk > dlen)
+ chunk = dlen;
+ if (chunk > len)
+ chunk = len;
+
+ bcopy(s, buf, chunk);
+ buf += chunk;
+ len -= chunk;
+ dlen -= chunk;
+
+ if (dlen > 0 && (d = d->next))
+ {
+ chunk = DBUFSIZ;
+ s = d->data;
+ }
+ else
+ break;
+ }
+ return length - len;
+}
+*/
+
+/*
+** dbuf_getmsg
+**
+** Check the buffers to see if there is a string which is terminted with
+** either a \r or \n prsent. If so, copy as much as possible (determined by
+** length) into buf and return the amount copied - else return 0.
+*/
+int dbuf_getmsg(dyn, buf, length)
+dbuf *dyn;
+char *buf;
+register int length;
+{
+ dbufbuf *d;
+ register char *s;
+ register int dlen;
+ register int i;
+ int copy;
+
+getmsg_init:
+ d = dyn->head;
+ dlen = dyn->length;
+ i = DBUFSIZ - dyn->offset;
+ if (i <= 0)
+ return -1;
+ copy = 0;
+ if (d && dlen)
+ s = dyn->offset + d->data;
+ else
+ return 0;
+
+ if (i > dlen)
+ i = dlen;
+ while (length > 0 && dlen > 0)
+ {
+ dlen--;
+ if (*s == '\n' || *s == '\r')
+ {
+ copy = dyn->length - dlen;
+ /*
+ ** Shortcut this case here to save time elsewhere.
+ ** -avalon
+ */
+ if (copy == 1)
+ {
+ (void)dbuf_delete(dyn, 1);
+ goto getmsg_init;
+ }
+ break;
+ }
+ length--;
+ if (!--i)
+ {
+ if ((d = d->next))
+ {
+ s = d->data;
+ i = MIN(DBUFSIZ, dlen);
+ }
+ }
+ else
+ s++;
+ }
+
+ if (copy <= 0)
+ return 0;
+
+ /*
+ ** copy as much of the message as wanted into parse buffer
+ */
+ i = dbuf_get(dyn, buf, MIN(copy, length));
+ /*
+ ** and delete the rest of it!
+ */
+ if (copy - i > 0)
+ (void)dbuf_delete(dyn, copy - i);
+ if (i >= 0)
+ *(buf+i) = '\0'; /* mark end of messsage */
+
+ return i;
+}
diff --git a/common/dbuf_def.h b/common/dbuf_def.h
new file mode 100644
index 0000000..1295d2d
--- /dev/null
+++ b/common/dbuf_def.h
@@ -0,0 +1,96 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, common/dbuf_def.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.
+ */
+
+#define DBUF_TAIL
+
+/*
+** 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 */
+#ifdef DBUF_TAIL
+ /* added by mnystrom@mit.edu: */
+ struct dbufbuf *tail; /* last data buffer, if length > 0 */
+#endif
+ } 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 */
+#ifdef DBUF_TAIL
+ /* added by mnystrom@mit.edu: */
+ struct dbufbuf *tail; /* last data buffer, if length > 0 */
+#endif
+ } 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;
+
+/*
+** 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))
+
+/* 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)
diff --git a/common/dbuf_ext.h b/common/dbuf_ext.h
new file mode 100644
index 0000000..da0a659
--- /dev/null
+++ b/common/dbuf_ext.h
@@ -0,0 +1,49 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, common/dbuf_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in common/dbuf.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef DBUF_C
+#ifdef CLIENT_COMPILE
+extern u_int dbufalloc;
+#endif
+extern u_int poolsize;
+extern dbufbuf *freelist;
+#endif /* DBUF_C */
+
+/* External definitions for global functions.
+ */
+#ifndef DBUF_C
+#define EXTERN extern
+#else /* DBUF_C */
+#define EXTERN
+#endif /* DBUF_C */
+EXTERN void dbuf_init();
+EXTERN int dbuf_malloc_error __P((dbuf *dyn));
+EXTERN int dbuf_put __P((dbuf *dyn, char *buf, int length));
+EXTERN char *dbuf_map __P((dbuf *dyn, int *length));
+EXTERN int dbuf_delete __P((dbuf *dyn, int length));
+EXTERN int dbuf_get __P((dbuf *dyn, char *buf, int length));
+EXTERN int dbuf_copy __P((dbuf *dyn, register char *buf, int length));
+EXTERN int dbuf_getmsg __P((dbuf *dyn, char *buf, register int length));
+#undef EXTERN
diff --git a/common/match.c b/common/match.c
new file mode 100644
index 0000000..ad2bda6
--- /dev/null
+++ b/common/match.c
@@ -0,0 +1,314 @@
+/************************************************************************
+ * 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: match.c,v 1.5 1999/02/05 22:00:25 kalt Exp $";
+#endif
+
+#include "os.h"
+#ifndef CLIENT_COMPILE
+# include "s_defines.h"
+#else
+# include "c_defines.h"
+#endif
+#define MATCH_C
+#ifndef CLIENT_COMPILE
+# include "s_externs.h"
+#else
+# include "c_externs.h"
+#endif
+#undef MATCH_C
+
+unsigned 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 };
+
+unsigned 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 };
+
+unsigned 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, PRINT, PRINT,
+/* 0123 */ PRINT|DIGIT, PRINT|DIGIT, PRINT|DIGIT, PRINT|DIGIT,
+/* 4567 */ PRINT|DIGIT, PRINT|DIGIT, PRINT|DIGIT, PRINT|DIGIT,
+/* 89:; */ PRINT|DIGIT, PRINT|DIGIT, PRINT, PRINT,
+/* <=>? */ PRINT, PRINT, PRINT, PRINT,
+/* @ */ PRINT,
+/* ABC */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
+/* DEF */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
+/* GHI */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
+/* JKL */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
+/* MNO */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
+/* PQR */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
+/* STU */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
+/* VWX */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
+/* YZ[ */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
+/* \]^ */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
+/* _ */ PRINT,
+/* abc */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
+/* def */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
+/* ghi */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
+/* jkl */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
+/* mno */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
+/* pqr */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
+/* stu */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
+/* vwx */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
+/* yz{ */ PRINT|ALPHA, PRINT|ALPHA, 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
+ };
+
+#define MAX_ITERATIONS 512
+/*
+** 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()
+** Iterative matching function, rather than recursive.
+** Written by Douglas A Lewis (dalewis@acsu.buffalo.edu)
+*/
+
+int match(mask, name)
+char *mask, *name;
+{
+ Reg u_char *m = (u_char *)mask, *n = (u_char *)name;
+ char *ma = mask, *na = name;
+ int wild = 0, q = 0, calls = 0;
+
+ while (1)
+ {
+#ifdef MAX_ITERATIONS
+ if (calls++ > MAX_ITERATIONS)
+ break;
+#endif
+
+ 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--)
+ ;
+ if ((m > (u_char *)mask) && (*m == '*') &&
+ (m[-1] != '\\'))
+ return 0;
+ if (!wild)
+ return 1;
+ m = (u_char *)ma;
+ n = (u_char *)++na;
+ }
+ else if (!*n)
+ return 1;
+ if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
+ {
+ m++;
+ q = 1;
+ }
+ else
+ 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++;
+ }
+ }
+
+ return 1;
+}
+
+
+/*
+** 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;
+{
+ Reg char *s = pattern, *s1, *t;
+
+ 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;
+ {
+ Reg unsigned char *str1 = (unsigned char *)s1;
+ Reg unsigned char *str2 = (unsigned char *)s2;
+ Reg int res;
+
+ while ((res = toupper(*str1) - toupper(*str2)) == 0)
+ {
+ if (*str1 == '\0')
+ return 0;
+ str1++;
+ str2++;
+ }
+ return (res);
+ }
+
+
+int myncmp(str1, str2, n)
+char *str1;
+char *str2;
+int n;
+ {
+ Reg unsigned char *s1 = (unsigned char *)str1;
+ Reg unsigned char *s2 = (unsigned char *)str2;
+ Reg int res;
+
+ while ((res = toupper(*s1) - toupper(*s2)) == 0)
+ {
+ s1++; s2++; n--;
+ if (n == 0 || (*s1 == '\0' && *s2 == '\0'))
+ return 0;
+ }
+ return (res);
+ }
diff --git a/common/match_ext.h b/common/match_ext.h
new file mode 100644
index 0000000..4953bcf
--- /dev/null
+++ b/common/match_ext.h
@@ -0,0 +1,43 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, common/match_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in common/match.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef MATCH_C
+extern unsigned char tolowertab[];
+extern unsigned char touppertab[];
+extern unsigned char char_atribs[];
+#endif /* MATCH_C */
+
+/* External definitions for global functions.
+ */
+#ifndef MATCH_C
+#define EXTERN extern
+#else /* MATCH_C */
+#define EXTERN
+#endif /* MATCH_C */
+EXTERN int match __P((char *mask, char *name));
+EXTERN char *collapse __P((char *pattern));
+EXTERN int mycmp __P((char *s1, char *s2));
+EXTERN int myncmp __P((char *str1, char *str2, int n));
+#undef EXTERN
diff --git a/common/msg_def.h b/common/msg_def.h
new file mode 100644
index 0000000..9d6096d
--- /dev/null
+++ b/common/msg_def.h
@@ -0,0 +1,77 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, common/msg_def.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.
+ */
+
+#define MSG_PRIVATE "PRIVMSG" /* PRIV */
+#define MSG_WHO "WHO" /* WHO -> WHOC */
+#define MSG_WHOIS "WHOIS" /* WHOI */
+#define MSG_WHOWAS "WHOWAS" /* WHOW */
+#define MSG_USER "USER" /* USER */
+#define MSG_NICK "NICK" /* NICK */
+#define MSG_SERVER "SERVER" /* SERV */
+#define MSG_LIST "LIST" /* LIST */
+#define MSG_TOPIC "TOPIC" /* TOPI */
+#define MSG_INVITE "INVITE" /* INVI */
+#define MSG_VERSION "VERSION" /* VERS */
+#define MSG_QUIT "QUIT" /* QUIT */
+#define MSG_SQUIT "SQUIT" /* SQUI */
+#define MSG_KILL "KILL" /* KILL */
+#define MSG_INFO "INFO" /* INFO */
+#define MSG_LINKS "LINKS" /* LINK */
+#define MSG_SUMMON "SUMMON" /* SUMM */
+#define MSG_STATS "STATS" /* STAT */
+#define MSG_USERS "USERS" /* USER -> USRS */
+#define MSG_HELP "HELP" /* HELP */
+#define MSG_ERROR "ERROR" /* ERRO */
+#define MSG_AWAY "AWAY" /* AWAY */
+#define MSG_CONNECT "CONNECT" /* CONN */
+#define MSG_PING "PING" /* PING */
+#define MSG_PONG "PONG" /* PONG */
+#define MSG_OPER "OPER" /* OPER */
+#define MSG_PASS "PASS" /* PASS */
+#define MSG_WALLOPS "WALLOPS" /* WALL */
+#define MSG_TIME "TIME" /* TIME */
+#define MSG_NAMES "NAMES" /* NAME */
+#define MSG_ADMIN "ADMIN" /* ADMI */
+#define MSG_TRACE "TRACE" /* TRAC */
+#define MSG_NOTICE "NOTICE" /* NOTI */
+#define MSG_JOIN "JOIN" /* JOIN */
+#define MSG_NJOIN "NJOIN" /* NJOIN */
+#define MSG_PART "PART" /* PART */
+#define MSG_LUSERS "LUSERS" /* LUSE */
+#define MSG_MOTD "MOTD" /* MOTD */
+#define MSG_MODE "MODE" /* MODE */
+#define MSG_UMODE "UMODE" /* UMOD */
+#define MSG_KICK "KICK" /* KICK */
+#define MSG_RECONECT "RECONNECT" /* RECONNECT -> RECO */
+#define MSG_SERVICE "SERVICE" /* SERV -> SRVI */
+#define MSG_USERHOST "USERHOST" /* USER -> USRH */
+#define MSG_ISON "ISON" /* ISON */
+#define MSG_NOTE "NOTE" /* NOTE */
+#define MSG_SQUERY "SQUERY" /* SQUE */
+#define MSG_SERVLIST "SERVLIST" /* SERV -> SLIS */
+#define MSG_SERVSET "SERVSET" /* SERV -> SSET */
+#define MSG_REHASH "REHASH" /* REHA */
+#define MSG_RESTART "RESTART" /* REST */
+#define MSG_CLOSE "CLOSE" /* CLOS */
+#define MSG_DIE "DIE"
+#define MSG_HASH "HAZH" /* HASH */
+#define MSG_DNS "DNS" /* DNS -> DNSS */
+
+#define MAXPARA 15
diff --git a/common/numeric_def.h b/common/numeric_def.h
new file mode 100644
index 0000000..c1b095c
--- /dev/null
+++ b/common/numeric_def.h
@@ -0,0 +1,337 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, common/numeric_def.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.
+ */
+
+/*
+ * -- Avalon -- 1 Sep 1992
+ *
+ * Added RPL_TRACELOG, RPL_STATSOLINE
+ */
+
+/*
+ * -- Avalon -- 13 Aug 1992
+ *
+ * Added ERR_BADCHANNELKEY, ERR_KEYSET
+ */
+
+/*
+ * -- Avalon -- 10 Aug 1992
+ *
+ * Added RPL_SUMMONING
+ */
+
+/*
+ * -- Avalon -- 5 Jul 1992
+ *
+ * Added ERR_NICKCOLLISION
+ */
+
+/*
+ * -- Avalon -- 14 Jul 1992
+ *
+ * Added RPL_UNAWAY, RPL_NOWAWAY, ERR_NOORIGIN, ERR_FILEERROR, ERR_NOLOGIN,
+ * ERR_SUMMONDISABLED, ERR_USERSDISABLED, RPL_USERSSTART, RPL_USERS,
+ * RPL_ENDOFUSERS, RPL_NOUSERS
+ */
+
+/*
+ * -- Avalon -- 12 Jul 1992
+ *
+ * Added RPL_CLOSING RPL_CLOSEEND
+ */
+
+/*
+ * -- Avalon -- 10-11 Jul 1992
+ *
+ * Added RPL_MOTD, RPL_MOTDSTART, RPL_ENDOFMOTD, ERR_NOMOTD,
+ * RPL_INFO, RPL_INFOSTART, RPL_ENDOFINFO, ERR_CANTKILLSERVER,
+ * RPL_LUSERCLIENT, RPL_LUSEROP, RPL_LUSERUNKNOWN, RPL_LUSERCHAN, RPL_LUSERME,
+ * RPL_STATSUPTIME, RPL_ADMINLOC1, RPL_ADMINLOC2, RPL_ADMINME,
+ * RPL_ADMINEMAIL, ERR_NOADMININFO
+ */
+
+/*
+ * -- Avalon -- 28 Jun 1992
+ *
+ * Added ERR_BADCHANMASK and RPL_ENDOFWHOWAS
+ */
+
+/*
+ * -- Avalon -- 13 May 1992
+ *
+ * Added RPL_STATSLLINE
+ */
+
+/*
+ * -- Avalon -- 12 Jan 1992
+ *
+ * Added RPL_TRACELINK
+ */
+
+/*
+ * -- Wumpus -- 30 Nov 1991
+ *
+ * It's very important that you never change what a numeric means --
+ * you can delete old ones (maybe) and add new ones, but never ever
+ * take a number and make it suddenly mean something else, or change
+ * an old number just for the hell of it.
+ */
+
+/*
+ * -- avalon -- 19 Nov 1991
+ * Added ERR_USERSDONTMATCH
+ *
+ * -- avalon -- 06 Nov 1991
+ * Added RPL_BANLIST, RPL_BANLISTEND, ERR_BANNEDFROMCHAN
+ *
+ * -- avalon -- 15 Oct 1991
+ * Added RPL_TRACEs (201-209)
+ * Added RPL_STATSs (211-219)
+ */
+
+/* -- Jto -- 16 Jun 1990
+ * A couple of new numerics added...
+ */
+
+/* -- Jto -- 03 Jun 1990
+ * Added ERR_YOUWILLBEBANNED and Check defines (sigh, had to put 'em here..)
+ * Added ERR_UNKNOWNMODE...
+ * Added ERR_CANNOTSENDTOCHAN...
+ */
+
+/*
+ * 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_BOUNCE 005
+
+/*
+ * Errors are in the range from 400-599 currently and are grouped by what
+ * commands they come from.
+ */
+#define ERR_NOSUCHNICK 401
+#define ERR_NOSUCHSERVER 402
+#define ERR_NOSUCHCHANNEL 403
+#define ERR_CANNOTSENDTOCHAN 404
+#define ERR_TOOMANYCHANNELS 405
+#define ERR_WASNOSUCHNICK 406
+#define ERR_TOOMANYTARGETS 407
+#define ERR_NOSUCHSERVICE 408
+#define ERR_NOORIGIN 409
+
+#define ERR_NORECIPIENT 411
+#define ERR_NOTEXTTOSEND 412
+#define ERR_NOTOPLEVEL 413
+#define ERR_WILDTOPLEVEL 414
+#define ERR_BADMASK 415
+#define ERR_TOOMANYMATCHES 416
+
+#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_UNAVAILRESOURCE 437
+/* #define ERR_DEAD 438 reserved for later use -krys */
+
+#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_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_CHANNELISFULL 471
+#define ERR_UNKNOWNMODE 472
+#define ERR_INVITEONLYCHAN 473
+#define ERR_BANNEDFROMCHAN 474
+#define ERR_BADCHANNELKEY 475
+#define ERR_BADCHANMASK 476
+#define ERR_NOCHANMODES 477
+#define ERR_BANLISTFULL 478
+
+#define ERR_NOPRIVILEGES 481
+#define ERR_CHANOPRIVSNEEDED 482
+#define ERR_CANTKILLSERVER 483
+#define ERR_RESTRICTED 484
+#define ERR_UNIQOPRIVSNEEDED 485
+
+#define ERR_NOOPERHOST 491
+#define ERR_NOSERVICEHOST 492
+
+#define ERR_UMODEUNKNOWNFLAG 501
+#define ERR_USERSDONTMATCH 502
+
+/*
+ * 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_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_LISTSTART 321
+#define RPL_LIST 322
+#define RPL_LISTEND 323
+#define RPL_CHANNELMODEIS 324
+#define RPL_UNIQOPIS 325
+
+#define RPL_NOTOPIC 331
+#define RPL_TOPIC 332
+
+#define RPL_INVITING 341
+#define RPL_SUMMONING 342
+
+#define RPL_INVITELIST 346
+#define RPL_ENDOFINVITELIST 347
+
+#define RPL_EXCEPTLIST 348
+#define RPL_ENDOFEXCEPTLIST 349
+
+#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_YOUREOPER 381
+#define RPL_REHASHING 382
+#define RPL_YOURESERVICE 383
+#define RPL_MYPORTIS 384
+#define RPL_NOTOPERANYMORE 385
+
+#define RPL_TIME 391
+#define RPL_USERSSTART 392
+#define RPL_USERS 393
+#define RPL_ENDOFUSERS 394
+#define RPL_NOUSERS 395
+
+#define RPL_TRACELINK 200
+#define RPL_TRACECONNECTING 201
+#define RPL_TRACEHANDSHAKE 202
+#define RPL_TRACEUNKNOWN 203
+#define RPL_TRACEOPERATOR 204
+#define RPL_TRACEUSER 205
+#define RPL_TRACESERVER 206
+#define RPL_TRACESERVICE 207
+#define RPL_TRACENEWTYPE 208
+#define RPL_TRACECLASS 209
+#define RPL_TRACERECONNECT 210
+
+#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_UMODEIS 221
+
+#define RPL_SERVICEINFO 231
+#define RPL_ENDOFSERVICES 232
+#define RPL_SERVICE 233
+#define RPL_SERVLIST 234
+#define RPL_SERVLISTEND 235
+
+#define RPL_STATSIAUTH 239
+#define RPL_STATSVLINE 240
+#define RPL_STATSLLINE 241
+#define RPL_STATSUPTIME 242
+#define RPL_STATSOLINE 243
+#define RPL_STATSHLINE 244
+#define RPL_STATSSLINE 245
+#define RPL_STATSPING 246
+#define RPL_STATSBLINE 247
+#define RPL_STATSDEFINE 248
+#define RPL_STATSDEBUG 249
+#define RPL_STATSDLINE 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_TRACEEND 262
+#define RPL_TRYAGAIN 263
+
diff --git a/common/os.h b/common/os.h
new file mode 100644
index 0000000..a556764
--- /dev/null
+++ b/common/os.h
@@ -0,0 +1,765 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, include/os.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains the various system-relative "#include" lines needed for
+ getting all system types, macros, external variables and functions defined.
+
+ This file also contains definitions of types, constants, macros, external
+ variables and functions that are missing in the include files of some OS,
+ or need to be redefined for various reasons.
+ */
+
+#include "setup.h"
+
+#if HAVE_STDIO_H
+# include <stdio.h>
+#endif
+
+#if HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#if HAVE_SYS_BITYPES_H
+# include <sys/bitypes.h>
+#endif
+
+#if HAVE_STDDEF_H
+# include <stddef.h>
+#endif
+
+#if USE_STDARG
+# include <stdarg.h>
+#endif
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if HAVE_CTYPE_H
+# include <ctype.h>
+#endif
+
+#if HAVE_MEMORY_H
+# include <memory.h>
+#endif
+
+#if HAVE_VFORK_H
+# include <vfork.h>
+#endif
+
+#if HAVE_ERRNO_H
+# include <errno.h>
+#endif
+
+#if HAVE_SYS_ERRNO_H
+# include <sys/errno.h>
+#endif
+
+#if HAVE_SYS_SYSCALL_H
+# include <sys/syscall.h>
+#endif
+
+#if HAVE_PWD_H
+# include <pwd.h>
+#endif
+
+#if HAVE_MATH_H
+# include <math.h>
+#endif
+
+#if HAVE_UTMP_H
+# include <utmp.h>
+#endif
+
+#if HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#if HAVE_SIGNAL_H
+# include <signal.h>
+#endif
+
+#if HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+
+#if HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+
+#if HAVE_SYS_FILE_H
+# include <sys/file.h>
+#endif
+
+#if HAVE_SYS_FILIO_H
+# include <sys/filio.h>
+#endif
+
+#if HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+
+#if HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif
+
+#if HAVE_SYS_POLL_H
+# if linux
+/* Linux is just soooo broken */
+# define _GNU_SOURCE 1
+# endif
+# include <sys/poll.h>
+# if linux && !defined(POLLRDNORM)
+/* Linux 2.1.xx supports poll(), header files are not upto date yet */
+# define POLLRDNORM 0x0040
+# endif
+#endif
+
+#if HAVE_STROPTS_H
+# include <stropts.h>
+#endif
+
+#if HAVE_NETDB_H
+# if BAD___CONST_NETDB_H
+# ifndef __const
+# define __const
+# include <netdb.h>
+# undef __const
+# else
+# include <netdb.h>
+# endif
+# else
+# include <netdb.h>
+# endif
+#endif
+
+#if HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#if HAVE_SYS_UN_H
+# include <sys/un.h>
+#endif
+
+#if HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+
+#if HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+
+#if HAVE_SYS_SYSLOG_H
+# include <sys/syslog.h>
+#else
+# if HAVE_SYSLOG_H
+# include <syslog.h>
+# endif
+#endif
+
+#if HAVE_STRING_H
+# include <string.h>
+#else
+# if HAVE_STRINGS_H
+# include <strings.h>
+# endif
+#endif
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#if HAVE_SYS_RESOURCE_H
+# include <sys/resource.h>
+#endif
+
+#if HAVE_SYS_TIMES_H
+# include <sys/times.h>
+#endif
+
+#if HAVE_NETINET_IN_SYSTM_H
+# include <netinet/in_systm.h>
+#endif
+
+#if HAVE_NETINFO_NI_H
+# include <netinfo/ni.h>
+#endif
+
+#if USE_ZLIB && !defined(CLIENT_COMPILE) && !defined(CHKCONF_COMPILE) && \
+ !defined(CONTRIB_COMPILE)
+# include <zlib.h>
+#endif
+
+#if defined(INET6) && defined(CLIENT_COMPILE)
+# if (defined(linux) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__osf__)) && \
+ HAVE_RESOLV_H
+# include <resolv.h>
+# endif
+# if HAVE_ARPA_NAMESER_H
+# include <arpa/nameser.h>
+# endif
+#endif
+
+#if defined(HAVE_DLFCN_H)
+# include <dlfcn.h>
+#endif
+
+#if (defined(__FreeBSD__) ||\
+ defined(__OpenBSD__) ||\
+ defined(__NetBSD__) ) && !defined(__ELF__)
+# define DLSYM_NEEDS_UNDERSCORE
+#endif
+
+/* Some special include files for a special OS. :)
+ */
+
+#ifdef ISC
+# include <sys/bsdtypes.h>
+# include <sys/sioctl.h>
+# include <sys/stream.h>
+# include <net/errno.h>
+#endif
+
+/* Definition of __P for handling possible prototype-syntax problems.
+ */
+
+#ifdef __P
+# undef __P
+#endif
+#if __STDC__
+# define __P(x) x
+#else
+# define __P(x) ()
+#endif
+
+/* Some additional system-relative defines that make the code easier.
+ *
+ * Note. In fact, the C code should never use system-specific tests; as you
+ * know, numerous people worked on it in the past, so now it is
+ * difficult for me to know why such tests are used in the code. But I
+ * still hope this part of the include file will be cleaned up in
+ * further releases. -- Alain.Nissen@ulg.ac.be
+ */
+
+#if defined(ultrix) || defined(__ultrix) || defined(__ultrix__)
+# ifdef ULTRIX
+# undef ULTRIX
+# endif
+# define ULTRIX
+#endif
+
+#if defined(aix) || defined(_AIX)
+# ifdef AIX
+# undef AIX
+# endif
+# define AIX
+#endif
+
+#if defined(sgi) || defined(__sgi) || defined(__sgi__)
+# ifdef SGI
+# undef SGI
+# endif
+# define SGI
+#endif
+
+#ifdef NeXT
+# ifdef NEXT
+# undef NEXT
+# endif
+# define NEXT
+#endif
+
+#if defined(hpux) || defined(__hpux)
+# ifdef HPUX
+# undef HPUX
+# endif
+# define HPUX
+#endif
+
+#if defined(_SVR4) || defined(__SVR4) || defined(__SVR4__) || defined(__svr4__)
+# ifdef SVR4
+# undef SVR4
+# endif
+# define SVR4
+#endif
+
+#ifdef __osf__
+# ifdef OSF
+# undef OSF
+# endif
+# define OSF
+# ifndef BSD
+# define BSD 1
+# endif
+#endif
+
+#if defined(sequent) || defined(__sequent) || defined(__sequent)
+# ifdef _SEQUENT_
+# undef _SEQUENT_
+# endif
+# define _SEQUENT_
+# undef BSD
+# define SYSV
+# define DYNIXPTX
+#endif
+
+#if defined(mips) || defined(PCS)
+#undef SYSV
+#endif
+
+#ifdef MIPS
+#undef BSD
+#define BSD 1 /* mips only works in bsd43 environment */
+#endif
+
+#define Reg register
+
+/* Strings and memory functions portability problems.
+ */
+
+#if HAVE_MEMCMP && MEMCMP_BROKEN
+# define memcmp irc_memcmp
+#endif
+
+#if HAVE_STRCHR
+# ifdef index
+# undef index
+# endif
+# define index strchr
+#endif
+
+#if HAVE_STRRCHR
+# ifdef rindex
+# undef rindex
+# endif
+# define rindex strrchr
+#endif
+
+#if ! HAVE_STRCHR && HAVE_INDEX
+# ifdef strchr
+# undef strchr
+# endif
+# define strchr index
+#endif
+
+#if ! HAVE_STRRCHR && HAVE_RINDEX
+# ifdef strrchr
+# undef strrchr
+# endif
+# define strrchr rindex
+#endif
+
+#if HAVE_MEMCMP
+# ifdef bcmp
+# undef bcmp
+# endif
+# define bcmp memcmp
+#endif
+
+#if HAVE_MEMSET
+# ifdef bzero
+# undef bzero
+# endif
+# define bzero(a,b) memset((a),0,(b))
+#endif
+
+#if HAVE_MEMMOVE
+# ifdef bcopy
+# undef bcopy
+# endif
+# define bcopy(a,b,c) memmove((b),(a),(c))
+#endif
+
+#if ! HAVE_MEMCMP && HAVE_BCMP
+# ifdef memcmp
+# undef memcmp
+# endif
+# define memcmp bcmp
+#endif
+
+#if ! HAVE_MEMCPY && HAVE_BCOPY
+# ifdef memcpy
+# undef memcpy
+# endif
+# define memcpy(d,s,n) bcopy((s),(d),(n))
+#endif
+
+#define strcasecmp mycmp
+#define strncasecmp myncmp
+
+/* inet_ntoa(), inet_aton(), inet_addr() and inet_netof() portability
+ * problems.
+ *
+ * The undefs and prototypes are "needed" because of the way Paul Vixie
+ * majorly screws up system's include files with Bind. In this case, it's
+ * Bind 8.x installing /usr[/local]/include/arpa/inet.h -krys
+ */
+
+#if HAVE_INET_NTOA
+# ifdef inet_ntoa
+# undef inet_ntoa
+extern char *inet_ntoa __P((struct in_addr in));
+# endif
+# define inetntoa(x) inet_ntoa(*(struct in_addr *)(x))
+#endif
+#if HAVE_INET_ATON
+# ifdef inet_aton
+# undef inet_aton
+extern int inet_aton __P((const char *cp, struct in_addr *addr));
+# endif
+# define inetaton inet_aton
+#endif
+#if HAVE_INET_ADDR
+# ifdef inet_addr
+# undef inet_addr
+extern unsigned long int inet_addr __P((const char *cp));
+# endif
+# define inetaddr inet_addr
+#endif
+#if HAVE_INET_NETOF
+# ifdef inet_netof
+# undef inet_netof
+extern int inet_netof __P((struct in_addr in));
+# endif
+# define inetnetof inet_netof
+#endif
+#if ! HAVE_ARPA_INET_H
+extern unsigned long int inet_addr __P((const char *cp));
+extern int inet_aton __P((const char *cp, struct in_addr *addr));
+extern int inet_netof __P((struct in_addr in));
+extern char *inet_ntoa __P((struct in_addr in));
+#endif
+
+/* Signals portability problems.
+ */
+
+#ifdef HPUX
+# ifndef SIGWINCH /*pre 9.0*/
+# define SIGWINCH SIGWINDOW
+# endif
+#endif
+
+#if BSD_RELIABLE_SIGNALS || POSIX_SIGNALS
+#define HAVE_RELIABLE_SIGNALS
+#endif
+
+/* Curses/Termcap portability problems (client only).
+ */
+
+#ifdef CLIENT_COMPILE
+#if USE_NCURSES || USE_CURSESX || USE_CURSES
+# define DOCURSES
+# if USE_CURSESX && HAVE_CURSESX_H
+# include <cursesX.h>
+# endif
+# if (USE_NCURSES || USE_CURSES) && HAVE_CURSES_H
+# if HAVE_NCURSES_H
+# include <ncurses.h>
+# else
+# include <curses.h>
+# endif
+# endif
+#else
+# undef DOCURSES
+#endif /* USE_NCURSES || ... */
+
+#if USE_TERMCAP
+# define DOTERMCAP
+# if HAVE_SGTTY_H
+# include <sgtty.h>
+# endif
+#else
+# undef DOTERMCAP
+#endif /* USE_TERMCAP */
+#endif /* CLIENT_COMPILE */
+
+/* ctime portability problems.
+ */
+
+#if defined(HPUX) && __STDC__
+# define ctime(x) (ctime((const time_t *)(x)))
+#endif
+
+/* getsockopt portability problems.
+ */
+
+#ifdef apollo
+# undef IP_OPTIONS /* Defined in /usr/include/netinet/in.h but doesn't work */
+#endif
+
+/* setlinebuf portability problems.
+ */
+
+#if defined(HPUX) && !defined(SYSV) && !defined(SVR4) || defined(__CYGWIN32__)
+# define setlinebuf(x) (setvbuf((x), NULL, _IOLBF, BUFSIZ))
+#endif
+
+
+/* gethostbyname portability problems.
+ */
+
+#if SOLARIS_2_0_2_1_2_2
+/*
+ * On Solaris 2.0, 2.1 and 2.2 (SunOS 5.0, 5.1 and 5.2) systems,
+ * gethostbyname() has a bug, it always returns null in h->aliases.
+ * Workaround: use the undocumented __switch_gethostbyname(...).
+ */
+extern struct hostent *__switch_gethostbyname __P((const char *name));
+#define gethostbyname __switch_gethostbyname
+#endif
+
+#if SOLARIS_2_3
+/*
+ * On Solaris 2.3 (SunOS 5.3) systems, gethostbyname() has a bug, it always
+ * returns null in h->aliases. Workaround: use the undocumented
+ * _switch_gethostbyname_r(...).
+ */
+extern struct hostent *_switch_gethostbyname_r __P((const char *name,
+ struct hostent *hp,
+ char *buf, int size,
+ int *h_errno));
+#define gethostbyname solaris_gethostbyname
+#endif
+
+/* Resolver portability problems.
+ */
+
+#ifdef __m88k__
+# define __BIND_RES_TEXT
+#endif
+
+#ifndef NETDB_INTERNAL /* defined in latest BIND's <netdb.h> */
+# define NETDB_INTERNAL -1 /* but not in every vendors' <netdb.h> */
+#endif
+
+/* getrusage portability problems.
+ */
+
+#if defined(HPUX) && ! HAVE_GETRUSAGE
+# define getrusage(a,b) (syscall(SYS_GETRUSAGE, (a), (b)))
+# define HAVE_GETRUSAGE 1
+#endif
+
+/* select portability problems - some systems do not define FD_... macros; on
+ * some systems (for example HPUX), select uses an int * instead of an
+ * fd_set * for its 2nd, 3rd and 4th arguments.
+ *
+ * Note. This test should be more portable and put in configure ... but I've
+ * no idea on how to build a test for configure that will guess if the
+ * system uses int * or fd_set * inside select(). If you've some idea,
+ * please tell it to me. :) -- Alain.Nissen@ulg.ac.be
+ */
+
+#if ! USE_POLL
+# 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 /* FD_ZERO */
+# if defined(HPUX) && (! defined(_XPG4_EXTENDED) || (defined(_XPG4_EXTENDED) && defined(__INCLUDE_FROM_TIME_H) && !defined(_XOPEN_SOURCE_EXTENDED)))
+# define SELECT_FDSET_TYPE int
+# else
+# define SELECT_FDSET_TYPE fd_set
+# endif
+#else /* should not be here - due to irc/c_bsd.c that does not support poll */
+# define SELECT_FDSET_TYPE fd_set
+#endif /* USE_POLL */
+
+/* <sys/wait.h> POSIX.1 portability problems - HAVE_SYS_WAIT_H is defined
+ * only if <sys/wait.h> is compatible with POSIX.1 - if not included, a
+ * prototype must be supplied for wait (wait3 and waitpid are unused here).
+ */
+
+#if ! HAVE_SYS_WAIT_H
+# if USE_UNION_WAIT
+extern pid_t wait __P((union wait *));
+# else
+extern pid_t wait __P((int *));
+# endif
+#endif
+
+/* <sys/socket.h> portability problems - X/Open SPEC 1170 specifies that
+ * the length parameter of socket operations must be a size_t
+ * (resp. size_t *), instead of an int (resp. int *); the problem is that
+ * only a few systems (for example AIX 4.2) follow this specification; others
+ * systems still use int (resp. int *), which is not always equal to size_t
+ * (resp. size_t *).
+ *
+ * Note. This test should be more portable and put in configure ... but I've
+ * no idea on how to build a test for configure that will guess if the
+ * system uses size_t or int for their socket operations. If you've some
+ * idea, please tell it to me. :) -- Alain.Nissen@ulg.ac.be
+ */
+
+#if defined(AIX) && defined(_XOPEN_SOURCE_EXTENDED) && _XOPEN_SOURCE_EXTENDED
+# define SOCK_LEN_TYPE size_t
+#else
+# define SOCK_LEN_TYPE int
+#endif
+
+/* Stupid typo in AIX 3.2's <sys/stropts.h>.
+ */
+
+#if AIX_3_2
+# ifdef _IO
+# undef _IO
+# endif
+# define _IO(x,y) (IOC_VOID|((x)<<8)|(y))
+#endif
+
+/* These macros may be broken.
+ */
+
+#if STAT_MACROS_BROKEN
+# ifdef S_ISFIFO
+# undef S_ISFIFO
+# endif
+# define S_ISFIFO(m) (((m)&(_S_IFMT)) == (_S_IFIFO))
+# ifdef S_ISDIR
+# undef S_ISDIR
+# endif
+# define S_ISDIR(m) (((m)&(_S_IFMT)) == (_S_IFDIR))
+# ifdef S_ISCHR
+# undef S_ISCHR
+# endif
+# define S_ISCHR(m) (((m)&(_S_IFMT)) == (_S_IFCHR))
+# ifdef S_ISBLK
+# undef S_ISBLK
+# endif
+# define S_ISBLK(m) (((m)&(_S_IFMT)) == (_S_IFBLK))
+# ifdef S_ISREG
+# undef S_ISREG
+# endif
+# define S_ISREG(m) (((m)&(_S_IFMT)) == (_S_IFREG))
+#endif
+
+/* These constants may be missing.
+ */
+
+#ifndef NULL
+#define NULL 0
+#endif
+#ifdef FALSE
+#undef FALSE
+#endif
+#define FALSE (0)
+#ifdef TRUE
+#undef TRUE
+#endif
+#define TRUE (!FALSE)
+
+/* These macros may be missing.
+ */
+
+#ifndef MAX
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+#ifndef MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+/* These external may be missing.
+ */
+
+#if ! SYS_ERRLIST_DECLARED
+extern char *sys_errlist[];
+#endif
+
+#if ! SYS_NERR_DECLARED
+extern int sys_nerr;
+#endif
+
+#if ! ERRNO_DECLARED
+extern int errno;
+#endif
+
+#if ! H_ERRNO_DECLARED
+extern int h_errno;
+#endif
+
+/*
+ * IPv4 or IPv6 structures?
+ */
+
+#ifdef INET6
+
+# define AND16(x) ((x)[0]&(x)[1]&(x)[2]&(x)[3]&(x)[4]&(x)[5]&(x)[6]&(x)[7]&(x)[8]&(x)[9]&(x)[10]&(x)[11]&(x)[12]&(x)[13]&(x)[14]&(x)[15])
+static unsigned char minus_one[]={ 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 0};
+# define WHOSTENTP(x) ((x)[0]|(x)[1]|(x)[2]|(x)[3]|(x)[4]|(x)[5]|(x)[6]|(x)[7]|(x)[8]|(x)[9]|(x)[10]|(x)[11]|(x)[12]|(x)[13]|(x)[14]|(x)[15])
+
+# define AFINET AF_INET6
+# define SOCKADDR_IN sockaddr_in6
+# define SOCKADDR sockaddr
+# define SIN_FAMILY sin6_family
+# define SIN_PORT sin6_port
+# define SIN_ADDR sin6_addr
+# define S_ADDR s6_addr
+# define IN_ADDR in6_addr
+
+# ifndef uint32_t
+# define uint32_t __u32
+# endif
+
+# define MYDUMMY_SIZE 128
+char mydummy[MYDUMMY_SIZE];
+char mydummy2[MYDUMMY_SIZE];
+
+# if defined(linux) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(bsdi)
+# ifndef s6_laddr
+# define s6_laddr s6_addr32
+# endif
+# endif
+
+# if defined(linux)
+static const struct in6_addr in6addr_any={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0};
+# endif
+
+# define IRCDCONF_DELIMITER '%'
+
+#else
+# define AFINET AF_INET
+# define SOCKADDR_IN sockaddr_in
+# define SOCKADDR sockaddr
+# define SIN_FAMILY sin_family
+# define SIN_PORT sin_port
+# define SIN_ADDR sin_addr
+# define S_ADDR s_addr
+# define IN_ADDR in_addr
+
+# define WHOSTENTP(x) (x)
+# define IRCDCONF_DELIMITER ':'
+#endif
diff --git a/common/packet.c b/common/packet.c
new file mode 100644
index 0000000..75bc2e6
--- /dev/null
+++ b/common/packet.c
@@ -0,0 +1,197 @@
+/************************************************************************
+ * 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: packet.c,v 1.8 1999/04/19 22:26:22 kalt Exp $";
+#endif
+
+#include "os.h"
+#ifndef CLIENT_COMPILE
+# include "s_defines.h"
+#else
+# include "c_defines.h"
+#endif
+#define PACKET_C
+#ifndef CLIENT_COMPILE
+# include "s_externs.h"
+#else
+# include "c_externs.h"
+#endif
+#undef PACKET_C
+
+/*
+** 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
+**
+** The buffer might be partially or totally zipped.
+** At the beginning of the compressed flow, it is possible that
+** an uncompressed ERROR message will be found. This occurs when
+** the connection fails on the other server before switching
+** to compressed mode.
+**
+** 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)
+Reg aClient *cptr;
+char *buffer;
+Reg int length;
+{
+ Reg char *ch1;
+ Reg char *ch2, *bufptr;
+ aClient *acpt = cptr->acpt;
+ int r = 1;
+#ifdef ZIP_LINKS
+ int unzipped = 0;
+#endif
+
+ 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;
+ }
+
+ bufptr = cptr->buffer;
+ ch1 = bufptr + cptr->count;
+ ch2 = buffer;
+
+#ifdef ZIP_LINKS
+ while ((length > 0 && ch2) || ((cptr->flags & FLAGS_ZIP) &&
+ (cptr->zip->in->avail_in ||
+ !unzipped)))
+#else
+ while (length > 0 && ch2)
+#endif
+ {
+ Reg char c;
+
+#ifdef ZIP_LINKS
+ if (cptr->flags & FLAGS_ZIPSTART)
+ {
+ /*
+ ** beginning of server connection, the buffer
+ ** contained PASS/SERVER and is now zipped!
+ ** Ignore the '\n' that should be here.
+ */
+ if (*ch2 == '\n') /* also check \r ? */
+ {
+ ch2++;
+ length--;
+ cptr->flags &= ~FLAGS_ZIPSTART;
+ }
+ if (length == 0)
+ return 1;
+ }
+
+ if ((cptr->flags & FLAGS_ZIP) && !(unzipped && length))
+ {
+ /* uncompressed buffer first */
+ unzipped = length; /* length is register, store
+ temp in unzipped */
+ ch2 = unzip_packet(cptr, ch2, &unzipped);
+ length = unzipped;
+ unzipped = 1;
+ if (length == -1)
+ return exit_client(cptr, cptr, &me,
+ "fatal error in unzip_packet()");
+ if (length == 0 || *ch2 == '\0')
+ break;
+ }
+#endif
+ length--;
+ c = (*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 ((c <= '\r') && (c == '\n' || c == '\r'))
+ {
+ if (ch1 == bufptr)
+ 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 ((r = parse(cptr, bufptr, ch1)) ==
+ FLUSH_BUFFER)
+ /*
+ ** FLUSH_BUFFER means actually that cptr
+ ** structure *does* not exist anymore!!! --msa
+ */
+ return FLUSH_BUFFER;
+#ifndef CLIENT_COMPILE
+ /*
+ ** Socket is dead so exit (which always returns with
+ ** FLUSH_BUFFER here). - avalon
+ */
+ if (cptr->flags & FLAGS_DEADSOCKET)
+ {
+ if (cptr->exitc == EXITC_REG)
+ cptr->exitc = EXITC_DEAD;
+ return exit_client(cptr, cptr, &me,
+ "Dead Socket");
+ }
+ /*
+ ** Something is wrong, really wrong, and nothing
+ ** else should be allowed to be parsed!
+ ** This covers a bug which is somewhere else,
+ ** since no decent server would send such thing
+ ** as an unknown command. -krys
+ */
+ if (IsServer(cptr) && (cptr->flags & FLAGS_UNKCMD))
+ break;
+#endif
+ ch1 = bufptr;
+ }
+ else if (ch1 < bufptr + (sizeof(cptr->buffer)-1))
+ ch1++; /* There is always room for the null */
+ }
+ cptr->count = ch1 - bufptr;
+ return r;
+}
diff --git a/common/packet_ext.h b/common/packet_ext.h
new file mode 100644
index 0000000..9493fc8
--- /dev/null
+++ b/common/packet_ext.h
@@ -0,0 +1,32 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, common/packet_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in common/packet.c.
+ */
+
+/* External definitions for global functions.
+ */
+#ifndef PACKET_C
+#define EXTERN extern
+#else /* PACKET_C */
+#define EXTERN
+#endif /* PACKET_C */
+EXTERN int dopacket __P((Reg aClient *cptr, char *buffer, Reg int length));
+#undef EXTERN
diff --git a/common/parse.c b/common/parse.c
new file mode 100644
index 0000000..9bb496c
--- /dev/null
+++ b/common/parse.c
@@ -0,0 +1,786 @@
+/************************************************************************
+ * 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: parse.c,v 1.25 1999/04/14 17:29:36 kalt Exp $";
+#endif
+
+#include "os.h"
+#ifndef CLIENT_COMPILE
+# include "s_defines.h"
+#else
+# include "c_defines.h"
+#endif
+#define PARSE_C
+#ifndef CLIENT_COMPILE
+# include "s_externs.h"
+#else
+# include "c_externs.h"
+#endif
+#undef PARSE_C
+
+struct Message msgtab[] = {
+ { MSG_PRIVATE, m_private, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L},
+#ifndef CLIENT_COMPILE
+ { MSG_NJOIN, m_njoin, MAXPARA, MSG_LAG|MSG_NOU, 0, 0, 0L},
+#endif
+ { MSG_JOIN, m_join, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L},
+ { MSG_MODE, m_mode, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L},
+ { MSG_NICK, m_nick, MAXPARA, MSG_LAG, 0, 0, 0L},
+ { MSG_PART, m_part, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L},
+ { MSG_QUIT, m_quit, MAXPARA, MSG_LAG, 0, 0, 0L},
+ { MSG_NOTICE, m_notice, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L},
+ { MSG_KICK, m_kick, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L},
+ { MSG_SERVER, m_server, MAXPARA, MSG_LAG|MSG_NOU, 0, 0, 0L},
+#ifndef CLIENT_COMPILE
+ { MSG_TRACE, m_trace, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L},
+#endif
+ { MSG_TOPIC, m_topic, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L},
+ { MSG_INVITE, m_invite, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L},
+ { MSG_WALLOPS, m_wallops, MAXPARA, MSG_LAG|MSG_REG|MSG_NOU, 0, 0, 0L},
+ { MSG_PING, m_ping, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L},
+ { MSG_PONG, m_pong, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L},
+ { MSG_ERROR, m_error, MAXPARA, MSG_LAG|MSG_REG|MSG_NOU, 0, 0, 0L},
+#ifdef OPER_KILL
+ { MSG_KILL, m_kill, MAXPARA, MSG_LAG|MSG_REG|MSG_OP|MSG_LOP, 0,0, 0L},
+#else
+ { MSG_KILL, m_kill, MAXPARA, MSG_LAG|MSG_REG|MSG_NOU, 0, 0, 0L},
+#endif
+#ifndef CLIENT_COMPILE
+ { MSG_USER, m_user, MAXPARA, MSG_LAG|MSG_NOU, 0, 0, 0L},
+ { MSG_AWAY, m_away, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L},
+ { MSG_UMODE, m_umode, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L},
+ { MSG_ISON, m_ison, 1, MSG_LAG|MSG_REG, 0, 0, 0L},
+ { MSG_SQUIT, m_squit, MAXPARA, MSG_LAG|MSG_REG|MSG_OP|MSG_LOP, 0,0, 0L},
+ { MSG_WHOIS, m_whois, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L},
+ { MSG_WHO, m_who, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L},
+ { MSG_WHOWAS, m_whowas, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L},
+ { MSG_LIST, m_list, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L},
+ { MSG_NAMES, m_names, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L},
+ { MSG_USERHOST,m_userhost, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L},
+ { MSG_PASS, m_pass, MAXPARA, MSG_LAG|MSG_NOU, 0, 0, 0L},
+ { MSG_LUSERS, m_lusers, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L},
+ { MSG_TIME, m_time, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L},
+ { MSG_OPER, m_oper, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L},
+ { MSG_CONNECT, m_connect, MAXPARA,
+ MSG_LAG|MSG_REGU|MSG_OP|MSG_LOP, 0, 0, 0L},
+ { MSG_VERSION, m_version, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L},
+ { MSG_STATS, m_stats, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L},
+ { MSG_LINKS, m_links, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L},
+ { MSG_ADMIN, m_admin, MAXPARA, MSG_LAG, 0, 0, 0L},
+ { MSG_USERS, m_users, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L},
+ { MSG_SUMMON, m_summon, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L},
+ { MSG_HELP, m_help, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L},
+ { MSG_INFO, m_info, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L},
+ { MSG_MOTD, m_motd, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L},
+ { MSG_CLOSE, m_close, MAXPARA, MSG_LAG|MSG_REGU|MSG_OP, 0, 0, 0L},
+ { MSG_RECONECT,m_reconnect,MAXPARA, MSG_LAG|MSG_NOU, 0, 0, 0L},
+ { MSG_SERVICE, m_service, MAXPARA, MSG_LAG|MSG_NOU, 0, 0, 0L},
+#ifdef USE_SERVICES
+ { MSG_SERVSET, m_servset, MAXPARA, MSG_LAG|MSG_SVC, 0, 0, 0L},
+#endif
+ { MSG_SQUERY, m_squery, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L},
+ { MSG_SERVLIST,m_servlist, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L},
+ { MSG_HASH, m_hash, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L},
+ { MSG_DNS, m_dns, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L},
+#ifdef OPER_REHASH
+ { MSG_REHASH, m_rehash, MAXPARA, MSG_REGU|MSG_OP
+# ifdef LOCOP_REHASH
+ |MSG_LOP
+# endif
+ , 0, 0, 0L},
+#endif
+#ifdef OPER_RESTART
+ { MSG_RESTART, m_restart, MAXPARA, MSG_REGU|MSG_OP
+# ifdef LOCOP_RESTART
+ |MSG_LOP
+# endif
+ , 0, 0, 0L},
+#endif
+#ifdef OPER_DIE
+ { MSG_DIE, m_die, MAXPARA, MSG_REGU|MSG_OP
+# ifdef LOCOP_DIE
+ |MSG_LOP
+# endif
+ , 0, 0, 0L},
+#endif
+#endif /* !CLIENT_COMPILE */
+ { (char *) 0, (int (*)()) 0, 0, 0, 0, 0, 0L}
+};
+
+/*
+ * NOTE: parse() should not be called recursively by other functions!
+ */
+static char *para[MAXPARA+1];
+
+#ifdef CLIENT_COMPILE
+static char sender[NICKLEN+USERLEN+HOSTLEN+3];
+char userhost[USERLEN+HOSTLEN+2];
+#define timeofday time(NULL)
+#else
+static char sender[HOSTLEN+1];
+static int cancel_clients __P((aClient *, aClient *, char *));
+static void remove_unknown __P((aClient *, char *));
+#endif
+
+/*
+** 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.
+*/
+#ifndef CLIENT_COMPILE
+aClient *find_client(name, cptr)
+char *name;
+Reg aClient *cptr;
+ {
+ aClient *acptr = cptr;
+
+ if (name && *name)
+ acptr = hash_find_client(name, cptr);
+
+ return acptr;
+ }
+
+aClient *find_service(name, cptr)
+char *name;
+Reg aClient *cptr;
+ {
+ aClient *acptr = cptr;
+
+ if (index(name, '@'))
+ acptr = hash_find_client(name, cptr);
+ return acptr;
+ }
+
+#else /* CLIENT_COMPILE */
+
+aClient *find_client(name, cptr)
+char *name;
+aClient *cptr;
+ {
+ Reg aClient *c2ptr = cptr;
+
+ if (!name || !*name)
+ return c2ptr;
+
+ for (c2ptr = client; c2ptr; c2ptr = c2ptr->next)
+ if (mycmp(name, c2ptr->name) == 0)
+ return c2ptr;
+ return cptr;
+ }
+#endif /* CLIENT_COMPILE */
+
+/*
+** Find a user@host (server or user).
+**
+** *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_userhost(user, host, cptr, count)
+char *user, *host;
+aClient *cptr;
+int *count;
+ {
+ Reg aClient *c2ptr;
+ Reg aClient *res = cptr;
+
+ *count = 0;
+ if (user)
+ for (c2ptr = client; c2ptr; c2ptr = c2ptr->next)
+ {
+ if (!MyClient(c2ptr)) /* implies mine and a user */
+ continue;
+ if ((!host || !match(host, c2ptr->user->host)) &&
+ mycmp(user, c2ptr->user->username) == 0)
+ {
+ (*count)++;
+ res = c2ptr;
+ }
+ }
+ return res;
+ }
+
+/*
+** 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.
+*/
+#ifndef CLIENT_COMPILE
+/*
+** Find a server from hash table, given its name
+*/
+aClient *find_server(name, cptr)
+char *name;
+Reg aClient *cptr;
+{
+ aClient *acptr = cptr;
+
+ if (name && *name)
+ acptr = hash_find_server(name, cptr);
+ return acptr;
+}
+
+/*
+** Given a server name, find the server mask behind which the server
+** is hidden.
+*/
+aClient *find_mask(name, cptr)
+char *name;
+aClient *cptr;
+{
+ static char servermask[HOSTLEN+1];
+ Reg aClient *c2ptr = cptr;
+ Reg char *mask = servermask;
+
+ if (!name || !*name)
+ return c2ptr;
+ if ((c2ptr = hash_find_server(name, cptr)))
+ return (c2ptr);
+ if (index(name, '*'))
+ return c2ptr;
+ strcpy (servermask, name);
+ while (*mask)
+ {
+ if (*(mask+1) == '.')
+ {
+ *mask = '*';
+ if ((c2ptr = hash_find_server(mask, cptr)))
+ return (c2ptr);
+ }
+ mask++;
+ }
+ return (c2ptr ? c2ptr : cptr);
+}
+
+/*
+** Find a server from hash table, given its token
+*/
+aServer *find_tokserver(token, cptr, c2ptr)
+int token;
+aClient *cptr, *c2ptr;
+{
+ return hash_find_stoken(token, cptr, c2ptr);
+}
+
+/*
+** Find a server, given its name (which might contain *'s, in which case
+** the first match will be return [not the best one])
+*/
+aClient *find_name(name, cptr)
+char *name;
+aClient *cptr;
+{
+ Reg aClient *c2ptr = cptr;
+ Reg aServer *sp = NULL;
+
+ if (!name || !*name)
+ return c2ptr;
+
+ if ((c2ptr = hash_find_server(name, cptr)))
+ return (c2ptr);
+ if (!index(name, '*'))
+ return c2ptr;
+ for (sp = svrtop; sp; sp = sp->nexts)
+ {
+ /*
+ ** A server present in the list necessarily has a non NULL
+ ** bcptr pointer.
+ */
+ if (match(name, sp->bcptr->name) == 0)
+ break;
+ if (index(sp->bcptr->name, '*'))
+ if (match(sp->bcptr->name, name) == 0)
+ break;
+ }
+ return (sp ? sp->bcptr : cptr);
+}
+#else
+aClient *find_server(name, cptr)
+char *name;
+aClient *cptr;
+{
+ Reg aClient *c2ptr = cptr;
+
+ if (!name || !*name)
+ return c2ptr;
+
+ for (c2ptr = client; c2ptr; c2ptr = c2ptr->next)
+ {
+ if (!IsServer(c2ptr) && !IsMe(c2ptr))
+ continue;
+ if (match(c2ptr->name, name) == 0 ||
+ match(name, c2ptr->name) == 0)
+ break;
+ }
+ return (c2ptr ? c2ptr : cptr);
+}
+#endif /* CLIENT_COMPILE */
+
+/*
+** Find person by (nick)name.
+*/
+aClient *find_person(name, cptr)
+char *name;
+aClient *cptr;
+ {
+ Reg aClient *c2ptr = cptr;
+
+ c2ptr = find_client(name, c2ptr);
+
+ if (c2ptr && IsClient(c2ptr) && c2ptr->user)
+ return c2ptr;
+ else
+ return cptr;
+ }
+
+/*
+ * parse a buffer.
+ * Return values:
+ * errors: -3 for unknown origin/sender, -2 for FLUSH_BUFFER, -1 for bad cptr
+ *
+ * NOTE: parse() should not be called recusively by any other fucntions!
+ */
+int parse(cptr, buffer, bufend)
+aClient *cptr;
+char *buffer, *bufend;
+ {
+ Reg aClient *from = cptr;
+ Reg char *ch, *s;
+ Reg int len, i, numeric = 0, paramcount;
+ Reg struct Message *mptr = NULL;
+ int ret;
+
+#ifndef CLIENT_COMPILE
+ Debug((DEBUG_DEBUG, "Parsing %s: %s",
+ get_client_name(cptr, FALSE), buffer));
+ if (IsDead(cptr))
+ return -1;
+#endif
+
+ 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';
+#ifdef CLIENT_COMPILE
+ if ((s = index(sender, '!')))
+ {
+ *s++ = '\0';
+ strncpyzt(userhost, s, sizeof(userhost));
+ }
+ else if ((s = index(sender, '@')))
+ {
+ *s++ = '\0';
+ strncpyzt(userhost, s, sizeof(userhost));
+ }
+#endif
+ /*
+ ** 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 ||
+ /*
+ ** I really believe that the followin line is
+ ** useless. What a waste, especially with 2.9
+ ** hostmasks.. at least the test on from->name
+ ** will make it a bit better. -krys
+ */
+ (*from->name == '*' && match(from->name, sender)))
+ from = find_server(sender, (aClient *)NULL);
+#ifndef CLIENT_COMPILE
+ /* Is there svc@server prefix ever? -Vesa */
+ /* every time a service talks -krys */
+ if (!from && index(sender, '@'))
+ from = find_service(sender, (aClient *)NULL);
+ if (!from)
+ from = find_mask(sender, (aClient *) NULL);
+#endif
+
+ 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
+ * Since 2.9 we pick them up and .. --Vesa
+ */
+ if (!from)
+ {
+ Debug((DEBUG_ERROR,
+ "Unknown prefix (%s)(%s) from (%s)",
+ sender, buffer, cptr->name));
+ ircstp->is_unpf++;
+#ifndef CLIENT_COMPILE
+ remove_unknown(cptr, sender);
+#endif
+ return -3; /* Grab it in read_message() */
+ }
+ if (from->from != cptr)
+ {
+ ircstp->is_wrdi++;
+ Debug((DEBUG_ERROR,
+ "Message (%s) coming from (%s)",
+ buffer, cptr->name));
+#ifndef CLIENT_COMPILE
+ return cancel_clients(cptr, from, buffer);
+#else
+ return -1;
+#endif
+ }
+ }
+ while (*ch == ' ')
+ ch++;
+ }
+ 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)))
+ {
+ numeric = (*ch - '0') * 100 + (*(ch + 1) - '0') * 10
+ + (*(ch + 2) - '0');
+ paramcount = MAXPARA;
+ ircstp->is_num++;
+ }
+ else
+ {
+ if (s)
+ *s++ = '\0';
+ for (mptr = msgtab; 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')
+ {
+ cptr->flags |= FLAGS_UNKCMD;
+ if (IsPerson(from))
+ sendto_one(from,
+ ":%s %d %s %s :Unknown command",
+ me.name, ERR_UNKNOWNCOMMAND,
+ from->name, ch);
+#ifdef CLIENT_COMPILE
+ Debug((DEBUG_ERROR,"Unknown (%s) from %s[%s]",
+ ch, cptr->name, cptr->sockhost));
+#else
+ else if (IsServer(cptr))
+ sendto_flag(SCH_ERROR,
+ "Unknown command from %s:%s",
+ get_client_name(cptr, TRUE), ch);
+ Debug((DEBUG_ERROR,"Unknown (%s) from %s",
+ ch, get_client_name(cptr, TRUE)));
+#endif
+ }
+ ircstp->is_unco++;
+ return -1;
+ }
+ paramcount = mptr->parameters;
+ i = bufend - ((s) ? s : ch);
+ mptr->bytes += i;
+#ifndef CLIENT_COMPILE
+ if ((mptr->flags & MSG_LAG) &&
+ !(IsServer(cptr) || IsService(cptr)))
+ { /* Flood control partly migrated into penalty */
+ if (bootopt & BOOT_PROT)
+ cptr->since += (1 + i / 100);
+ else
+ cptr->since = timeofday;
+ /* 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
+ */
+ }
+#endif
+ }
+ /*
+ ** 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' !! */
+
+#ifdef CLIENT_COMPILE
+ if (me.user)
+ para[0] = sender;
+#endif
+ 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-1)
+ break;
+ for (; *s != ' ' && *s; s++)
+ ;
+ }
+ }
+ para[++i] = NULL; /* at worst, ++i is paramcount (MAXPARA) */
+ if (mptr == NULL)
+ return (do_numeric(numeric, cptr, from, i, para));
+ mptr->count++;
+ if (!MyConnect(from))
+ mptr->rcount++;
+ if (IsRegisteredUser(cptr) &&
+#ifdef IDLE_FROM_MSG
+ mptr->func == m_private)
+#else
+ mptr->func != m_ping && mptr->func != m_pong)
+#endif
+ from->user->last = timeofday;
+ Debug((DEBUG_DEBUG, "Function: %#x = %s parc %d parv %#x",
+ mptr->func, mptr->cmd, i, para));
+#ifndef CLIENT_COMPILE
+ if ((mptr->flags & MSG_REGU) && check_registered_user(from))
+ return -1;
+ if ((mptr->flags & MSG_SVC) && check_registered_service(from))
+ return -1;
+ if ((mptr->flags & MSG_REG) && check_registered(from))
+ return -1;
+ if ((mptr->flags & MSG_NOU) && (MyPerson(from) || MyService(from)))
+ {
+ sendto_one(from, err_str(ERR_ALREADYREGISTRED, para[0]));
+ return-1;
+ }
+ if (MyConnect(from) && !IsServer(from) &&
+ (mptr->flags & (MSG_LOP|MSG_OP)) &&
+ !((mptr->flags & MSG_OP) && (IsOper(from))) &&
+ !((mptr->flags & MSG_LOP) && (IsLocOp(from))))
+ {
+ sendto_one(from, err_str(ERR_NOPRIVILEGES, para[0]));
+ return -1;
+ }
+#endif
+ /*
+ ** ALL m_functions return now UNIFORMLY:
+ ** -2 old FLUSH_BUFFER return value (unchanged).
+ ** -1 if parsing of a protocol message leads in a syntactic/semantic
+ ** error and NO penalty scoring should be applied.
+ ** >=0 if protocol message processing was successful. The return
+ ** value indicates the penalty score.
+ */
+ ret = (*mptr->func)(cptr, from, i, para);
+
+#ifndef CLIENT_COMPILE
+ /*
+ ** Add penalty score for sucessfully parsed command if issued by
+ ** a LOCAL user client.
+ */
+ if ((ret > 0) && IsRegisteredUser(cptr) && (bootopt & BOOT_PROT))
+ {
+ cptr->since += ret;
+/* only to lurk
+ sendto_one(cptr,
+ ":%s NOTICE %s :*** Penalty INCR [%s] +%d",
+ me.name, cptr->name, ch, ret);
+*/
+ }
+#endif
+ return (ret != FLUSH_BUFFER) ? 2 : FLUSH_BUFFER;
+}
+
+/*
+ * field breakup for ircd.conf file.
+ */
+char *getfield(irc_newline)
+char *irc_newline;
+{
+ static char *line = NULL;
+ char *end, *field;
+
+ if (irc_newline)
+ line = irc_newline;
+ if (line == NULL)
+ return(NULL);
+
+ field = line;
+ if ((end = (char *)index(line, IRCDCONF_DELIMITER)) == NULL)
+ {
+ line = NULL;
+ if ((end = (char *)index(field,'\n')) == NULL)
+ end = field + strlen(field);
+ }
+ else
+ line = end + 1;
+ *end = '\0';
+ return(field);
+}
+
+#ifndef CLIENT_COMPILE
+static int cancel_clients(cptr, sptr, cmd)
+aClient *cptr, *sptr;
+char *cmd;
+{
+ /*
+ * kill all possible points that are causing confusion here,
+ * I'm not sure I've got this all right...
+ * - avalon
+ */
+ sendto_flag(SCH_NOTICE, "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))
+ {
+ sendto_flag(SCH_NOTICE, "Dropping server %s",cptr->name);
+ return exit_client(cptr, cptr, &me, "Fake Direction");
+ }
+ /*
+ * 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))
+ {
+ sendto_serv_butone(NULL, ":%s KILL %s :%s (%s[%s] != %s)",
+ me.name, sptr->name, me.name,
+ sptr->name, sptr->from->name,
+ get_client_name(cptr, TRUE));
+ sptr->flags |= FLAGS_KILLED;
+ return exit_client(cptr, sptr, &me, "Fake Prefix");
+ }
+ 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;
+ /*
+ * squit if it is a server because it means something is really
+ * wrong.
+ */
+ if (index(sender, '.') /* <- buggy, it could be a service! */
+ && !index(sender, '@')) /* better.. */
+ {
+ sendto_flag(SCH_LOCAL, "Squitting unknown %s brought by %s.",
+ sender, get_client_name(cptr, FALSE));
+ sendto_one(cptr, ":%s SQUIT %s :(Unknown from %s)",
+ me.name, sender, get_client_name(cptr, FALSE));
+ }
+ else
+ /*
+ * 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
+ * it can simply be caused by lag (among other things), so just
+ * drop it if it is not a server. -krys
+ * services aren't prone to collisions, so lag shouldn't be responsible
+ * if we get here and sender is a service, we should probably issue
+ * a kill in this case! -krys
+ */
+ sendto_flag(SCH_LOCAL, "Dropping unknown %s brought by %s.",
+ sender, get_client_name(cptr, FALSE));
+}
+#endif
diff --git a/common/parse_ext.h b/common/parse_ext.h
new file mode 100644
index 0000000..6fdd118
--- /dev/null
+++ b/common/parse_ext.h
@@ -0,0 +1,56 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, common/parse_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in common/parse.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef PARSE_C
+#ifdef CLIENT_COMPILE
+extern char userhost[];
+#endif /* CLIENT_COMPILE */
+extern struct Message msgtab[];
+#endif /* PARSE_C */
+
+/* External definitions for global functions.
+ */
+#ifndef PARSE_C
+#define EXTERN extern
+#else /* PARSE_C */
+#define EXTERN
+#endif /* PARSE_C */
+#ifndef CLIENT_COMPILE
+EXTERN aClient *find_client __P((char *name, Reg aClient *cptr));
+EXTERN aClient *find_service __P((char *name, Reg aClient *cptr));
+EXTERN aClient *find_server __P((char *name, Reg aClient *cptr));
+EXTERN aClient *find_mask __P((char *name, aClient *cptr));
+EXTERN aServer *find_tokserver __P((int token, aClient *cptr, aClient *c2ptr));
+EXTERN aClient *find_name __P((char *name, aClient *cptr));
+#else /* CLIENT_COMPILE */
+EXTERN aClient *find_client __P((char *name, aClient *cptr));
+EXTERN aClient *find_server __P((char *name, aClient *cptr));
+#endif /* CLIENT_COMPILE */
+EXTERN aClient *find_userhost __P((char *user, char *host, aClient *cptr,
+ int *count));
+EXTERN aClient *find_person __P((char *name, aClient *cptr));
+EXTERN int parse __P((aClient *cptr, char *buffer, char *bufend));
+EXTERN char *getfield __P((char *irc_newline));
+#undef EXTERN
diff --git a/common/patchlevel.h b/common/patchlevel.h
new file mode 100644
index 0000000..6b84548
--- /dev/null
+++ b/common/patchlevel.h
@@ -0,0 +1,22 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, common/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.
+ */
+
+#ifndef PATCHLEVEL
+#define PATCHLEVEL "0210030000" /* for server identification */
+#define DEVLEVEL 'b'
+#endif
diff --git a/common/send.c b/common/send.c
new file mode 100644
index 0000000..c61e3e5
--- /dev/null
+++ b/common/send.c
@@ -0,0 +1,1555 @@
+/*
+ * IRC - Internet Relay Chat, common/send.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: send.c,v 1.39 1999/07/21 22:57:40 kalt Exp $";
+#endif
+
+#include "os.h"
+#ifndef CLIENT_COMPILE
+# include "s_defines.h"
+#else
+# include "c_defines.h"
+#endif
+#define SEND_C
+#ifndef CLIENT_COMPILE
+# include "s_externs.h"
+#else
+# include "c_externs.h"
+#endif
+#undef SEND_C
+
+static char sendbuf[2048];
+static int send_message __P((aClient *, char *, int));
+
+#if USE_STDARG
+static void vsendto_prefix_one(aClient *, aClient *, char *, va_list);
+#endif
+
+
+#ifndef CLIENT_COMPILE
+static char psendbuf[2048];
+static int sentalong[MAXCONNECTIONS];
+#endif
+
+/*
+** 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. It 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 (IsHeld(to))
+ return -1;
+ to->flags |= FLAGS_DEADSOCKET;
+ /*
+ * If because of BUFFERPOOL problem then clean dbufs now so that
+ * notices don't hurt operators below.
+ */
+ DBufClear(&to->recvQ);
+ DBufClear(&to->sendQ);
+#ifndef CLIENT_COMPILE
+ if (!IsPerson(to) && !IsUnknown(to) && !(to->flags & FLAGS_CLOSING))
+ sendto_flag(SCH_ERROR, notice, get_client_name(to, FALSE));
+ Debug((DEBUG_ERROR, notice, get_client_name(to, FALSE)));
+#endif
+ return -1;
+}
+
+#ifndef CLIENT_COMPILE
+/*
+** flush_fdary
+** Used to empty all output buffers for connections in fdary.
+*/
+void flush_fdary(fdp)
+FdAry *fdp;
+{
+ int i;
+ aClient *cptr;
+
+ for (i = 0; i <= fdp->highest; i++)
+ {
+ if (!(cptr = local[fdp->fd[i]]))
+ continue;
+ if (!IsRegistered(cptr)) /* is this needed?? -kalt */
+ continue;
+ if (DBufLength(&cptr->sendQ) > 0)
+ (void)send_queued(cptr);
+ }
+}
+
+/*
+** 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 can't send it, it goes into the sendQ
+** -avalon
+*/
+void flush_connections(fd)
+int fd;
+{
+ Reg int i;
+ Reg aClient *cptr;
+
+ if (fd == me.fd)
+ {
+ for (i = highest_fd; i >= 0; i--)
+ if ((cptr = local[i]) && DBufLength(&cptr->sendQ) > 0)
+ (void)send_queued(cptr);
+ }
+ else if (fd >= 0 && (cptr = local[fd]) && DBufLength(&cptr->sendQ) > 0)
+ (void)send_queued(cptr);
+}
+#endif
+
+/*
+** send_message
+** Internal utility which delivers one message buffer to the
+** socket. Takes care of the error handling and buffering, if
+** needed.
+** if ZIP_LINKS is defined, the message will eventually be compressed,
+** anything stored in the sendQ is compressed.
+*/
+static int send_message(to, msg, len)
+aClient *to;
+char *msg; /* if msg is a null pointer, we are flushing connection */
+int len;
+#if !defined(CLIENT_COMPILE)
+{
+ int i;
+
+ Debug((DEBUG_SEND,"Sending %s %d [%s] ", to->name, to->fd, msg));
+
+ if (to->from)
+ to = to->from;
+ if (to->fd < 0)
+ {
+ Debug((DEBUG_ERROR,
+ "Local socket %s with negative fd... AARGH!",
+ to->name));
+ }
+ if (IsMe(to))
+ {
+ sendto_flag(SCH_ERROR, "Trying to send to myself! [%s]", msg);
+ return 0;
+ }
+ if (IsDead(to))
+ return 0; /* This socket has already been marked as dead */
+ if (DBufLength(&to->sendQ) > get_sendq(to))
+ {
+# ifdef HUB
+ if (CBurst(to))
+ {
+ aConfItem *aconf = to->serv->nline;
+
+ poolsize -= MaxSendq(aconf->class) >> 1;
+ IncSendq(aconf->class);
+ poolsize += MaxSendq(aconf->class) >> 1;
+ sendto_flag(SCH_NOTICE,
+ "New poolsize %d. (sendq adjusted)",
+ poolsize);
+ istat.is_dbufmore++;
+ }
+ else if (IsServer(to) || IsService(to))
+ sendto_flag(SCH_ERROR,
+ "Max SendQ limit exceeded for %s: %d > %d",
+ get_client_name(to, FALSE),
+ DBufLength(&to->sendQ), get_sendq(to));
+ if (!CBurst(to))
+ {
+ to->exitc = EXITC_SENDQ;
+ return dead_link(to, "Max Sendq exceeded");
+ }
+# else /* HUB */
+ if (IsService(to) || IsServer(to))
+ sendto_flag(SCH_ERROR,
+ "Max SendQ limit exceeded for %s: %d > %d",
+ get_client_name(to, FALSE),
+ DBufLength(&to->sendQ), get_sendq(to));
+ to->exitc = EXITC_SENDQ;
+ return dead_link(to, "Max Sendq exceeded");
+# endif /* HUB */
+ }
+ else
+ {
+tryagain:
+# 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.
+ */
+ if (to->flags & FLAGS_ZIP)
+ msg = zip_buffer(to, msg, &len, 0);
+
+ if (len && (i = dbuf_put(&to->sendQ, msg, len)) < 0)
+# else /* ZIP_LINKS */
+ if ((i = dbuf_put(&to->sendQ, msg, len)) < 0)
+# endif /* ZIP_LINKS */
+ if (i == -2 && CBurst(to))
+ { /* poolsize was exceeded while connect burst */
+ aConfItem *aconf = to->serv->nline;
+
+ poolsize -= MaxSendq(aconf->class) >> 1;
+ IncSendq(aconf->class);
+ poolsize += MaxSendq(aconf->class) >> 1;
+ sendto_flag(SCH_NOTICE,
+ "New poolsize %d. (reached)",
+ poolsize);
+ istat.is_dbufmore++;
+ goto tryagain;
+ }
+ else
+ {
+ to->exitc = EXITC_MBUF;
+ 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).
+ */
+ if (DBufLength(&to->sendQ)/1024 > to->lastsq)
+ send_queued(to);
+ return 0;
+}
+#else /* CLIENT_COMPILE */
+{
+ int rlen = 0, i;
+
+ Debug((DEBUG_SEND,"Sending %s %d [%s] ", to->name, to->fd, msg));
+
+ if (to->from)
+ to = to->from;
+ if (to->fd < 0)
+ {
+ Debug((DEBUG_ERROR,
+ "Local socket %s with negative fd... AARGH!",
+ to->name));
+ }
+ if (IsDead(to))
+ return 0; /* This socket has already been marked as dead */
+
+ if ((rlen = deliver_it(to, msg, len)) < 0 && rlen < len)
+ return dead_link(to,"Write error to %s, closing link");
+ /*
+ ** 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;
+ return 0;
+}
+#endif
+
+/*
+** send_queued
+** This function is called from the main select-loop (or whatever)
+** when there is a chance the some output would be possible. This
+** attempts to empty the send queue as far as possible...
+*/
+int send_queued(to)
+aClient *to;
+{
+ char *msg;
+ int len, rlen, more = 0;
+
+ /*
+ ** 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
+ /*
+ ** Here, we must make sure than nothing will be left in to->zip->outbuf
+ ** This buffer needs to be compressed and sent if all the sendQ is sent
+ */
+ if ((to->flags & FLAGS_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)
+ {
+ to->exitc = EXITC_MBUF;
+ return dead_link(to,
+ "Buffer allocation error for %s");
+ }
+ }
+ }
+#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) /* ..or should I continue until rlen==0? */
+ break;
+
+#ifdef ZIP_LINKS
+ if (DBufLength(&to->sendQ) == 0 && more)
+ {
+ /*
+ ** The sendQ is now empty, compress what's left
+ ** uncompressed and try to send it too
+ */
+ 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)
+ {
+ to->exitc = EXITC_MBUF;
+ return dead_link(to,
+ "Buffer allocation error for %s");
+ }
+ }
+#endif
+ }
+
+ return (IsDead(to)) ? -1 : 0;
+}
+
+
+#ifndef CLIENT_COMPILE
+static anUser ausr = { NULL, NULL, NULL, NULL, 0, 0, 0, 0, NULL,
+ NULL, "anonymous", "anonymous.", "anonymous."};
+
+static aClient anon = { NULL, NULL, NULL, &ausr, NULL, NULL, 0, 0,/*flags*/
+ &anon, -2, 0, STAT_CLIENT, "anonymous", "anonymous",
+ "anonymous identity hider", 0, "",
+# ifdef ZIP_LINKS
+ NULL,
+# endif
+ 0, {0, 0, NULL }, {0, 0, NULL },
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, NULL, 0
+# if defined(__STDC__) /* hack around union{} initialization -Vesa */
+ ,{0}, NULL, "", ""
+# endif
+ };
+#endif
+
+/*
+ *
+ */
+#if ! USE_STDARG
+static int sendprep(pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11)
+char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11;
+#else
+static int vsendprep(char *pattern, va_list va)
+#endif
+{
+ int len;
+
+ Debug((DEBUG_L10, "sendprep(%s)", pattern));
+#if ! USE_STDARG
+ len = irc_sprintf(sendbuf, pattern, p1, p2, p3, p4, p5, p6,
+ p7, p8, p9, p10, p11);
+ if (len == -1)
+ len = strlen(sendbuf);
+#else
+ len = vsprintf(sendbuf, pattern, va);
+#endif
+ if (len > 510)
+#ifdef IRCII_KLUDGE
+ len = 511;
+#else
+ len = 510;
+ sendbuf[len++] = '\r';
+#endif
+ sendbuf[len++] = '\n';
+ sendbuf[len] = '\0';
+ return len;
+}
+
+#ifndef CLIENT_COMPILE
+#if ! USE_STDARG
+static int sendpreprep(to, from, pattern,
+ p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11)
+aClient *to, *from;
+char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11;
+{
+ static char sender[HOSTLEN+NICKLEN+USERLEN+5];
+ Reg anUser *user;
+ char *par;
+ int flag = 0, len;
+
+ Debug((DEBUG_L10, "sendpreprep(%#x(%s),%#x(%s),%s)",
+ to, to->name, from, from->name, pattern));
+ 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, "@");
+ (void)strcat(sender, user->host);
+ 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 (IsUnixSocket(from))
+ (void)strcat(sender, user->host);
+ else
+ (void)strcat(sender, from->sockhost);
+ }
+ par = sender;
+ }
+ len = irc_sprintf(psendbuf, pattern, par, p2, p3, p4, p5, p6,
+ p7, p8, p9, p10, p11);
+ if (len == -1)
+ len = strlen(psendbuf);
+ if (len > 510)
+#ifdef IRCII_KLUDGE
+ len = 511;
+#else
+ len = 510;
+ psendbuf[len++] = '\r';
+#endif
+ psendbuf[len++] = '\n';
+ psendbuf[len] = '\0';
+ return len;
+}
+
+#else /* USE_STDARG */
+
+static int vsendpreprep(aClient *to, aClient *from, char *pattern, va_list va)
+{
+ Reg anUser *user;
+ int flag = 0, len;
+
+ Debug((DEBUG_L10, "sendpreprep(%#x(%s),%#x(%s),%s)",
+ to, to->name, from, from->name, pattern));
+ if (to && from && MyClient(to) && IsPerson(from) &&
+ !strncmp(pattern, ":%s", 3))
+ {
+ char *par = va_arg(va, char *);
+ if (from == &anon || !mycmp(par, from->name))
+ {
+ user = from->user;
+ (void)strcpy(psendbuf, ":");
+ (void)strcat(psendbuf, from->name);
+ if (user)
+ {
+ if (*user->username)
+ {
+ (void)strcat(psendbuf, "!");
+ (void)strcat(psendbuf, user->username);
+ }
+ if (*user->host && !MyConnect(from))
+ {
+ (void)strcat(psendbuf, "@");
+ (void)strcat(psendbuf, user->host);
+ flag = 1;
+ }
+ }
+ /*
+ ** flag is used instead of index(newpat, '@') for speed and
+ ** also since username/nick may have had a '@' in them. -avalon
+ */
+ if (!flag && MyConnect(from) && *user->host)
+ {
+ (void)strcat(psendbuf, "@");
+ if (IsUnixSocket(from))
+ (void)strcat(psendbuf, user->host);
+ else
+ (void)strcat(psendbuf, from->sockhost);
+ }
+ }
+ else
+ {
+ (void)strcpy(psendbuf, ":");
+ (void)strcat(psendbuf, par);
+ }
+
+ len = strlen(psendbuf);
+ len += vsprintf(psendbuf+len, pattern+3, va);
+ }
+ else
+ len = vsprintf(psendbuf, pattern, va);
+
+ if (len > 510)
+#ifdef IRCII_KLUDGE
+ len = 511;
+#else
+ len = 510;
+ psendbuf[len++] = '\r';
+#endif
+ psendbuf[len++] = '\n';
+ psendbuf[len] = '\0';
+ return len;
+}
+#endif /* USE_STDARG */
+#endif /* CLIENT_COMPILE */
+
+/*
+** send message to single client
+*/
+#if ! USE_STDARG
+int 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;
+#else
+int vsendto_one(aClient *to, char *pattern, va_list va)
+#endif
+{
+ int len;
+
+#if ! USE_STDARG
+ len = sendprep(pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11);
+#else
+ len = vsendprep(pattern, va);
+#endif
+
+ (void)send_message(to, sendbuf, len);
+ return len;
+}
+
+#if USE_STDARG
+int sendto_one(aClient *to, char *pattern, ...)
+{
+ int len;
+ va_list va;
+ va_start(va, pattern);
+ len = vsendto_one(to, pattern, va);
+ va_end(va);
+ return len;
+}
+#endif
+
+#ifndef CLIENT_COMPILE
+#if ! USE_STDARG
+/*VARARGS*/
+void sendto_channel_butone(one, from, chptr, pattern,
+ p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11)
+aClient *one, *from;
+aChannel *chptr;
+char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11;
+#else
+void sendto_channel_butone(aClient *one, aClient *from, aChannel *chptr, char *pattern, ...)
+#endif
+{
+ Reg Link *lp;
+ Reg aClient *acptr, *lfrm = from;
+ int len1, len2 = 0;
+
+ if (IsAnonymous(chptr) && IsClient(from))
+ {
+#if ! USE_STDARG
+ if (p1 && *p1 && !mycmp(p1, from->name))
+ p1 = anon.name;
+#endif
+ lfrm = &anon;
+ }
+
+ if (one != from && MyConnect(from) && IsRegisteredUser(from))
+ {
+ /* useless junk? */
+#if ! USE_STDARG
+ sendto_prefix_one(from, from, pattern, p1, p2, p3, p4,
+ p5, p6, p7, p8, p9, p10, p11);
+#else
+ va_list va;
+ va_start(va, pattern);
+ vsendto_prefix_one(from, from, pattern, va);
+ va_end(va);
+#endif
+ }
+
+#if ! USE_STDARG
+ len1 = sendprep(pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11);
+#else
+ {
+ va_list va;
+ va_start(va, pattern);
+ len1 = vsendprep(pattern, va);
+ va_end(va);
+ }
+#endif
+
+
+ for (lp = chptr->clist; lp; lp = lp->next)
+ {
+ acptr = lp->value.cptr;
+ if (acptr->from == one || IsMe(acptr))
+ continue; /* ...was the one I should skip */
+ if (MyConnect(acptr) && IsRegisteredUser(acptr))
+ {
+ if (!len2)
+ {
+#if ! USE_STDARG
+ len2 = sendpreprep(acptr, lfrm, pattern, p1,
+ p2, p3, p4, p5, p6, p7, p8,
+ p9, p10, p11);
+#else
+ va_list va;
+ va_start(va, pattern);
+ len2 = vsendpreprep(acptr, lfrm, pattern, va);
+ va_end(va);
+#endif
+ }
+
+ if (acptr != from)
+ (void)send_message(acptr, psendbuf, len2);
+ }
+ else
+ (void)send_message(acptr, sendbuf, len1);
+ }
+ return;
+}
+
+/*
+ * sendto_server_butone
+ *
+ * Send a message to all connected servers except the client 'one'.
+ */
+#if ! USE_STDARG
+/*VARARGS*/
+void sendto_serv_butone(one, pattern, p1, p2, p3, p4,p5,p6,p7,p8,p9,p10,p11)
+aClient *one;
+char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11;
+#else
+void sendto_serv_butone(aClient *one, char *pattern, ...)
+#endif
+{
+ Reg int i, len=0;
+ Reg aClient *cptr;
+
+ for (i = fdas.highest; i >= 0; i--)
+ if ((cptr = local[fdas.fd[i]]) &&
+ (!one || cptr != one->from) && !IsMe(cptr)) {
+ if (!len)
+ {
+#if ! USE_STDARG
+ len = sendprep(pattern, p1, p2, p3, p4, p5,
+ p6, p7, p8, p9, p10, p11);
+#else
+ va_list va;
+ va_start(va, pattern);
+ len = vsendprep(pattern, va);
+ va_end(va);
+#endif
+ }
+ (void)send_message(cptr, sendbuf, len);
+ }
+ return;
+}
+
+#if ! USE_STDARG
+int
+sendto_serv_v(one, ver, pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11)
+aClient *one;
+int ver;
+char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11;
+#else
+int
+sendto_serv_v(aClient *one, int ver, char *pattern, ...)
+#endif
+{
+ Reg int i, len=0, rc=0;
+ Reg aClient *cptr;
+
+ for (i = fdas.highest; i >= 0; i--)
+ if ((cptr = local[fdas.fd[i]]) &&
+ (!one || cptr != one->from) && !IsMe(cptr))
+ if (cptr->serv->version & ver)
+ {
+ if (!len)
+ {
+#if ! USE_STDARG
+ len = sendprep(pattern, p1, p2, p3, p4,
+ p5, p6, p7, p8, p9, p10,
+ p11);
+#else
+ va_list va;
+ va_start(va, pattern);
+ len = vsendprep(pattern, va);
+ va_end(va);
+#endif
+ }
+ (void)send_message(cptr, sendbuf, len);
+ }
+ else
+ rc = 1;
+ return rc;
+}
+
+#if ! USE_STDARG
+int
+sendto_serv_notv(one, ver, pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9,p10,p11)
+aClient *one;
+int ver;
+char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11;
+#else
+int
+sendto_serv_notv(aClient *one, int ver, char *pattern, ...)
+#endif
+{
+ Reg int i, len=0, rc=0;
+ Reg aClient *cptr;
+
+ for (i = fdas.highest; i >= 0; i--)
+ if ((cptr = local[fdas.fd[i]]) &&
+ (!one || cptr != one->from) && !IsMe(cptr))
+ if ((cptr->serv->version & ver) == 0)
+ {
+ if (!len)
+ {
+#if ! USE_STDARG
+ len = sendprep(pattern, p1, p2, p3, p4,
+ p5, p6, p7, p8, p9, p10,
+ p11);
+#else
+ va_list va;
+ va_start(va, pattern);
+ len = vsendprep(pattern, va);
+ va_end(va);
+#endif
+ }
+ (void)send_message(cptr, sendbuf, len);
+ }
+ else
+ rc = 1;
+ return rc;
+}
+
+/*
+ * sendto_common_channels()
+ *
+ * Sends a message to all people (inclusing user) on local server who are
+ * in same channel with user, except for channels set Quiet or Anonymous
+ * The calling procedure must take the necessary steps for such channels.
+ */
+#if ! USE_STDARG
+/*VARARGS*/
+void sendto_common_channels(user,pattern,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11)
+aClient *user;
+char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11;
+#else
+void sendto_common_channels(aClient *user, char *pattern, ...)
+#endif
+{
+ Reg int i;
+ Reg aClient *cptr;
+ Reg Link *channels, *lp;
+ int len = 0;
+
+/* This is kind of funky, but should work. The first part below
+ is optimized for HUB servers or servers with few clients on
+ them. The second part is optimized for bigger client servers
+ where looping through the whole client list is bad. I'm not
+ really certain of the point at which each function equals
+ out...but I do know the 2nd part will help big client servers
+ fairly well... - Comstud 97/04/24
+*/
+
+ if (highest_fd < 50) /* This part optimized for HUB servers... */
+ {
+ if (MyConnect(user))
+ {
+#if ! USE_STDARG
+ len = sendpreprep(user, user, pattern,
+ p1, p2, p3, p4, p5, p6, p7, p8, p9, p10,p11);
+
+#else
+ va_list va;
+ va_start(va, pattern);
+ len = vsendpreprep(user, user, pattern, va);
+ va_end(va);
+#endif
+ (void)send_message(user, psendbuf, len);
+ }
+ for (i = 0; i <= highest_fd; i++)
+ {
+ if (!(cptr = local[i]) || IsServer(cptr) ||
+ user == cptr || !user->user)
+ continue;
+ for (lp = user->user->channel; lp; lp = lp->next)
+ {
+ if (!IsMember(cptr, lp->value.chptr))
+ continue;
+ if (IsAnonymous(lp->value.chptr))
+ continue;
+ if (!IsQuiet(lp->value.chptr))
+ {
+#ifndef DEBUGMODE
+ if (!len) /* This saves little cpu,
+ but breaks the debug code.. */
+#endif
+ {
+#if ! USE_STDARG
+ len = sendpreprep(cptr, user, pattern,
+ p1, p2, p3, p4, p5,
+ p6, p7, p8, p9, p10,
+ p11);
+#else
+ va_list va;
+ va_start(va, pattern);
+ len = vsendpreprep(cptr, user, pattern, va);
+ va_end(va);
+#endif
+ }
+ (void)send_message(cptr, psendbuf,
+ len);
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* This part optimized for client servers */
+ bzero((char *)&sentalong[0], sizeof(int) * MAXCONNECTIONS);
+ if (MyConnect(user))
+ {
+#if ! USE_STDARG
+ len = sendpreprep(user, user, pattern, p1, p2, p3, p4,
+ p5, p6, p7, p8, p9, p10, p11);
+#else
+ va_list va;
+ va_start(va, pattern);
+ len = vsendpreprep(user, user, pattern, va);
+ va_end(va);
+#endif
+ (void)send_message(user, psendbuf, len);
+ sentalong[user->fd] = 1;
+ }
+ if (!user->user)
+ return;
+ for (channels=user->user->channel; channels;
+ channels=channels->next)
+ {
+ if (IsQuiet(channels->value.chptr))
+ continue;
+ if (IsAnonymous(channels->value.chptr))
+ continue;
+ for (lp=channels->value.chptr->members;lp;
+ lp=lp->next)
+ {
+ cptr = lp->value.cptr;
+ if (user == cptr)
+ continue;
+ if (!MyConnect(cptr) || sentalong[cptr->fd])
+ continue;
+ sentalong[cptr->fd]++;
+#ifndef DEBUGMODE
+ if (!len) /* This saves little cpu,
+ but breaks the debug code.. */
+#endif
+ {
+#if ! USE_STDARG
+ len = sendpreprep(cptr, user, pattern,
+ p1, p2, p3, p4, p5,
+ p6, p7, p8, p9, p10,
+ p11);
+#else
+ va_list va;
+ va_start(va, pattern);
+ len = vsendpreprep(cptr, user, pattern, va);
+ va_end(va);
+#endif
+ }
+ (void)send_message(cptr, psendbuf, len);
+ }
+ }
+ }
+ return;
+}
+
+/*
+ * sendto_channel_butserv
+ *
+ * Send a message to all members of a channel that are connected to this
+ * server.
+ */
+#if ! USE_STDARG
+/*VARARGS*/
+void sendto_channel_butserv(chptr, from, pattern, p1, p2, p3,
+ p4, p5, p6, p7, p8, p9, p10, p11)
+aChannel *chptr;
+aClient *from;
+char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11;
+#else
+void sendto_channel_butserv(aChannel *chptr, aClient *from, char *pattern, ...)
+#endif
+{
+ Reg Link *lp;
+ Reg aClient *acptr, *lfrm = from;
+ int len = 0;
+
+ if (MyClient(from))
+ { /* Always send to the client itself */
+#if ! USE_STDARG
+ sendto_prefix_one(from, from, pattern, p1, p2, p3, p4,
+ p5, p6, p7, p8, p9, p10, p11);
+#else
+ va_list va;
+ va_start(va, pattern);
+ vsendto_prefix_one(from, from, pattern, va);
+ va_end(va);
+#endif
+ if (IsQuiet(chptr)) /* Really shut up.. */
+ return;
+ }
+ if (IsAnonymous(chptr) && IsClient(from))
+ {
+#if ! USE_STDARG
+ if (p1 && *p1 && !mycmp(p1, from->name))
+ p1 = anon.name;
+#endif
+ lfrm = &anon;
+ }
+
+ for (lp = chptr->members; lp; lp = lp->next)
+ if (MyClient(acptr = lp->value.cptr) && acptr != from)
+ {
+ if (!len)
+ {
+#if ! USE_STDARG
+ len = sendpreprep(acptr, lfrm, pattern, p1, p2,
+ p3, p4, p5, p6, p7, p8, p9,
+ p10, p11);
+#else
+ va_list va;
+ va_start(va, pattern);
+ len = vsendpreprep(acptr, lfrm, pattern, va);
+ va_end(va);
+#endif
+ }
+ (void)send_message(acptr, psendbuf, len);
+ }
+
+ 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.
+ */
+#if ! USE_STDARG
+/*VARARGS*/
+void sendto_match_servs(chptr, from, format, p1, p2, p3, p4, p5, p6, p7,
+ p8, p9, p10, p11)
+aChannel *chptr;
+aClient *from;
+char *format, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11;
+#else
+void sendto_match_servs(aChannel *chptr, aClient *from, char *format, ...)
+#endif
+{
+ Reg int i, len=0;
+ Reg aClient *cptr;
+ char *mask;
+
+ if (chptr)
+ {
+ if (*chptr->chname == '&')
+ return;
+ if ((mask = (char *)rindex(chptr->chname, ':')))
+ mask++;
+ }
+ else
+ mask = (char *)NULL;
+
+ for (i = fdas.highest; i >= 0; i--)
+ {
+ if (!(cptr = local[fdas.fd[i]]) || (cptr == from) ||
+ IsMe(cptr))
+ continue;
+ if (!BadPtr(mask) && match(mask, cptr->name))
+ continue;
+ if (chptr &&
+ *chptr->chname == '!' && !(cptr->serv->version & SV_NJOIN))
+ continue;
+ if (!len)
+ {
+#if ! USE_STDARG
+ len = sendprep(format, p1, p2, p3, p4, p5, p6, p7,
+ p8, p9, p10, p11);
+#else
+ va_list va;
+ va_start(va, format);
+ len = vsendprep(format, va);
+ va_end(va);
+#endif
+ }
+ (void)send_message(cptr, sendbuf, len);
+ }
+}
+
+#if ! USE_STDARG
+/*VARARGS*/
+int
+sendto_match_servs_v(chptr, from, ver, format, p1, p2, p3, p4, p5, p6,
+ p7, p8, p9, p10, p11)
+aChannel *chptr;
+aClient *from;
+char *format, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11;
+int ver;
+#else
+int
+sendto_match_servs_v(aChannel *chptr, aClient *from, int ver,
+ char *format, ...)
+#endif
+{
+ Reg int i, len=0, rc=0;
+ Reg aClient *cptr;
+ char *mask;
+
+ if (chptr)
+ {
+ if (*chptr->chname == '&')
+ return 0;
+ if ((mask = (char *)rindex(chptr->chname, ':')))
+ mask++;
+ }
+ else
+ mask = (char *)NULL;
+
+ for (i = fdas.highest; i >= 0; i--)
+ {
+ if (!(cptr = local[fdas.fd[i]]) || (cptr == from) ||
+ IsMe(cptr))
+ continue;
+ if (!BadPtr(mask) && match(mask, cptr->name))
+ continue;
+ if (chptr &&
+ *chptr->chname == '!' && !(cptr->serv->version & SV_NJOIN))
+ continue;
+ if ((ver & cptr->serv->version) == 0)
+ {
+ rc = 1;
+ continue;
+ }
+ if (!len)
+ {
+#if ! USE_STDARG
+ len = sendprep(format, p1, p2, p3, p4, p5, p6, p7,
+ p8, p9, p10, p11);
+#else
+ va_list va;
+ va_start(va, format);
+ len = vsendprep(format, va);
+ va_end(va);
+#endif
+ }
+ (void)send_message(cptr, sendbuf, len);
+ }
+ return rc;
+}
+
+#if ! USE_STDARG
+/*VARARGS*/
+int
+sendto_match_servs_notv(chptr, from, ver, format, p1, p2, p3, p4, p5,
+ p6, p7, p8, p9, p10, p11)
+aChannel *chptr;
+aClient *from;
+char *format, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11;
+int ver;
+#else
+int
+sendto_match_servs_notv(aChannel *chptr, aClient *from, int ver,
+ char *format, ...)
+#endif
+{
+ Reg int i, len=0, rc=0;
+ Reg aClient *cptr;
+ char *mask;
+
+ if (chptr)
+ {
+ if (*chptr->chname == '&')
+ return 0;
+ if ((mask = (char *)rindex(chptr->chname, ':')))
+ mask++;
+ }
+ else
+ mask = (char *)NULL;
+
+ for (i = fdas.highest; i >= 0; i--)
+ {
+ if (!(cptr = local[fdas.fd[i]]) || (cptr == from) ||
+ IsMe(cptr))
+ continue;
+ if (!BadPtr(mask) && match(mask, cptr->name))
+ continue;
+ if (chptr &&
+ *chptr->chname == '!' && !(cptr->serv->version & SV_NJOIN))
+ continue;
+ if ((ver & cptr->serv->version) != 0)
+ {
+ rc = 1;
+ continue;
+ }
+ if (!len)
+ {
+#if ! USE_STDARG
+ len = sendprep(format, p1, p2, p3, p4, p5, p6, p7,
+ p8, p9, p10, p11);
+#else
+ va_list va;
+ va_start(va, format);
+ len = vsendprep(format, va);
+ va_end(va);
+#endif
+ }
+ (void)send_message(cptr, sendbuf, len);
+ }
+ return rc;
+}
+
+/*
+ * sendto_match_butone
+ *
+ * Send to all clients which match the mask in a way defined on 'what';
+ * either by user hostname or user servername.
+ */
+/*VARARGS*/
+#if ! USE_STDARG
+void sendto_match_butone(one, from, mask, what, pattern,
+ p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11)
+aClient *one, *from;
+int what;
+char *mask, *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9,*p10,*p11;
+#else
+void sendto_match_butone(aClient *one, aClient *from, char *mask, int what, char *pattern, ...)
+
+#endif
+{
+ int i;
+ aClient *cptr,
+ *srch;
+
+ 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))
+ {
+ /*
+ ** we can save some CPU here by not searching the
+ ** entire list of users since it is ordered!
+ ** original idea/code from pht.
+ ** it could be made better by looping on the list of
+ ** servers to avoid non matching blocks in the list
+ ** (srch->from != cptr), but then again I never
+ ** bothered to worry or optimize this routine -kalt
+ */
+ for (srch = cptr->prev; srch; srch = srch->prev)
+ {
+ if (!IsRegisteredUser(srch))
+ continue;
+ if (srch->from == cptr &&
+ match_it(srch, mask, what))
+ break;
+ }
+ if (srch == NULL)
+ continue;
+ }
+ /* my client, does he match ? */
+ else if (!(IsRegisteredUser(cptr) &&
+ match_it(cptr, mask, what)))
+ continue;
+#if ! USE_STDARG
+ sendto_prefix_one(cptr, from, pattern,
+ p1, p2, p3, p4, p5, p6, p7, p8, p9, p10,p11);
+#else
+ {
+ va_list va;
+ va_start(va, pattern);
+ vsendto_prefix_one(cptr, from, pattern, va);
+ va_end(va);
+ }
+#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!!
+*/
+#if ! USE_STDARG
+/*VARARGS*/
+void sendto_ops_butone(one, from, pattern,
+ p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11)
+aClient *one, *from;
+char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11;
+#else
+void sendto_ops_butone(aClient *one, aClient *from, char *pattern, ...)
+#endif
+{
+ Reg int i;
+ Reg aClient *cptr;
+
+ bzero((char *)&sentalong[0], sizeof(int) * MAXCONNECTIONS);
+ for (cptr = client; cptr; cptr = cptr->next)
+ {
+ if (IsService(cptr) || !IsRegistered(cptr))
+ continue;
+ if ((IsPerson(cptr) && !SendWallops(cptr)) || IsMe(cptr))
+ continue;
+ if (MyClient(cptr) && !(IsServer(from) || IsMe(from)))
+ 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;
+#if ! USE_STDARG
+ sendto_prefix_one(cptr->from, from, pattern,
+ p1, p2, p3, p4, p5, p6, p7, p8, p9, p10,p11);
+#else
+ {
+ va_list va;
+ va_start(va, pattern);
+ vsendto_prefix_one(cptr->from, from, pattern, va);
+ va_end(va);
+ }
+#endif
+ }
+ return;
+}
+
+/*
+ * to - destination client
+ * from - client which message is from
+ *
+ * NOTE: NEITHER OF THESE SHOULD *EVER* BE NULL!!
+ * -avalon
+ */
+#if ! USE_STDARG
+/*VARARGS*/
+void sendto_prefix_one(to, from, pattern,
+ p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11)
+Reg aClient *to;
+Reg aClient *from;
+char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11;
+#else
+void sendto_prefix_one(aClient *to, aClient *from, char *pattern, ...)
+#endif
+{
+ int len;
+
+#if ! USE_STDARG
+ len = sendpreprep(to, from, pattern, p1, p2, p3, p4, p5, p6, p7, p8,
+ p9, p10, p11);
+#else
+ va_list va;
+ va_start(va, pattern);
+ len = vsendpreprep(to, from, pattern, va);
+ va_end(va);
+#endif
+ send_message(to, psendbuf, len);
+ return;
+}
+
+#if USE_STDARG
+static void vsendto_prefix_one(aClient *to, aClient *from, char *pattern, va_list va)
+{
+ int len;
+
+ len = vsendpreprep(to, from, pattern, va);
+ send_message(to, psendbuf, len);
+ return;
+}
+#endif
+
+
+/*
+ * sends a message to a server-owned channel
+ */
+static SChan svchans[SCH_MAX] = {
+ { SCH_ERROR, "&ERRORS", NULL },
+ { SCH_NOTICE, "&NOTICES", NULL },
+ { SCH_KILL, "&KILLS", NULL },
+ { SCH_CHAN, "&CHANNEL", NULL },
+ { SCH_NUM, "&NUMERICS", NULL },
+ { SCH_SERVER, "&SERVERS", NULL },
+ { SCH_HASH, "&HASH", NULL },
+ { SCH_LOCAL, "&LOCAL", NULL },
+ { SCH_SERVICE, "&SERVICES", NULL },
+ { SCH_DEBUG, "&DEBUG", NULL },
+ { SCH_AUTH, "&AUTH", NULL },
+};
+
+
+void setup_svchans()
+{
+ int i;
+ SChan *shptr;
+
+ for (i = SCH_MAX, shptr = svchans + (i - 1); i > 0; i--, shptr--)
+ shptr->svc_ptr = find_channel(shptr->svc_chname, NULL);
+}
+
+#if ! USE_STDARG
+void sendto_flag(chan, pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10,p11)
+u_int chan;
+char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11;
+#else
+void sendto_flag(u_int chan, char *pattern, ...)
+#endif
+{
+ Reg aChannel *chptr = NULL;
+ SChan *shptr;
+ char nbuf[1024];
+
+ if (chan < 1 || chan > SCH_MAX)
+ chan = SCH_NOTICE;
+ shptr = svchans + (chan - 1);
+
+ if ((chptr = shptr->svc_ptr))
+ {
+#if ! USE_STDARG
+ (void)sprintf(nbuf, pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11);
+#else
+ {
+ va_list va;
+ va_start(va, pattern);
+ (void)vsprintf(nbuf, pattern, va);
+ va_end(va);
+ }
+#endif
+ sendto_channel_butserv(chptr, &me, ":%s NOTICE %s :%s", ME, chptr->chname, nbuf);
+
+#ifdef USE_SERVICES
+ switch (chan)
+ {
+ case SCH_ERROR:
+ check_services_butone(SERVICE_WANT_ERRORS, NULL, &me,
+ "&ERRORS :%s", nbuf);
+ break;
+ case SCH_NOTICE:
+ check_services_butone(SERVICE_WANT_NOTICES, NULL, &me,
+ "&NOTICES :%s", nbuf);
+ break;
+ case SCH_LOCAL:
+ check_services_butone(SERVICE_WANT_LOCAL, NULL, &me,
+ "&LOCAL :%s", nbuf);
+ break;
+ case SCH_NUM:
+ check_services_butone(SERVICE_WANT_NUMERICS, NULL, &me,
+ "&NUMERICS :%s", nbuf);
+ break;
+ }
+#endif
+ }
+
+ return;
+}
+
+/*
+ * sendto_flog
+ * cptr used for firsttime, auth, exitc, send/received M/K
+ * msg replaces duration if duration is 0
+ * duration only used if non 0
+ * username can't get it from cptr
+ * hostname i.e.
+ */
+void sendto_flog(cptr, msg, duration, username, hostname)
+aClient *cptr;
+char *msg, *username, *hostname;
+time_t duration;
+{
+ char linebuf[1024]; /* auth reply might be long.. */
+ int logfile;
+
+#ifdef USE_SERVICES
+ if (duration)
+ {
+ (void)sprintf(linebuf,
+ "%s (%3d:%02d:%02d): %s@%s [%s] %c %lu %luKb %lu %luKb\n",
+ myctime(cptr->firsttime),
+ (int) (duration / 3600),
+ (int) ((duration % 3600) / 60),
+ (int) (duration % 60),
+ username, hostname, cptr->auth,
+ cptr->exitc, cptr->sendM, cptr->sendK,
+ cptr->receiveM, cptr->receiveK);
+ check_services_butone(SERVICE_WANT_USERLOG, NULL, &me,
+ "USERLOG :%s", linebuf);
+ }
+ else
+ {
+ (void)sprintf(linebuf,
+ "%s (%s): %s@%s [%s] %c %lu %luKb %lu %luKb\n",
+ myctime(cptr->firsttime), msg, username,
+ hostname, cptr->auth,
+ cptr->exitc, cptr->sendM, cptr->sendK,
+ cptr->receiveM, cptr->receiveK);
+ check_services_butone(SERVICE_WANT_CONNLOG, NULL, &me,
+ "CONNLOG :%s", linebuf);
+ }
+#endif
+ /*
+ * 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
+ * file in 3 seconds. -avalon (curtesy of wumpus)
+ */
+ (void)alarm(3);
+ if (
+#ifdef FNAME_USERLOG
+ (duration &&
+ (logfile = open(FNAME_USERLOG, O_WRONLY|O_APPEND)) != -1)
+# ifdef FNAME_CONNLOG
+ ||
+# endif
+#endif
+#ifdef FNAME_CONNLOG
+ (!duration &&
+ (logfile = open(FNAME_CONNLOG, O_WRONLY|O_APPEND)) != -1)
+#else
+# ifndef FNAME_USERLOG
+ 0
+# endif
+#endif
+ )
+ {
+ (void)alarm(0);
+#ifndef USE_SERVICES
+ if (duration)
+ (void)sprintf(linebuf,
+ "%s (%3d:%02d:%02d): %s@%s [%s] %c %lu %luKb %lu %luKb\n",
+ myctime(cptr->firsttime),
+ (int) (duration / 3600),
+ (int) ((duration % 3600) / 60),
+ (int) (duration % 60),
+ username, hostname, cptr->auth,
+ cptr->exitc, cptr->sendM, cptr->sendK,
+ cptr->receiveM, cptr->receiveK);
+ else
+ (void)sprintf(linebuf,
+ "%s (%s): %s@%s [%s] %c %lu %luKb %lu %luKb\n",
+ myctime(cptr->firsttime), msg, username,
+ hostname, cptr->auth,
+ cptr->exitc, cptr->sendM, cptr->sendK,
+ cptr->receiveM, cptr->receiveK);
+#endif
+ (void)alarm(3);
+ (void)write(logfile, linebuf, strlen(linebuf));
+ (void)alarm(0);
+ (void)close(logfile);
+ }
+ (void)alarm(0);
+}
+#endif /* CLIENT_COMPILE */
diff --git a/common/send_ext.h b/common/send_ext.h
new file mode 100644
index 0000000..7f0d409
--- /dev/null
+++ b/common/send_ext.h
@@ -0,0 +1,82 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, common/send_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in common/send.c.
+ */
+
+/* External definitions for global functions.
+ */
+#ifndef SEND_C
+#define EXTERN extern
+#else /* SEND_C */
+#define EXTERN
+#endif /* SEND_C */
+EXTERN int send_queued __P((aClient *to));
+#if ! USE_STDARG
+EXTERN int sendto_one();
+#else /* USE_STDARG */
+EXTERN int vsendto_one (aClient *to, char *pattern, va_list va);
+EXTERN int sendto_one (aClient *to, char *pattern, ...);
+#endif /* USE_STDARG */
+#ifndef CLIENT_COMPILE
+EXTERN void flush_connections __P((int fd));
+EXTERN void flush_fdary __P((FdAry *));
+EXTERN void setup_svchans();
+EXTERN void sendto_flog __P((aClient *cptr, char *msg, time_t duration,
+ char *username, char *hostname));
+#if ! USE_STDARG
+EXTERN void sendto_channel_butone();
+EXTERN void sendto_serv_butone();
+EXTERN int sendto_serv_v();
+EXTERN int sendto_serv_notv();
+EXTERN void sendto_common_channels();
+EXTERN void sendto_channel_butserv();
+EXTERN void sendto_match_servs();
+EXTERN int sendto_match_servs_v();
+EXTERN int sendto_match_servs_notv();
+EXTERN void sendto_match_butone();
+EXTERN void sendto_ops_butone();
+EXTERN void sendto_prefix_one();
+EXTERN void sendto_flag();
+#else /* USE_STDARG */
+EXTERN void sendto_channel_butone (aClient *one, aClient *from,
+ aChannel *chptr, char *pattern, ...);
+EXTERN void sendto_serv_butone (aClient *one, char *pattern, ...);
+EXTERN int sendto_serv_v (aClient *one, int ver, char *pattern, ...);
+EXTERN int sendto_serv_notv (aClient *one, int ver, char *pattern, ...);
+EXTERN void sendto_common_channels (aClient *user, char *pattern, ...);
+EXTERN void sendto_channel_butserv (aChannel *chptr, aClient *from,
+ char *pattern, ...);
+EXTERN void sendto_match_servs (aChannel *chptr, aClient *from,
+ char *format, ...);
+EXTERN int sendto_match_servs_v (aChannel *chptr, aClient *from, int ver,
+ char *format, ...);
+EXTERN int sendto_match_servs_notv (aChannel *chptr, aClient *from, int ver,
+ char *format, ...);
+EXTERN void sendto_match_butone (aClient *one, aClient *from, char *mask,
+ int what, char *pattern, ...);
+EXTERN void sendto_ops_butone (aClient *one, aClient *from, char *pattern,
+ ...);
+EXTERN void sendto_prefix_one (aClient *to, aClient *from, char *pattern,
+ ...);
+EXTERN void sendto_flag (u_int chan, char *pattern, ...);
+#endif /* USE_STDARG */
+#endif /* CLIENT_COMPILE */
+#undef EXTERN
diff --git a/common/struct_def.h b/common/struct_def.h
new file mode 100644
index 0000000..720a531
--- /dev/null
+++ b/common/struct_def.h
@@ -0,0 +1,832 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, common/struct_def.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.
+ */
+
+typedef struct ConfItem aConfItem;
+typedef struct Client aClient;
+typedef struct Channel aChannel;
+typedef struct User anUser;
+typedef struct Server aServer;
+typedef struct Service aService;
+typedef struct SLink Link;
+typedef struct SMode Mode;
+typedef struct fdarray FdAry;
+typedef struct CPing aCPing;
+typedef struct Zdata aZdata;
+#if defined(CACHED_MOTD)
+typedef struct LineItem aMotd;
+#endif
+#if defined(USE_IAUTH)
+typedef struct LineItem aExtCf;
+typedef struct LineItem aExtData;
+#endif
+
+#define HOSTLEN 63 /* Length of hostname. Updated to */
+ /* comply with RFC1123 */
+
+#define NICKLEN 9 /* 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 80
+#define CHANNELLEN 50
+#define PASSWDLEN 20
+#define KEYLEN 23
+#define BUFSIZE 512 /* WARNING: *DONT* CHANGE THIS!!!! */
+#define MAXRECIPIENTS 20
+#define MAXBANS 30
+#define MAXBANLENGTH 1024
+#define BANLEN (USERLEN + NICKLEN + HOSTLEN + 3)
+#define MAXPENALTY 10
+#define CHIDLEN 5 /* WARNING: *DONT* CHANGE THIS!!!! */
+
+#define READBUF_SIZE 16384 /* used in s_bsd.c *AND* s_zip.c ! */
+
+/*
+ * Make up some numbers which should reflect average leaf server connect
+ * queue max size.
+ * queue=(<# of channels> * <channel size> + <user size> * <# of users>) * 2
+ * pool=<queue per client> * <avg. # of clients having data in queue>
+ */
+#define QUEUELEN (((MAXCONNECTIONS / 10) * (CHANNELLEN + BANLEN + 16) +\
+ (HOSTLEN * 4 + REALLEN + NICKLEN + USERLEN + 24) *\
+ (MAXCONNECTIONS / 2)) * 2)
+
+#define BUFFERPOOL (DBUFSIZ * MAXCONNECTIONS * 2) + \
+ (QUEUELEN * MAXSERVERS)
+
+#define USERHOST_REPLYLEN (NICKLEN+HOSTLEN+USERLEN+5)
+
+/*
+** '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 0x001
+#define BOOT_QUICK 0x002
+#define BOOT_DEBUG 0x004
+#define BOOT_INETD 0x008
+#define BOOT_TTY 0x010
+#define BOOT_OPER 0x020
+#define BOOT_AUTODIE 0x040
+#define BOOT_BADTUNE 0x080
+#define BOOT_PROT 0x100
+#define BOOT_STRICTPROT 0x200
+#define BOOT_NOIAUTH 0x400
+
+#define STAT_RECONNECT -7 /* Reconnect attempt for server connections */
+#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_UNKNOWN -2
+#define STAT_ME -1
+#define STAT_SERVER 0
+#define STAT_CLIENT 1
+#define STAT_SERVICE 2
+
+/*
+ * status macros.
+ */
+#define IsRegisteredUser(x) ((x)->status == STAT_CLIENT && (x)->user)
+#define IsRegistered(x) ((x)->status >= STAT_SERVER || \
+ (x)->status == STAT_ME)
+#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) ((x)->status == STAT_SERVICE && (x)->service)
+#define IsReconnect(x) ((x)->status == STAT_RECONNECT)
+
+#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 [unused] */
+#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_XAUTHDONE 0x0080 /* iauth is finished with this client */
+#define FLAGS_DOINGDNS 0x0100 /* client is waiting for a DNS response */
+#define FLAGS_AUTH 0x0200 /* client is waiting on rfc931 response */
+#define FLAGS_WRAUTH 0x0400 /* set if we havent writen to ident server */
+#define FLAGS_LOCAL 0x0800 /* set for local clients */
+#define FLAGS_GOTID 0x1000 /* successful ident lookup achieved */
+#define FLAGS_XAUTH 0x2000 /* waiting on external authentication */
+#define FLAGS_WXAUTH 0x4000 /* same as above, but also prevent parsing */
+#define FLAGS_NONL 0x8000 /* No \n in buffer */
+#define FLAGS_CBURST 0x10000 /* set to mark connection burst being sent */
+#define FLAGS_RILINE 0x20000 /* Restricted i-line [unused?] */
+#define FLAGS_QUIT 0x40000 /* QUIT :comment shows it's not a split */
+#define FLAGS_SPLIT 0x80000 /* client QUITting because of a netsplit */
+#define FLAGS_HIDDEN 0x100000 /* netsplit is behind a hostmask */
+#define FLAGS_UNKCMD 0x200000 /* has sent an unknown command */
+#define FLAGS_ZIP 0x400000 /* link is zipped */
+#define FLAGS_ZIPRQ 0x800000 /* zip requested */
+#define FLAGS_ZIPSTART 0x1000000 /* start of zip (ignore any CRLF) */
+#define FLAGS_HELD 0x8000000 /* connection held and reconnect try */
+
+#define FLAGS_OPER 0x0001 /* Operator */
+#define FLAGS_LOCOP 0x0002 /* Local operator -- SRB */
+#define FLAGS_WALLOP 0x0004 /* send wallops to them */
+#define FLAGS_INVISIBLE 0x0008 /* makes user invisible */
+#define FLAGS_RESTRICTED 0x0010 /* Restricted user */
+#define FLAGS_AWAY 0x0020 /* user is away */
+
+#define SEND_UMODES (FLAGS_INVISIBLE|FLAGS_OPER|FLAGS_WALLOP|FLAGS_AWAY)
+#define ALL_UMODES (SEND_UMODES|FLAGS_LOCOP|FLAGS_RESTRICTED)
+
+/*
+ * flags macros.
+ */
+#define IsOper(x) ((x)->user && (x)->user->flags & FLAGS_OPER)
+#define IsLocOp(x) ((x)->user && (x)->user->flags & FLAGS_LOCOP)
+#define IsInvisible(x) ((x)->user->flags & FLAGS_INVISIBLE)
+#define IsRestricted(x) ((x)->user && \
+ (x)->user->flags & FLAGS_RESTRICTED)
+#define IsAnOper(x) ((x)->user && \
+ (x)->user->flags & (FLAGS_OPER|FLAGS_LOCOP))
+#define IsPerson(x) ((x)->user && IsClient(x))
+#define IsPrivileged(x) (IsServer(x) || IsAnOper(x))
+#define SendWallops(x) ((x)->user->flags & FLAGS_WALLOP)
+#define IsUnixSocket(x) ((x)->flags & FLAGS_UNIX)
+#define IsListening(x) ((x)->flags & FLAGS_LISTEN)
+#define IsLocal(x) (MyConnect(x) && (x)->flags & FLAGS_LOCAL)
+#define IsDead(x) ((x)->flags & FLAGS_DEADSOCKET)
+#define IsHeld(x) ((x)->flags & FLAGS_HELD)
+#define CBurst(x) ((x)->flags & FLAGS_CBURST)
+
+#define SetOper(x) ((x)->user->flags |= FLAGS_OPER)
+#define SetLocOp(x) ((x)->user->flags |= FLAGS_LOCOP)
+#define SetInvisible(x) ((x)->user->flags |= FLAGS_INVISIBLE)
+#define SetRestricted(x) ((x)->user->flags |= FLAGS_RESTRICTED)
+#define SetWallops(x) ((x)->user->flags |= FLAGS_WALLOP)
+#define SetUnixSock(x) ((x)->flags |= FLAGS_UNIX)
+#define SetDNS(x) ((x)->flags |= FLAGS_DOINGDNS)
+#define SetDoneXAuth(x) ((x)->flags |= FLAGS_XAUTHDONE)
+#define DoingDNS(x) ((x)->flags & FLAGS_DOINGDNS)
+#define DoingAuth(x) ((x)->flags & FLAGS_AUTH)
+#define DoingXAuth(x) ((x)->flags & FLAGS_XAUTH)
+#define WaitingXAuth(x) ((x)->flags & FLAGS_WXAUTH)
+#define DoneXAuth(x) ((x)->flags & FLAGS_XAUTHDONE)
+#define NoNewLine(x) ((x)->flags & FLAGS_NONL)
+
+#define ClearOper(x) ((x)->user->flags &= ~FLAGS_OPER)
+#define ClearInvisible(x) ((x)->user->flags &= ~FLAGS_INVISIBLE)
+#define ClearRestricted(x) ((x)->user->flags &= ~FLAGS_RESTRICTED)
+#define ClearWallops(x) ((x)->user->flags &= ~FLAGS_WALLOP)
+#define ClearDNS(x) ((x)->flags &= ~FLAGS_DOINGDNS)
+#define ClearAuth(x) ((x)->flags &= ~FLAGS_AUTH)
+#define ClearXAuth(x) ((x)->flags &= ~FLAGS_XAUTH)
+#define ClearWXAuth(x) ((x)->flags &= ~FLAGS_WXAUTH)
+
+/*
+ * defined debugging levels
+ */
+#define DEBUG_FATAL 0
+#define DEBUG_ERROR 1 /* report_error() and other errors that are found */
+#define DEBUG_READ 2
+#define DEBUG_WRITE 2
+#define DEBUG_NOTICE 3
+#define DEBUG_DNS 4 /* used by all DNS related routines - a *lot* */
+#define DEBUG_INFO 5 /* general usful info */
+#define DEBUG_NUM 6 /* numerics */
+#define DEBUG_SEND 7 /* everything that is sent out */
+#define DEBUG_DEBUG 8 /* anything to do with debugging, ie unimportant :) */
+#define DEBUG_MALLOC 9 /* malloc/free calls */
+#define DEBUG_LIST 10 /* debug list use */
+#define DEBUG_L10 10
+#define DEBUG_L11 11
+
+/*
+ * defines for curses in client
+ */
+#define DUMMY_TERM 0
+#define CURSES_TERM 1
+#define TERMCAP_TERM 2
+
+struct CPing {
+ u_short port; /* port to send pings to */
+ u_long rtt; /* average RTT */
+ u_long ping;
+ u_long seq; /* # sent still in the "window" */
+ u_long lseq; /* sequence # of last sent */
+ u_long recvd; /* # received still in the "window" */
+ u_long lrecvd; /* # received */
+};
+
+struct ConfItem {
+ u_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;
+ u_int pref; /* preference value */
+ struct CPing *ping;
+ time_t hold; /* Hold action until this time (calendar time) */
+#ifndef VMSP
+ aClass *class; /* Class of connection */
+#endif
+ struct ConfItem *next;
+};
+
+#define CONF_ILLEGAL 0x80000000
+#define CONF_MATCH 0x40000000
+#define CONF_QUARANTINED_SERVER 0x000001
+#define CONF_CLIENT 0x000002
+#define CONF_RCLIENT 0x000004
+#define CONF_CONNECT_SERVER 0x000008
+#define CONF_NOCONNECT_SERVER 0x000010
+#define CONF_ZCONNECT_SERVER 0x000020
+#define CONF_LOCOP 0x000040
+#define CONF_OPERATOR 0x000080
+#define CONF_ME 0x000100
+#define CONF_KILL 0x000200
+#define CONF_ADMIN 0x000400
+#ifdef R_LINES
+#define CONF_RESTRICT 0x000800
+#endif
+#define CONF_CLASS 0x001000
+#define CONF_SERVICE 0x002000
+#define CONF_LEAF 0x004000
+#define CONF_LISTEN_PORT 0x008000
+#define CONF_HUB 0x010000
+#define CONF_VER 0x020000
+#define CONF_BOUNCE 0x040000
+#define CONF_OTHERKILL 0x080000
+#define CONF_DENY 0x100000
+
+#define CONF_OPS (CONF_OPERATOR | CONF_LOCOP)
+#define CONF_SERVER_MASK (CONF_CONNECT_SERVER | CONF_NOCONNECT_SERVER |\
+ CONF_ZCONNECT_SERVER)
+#define CONF_CLIENT_MASK (CONF_CLIENT | CONF_RCLIENT | CONF_SERVICE | CONF_OPS | \
+ CONF_SERVER_MASK)
+
+#define IsIllegal(x) ((x)->status & CONF_ILLEGAL)
+
+typedef struct {
+ u_long pi_id;
+ u_long pi_seq;
+ struct timeval pi_tv;
+ aConfItem *pi_cp;
+} Ping;
+
+
+#define PING_REPLY 0x01
+#define PING_CPING 0x02
+
+#ifdef ZIP_LINKS
+/* the minimum amount of data needed to trigger compression */
+# define ZIP_MINIMUM 4096
+
+/* the maximum amount of data to be compressed (can actually be a bit more) */
+# define ZIP_MAXIMUM 8192 /* WARNING: *DON'T* CHANGE THIS!!!! */
+
+struct Zdata {
+ z_stream *in; /* input zip stream data */
+ z_stream *out; /* output zip stream data */
+ char outbuf[ZIP_MAXIMUM]; /* outgoing (unzipped) buffer */
+ int outcount; /* size of outbuf content */
+};
+#endif
+
+struct LineItem
+{
+ char *line;
+ struct LineItem *next;
+};
+
+/*
+ * Client structures
+ */
+struct User {
+ Link *channel; /* chain of channel pointer blocks */
+ Link *invited; /* chain of invite pointer blocks */
+ Link *uwas; /* chain of whowas pointer blocks */
+ char *away; /* pointer to away message */
+ time_t last; /* "idle" time */
+ int refcnt; /* Number of times this block is referenced
+ ** from aClient (field user), aServer (field
+ ** by) and whowas array (field ww_user).
+ */
+ int joined; /* number of channels joined */
+ int flags; /* user modes */
+ struct Server *servp;
+ /*
+ ** 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
+ */
+ aClient *bcptr;
+ char username[USERLEN+1];
+ char host[HOSTLEN+1];
+ char *server;
+};
+
+struct Server {
+ anUser *user; /* who activated this connection */
+ char *up; /* uplink for this server */
+ aConfItem *nline; /* N-line pointer for this server */
+ int version; /* version id for local client */
+ int snum;
+ int stok,
+ ltok;
+ int refcnt; /* Number of times this block is referenced
+ ** from anUser (field servp), aService (field
+ ** servp) and aClient (field serv)
+ */
+ struct Server *nexts, *prevs, *shnext;
+ aClient *bcptr;
+ char by[NICKLEN+1];
+ char tok[5];
+ time_t lastload; /* penalty like counters, see s_serv.c
+ ** should be in the local part, but..
+ */
+};
+
+struct Service {
+ int wants;
+ int type;
+ char *server;
+ aServer *servp;
+ struct Service *nexts, *prevs;
+ aClient *bcptr;
+ char dist[HOSTLEN+1];
+};
+
+struct Client {
+ struct Client *next,*prev, *hnext;
+ anUser *user; /* ...defined, if this is a User */
+ aServer *serv; /* ...defined, if this is a server */
+ aService *service;
+ u_int hashv; /* raw hash value */
+ long flags; /* client flags */
+ 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; /* Free form additional client information */
+ /*
+ ** The following fields are allocated only for local clients
+ ** (directly connected to *this* server with a socket.
+ ** The first of them *MUST* be the "count"--it is the field
+ ** to which the allocation is tied to! *Never* refer to
+ ** these fields, if (from != self).
+ */
+ int count; /* Amount of data in buffer */
+ char buffer[BUFSIZE]; /* Incoming message buffer */
+#ifdef ZIP_LINKS
+ aZdata *zip; /* zip data */
+#endif
+ 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 */
+ 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 */
+ u_short sendB; /* counters to count upto 1-k lots of bytes */
+ u_short receiveB; /* sent and received. */
+ time_t lasttime; /* last time we received data */
+ time_t firsttime; /* time client was created */
+ time_t since; /* last time we parsed something */
+ aClient *acpt; /* listening client which we accepted from */
+ Link *confs; /* Configuration record associated */
+ int authfd; /* fd for rfc931 authentication */
+ char *auth;
+ u_short port; /* and the remote port# too :-) */
+ struct IN_ADDR ip; /* keep real ip# too */
+ struct hostent *hostp;
+ char sockhost[HOSTLEN+1]; /* This is the host name from the socket
+ ** and after which the connection was
+ ** accepted.
+ */
+ char passwd[PASSWDLEN+1];
+ char exitc;
+};
+
+#define CLIENT_LOCAL_SIZE sizeof(aClient)
+#define CLIENT_REMOTE_SIZE offsetof(aClient,count)
+
+/*
+ * statistics structures
+ */
+struct stats {
+ u_int is_cl; /* number of client connections */
+ u_int is_sv; /* number of server connections */
+ u_int is_ni; /* connection but no idea who it was
+ * (can be a P: line that has been removed -krys) */
+ u_short is_cbs; /* bytes sent to clients */
+ u_short is_cbr; /* bytes received to clients */
+ u_short is_sbs; /* bytes sent to servers */
+ u_short is_sbr; /* bytes received to servers */
+ u_long is_cks; /* k-bytes sent to clients */
+ u_long is_ckr; /* k-bytes received to clients */
+ u_long is_sks; /* k-bytes sent to servers */
+ u_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 */
+ u_int is_ac; /* connections accepted */
+ u_int is_ref; /* accepts refused */
+ u_int is_unco; /* unknown commands */
+ u_int is_wrdi; /* command going in wrong direction */
+ u_int is_unpf; /* unknown prefix */
+ u_int is_empt; /* empty message */
+ u_int is_num; /* numeric message */
+ u_int is_kill; /* number of kills generated on collisions */
+ u_int is_fake; /* MODE 'fakes' */
+ u_int is_asuc; /* successful auth requests */
+ u_int is_abad; /* bad auth requests */
+ u_int is_udpok; /* packets recv'd on udp port */
+ u_int is_udperr; /* packets recvfrom errors on udp port */
+ u_int is_udpdrop; /* packets recv'd but dropped on udp port */
+ u_int is_loc; /* local connections made */
+ u_int is_nosrv; /* user without server */
+ u_long is_wwcnt; /* number of nicks overwritten in whowas[] */
+ u_long is_wwt; /* sum of elapsed time on when overwriting whowas[]*/
+ u_long is_wwMt; /* max elapsed time on when overwriting whowas[] */
+ u_long is_wwmt; /* min elapsed time on when overwriting whowas[] */
+ u_long is_lkcnt; /* number of nicks overwritten in locked[] */
+ u_long is_lkt; /* sum of elapsed time on when overwriting locked[]*/
+ u_long is_lkMt; /* max elapsed time on when overwriting locked[] */
+ u_long is_lkmt; /* min elapsed time on when overwriting locked[] */
+ u_int is_ckl; /* calls to check_link() */
+ u_int is_cklQ; /* rejected: SendQ too high */
+ u_int is_ckly; /* rejected: link too young */
+ u_int is_cklno; /* rejected: "flood" */
+ u_int is_cklok; /* accepted */
+ u_int is_cklq; /* accepted early */
+};
+
+/* mode structure for channels */
+
+struct SMode {
+ u_int mode;
+ int limit;
+ char key[KEYLEN+1];
+};
+
+/* Message table structure */
+
+struct Message {
+ char *cmd;
+ int (* func)();
+ int parameters;
+ u_int flags;
+ /* bit 0 set means that this command is allowed to be used
+ * only on the average of once per 2 seconds -SRB */
+ u_int count; /* total count */
+ u_int rcount; /* remote count */
+ u_long bytes;
+};
+
+#define MSG_LAG 0x0001
+#define MSG_NOU 0x0002 /* Not available to users */
+#define MSG_SVC 0x0004 /* Services only */
+#define MSG_NOUK 0x0008 /* Not available to unknowns */
+#define MSG_REG 0x0010 /* Must be registered */
+#define MSG_REGU 0x0020 /* Must be a registered user */
+/*#define MSG_PP 0x0040*/
+/*#define MSG_FRZ 0x0080*/
+#define MSG_OP 0x0100 /* opers only */
+#define MSG_LOP 0x0200 /* locops only */
+
+/* fd array structure */
+
+struct fdarray {
+ int fd[MAXCONNECTIONS];
+ int highest;
+};
+
+/* general link structure used for chains */
+
+struct SLink {
+ struct SLink *next;
+ union {
+ aClient *cptr;
+ aChannel *chptr;
+ aConfItem *aconf;
+ char *cp;
+ int i;
+ } value;
+ int flags;
+};
+
+/* channel structure */
+
+struct Channel {
+ struct Channel *nextch, *prevch, *hnextch;
+ u_int hashv; /* raw hash value */
+ Mode mode;
+ char topic[TOPICLEN+1];
+ int users; /* current membership total */
+ Link *members; /* channel members */
+ Link *invites; /* outstanding invitations */
+ Link *mlist; /* list of extended modes: +b/+e/+I */
+ Link *clist; /* list of connections which are members */
+ time_t history; /* channel history (aka channel delay) */
+ time_t reop; /* server reop stamp for !channels */
+ char chname[1];
+};
+
+/*
+** Channel Related macros follow
+*/
+
+/* Channel related flags */
+
+#define CHFL_UNIQOP 0x0001 /* Channel creator */
+#define CHFL_CHANOP 0x0002 /* Channel operator */
+#define CHFL_VOICE 0x0004 /* the power to speak */
+#define CHFL_BAN 0x0008 /* ban channel flag */
+#define CHFL_EXCEPTION 0x0010 /* exception channel flag */
+#define CHFL_INVITE 0x0020 /* invite channel flag */
+
+/* Channel Visibility macros */
+
+#define MODE_UNIQOP CHFL_UNIQOP
+#define MODE_CHANOP CHFL_CHANOP
+#define MODE_VOICE CHFL_VOICE
+#define MODE_PRIVATE 0x0008
+#define MODE_SECRET 0x0010
+#define MODE_MODERATED 0x0020
+#define MODE_TOPICLIMIT 0x0040
+#define MODE_INVITEONLY 0x0080
+#define MODE_NOPRIVMSGS 0x0100
+#define MODE_KEY 0x0200
+#define MODE_BAN 0x0400
+#define MODE_LIMIT 0x0800
+#define MODE_ANONYMOUS 0x1000
+#define MODE_QUIET 0x2000
+#define MODE_EXCEPTION 0x4000
+#define MODE_INVITE 0x8000
+#define MODE_REOP 0x10000
+#define MODE_FLAGS 0x1ffff
+/*
+ * mode flags which take another parameter (With PARAmeterS)
+ */
+#define MODE_WPARAS (MODE_UNIQOP|MODE_CHANOP|MODE_VOICE|MODE_BAN|MODE_KEY\
+ |MODE_LIMIT|MODE_INVITE|MODE_EXCEPTION)
+/*
+ * 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 not shown but names are */
+#define HiddenChannel(x) ((x) && ((x)->mode.mode & MODE_PRIVATE))
+/* channel visible */
+#define ShowChannel(v,c) (PubChannel(c) || IsMember((v),(c)))
+#define IsAnonymous(c) ((c) && ((c)->mode.mode & MODE_ANONYMOUS))
+#define PubChannel(x) ((!x) || ((x)->mode.mode &\
+ (MODE_PRIVATE | MODE_SECRET)) == 0)
+
+/*
+#define IsMember(u, c) (assert(*(c)->chname != '\0'), find_user_link((c)->members, u) ? 1 : 0)
+#define IsMember(u, c) (find_user_link((c)->members, u) ? 1 : 0)
+*/
+#define IsMember(u, c) (u && (u)->user && \
+ find_channel_link((u)->user->channel, c) ? 1 : 0)
+#ifdef CLIENT_COMPILE
+# define IsChannelName(n) ((n) && (*(n) == '#' || *(n) == '&' ||\
+ *(n) == '+' || *(n) == '!'))
+#else
+# define IsChannelName(n) ((n) && (*(n) == '#' || *(n) == '&' ||\
+ *(n) == '+' || \
+ (*(n) == '!' && cid_ok(n))))
+#endif
+#define IsQuiet(x) ((x)->mode.mode & MODE_QUIET)
+#define UseModes(n) ((n) && (*(n) == '#' || *(n) == '&' || \
+ *(n) == '!'))
+
+/* 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 MyPerson(x) (MyConnect(x) && IsPerson(x))
+#define MyOper(x) (MyConnect(x) && IsOper(x))
+#define MyService(x) (MyConnect(x) && IsService(x))
+#define ME me.name
+
+#define GotDependantClient(x) (x->prev && \
+ ((IsRegisteredUser(x->prev) && \
+ x->prev->user->servp == x->serv) || \
+ (IsService(x->prev) && \
+ x->prev->service->servp == x->serv)))
+
+typedef struct {
+ u_long is_user[2]; /* users, non[0] invis and invis[1] */
+ u_long is_serv; /* servers */
+ u_long is_service; /* services */
+ u_long is_chan; /* channels */
+ u_long is_chanmem;
+ u_long is_chanusers; /* channels users */
+ u_long is_hchan; /* channels in history */
+ u_long is_hchanmem;
+ u_long is_cchan; /* channels in cache */
+ u_long is_cchanmem;
+ u_long is_away; /* away sets */
+ u_long is_awaymem;
+ u_long is_oper; /* opers */
+ u_long is_bans; /* bans */
+ u_long is_banmem;
+ u_long is_invite; /* invites */
+ u_long is_class; /* classes */
+ u_long is_conf; /* conf lines */
+ u_long is_confmem;
+ u_long is_conflink; /* attached conf lines */
+ u_long is_myclnt; /* local clients */
+ u_long is_myserv; /* local servers */
+ u_long is_myservice; /* local services */
+ u_long is_unknown; /* unknown (local) connections */
+ u_long is_wwusers; /* users kept for whowas[] */
+ u_long is_wwaways; /* aways in users in whowas[] */
+ u_long is_wwawaysmem;
+ u_long is_wwuwas; /* uwas links */
+ u_long is_localc; /* local items (serv+service+client+..) */
+ u_long is_remc; /* remote clients */
+ u_long is_users; /* user structs */
+ u_long is_useri; /* user invites */
+ u_long is_userc; /* user links to channels */
+ u_long is_auth; /* OTHER ident reply block */
+ u_long is_authmem;
+ u_int is_dbuf; /* number of dbuf allocated (originally) */
+ u_int is_dbufnow; /* number of dbuf allocated */
+ u_int is_dbufuse; /* number of dbuf in use */
+ u_int is_dbufmin; /* min number of dbuf in use */
+ u_int is_dbufmax; /* max number of dbuf in use */
+ u_int is_dbufmore; /* how many times we increased the bufferpool*/
+} istat_t;
+
+/* 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 sendto_serv */
+
+#define SV_OLD 0x0000
+#define SV_29 0x0001 /* useless, but preserved for coherence */
+#define SV_NJOIN 0x0002 /* server understands the NJOIN command */
+#define SV_NMODE 0x0004 /* server knows new MODEs (+e/+I) */
+#define SV_NCHAN 0x0008 /* server knows new channels -????name */
+ /* ! SV_NJOIN implies ! SV_NCHAN */
+#define SV_2_10 (SV_29|SV_NJOIN|SV_NMODE|SV_NCHAN)
+#define SV_OLDSQUIT 0x1000 /* server uses OLD SQUIT logic */
+
+/* used for sendto_flag */
+
+typedef struct {
+ int svc_chan;
+ char *svc_chname;
+ struct Channel *svc_ptr;
+} SChan;
+
+#define SCH_ERROR 1
+#define SCH_NOTICE 2
+#define SCH_KILL 3
+#define SCH_CHAN 4
+#define SCH_NUM 5
+#define SCH_SERVER 6
+#define SCH_HASH 7
+#define SCH_LOCAL 8
+#define SCH_SERVICE 9
+#define SCH_DEBUG 10
+#define SCH_AUTH 11
+#define SCH_MAX 11
+
+/* 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
+
+/* Client exit codes for log file */
+#define EXITC_UNDEF '-' /* unregistered client */
+#define EXITC_REG '0' /* normal exit */
+#define EXITC_DIE 'd' /* server died */
+#define EXITC_DEAD 'D' /* socket died */
+#define EXITC_ERROR 'E' /* socket error */
+#define EXITC_FLOOD 'F' /* client flooding */
+#define EXITC_KLINE 'k' /* K-lined */
+#define EXITC_KILL 'K' /* KILLed */
+#define EXITC_MBUF 'M' /* mem alloc error */
+#define EXITC_PING 'P' /* ping timeout */
+#define EXITC_SENDQ 'Q' /* send queue exceeded */
+#define EXITC_RLINE 'r' /* R-lined */
+#define EXITC_REF 'R' /* Refused */
+#define EXITC_AREF 'U' /* Unauthorized by iauth */
+#define EXITC_AREFQ 'u' /* Unauthorized by iauth, be quiet */
+#define EXITC_AUTHFAIL 'A' /* Authentication failure (iauth problem) */
+#define EXITC_AUTHTOUT 'a' /* Authentication time out */
+
+/* eXternal authentication slave OPTions */
+#define XOPT_REQUIRED 0x01 /* require authentication be done by iauth */
+#define XOPT_NOTIMEOUT 0x02 /* disallow iauth time outs */
+#define XOPT_EXTWAIT 0x10 /* extend registration ping timeout */
+#define XOPT_EARLYPARSE 0x20 /* allow early parsing and send USER/PASS
+ information to iauth */
+
+/* misc defines */
+
+#define FLUSH_BUFFER -2
+#define UTMP "/etc/utmp"
+#define COMMA ","
+
+#define SAP struct SOCKADDR *
+
+/* IRC client structures */
+
+#ifdef CLIENT_COMPILE
+typedef struct Ignore {
+ char user[NICKLEN+1];
+ char from[USERLEN+HOSTLEN+2];
+ int flags;
+ struct Ignore *next;
+} anIgnore;
+
+#define IGNORE_PRIVATE 1
+#define IGNORE_PUBLIC 2
+#define IGNORE_TOTAL 3
+
+#define HEADERLEN 200
+
+#endif /* CLIENT_COMPILE */
diff --git a/common/support.c b/common/support.c
new file mode 100644
index 0000000..f90e6b0
--- /dev/null
+++ b/common/support.c
@@ -0,0 +1,1190 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, common/support.c
+ * Copyright (C) 1990, 1991 Armin Gruner
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: support.c,v 1.17 1999/06/25 15:36:16 kalt Exp $";
+#endif
+
+#include "os.h"
+#ifndef CLIENT_COMPILE
+# include "s_defines.h"
+#else
+# include "c_defines.h"
+#endif
+#define SUPPORT_C
+#ifndef CLIENT_COMPILE
+# include "s_externs.h"
+#else
+# include "c_externs.h"
+#endif
+#undef SUPPORT_C
+
+char *mystrdup(s)
+char *s;
+{
+ /* Portable strdup(), contributed by mrg, thanks! -roy */
+
+ char *t;
+
+ t = (char *) MyMalloc(strlen(s) + 1);
+ if (t)
+ return ((char *)strcpy(t, s));
+ return NULL;
+}
+
+#if ! 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 */
+ Reg 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 */
+
+#if ! HAVE_STRTOK
+/*
+** NOT encouraged to use!
+*/
+
+char *strtok(str, fs)
+char *str, *fs;
+{
+ static char *pos;
+
+ return strtoken(&pos, str, fs);
+}
+
+#endif /* HAVE_STRTOK */
+
+#if ! HAVE_STRERROR
+/*
+** strerror - return an appropriate system error string to a given errno
+**
+** argv 11/90
+*/
+
+char *strerror(err_no)
+int err_no;
+{
+ static char buff[40];
+ char *errp;
+
+ errp = (err_no > sys_nerr ? (char *)NULL : sys_errlist[err_no]);
+
+ if (errp == (char *)NULL)
+ {
+ errp = buff;
+ SPRINTF(errp, "Unknown Error %d", err_no);
+ }
+ return errp;
+}
+
+#endif /* HAVE_STRERROR */
+
+/**
+ ** 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];
+ Reg char *p;
+
+ (void)strcpy(buf, ctime(&value));
+ if ((p = (char *)index(buf, '\n')) != NULL)
+ *p = '\0';
+
+ return buf;
+}
+
+/*
+** mybasename()
+** removes path from a filename
+*/
+char *
+mybasename(path)
+char *path;
+{
+ char *lastslash;
+
+ if (lastslash = rindex(path, '/'))
+ return lastslash + 1;
+ return path;
+}
+
+#ifdef INET6
+/*
+ * inetntop: return the : notation of a given IPv6 internet number.
+ * make sure the compressed representation (rfc 1884) isn't used.
+ */
+char *inetntop(af, in, out, the_size)
+int af;
+const void *in;
+char *out;
+size_t the_size;
+{
+ static char local_dummy[MYDUMMY_SIZE];
+
+ inet_ntop(af, in, local_dummy, the_size);
+ if (strstr(local_dummy, "::"))
+ {
+ char cnt = 0, *cp = local_dummy, *op = out;
+
+ while (*cp)
+ {
+ if (*cp == ':')
+ cnt += 1;
+ if (*cp++ == '.')
+ {
+ cnt += 1;
+ break;
+ }
+ }
+ cp = local_dummy;
+ while (*cp)
+ {
+ *op++ = *cp++;
+ if (*(cp-1) == ':' && *cp == ':')
+ {
+ if ((cp-1) == local_dummy)
+ {
+ op--;
+ *op++ = '0';
+ *op++ = ':';
+ }
+
+ *op++ = '0';
+ while (cnt++ < 7)
+ {
+ *op++ = ':';
+ *op++ = '0';
+ }
+ }
+ }
+ if (*(op-1)==':') *op++ = '0';
+ *op = '\0';
+ Debug((DEBUG_DNS,"Expanding `%s' -> `%s'", local_dummy,
+ out));
+ }
+ else
+ bcopy(local_dummy, out, 64);
+ return out;
+}
+#endif
+
+#if ! HAVE_INET_NTOA
+/*
+** 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];
+ Reg u_char *s = (u_char *)in;
+ Reg 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;
+}
+#endif
+
+#if ! HAVE_INET_NETOF
+/*
+** inet_netof -- return the net portion of an internet number
+** argv 11/90
+*/
+int inetnetof(in)
+struct in_addr in;
+{
+ register u_long i = ntohl(in.s_addr);
+
+ if (IN_CLASSA(i))
+ return (((i)&IN_CLASSA_NET) >> IN_CLASSA_NSHIFT);
+ else if (IN_CLASSB(i))
+ return (((i)&IN_CLASSB_NET) >> IN_CLASSB_NSHIFT);
+ else
+ return (((i)&IN_CLASSC_NET) >> IN_CLASSC_NSHIFT);
+}
+#endif
+
+#if ! HAVE_INET_ADDR
+# ifndef INADDR_NONE
+# define INADDR_NONE 0xffffffff
+# endif
+/*
+ * Ascii internet address interpretation routine.
+ * The value returned is in network order.
+ */
+u_long
+inetaddr(cp)
+ register const char *cp;
+{
+ struct in_addr val;
+
+ if (inetaton(cp, &val))
+ return (val.s_addr);
+ return (INADDR_NONE);
+}
+#endif
+
+#if ! HAVE_INET_ATON
+/*
+ * Check whether "cp" is a valid ascii representation
+ * of an Internet address and convert to a binary address.
+ * Returns 1 if the address is valid, 0 if not.
+ * This replaces inet_addr, the return value from which
+ * cannot distinguish between failure and a local broadcast address.
+ */
+int
+inetaton(cp, addr)
+ register const char *cp;
+ struct in_addr *addr;
+{
+ register u_long val;
+ register int base, n;
+ register char c;
+ u_int parts[4];
+ register u_int *pp = parts;
+
+ c = *cp;
+ for (;;) {
+ /*
+ * Collect number up to ``.''.
+ * Values are specified as for C:
+ * 0x=hex, 0=octal, isdigit=decimal.
+ */
+ if (!isdigit(c))
+ return (0);
+ val = 0; base = 10;
+ if (c == '0') {
+ c = *++cp;
+ if (c == 'x' || c == 'X')
+ base = 16, c = *++cp;
+ else
+ base = 8;
+ }
+ for (;;) {
+ if (isascii(c) && isdigit(c)) {
+ val = (val * base) + (c - '0');
+ c = *++cp;
+ } else if (base == 16 && isascii(c) && isxdigit(c)) {
+ val = (val << 4) |
+ (c + 10 - (islower(c) ? 'a' : 'A'));
+ c = *++cp;
+ } else
+ break;
+ }
+ if (c == '.') {
+ /*
+ * Internet format:
+ * a.b.c.d
+ * a.b.c (with c treated as 16 bits)
+ * a.b (with b treated as 24 bits)
+ */
+ if (pp >= parts + 3)
+ return (0);
+ *pp++ = val;
+ c = *++cp;
+ } else
+ break;
+ }
+ /*
+ * Check for trailing characters.
+ */
+ if (c != '\0' && (!isascii(c) || !isspace(c)))
+ return (0);
+ /*
+ * Concoct the address according to
+ * the number of parts specified.
+ */
+ n = pp - parts + 1;
+ switch (n) {
+
+ case 0:
+ return (0); /* initial nondigit */
+
+ case 1: /* a -- 32 bits */
+ break;
+
+ case 2: /* a.b -- 8.24 bits */
+ if (val > 0xffffff)
+ return (0);
+ val |= parts[0] << 24;
+ break;
+
+ case 3: /* a.b.c -- 8.8.16 bits */
+ if (val > 0xffff)
+ return (0);
+ val |= (parts[0] << 24) | (parts[1] << 16);
+ break;
+
+ case 4: /* a.b.c.d -- 8.8.8.8 bits */
+ if (val > 0xff)
+ return (0);
+ val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
+ break;
+ }
+ if (addr)
+ addr->s_addr = htonl(val);
+ return (1);
+}
+#endif
+
+#if defined(DEBUGMODE) && !defined(CLIENT_COMPILE)
+void dumpcore(msg, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11)
+char *msg, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11;
+{
+ 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(0);
+ if (now - lastd > 60)
+ {
+ lastd = now;
+ dumps = 1;
+ }
+ else
+ dumps++;
+ p = getpid();
+ if (fork()>0) {
+ kill(p, 3);
+ kill(p, 9);
+ }
+ write_pidfile();
+ SPRINTF(corename, "core.%d", p);
+ (void)rename("core", corename);
+ Debug((DEBUG_FATAL, "Dumped core : core.%d", p));
+ sendto_flag(SCH_ERROR, "Dumped core : core.%d", p);
+ Debug((DEBUG_FATAL, msg, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10,p11));
+ sendto_flag(SCH_ERROR, msg, p1, p2, p3, p4, p5, p6, p7, p8,p9,p10,p11);
+ (void)s_die(0);
+}
+#endif
+
+#if defined(DEBUGMODE) && !defined(CLIENT_COMPILE) && defined(DO_DEBUG_MALLOC)
+
+static char *marray[100000];
+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)
+ {
+# ifndef CLIENT_COMPILE
+ outofmemory();
+# else
+ perror("malloc");
+ exit(-1);
+# endif
+ }
+ bzero(ret, (int)x + SZ_EX);
+ bcopy((char *)&ret, ret, SZ_CH);
+ bcopy((char *)&x, ret + SZ_ST, SZ_ST);
+ bcopy("VAVA", ret + SZ_CHST + (int)x, 4);
+ Debug((DEBUG_MALLOC, "MyMalloc(%ld) = %#x", x, ret + SZ_CHST));
+ for(i = 0, s = marray; *s && i < mindex; i++, s++)
+ ;
+ if (i < 100000)
+ {
+ *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;
+
+ if (x != NULL)
+ {
+ 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)
+ {
+# ifndef CLIENT_COMPILE
+ outofmemory();
+# else
+ perror("realloc");
+ exit(-1);
+# endif
+ }
+ 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 < 100000)
+ {
+ *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]);
+
+ Debug((DEBUG_MALLOC, "MyFree(%#x)",x + SZ_CHST));
+#undef free
+ (void)free(x);
+#define free(x) MyFree(x)
+
+ for (l = 0, s = marray; *s != x && l < mindex; l++, s++)
+ ;
+ if (l < mindex)
+ *s = NULL;
+ else if (l == mindex)
+ Debug((DEBUG_MALLOC, "%#x !found", x));
+}
+#else
+char *MyMalloc(x)
+size_t x;
+{
+ char *ret = (char *)malloc(x);
+
+ if (!ret)
+ {
+# ifndef CLIENT_COMPILE
+ outofmemory();
+# else
+ perror("malloc");
+ exit(-1);
+# endif
+ }
+ return ret;
+}
+
+char *MyRealloc(x, y)
+char *x;
+size_t y;
+ {
+ char *ret = (char *)realloc(x, y);
+
+ if (!ret)
+ {
+# ifndef CLIENT_COMPILE
+ outofmemory();
+# else
+ perror("realloc");
+ exit(-1);
+# endif
+ }
+ return ret;
+ }
+#endif
+
+
+/*
+** read a string terminated by \r or \n in from a fd
+**
+** Created: Sat Dec 12 06:29:58 EST 1992 by avalon
+** Returns:
+** 0 - EOF
+** -1 - error on read
+** >0 - number of bytes returned (<=num)
+** After opening a fd, it is necessary to init dgets() by calling it as
+** dgets(x,y,0);
+** to mark the buffer as being empty.
+*/
+int dgets(fd, buf, num)
+int fd, num;
+char *buf;
+{
+ static char dgbuf[8192];
+ static char *head = dgbuf, *tail = dgbuf;
+ register char *s, *t;
+ register int n, nr;
+
+ /*
+ ** Sanity checks.
+ */
+ if (head == tail)
+ *head = '\0';
+ if (!num)
+ {
+ head = tail = dgbuf;
+ *head = '\0';
+ return 0;
+ }
+ if (num > sizeof(dgbuf) - 1)
+ num = sizeof(dgbuf) - 1;
+dgetsagain:
+ if (head > dgbuf)
+ {
+ for (nr = tail - head, s = head, t = dgbuf; nr > 0; nr--)
+ *t++ = *s++;
+ tail = t;
+ head = dgbuf;
+ }
+ /*
+ ** check input buffer for EOL and if present return string.
+ */
+ if (head < tail &&
+ ((s = index(head, '\n')) || (s = index(head, '\r'))) && s < tail)
+ {
+ n = MIN(s - head + 1, num); /* at least 1 byte */
+dgetsreturnbuf:
+ bcopy(head, buf, n);
+ head += n;
+ if (head == tail)
+ head = tail = dgbuf;
+ return n;
+ }
+
+ if (tail - head >= num) /* dgets buf is big enough */
+ {
+ n = num;
+ goto dgetsreturnbuf;
+ }
+
+ n = sizeof(dgbuf) - (tail - dgbuf) - 1;
+ nr = read(fd, tail, n);
+ if (nr == -1)
+ {
+ head = tail = dgbuf;
+ return -1;
+ }
+ if (!nr)
+ {
+ if (tail > head)
+ {
+ 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;
+}
+
+#if ! USE_STDARG
+/*
+ * By Mika
+ */
+int irc_sprintf(outp, formp,
+ i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11)
+char *outp;
+char *formp;
+char *i0, *i1, *i2, *i3, *i4, *i5, *i6, *i7, *i8, *i9, *i10, *i11;
+{
+ /* rp for Reading, wp for Writing, fp for the Format string */
+ /* we could hack this if we know the format of the stack */
+ char *inp[12];
+ Reg char *rp, *fp, *wp, **pp = inp;
+ Reg char f;
+ Reg long myi;
+ int i;
+
+ inp[0] = i0;
+ inp[1] = i1;
+ inp[2] = i2;
+ inp[3] = i3;
+ inp[4] = i4;
+ inp[5] = i5;
+ inp[6] = i6;
+ inp[7] = i7;
+ inp[8] = i8;
+ inp[9] = i9;
+ inp[10] = i10;
+ inp[11] = i11;
+
+ /*
+ * just scan the format string and puke out whatever is necessary
+ * along the way...
+ */
+
+ for (i = 0, wp = outp, fp = formp; (f = *fp++); )
+ if (f != '%')
+ *wp++ = f;
+ else
+ switch (*fp++)
+ {
+ /* put the most common case at the top */
+ /* copy a string */
+ case 's':
+ for (rp = *pp++; (*wp++ = *rp++); )
+ ;
+ --wp;
+ /* get the next parameter */
+ break;
+ /*
+ * reject range for params to this mean that the
+ * param must be within 100-999 and this +ve int
+ */
+ case 'd':
+ case 'u':
+ myi = (long)*pp++;
+ if ((myi < 100) || (myi > 999))
+ {
+ (void)sprintf(outp, formp, i0, i1, i2,
+ i3, i4, i5, i6, i7, i8,
+ i9, i10, i11);
+ return -1;
+ }
+
+ *wp++ = (char)(myi / 100 + (int) '0');
+ myi %= 100;
+ *wp++ = (char)(myi / 10 + (int) '0');
+ myi %= 10;
+ *wp++ = (char)(myi + (int) '0');
+ break;
+ case 'c':
+ *wp++ = (char)(long)*pp++;
+ break;
+ case '%':
+ *wp++ = '%';
+ break;
+ default :
+ (void)sprintf(outp, formp, i0, i1, i2, i3, i4,
+ i5, i6, i7, i8, i9, i10, i11);
+ return -1;
+ }
+ *wp = '\0';
+ return wp - outp;
+}
+#endif
+
+/*
+ * Make 'readable' version string.
+ */
+char *make_version()
+{
+ int ve, re, mi, dv, pl;
+ char ver[15];
+
+ sscanf(PATCHLEVEL, "%2d%2d%2d%2d%2d", &ve, &re, &mi, &dv, &pl);
+ /* version & revision */
+ sprintf(ver, "%d.%d", ve, (mi == 99) ? re + 1 : re);
+ if (mi == 99) mi = -1;
+ /* minor revision */
+ sprintf(ver + strlen(ver), ".%d", dv ? mi+1 : mi);
+ if (dv) /* alpha/beta, note how visual patchlevel is raised above */
+ sprintf(ver + strlen(ver), "%c%d", DEVLEVEL, dv);
+ if (pl) /* patchlevel */
+ sprintf(ver + strlen(ver), "p%d", pl);
+ return mystrdup(ver);
+}
+
+#ifndef HAVE_TRUNCATE
+/* truncate: set a file to a specified length
+ * I don't know of any UNIX that doesn't have truncate, but CYGWIN32 beta18
+ * doesn't have it. -krys
+ * Replacement version from Dave Miller.
+ */
+int truncate(path, length)
+const char *path;
+off_t length;
+{
+ int fd, res;
+ fd = open(path, O_WRONLY);
+ if (fd == -1)
+ return -1;
+ res = ftruncate(fd, length);
+ close(fd);
+ return res;
+}
+#endif /* HAVE_TRUNCATE */
+
+#if SOLARIS_2_3
+/*
+ * On Solaris 2.3 (SunOS 5.3) systems, gethostbyname() has a bug, it always
+ * returns null in h->aliases. Workaround: use the undocumented
+ * _switch_gethostbyname_r(...).
+ */
+#define HBUFSIZE 4096
+
+struct hostent *solaris_gethostbyname(name)
+ const char *name;
+{
+ static struct hostent hp;
+ static char buf[HBUFSIZE];
+
+ return _switch_gethostbyname_r(name, &hp, buf, sizeof(buf), &h_errno);
+}
+#endif /* SOLARIS_2_3 */
+
+#if HAVE_MEMCMP && MEMCMP_BROKEN
+/*
+ * Some OS may have a memcmp that is not 8-bit clean.
+ *
+ * Copyright (C) 1991, 1993, 1995 Free Software Foundation, Inc.
+ * Contributed by Torbjorn Granlund (tege@sics.se).
+ *
+ * NOTE: The canonical source of this part of the file is maintained with the
+ * GNU C Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+ */
+
+/* Type to use for aligned memory operations.
+ This should normally be the biggest type supported by a single load
+ and store. Must be an unsigned type. */
+#define op_t unsigned long int
+#define OPSIZ (sizeof(op_t))
+
+/* Threshold value for when to enter the unrolled loops. */
+#define OP_T_THRES 16
+
+/* Type to use for unaligned operations. */
+typedef unsigned char byte;
+
+#if ! WORDS_BIGENDIAN
+#define MERGE(w0, sh_1, w1, sh_2) (((w0) >> (sh_1)) | ((w1) << (sh_2)))
+#else
+#define MERGE(w0, sh_1, w1, sh_2) (((w0) << (sh_1)) | ((w1) >> (sh_2)))
+#endif
+
+#if WORDS_BIGENDIAN
+#define CMP_LT_OR_GT(a, b) ((a) > (b) ? 1 : -1)
+#else
+#define CMP_LT_OR_GT(a, b) memcmp_bytes ((a), (b))
+#endif
+
+/* BE VERY CAREFUL IF YOU CHANGE THIS CODE! */
+
+/* The strategy of this memcmp is:
+
+ 1. Compare bytes until one of the block pointers is aligned.
+
+ 2. Compare using memcmp_common_alignment or
+ memcmp_not_common_alignment, regarding the alignment of the other
+ block after the initial byte operations. The maximum number of
+ full words (of type op_t) are compared in this way.
+
+ 3. Compare the few remaining bytes. */
+
+#if ! WORDS_BIGENDIAN
+/* memcmp_bytes -- Compare A and B bytewise in the byte order of the machine.
+ A and B are known to be different.
+ This is needed only on little-endian machines. */
+#ifdef __GNUC__
+__inline
+#endif
+static int
+memcmp_bytes (a, b)
+ op_t a, b;
+{
+ long int srcp1 = (long int) &a;
+ long int srcp2 = (long int) &b;
+ op_t a0, b0;
+
+ do
+ {
+ a0 = ((byte *) srcp1)[0];
+ b0 = ((byte *) srcp2)[0];
+ srcp1 += 1;
+ srcp2 += 1;
+ }
+ while (a0 == b0);
+ return a0 - b0;
+}
+#endif
+
+/* memcmp_common_alignment -- Compare blocks at SRCP1 and SRCP2 with LEN `op_t'
+ objects (not LEN bytes!). Both SRCP1 and SRCP2 should be aligned for
+ memory operations on `op_t's. */
+#ifdef __GNUC__
+__inline
+#endif
+static int
+memcmp_common_alignment (srcp1, srcp2, len)
+ long int srcp1;
+ long int srcp2;
+ size_t len;
+{
+ op_t a0, a1;
+ op_t b0, b1;
+
+ switch (len % 4)
+ {
+ case 2:
+ a0 = ((op_t *) srcp1)[0];
+ b0 = ((op_t *) srcp2)[0];
+ srcp1 -= 2 * OPSIZ;
+ srcp2 -= 2 * OPSIZ;
+ len += 2;
+ goto do1;
+ case 3:
+ a1 = ((op_t *) srcp1)[0];
+ b1 = ((op_t *) srcp2)[0];
+ srcp1 -= OPSIZ;
+ srcp2 -= OPSIZ;
+ len += 1;
+ goto do2;
+ case 0:
+ if (OP_T_THRES <= 3 * OPSIZ && len == 0)
+ return 0;
+ a0 = ((op_t *) srcp1)[0];
+ b0 = ((op_t *) srcp2)[0];
+ goto do3;
+ case 1:
+ a1 = ((op_t *) srcp1)[0];
+ b1 = ((op_t *) srcp2)[0];
+ srcp1 += OPSIZ;
+ srcp2 += OPSIZ;
+ len -= 1;
+ if (OP_T_THRES <= 3 * OPSIZ && len == 0)
+ goto do0;
+ /* Fall through. */
+ }
+
+ do
+ {
+ a0 = ((op_t *) srcp1)[0];
+ b0 = ((op_t *) srcp2)[0];
+ if (a1 != b1)
+ return CMP_LT_OR_GT (a1, b1);
+
+ do3:
+ a1 = ((op_t *) srcp1)[1];
+ b1 = ((op_t *) srcp2)[1];
+ if (a0 != b0)
+ return CMP_LT_OR_GT (a0, b0);
+
+ do2:
+ a0 = ((op_t *) srcp1)[2];
+ b0 = ((op_t *) srcp2)[2];
+ if (a1 != b1)
+ return CMP_LT_OR_GT (a1, b1);
+
+ do1:
+ a1 = ((op_t *) srcp1)[3];
+ b1 = ((op_t *) srcp2)[3];
+ if (a0 != b0)
+ return CMP_LT_OR_GT (a0, b0);
+
+ srcp1 += 4 * OPSIZ;
+ srcp2 += 4 * OPSIZ;
+ len -= 4;
+ }
+ while (len != 0);
+
+ /* This is the right position for do0. Please don't move
+ it into the loop. */
+ do0:
+ if (a1 != b1)
+ return CMP_LT_OR_GT (a1, b1);
+ return 0;
+}
+
+/* memcmp_not_common_alignment -- Compare blocks at SRCP1 and SRCP2 with LEN
+ `op_t' objects (not LEN bytes!). SRCP2 should be aligned for memory
+ operations on `op_t', but SRCP1 *should be unaligned*. */
+#ifdef __GNUC__
+__inline
+#endif
+static int
+memcmp_not_common_alignment (srcp1, srcp2, len)
+ long int srcp1;
+ long int srcp2;
+ size_t len;
+{
+ op_t a0, a1, a2, a3;
+ op_t b0, b1, b2, b3;
+ op_t x;
+ int shl, shr;
+
+ /* Calculate how to shift a word read at the memory operation
+ aligned srcp1 to make it aligned for comparison. */
+
+ shl = 8 * (srcp1 % OPSIZ);
+ shr = 8 * OPSIZ - shl;
+
+ /* Make SRCP1 aligned by rounding it down to the beginning of the `op_t'
+ it points in the middle of. */
+ srcp1 &= -OPSIZ;
+
+ switch (len % 4)
+ {
+ case 2:
+ a1 = ((op_t *) srcp1)[0];
+ a2 = ((op_t *) srcp1)[1];
+ b2 = ((op_t *) srcp2)[0];
+ srcp1 -= 1 * OPSIZ;
+ srcp2 -= 2 * OPSIZ;
+ len += 2;
+ goto do1;
+ case 3:
+ a0 = ((op_t *) srcp1)[0];
+ a1 = ((op_t *) srcp1)[1];
+ b1 = ((op_t *) srcp2)[0];
+ srcp2 -= 1 * OPSIZ;
+ len += 1;
+ goto do2;
+ case 0:
+ if (OP_T_THRES <= 3 * OPSIZ && len == 0)
+ return 0;
+ a3 = ((op_t *) srcp1)[0];
+ a0 = ((op_t *) srcp1)[1];
+ b0 = ((op_t *) srcp2)[0];
+ srcp1 += 1 * OPSIZ;
+ goto do3;
+ case 1:
+ a2 = ((op_t *) srcp1)[0];
+ a3 = ((op_t *) srcp1)[1];
+ b3 = ((op_t *) srcp2)[0];
+ srcp1 += 2 * OPSIZ;
+ srcp2 += 1 * OPSIZ;
+ len -= 1;
+ if (OP_T_THRES <= 3 * OPSIZ && len == 0)
+ goto do0;
+ /* Fall through. */
+ }
+
+ do
+ {
+ a0 = ((op_t *) srcp1)[0];
+ b0 = ((op_t *) srcp2)[0];
+ x = MERGE(a2, shl, a3, shr);
+ if (x != b3)
+ return CMP_LT_OR_GT (x, b3);
+
+ do3:
+ a1 = ((op_t *) srcp1)[1];
+ b1 = ((op_t *) srcp2)[1];
+ x = MERGE(a3, shl, a0, shr);
+ if (x != b0)
+ return CMP_LT_OR_GT (x, b0);
+
+ do2:
+ a2 = ((op_t *) srcp1)[2];
+ b2 = ((op_t *) srcp2)[2];
+ x = MERGE(a0, shl, a1, shr);
+ if (x != b1)
+ return CMP_LT_OR_GT (x, b1);
+
+ do1:
+ a3 = ((op_t *) srcp1)[3];
+ b3 = ((op_t *) srcp2)[3];
+ x = MERGE(a1, shl, a2, shr);
+ if (x != b2)
+ return CMP_LT_OR_GT (x, b2);
+
+ srcp1 += 4 * OPSIZ;
+ srcp2 += 4 * OPSIZ;
+ len -= 4;
+ }
+ while (len != 0);
+
+ /* This is the right position for do0. Please don't move
+ it into the loop. */
+ do0:
+ x = MERGE(a2, shl, a3, shr);
+ if (x != b3)
+ return CMP_LT_OR_GT (x, b3);
+ return 0;
+}
+
+int
+irc_memcmp (s1, s2, len)
+ const __ptr_t s1;
+ const __ptr_t s2;
+ size_t len;
+{
+ op_t a0;
+ op_t b0;
+ long int srcp1 = (long int) s1;
+ long int srcp2 = (long int) s2;
+ op_t res;
+
+ if (len >= OP_T_THRES)
+ {
+ /* There are at least some bytes to compare. No need to test
+ for LEN == 0 in this alignment loop. */
+ while (srcp2 % OPSIZ != 0)
+ {
+ a0 = ((byte *) srcp1)[0];
+ b0 = ((byte *) srcp2)[0];
+ srcp1 += 1;
+ srcp2 += 1;
+ res = a0 - b0;
+ if (res != 0)
+ return res;
+ len -= 1;
+ }
+
+ /* SRCP2 is now aligned for memory operations on `op_t'.
+ SRCP1 alignment determines if we can do a simple,
+ aligned compare or need to shuffle bits. */
+
+ if (srcp1 % OPSIZ == 0)
+ res = memcmp_common_alignment (srcp1, srcp2, len / OPSIZ);
+ else
+ res = memcmp_not_common_alignment (srcp1, srcp2, len / OPSIZ);
+ if (res != 0)
+ return res;
+
+ /* Number of bytes remaining in the interval [0..OPSIZ-1]. */
+ srcp1 += len & -OPSIZ;
+ srcp2 += len & -OPSIZ;
+ len %= OPSIZ;
+ }
+
+ /* There are just a few bytes to compare. Use byte memory operations. */
+ while (len != 0)
+ {
+ a0 = ((byte *) srcp1)[0];
+ b0 = ((byte *) srcp2)[0];
+ srcp1 += 1;
+ srcp2 += 1;
+ res = a0 - b0;
+ if (res != 0)
+ return res;
+ len -= 1;
+ }
+
+ return 0;
+}
+#endif /* HAVE_MEMCMP && MEMCMP_BROKEN */
diff --git a/common/support_def.h b/common/support_def.h
new file mode 100644
index 0000000..500e88f
--- /dev/null
+++ b/common/support_def.h
@@ -0,0 +1,28 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, common/support_def.h
+ * Copyright (C) 1991, 1993, 1995 Free Software Foundation, Inc.
+ * Contributed by Torbjorn Granlund (tege@sics.se).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef __ptr_t
+#undef __ptr_t
+#endif
+#if defined (__STDC__) && __STDC__
+#define __ptr_t void *
+#else
+#define __ptr_t char *
+#endif
diff --git a/common/support_ext.h b/common/support_ext.h
new file mode 100644
index 0000000..6e81d18
--- /dev/null
+++ b/common/support_ext.h
@@ -0,0 +1,80 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, common/support_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in common/support.c.
+ */
+
+/* External definitions for global functions.
+ */
+#ifndef SUPPORT_C
+#define EXTERN extern
+#else /* SUPPORT_C */
+#define EXTERN
+#endif /* SUPPORT_C */
+EXTERN char *mystrdup __P((char *s));
+#if ! HAVE_STRTOKEN
+EXTERN char *strtoken __P((char **save, char *str, char *fs));
+#endif /* HAVE_STRTOKEN */
+#if ! HAVE_STRTOK
+EXTERN char *strtok __P((char *str, char *fs));
+#endif /* HAVE_STRTOK */
+#if ! HAVE_STRERROR
+EXTERN char *strerror __P((int err_no));
+#endif /* HAVE_STRERROR */
+EXTERN char *myctime __P((time_t value));
+EXTERN char *mybasename __P((char *));
+#ifdef INET6
+EXTERN char *inetntop(int af, const void *in, char *local_dummy, size_t the_size);
+#endif
+#if ! HAVE_INET_NTOA
+EXTERN char *inetntoa __P((char *in));
+#endif /* HAVE_INET_NTOA */
+#if ! HAVE_INET_NETOF
+EXTERN int inetnetof __P((struct in_addr in));
+#endif /* HAVE_INET_NETOF */
+#if ! HAVE_INET_ADDR
+EXTERN u_long inetaddr __P((register const char *cp));
+#endif /* HAVE_INET_ADDR */
+#if ! HAVE_INET_ATON
+EXTERN int inetaton __P((register const char *cp, struct in_addr *addr));
+#endif /* HAVE_INET_ATON */
+#if defined(DEBUGMODE) && !defined(CLIENT_COMPILE)
+EXTERN void dumpcore ();
+#endif /* DEBUGMODE && !CLIENT_COMPILE */
+#if defined(DEBUGMODE) && !defined(CLIENT_COMPILE) && defined(DO_DEBUG_MALLOC)
+EXTERN char *MyMalloc __P((size_t x));
+EXTERN char *MyRealloc __P((char *x, size_t y));
+EXTERN void MyFree __P((char *x));
+#else /* DEBUGMODE && !CLIENT_COMPILE && !DO_DEBUG_MALLOC */
+EXTERN char *MyMalloc __P((size_t x));
+EXTERN char *MyRealloc __P((char *x, size_t y));
+#endif /* DEBUGMODE && !CLIENT_COMPILE && !DO_DEBUG_MALLOC */
+#if ! USE_STDARG
+EXTERN int irc_sprintf();
+#endif /* USE_STDARG */
+EXTERN int dgets __P((int fd, char *buf, int num));
+EXTERN char *make_version();
+#if SOLARIS_2_3
+EXTERN struct hostent *solaris_gethostbyname __P((const char *name));
+#endif /* SOLARIS_2_3 */
+#if HAVE_MEMCMP && MEMCMP_BROKEN
+EXTERN int irc_memcmp __P((const __ptr_t s1, const __ptr_t s2, size_t len));
+#endif /* HAVE_MEMCMP && MEMCMP_BROKEN */
+#undef EXTERN
diff --git a/configure b/configure
new file mode 100755
index 0000000..6ea0218
--- /dev/null
+++ b/configure
@@ -0,0 +1,50 @@
+#! /bin/sh
+
+quick_fwd=
+for arg
+do
+ case "$arg" in
+ -help | --help | --hel | --he)
+ quick_fwd=yes
+ break ;;
+ -version | --version | --versio | --versi | --vers)
+ quick_fwd=yes
+ break ;;
+ *)
+ break ;;
+ esac
+done
+if test "x$quick_fwd" = xyes
+then
+ support/configure $*
+else
+ echo "retrieving the system name, type and OS release..."
+ rev=`support/config.guess`
+ if test "${rev}" # test for no output
+ then
+ echo " your system seems to be ${rev}."
+ if test ! -d "${rev}"
+ then
+ echo "creating directory ${rev}..."
+ mkdir "${rev}"
+ fi
+ cd "${rev}"
+ echo "now working in directory ${rev}..."
+ cp -p ../support/configure .
+ if test ! -f config.h
+ then
+ echo "copying config.h from config.h.dist..."
+ cp -p ../support/config.h.dist config.h
+ fi
+ ./configure $*
+ if test $? = 0
+ then
+ echo "Have you read doc/README? (I hope so)"
+ echo "Next cd ${rev}, edit \"config.h\" and \"Makefile\","
+ echo "run \"make all\" to build and \"make install\" to install."
+ fi
+ else
+ echo Failed to determine your host type, giving up.
+ echo Perhaps you should specify it manually.
+ fi
+fi
diff --git a/contrib/README b/contrib/README
new file mode 100644
index 0000000..7d62989
--- /dev/null
+++ b/contrib/README
@@ -0,0 +1,21 @@
+$Id: README,v 1.6 1999/03/13 23:06:15 kalt Exp $
+
+This directory contains ircd related contributions. Most of them fall
+ in one of the following categories:
+ * small side utility
+ * code sample
+ * service
+
+Each contribution lives in its own directory under contrib/ and has a
+README file. For those which need to be compiled, this can be done in
+the same directory as you compiled irc and/or ircd.
+
+If you want to submit a package for this directory, see the RULES file.
+
+---
+
+mkpasswd utility to crypt a password.
+ircdwatch utility to keep ircd running (eventually restarting it).
+tkserv stupid toy to manage "temporary" klines.
+mod_passwd example of DSM module for iauth
+antispoof.diff diff file to add extra code to ircd to prevent TCP spoofing
diff --git a/contrib/RULES b/contrib/RULES
new file mode 100644
index 0000000..f3de2a1
--- /dev/null
+++ b/contrib/RULES
@@ -0,0 +1,24 @@
+$Id: RULES,v 1.2 1998/11/09 20:07:12 kalt Exp $
+
+This file describes how to prepare a package for inclusion
+in the contrib/ directory. The goal is to have a consistent
+setup for all contributions, making it easy to install any
+of them.
+
+* each package must have a README file (at least) explaining
+ what it is about.
+* a man page would be nice ;-)
+
+* packages are stored in contrib/<package name>
+
+* C programs:
+ * If possible, use the same coding style as in the
+ rest of the package.
+ * They need to be portable
+ * They should use "setup.h" or "os.h"
+ * If needed, they may have a *.h file generated by configure
+ * They are to be compiled from within the same
+ directory as irc/ircd, using the same Makefile
+
+
+* questions, submissions should be sent to ircd-dev@irc.org
diff --git a/contrib/antispoof.README b/contrib/antispoof.README
new file mode 100644
index 0000000..fd1d5a7
--- /dev/null
+++ b/contrib/antispoof.README
@@ -0,0 +1,56 @@
+The nospoof patch was adapted from the nospoof5 patch in use on Undernet
+servers. It should NOT be needed unless you're running ircd on a really
+old OS which doesn't have a patch against TCP spoofing. Note that this
+patch should be applied BEFORE running ./configure -- this is very
+important, and the usual cause of any problems encountered.
+
+When a client connects to the server, they are sent a PING with a random
+number (please do not confuse this with a CTCP PING -- they're very
+different things). Until the client responds with a PONG and the correct
+random number, it is not registered with the server and cannot do
+anything.
+
+Please note that this does break the RFC. However, it has been tested
+with most popular clients and is in common use on large IRC networks
+currently. The only reported client to have problems is Homer (for
+the Macintosh).
+
+To cater for possibly broken clients, a message is also sent to clients
+on connect of the form:
+
+*** If your client freezes here, type /QUOTE PONG 12345678 or /PONG 12345678
+
+Because of this, it is a good idea to increase the allowed timeout on
+connections since the user might have to manually PONG the server with
+the ugly number (although hopefully they only need to cut'n'paste).
+
+If the client PONGs with the wrong number, another message is sent to
+the client directing the user what to type. In addition, if the
+connection does end up timing out due to no PONG, a message is sent to
+the user explaining the client may not be compatible, and lists where
+compatible clients for all the major platforms can be found.
+
+The random number sequence is based on an md5 series. I didn't write it.
+Someone else did. It's included because many have a dud random() in their
+libc (this applies to more people than you think). It is seeded on a
+#define value in config.h - YOU MUST CHANGE THIS FROM THE DEFAULT OR YOU
+CAN STILL BE SPOOFED. If you still find that you get spoofed, try
+changing this value again and recompiling.
+
+KNOWN BUGS:
+
+ - There is a known bug whereby the host provided by the client's
+ USER sequence is not checked for validity until after the PONG
+ reply (and registration takes place). This allows a form of
+ "spoofing" to take place, with the client showing under /whois
+ lookups with a fake hostname. At this stage the client can't
+ actually issue commands to the server though, and the hostmask
+ is corrected to what it should be upon the PONG being received
+ (and the client properly registered).
+
+ - The random number generator isn't 64-bit clean. On 64-bit
+ machines, a 64-bit random number is generated, but I'm not
+ convinced all 64-bits are random. At least 32 bits are
+ however, so this isn't a problem.
+
+ - Andrew (earthpig@yoyo.cc.monash.edu.au)
diff --git a/contrib/antispoof.diff b/contrib/antispoof.diff
new file mode 100644
index 0000000..b02832f
--- /dev/null
+++ b/contrib/antispoof.diff
@@ -0,0 +1,484 @@
+diff -urN irc-cvs/common/numeric_def.h irc-cvs-nospoof/common/numeric_def.h
+--- irc-cvs/common/numeric_def.h Wed Jan 20 12:28:46 1999
++++ irc-cvs-nospoof/common/numeric_def.h Tue Mar 16 12:45:56 1999
+@@ -198,6 +198,10 @@
+ #define ERR_UMODEUNKNOWNFLAG 501
+ #define ERR_USERSDONTMATCH 502
+
++#if defined(NOSPOOF)
++#define ERR_BADPING 513
++#endif
++
+ /*
+ * Numberic replies from server commands.
+ * These are currently in the range 200-399.
+diff -urN irc-cvs/common/parse.c irc-cvs-nospoof/common/parse.c
+--- irc-cvs/common/parse.c Tue Dec 29 02:44:57 1998
++++ irc-cvs-nospoof/common/parse.c Tue Mar 16 12:45:56 1999
+@@ -56,7 +56,11 @@
+ { MSG_INVITE, m_invite, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L},
+ { MSG_WALLOPS, m_wallops, MAXPARA, MSG_LAG|MSG_REG|MSG_NOU, 0, 0, 0L},
+ { MSG_PING, m_ping, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L},
++#if defined(NOSPOOF)
++ { MSG_PONG, m_pong, MAXPARA, MSG_LAG, 0, 0, 0L},
++#else
+ { MSG_PONG, m_pong, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L},
++#endif
+ { MSG_ERROR, m_error, MAXPARA, MSG_LAG|MSG_REG|MSG_NOU, 0, 0, 0L},
+ #ifdef OPER_KILL
+ { MSG_KILL, m_kill, MAXPARA, MSG_LAG|MSG_REG|MSG_OP|MSG_LOP, 0,0, 0L},
+diff -urN irc-cvs/common/send.c irc-cvs-nospoof/common/send.c
+--- irc-cvs/common/send.c Fri Feb 5 10:26:35 1999
++++ irc-cvs-nospoof/common/send.c Tue Mar 16 12:45:56 1999
+@@ -392,6 +392,9 @@
+ NULL,
+ # endif
+ 0, {0, 0, NULL }, {0, 0, NULL },
++#if defined(NOSPOOF)
++ -1,
++#endif
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, NULL, 0
+ # if defined(__STDC__) /* hack around union{} initialization -Vesa */
+ ,{0}, NULL, "", ""
+diff -urN irc-cvs/common/struct_def.h irc-cvs-nospoof/common/struct_def.h
+--- irc-cvs/common/struct_def.h Sun Mar 14 11:59:54 1999
++++ irc-cvs-nospoof/common/struct_def.h Tue Mar 16 12:45:56 1999
+@@ -432,6 +432,9 @@
+ 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 */
++#if defined(NOSPOOF)
++ u_long cookie; /* Random cookie local clients must PONG */
++#endif
+ long sendM; /* Statistics: protocol messages send */
+ long sendK; /* Statistics: total k-bytes send */
+ long receiveM; /* Statistics: protocol messages received */
+diff -urN irc-cvs/ircd/ircd.c irc-cvs-nospoof/ircd/ircd.c
+--- irc-cvs/ircd/ircd.c Sun Mar 14 11:59:58 1999
++++ irc-cvs-nospoof/ircd/ircd.c Tue Mar 16 12:45:56 1999
+@@ -493,6 +493,22 @@
+ else
+ {
+ cptr->exitc = EXITC_PING;
++#if defined(NOSPOOF)
++ if((!IsRegistered(cptr)) && (cptr->name) &&
++ (cptr->username))
++ {
++ sendto_one(cptr,
++ ":%s %d %s :Your client may not be compatible with this server.",
++ me.name, ERR_BADPING, cptr->name);
++ /* Someone suggest a better
++ * place? :) - Earthpig
++ */
++ sendto_one(cptr,
++ ":%s %d %s :Compatible clients are available at "
++ "ftp://yoyo.cc.monash.edu.au/pub/irc/clients/",
++ me.name, ERR_BADPING, cptr->name);
++ }
++#endif
+ (void)exit_client(cptr, cptr, &me,
+ "Ping timeout");
+ }
+diff -urN irc-cvs/ircd/list.c irc-cvs-nospoof/ircd/list.c
+--- irc-cvs/ircd/list.c Tue Dec 29 02:44:57 1998
++++ irc-cvs-nospoof/ircd/list.c Tue Mar 16 12:45:56 1999
+@@ -146,6 +146,9 @@
+ if (size == CLIENT_LOCAL_SIZE)
+ {
+ cptr->since = cptr->lasttime = cptr->firsttime = timeofday;
++#if defined(NOSPOOF)
++ cptr->cookie = 0;
++#endif
+ cptr->confs = NULL;
+ cptr->sockhost[0] = '\0';
+ cptr->buffer[0] = '\0';
+diff -urN irc-cvs/ircd/random.c irc-cvs-nospoof/ircd/random.c
+--- irc-cvs/ircd/random.c Thu Jan 1 10:00:00 1970
++++ irc-cvs-nospoof/ircd/random.c Tue Mar 16 12:45:56 1999
+@@ -0,0 +1,162 @@
++/************************************************************************
++ * IRC - Internet Relay Chat, ircd/random.c
++ *
++ * This program is free software; you can 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 <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <sys/time.h>
++#include "os.h"
++#include "s_defines.h"
++
++#ifdef NOSPOOF
++
++char localkey[8] = RANDOM_SEED;
++
++/*
++ * MD5 transform algorithm, taken from code written by Colin Plumb,
++ * and put into the public domain
++ *
++ * Kev: Taken from Ted T'so's /dev/random random.c code and modified to
++ * be slightly simpler. That code is released under a BSD-style copyright
++ * OR under the terms of the GNU Public License, which should be included
++ * at the top of this source file.
++ *
++ * record: Cleaned up to work with ircd. RANDOM_TOKEN is defined in
++ * setup.h by the make script; if people start to "guess" your cookies,
++ * consider recompiling your server with a different random token.
++ */
++
++/* The four core functions - F1 is optimized somewhat */
++
++#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. MD5Update blocks
++ * the data and converts bytes into longwords for this routine.
++ *
++ * original comment left in; this used to be called MD5Transform and took
++ * two arguments; I've internalized those arguments, creating the character
++ * array "localkey," which should contain 8 bytes of data. The function also
++ * originally returned nothing; now it returns an unsigned long that is the
++ * random number. It appears to be reallyrandom, so... -Kev
++ *
++ * I don't really know what this does. I tried to figure it out and got
++ * a headache. If you know what's good for you, you'll leave this stuff
++ * for the smart people and do something else. -record
++ */
++unsigned long ircrandom(void)
++{
++ unsigned long a, b, c, d;
++ unsigned char in[16];
++ struct timeval tv;
++
++ (void)gettimeofday(&tv, NULL);
++
++ (void)memcpy((void *)in, (void *)localkey, 8);
++ (void)memcpy((void *)(in+8), (void *)&tv.tv_sec, 4);
++ (void)memcpy((void *)(in+12), (void *)&tv.tv_usec, 4);
++
++ a = 0x67452301;
++ b = 0xefcdab89;
++ c = 0x98badcfe;
++ d = 0x10325476;
++
++ MD5STEP(F1, a, b, c, d, (long)in[ 0]+0xd76aa478, 7);
++ MD5STEP(F1, d, a, b, c, (long)in[ 1]+0xe8c7b756, 12);
++ MD5STEP(F1, c, d, a, b, (long)in[ 2]+0x242070db, 17);
++ MD5STEP(F1, b, c, d, a, (long)in[ 3]+0xc1bdceee, 22);
++ MD5STEP(F1, a, b, c, d, (long)in[ 4]+0xf57c0faf, 7);
++ MD5STEP(F1, d, a, b, c, (long)in[ 5]+0x4787c62a, 12);
++ MD5STEP(F1, c, d, a, b, (long)in[ 6]+0xa8304613, 17);
++ MD5STEP(F1, b, c, d, a, (long)in[ 7]+0xfd469501, 22);
++ MD5STEP(F1, a, b, c, d, (long)in[ 8]+0x698098d8, 7);
++ MD5STEP(F1, d, a, b, c, (long)in[ 9]+0x8b44f7af, 12);
++ MD5STEP(F1, c, d, a, b, (long)in[10]+0xffff5bb1, 17);
++ MD5STEP(F1, b, c, d, a, (long)in[11]+0x895cd7be, 22);
++ MD5STEP(F1, a, b, c, d, (long)in[12]+0x6b901122, 7);
++ MD5STEP(F1, d, a, b, c, (long)in[13]+0xfd987193, 12);
++ MD5STEP(F1, c, d, a, b, (long)in[14]+0xa679438e, 17);
++ MD5STEP(F1, b, c, d, a, (long)in[15]+0x49b40821, 22);
++
++ MD5STEP(F2, a, b, c, d, (long)in[ 1]+0xf61e2562, 5);
++ MD5STEP(F2, d, a, b, c, (long)in[ 6]+0xc040b340, 9);
++ MD5STEP(F2, c, d, a, b, (long)in[11]+0x265e5a51, 14);
++ MD5STEP(F2, b, c, d, a, (long)in[ 0]+0xe9b6c7aa, 20);
++ MD5STEP(F2, a, b, c, d, (long)in[ 5]+0xd62f105d, 5);
++ MD5STEP(F2, d, a, b, c, (long)in[10]+0x02441453, 9);
++ MD5STEP(F2, c, d, a, b, (long)in[15]+0xd8a1e681, 14);
++ MD5STEP(F2, b, c, d, a, (long)in[ 4]+0xe7d3fbc8, 20);
++ MD5STEP(F2, a, b, c, d, (long)in[ 9]+0x21e1cde6, 5);
++ MD5STEP(F2, d, a, b, c, (long)in[14]+0xc33707d6, 9);
++ MD5STEP(F2, c, d, a, b, (long)in[ 3]+0xf4d50d87, 14);
++ MD5STEP(F2, b, c, d, a, (long)in[ 8]+0x455a14ed, 20);
++ MD5STEP(F2, a, b, c, d, (long)in[13]+0xa9e3e905, 5);
++ MD5STEP(F2, d, a, b, c, (long)in[ 2]+0xfcefa3f8, 9);
++ MD5STEP(F2, c, d, a, b, (long)in[ 7]+0x676f02d9, 14);
++ MD5STEP(F2, b, c, d, a, (long)in[12]+0x8d2a4c8a, 20);
++
++ MD5STEP(F3, a, b, c, d, (long)in[ 5]+0xfffa3942, 4);
++ MD5STEP(F3, d, a, b, c, (long)in[ 8]+0x8771f681, 11);
++ MD5STEP(F3, c, d, a, b, (long)in[11]+0x6d9d6122, 16);
++ MD5STEP(F3, b, c, d, a, (long)in[14]+0xfde5380c, 23);
++ MD5STEP(F3, a, b, c, d, (long)in[ 1]+0xa4beea44, 4);
++ MD5STEP(F3, d, a, b, c, (long)in[ 4]+0x4bdecfa9, 11);
++ MD5STEP(F3, c, d, a, b, (long)in[ 7]+0xf6bb4b60, 16);
++ MD5STEP(F3, b, c, d, a, (long)in[10]+0xbebfbc70, 23);
++ MD5STEP(F3, a, b, c, d, (long)in[13]+0x289b7ec6, 4);
++ MD5STEP(F3, d, a, b, c, (long)in[ 0]+0xeaa127fa, 11);
++ MD5STEP(F3, c, d, a, b, (long)in[ 3]+0xd4ef3085, 16);
++ MD5STEP(F3, b, c, d, a, (long)in[ 6]+0x04881d05, 23);
++ MD5STEP(F3, a, b, c, d, (long)in[ 9]+0xd9d4d039, 4);
++ MD5STEP(F3, d, a, b, c, (long)in[12]+0xe6db99e5, 11);
++ MD5STEP(F3, c, d, a, b, (long)in[15]+0x1fa27cf8, 16);
++ MD5STEP(F3, b, c, d, a, (long)in[ 2]+0xc4ac5665, 23);
++
++ MD5STEP(F4, a, b, c, d, (long)in[ 0]+0xf4292244, 6);
++ MD5STEP(F4, d, a, b, c, (long)in[ 7]+0x432aff97, 10);
++ MD5STEP(F4, c, d, a, b, (long)in[14]+0xab9423a7, 15);
++ MD5STEP(F4, b, c, d, a, (long)in[ 5]+0xfc93a039, 21);
++ MD5STEP(F4, a, b, c, d, (long)in[12]+0x655b59c3, 6);
++ MD5STEP(F4, d, a, b, c, (long)in[ 3]+0x8f0ccc92, 10);
++ MD5STEP(F4, c, d, a, b, (long)in[10]+0xffeff47d, 15);
++ MD5STEP(F4, b, c, d, a, (long)in[ 1]+0x85845dd1, 21);
++ MD5STEP(F4, a, b, c, d, (long)in[ 8]+0x6fa87e4f, 6);
++ MD5STEP(F4, d, a, b, c, (long)in[15]+0xfe2ce6e0, 10);
++ MD5STEP(F4, c, d, a, b, (long)in[ 6]+0xa3014314, 15);
++ MD5STEP(F4, b, c, d, a, (long)in[13]+0x4e0811a1, 21);
++ MD5STEP(F4, a, b, c, d, (long)in[ 4]+0xf7537e82, 6);
++ MD5STEP(F4, d, a, b, c, (long)in[11]+0xbd3af235, 10);
++ MD5STEP(F4, c, d, a, b, (long)in[ 2]+0x2ad7d2bb, 15);
++ MD5STEP(F4, b, c, d, a, (long)in[ 9]+0xeb86d391, 21);
++
++ /*
++ * we have 4 unsigned longs generated by the above sequence; this scrambles
++ * them together so that if there is any pattern, it will be obscured.
++ */
++ return (a ^ b ^ c ^ d);
++}
++
++#endif
+diff -urN irc-cvs/ircd/s_debug.c irc-cvs-nospoof/ircd/s_debug.c
+--- irc-cvs/ircd/s_debug.c Fri Feb 5 10:44:16 1999
++++ irc-cvs-nospoof/ircd/s_debug.c Tue Mar 16 12:45:56 1999
+@@ -148,6 +148,9 @@
+ #ifdef INET6
+ '6',
+ #endif
++#if defined(NOSPOOF)
++'*',
++#endif
+ '\0'};
+
+ #ifdef DEBUGMODE
+@@ -344,7 +347,7 @@
+ sendto_one(cptr, ":%s %d %s :BS:%d MXR:%d MXB:%d MXBL:%d PY:%d",
+ ME, RPL_STATSDEFINE, nick, BUFSIZE, MAXRECIPIENTS, MAXBANS,
+ MAXBANLENGTH, MAXPENALTY);
+- sendto_one(cptr, ":%s %d %s :ZL:%d CM:%d CP:%d",
++ sendto_one(cptr, ":%s %d %s :ZL:%d CM:%d CP:%d NS:%s",
+ ME, RPL_STATSDEFINE, nick,
+ #ifdef ZIP_LINKS
+ ZIP_LEVEL,
+@@ -352,9 +355,14 @@
+ -1,
+ #endif
+ #ifdef CLONE_CHECK
+- CLONE_MAX, CLONE_PERIOD
++ CLONE_MAX, CLONE_PERIOD,
++#else
++ -1, -1,
++#endif
++#if defined(NOSPOOF)
++ "yes"
+ #else
+- -1, -1
++ "no"
+ #endif
+ );
+ }
+diff -urN irc-cvs/ircd/s_err.c irc-cvs-nospoof/ircd/s_err.c
+--- irc-cvs/ircd/s_err.c Sun Feb 28 02:45:29 1999
++++ irc-cvs-nospoof/ircd/s_err.c Tue Mar 16 12:45:56 1999
+@@ -162,6 +162,19 @@
+ { 0, (char *)NULL },
+ /* 501 */ { ERR_UMODEUNKNOWNFLAG, ":Unknown MODE flag" },
+ /* 502 */ { ERR_USERSDONTMATCH, ":Can't change mode for other users" },
++#if defined(NOSPOOF)
++ { 0, (char *)NULL },
++ { 0, (char *)NULL },
++ { 0, (char *)NULL },
++ { 0, (char *)NULL },
++ { 0, (char *)NULL },
++ { 0, (char *)NULL },
++ { 0, (char *)NULL },
++ { 0, (char *)NULL },
++ { 0, (char *)NULL },
++ { 0, (char *)NULL },
++/* 513 */ { ERR_BADPING, (char *)NULL },
++#endif
+ { 0, (char *)NULL }
+ };
+
+diff -urN irc-cvs/ircd/s_user.c irc-cvs-nospoof/ircd/s_user.c
+--- irc-cvs/ircd/s_user.c Tue Mar 16 12:32:51 1999
++++ irc-cvs-nospoof/ircd/s_user.c Tue Mar 16 12:51:41 1999
+@@ -335,9 +335,9 @@
+
+ /*
+ ** 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.
++** This function is called when both NICK and USER [and maybe PONG]
++** 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
+@@ -1007,9 +1007,30 @@
+
+ /* This had to be copied here to avoid problems.. */
+ (void)strcpy(sptr->name, nick);
++#if defined(NOSPOOF)
++ /* If the client hasn't gotten a cookie-ping yet,
++ choose a cookie and send it. -record!jegelhof@cloud9.net */
++
++ if (!sptr->cookie)
++ {
++ while((!sptr->cookie) || (sptr->cookie==-1))
++ sptr->cookie=(ircrandom());
++ sendto_one(cptr, "PING :%lu", sptr->cookie);
++ sendto_one(sptr,
++ ":%s %d %s :If your client freezes here, type /QUOTE PONG %lu "
++ "or /PONG %lu ",
++ me.name, ERR_BADPING, sptr->name,
++ sptr->cookie, sptr->cookie);
++ }
++
++ if ((sptr->user) && (sptr->cookie==-1))
++ {
++#else
+ if (sptr->user)
++#endif
+ /*
+- ** USER already received, now we have NICK.
++ ** USER [and possibly PONG] 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
+@@ -1020,6 +1041,9 @@
+ sptr->user->username)
+ == FLUSH_BUFFER)
+ return FLUSH_BUFFER;
++#if defined(NOSPOOF)
++ }
++#endif
+ }
+ /*
+ ** Finally set new nick name.
+@@ -1849,7 +1873,12 @@
+ if (strlen(realname) > REALLEN)
+ realname[REALLEN] = '\0';
+ sptr->info = mystrdup(realname);
+- if (sptr->name[0]) /* NICK already received, now we have USER... */
++ if ((sptr->name[0])
++#if defined(NOSPOOF)
++ && (!MyConnect(sptr) || (sptr->cookie==-1))
++#endif
++ )
++ /* NICK already received, now we have USER... */
+ {
+ if ((parc == 6) && IsServer(cptr)) /* internal m_user() */
+ {
+@@ -2222,7 +2251,32 @@
+ aClient *acptr;
+ char *origin, *destination;
+
+- if (parc < 2 || *parv[1] == '\0')
++#if defined(NOSPOOF)
++ /* Check to see if this is a PONG :cookie reply from an
++ unregistered user. If so, process it. -record */
++
++ if((!IsRegistered(sptr)) && (sptr->cookie!=0) &&
++ (sptr->cookie!=-1) && (parc>1))
++ {
++ if(strtoul(parv[parc-1],NULL,10)==sptr->cookie)
++ {
++ sptr->cookie=-1;
++ if((sptr->user) && (sptr->name[0]))
++ /* NICK and USER OK */
++ return register_user(cptr, sptr, sptr->name,
++ sptr->user->username);
++ }
++ else
++ sendto_one(sptr,
++ ":%s %d %s :To connect, type /QUOTE PONG %lu or /PONG %lu",
++ me.name, ERR_BADPING, sptr->name,
++ sptr->cookie, sptr->cookie);
++
++ return 1;
++ }
++#endif
++
++ if (parc < 2 || *parv[1] == '\0')
+ {
+ sendto_one(sptr, err_str(ERR_NOORIGIN, parv[0]));
+ return 1;
+diff -urN irc-cvs/support/Makefile.in irc-cvs-nospoof/support/Makefile.in
+--- irc-cvs/support/Makefile.in Fri Mar 12 20:06:00 1999
++++ irc-cvs-nospoof/support/Makefile.in Tue Mar 16 12:47:37 1999
+@@ -153,7 +153,7 @@
+ SERVER_OBJS = channel.o class.o hash.o ircd.o list.o res.o s_auth.o \
+ s_bsd.o s_conf.o s_debug.o s_err.o s_id.o s_misc.o s_numeric.o \
+ s_serv.o s_service.o s_user.o s_zip.o whowas.o \
+- res_init.o res_comp.o res_mkquery.o
++ res_init.o res_comp.o res_mkquery.o random.o
+
+ IAUTH_COMMON_OBJS = clsupport.o clmatch.o # This is a little evil
+ IAUTH_OBJS = iauth.o a_conf.o a_io.o a_log.o \
+@@ -431,6 +431,9 @@
+
+ res_mkquery.o: ../ircd/res_mkquery.c setup.h config.h
+ $(CC) $(S_CFLAGS) -c -o $@ ../ircd/res_mkquery.c
++
++random.o: ../ircd/random.c setup.h config.h
++ $(CC) $(S_CFLAGS) -c -o $@ ../ircd/random.c
+
+ iauth.o: ../iauth/iauth.c config.h setup.h
+ $(CC) $(A_CFLAGS) -c -o $@ ../iauth/iauth.c
+diff -urN irc-cvs/support/config.h.dist irc-cvs-nospoof/support/config.h.dist
+--- irc-cvs/support/config.h.dist Mon Feb 22 10:41:32 1999
++++ irc-cvs-nospoof/support/config.h.dist Tue Mar 16 12:45:57 1999
+@@ -374,6 +374,30 @@
+ */
+ #undef CLONE_CHECK
+
++/* Define this to turn on code that enables a PING/PONG cookies sequence
++ * whenever a client connects. The purpose of this is to prevent IP
++ * spoofing (normally based on predicting TCP/IP sequence numbers).
++ * This breaks the RFC slightly, but so far only one (old) client has
++ * been encountered that breaks. There's a small overhead if you define
++ * it, but it's essential for older BSD-based (or any other) TCP/IP
++ * stacks with predictable sequence numbers.
++ */
++
++#undef NOSPOOF
++
++/* Random number generator seed -- used for cookies if NOSPOOF is
++ * defined.
++ *
++ * Set this to an 8 character random text string.
++ * Do _NOT_ use the default text.
++ * If people are able to defeat the IP-spoofing protection on your
++ * server, please consider changing this value and recompiling.
++ */
++
++#if defined(NOSPOOF)
++#define RANDOM_SEED "ChangeMe"
++#endif
++
+ /* STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP */
+ /* STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP */
+ /* STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP */
diff --git a/contrib/ircdwatch/README b/contrib/ircdwatch/README
new file mode 100644
index 0000000..80653bd
--- /dev/null
+++ b/contrib/ircdwatch/README
@@ -0,0 +1,56 @@
+$Id: README,v 1.5 1998/11/09 22:56:34 borud Exp $
+
+DESCRIPTION
+===========
+ ircdwatch is a daemon that regularly checks to see if ircd is running.
+ if ircd should die or somehow stop running, ircdwatch will respawn the
+ ircd daemon. if desirable, ircdwatch can be configured to check if
+ the ircd configuration file is changed and send a SIGHUP to the ircd
+ daemon which then causes the daemon to reload the configuration
+ file.
+
+ the ircdwatch program itself is also used as sort of a remote
+ control depending on what command line arguments you feed it. you
+ can use it to start ircd and stop ircd and ircdwatch.
+
+OPTIONS
+=======
+ if you invoke ircdwatch without any command line arguments it will
+ either daemonize itself and become a daemon, or it will exit if it
+ detects that an ircdwatch daemon is already running.
+
+ for using the ircdwatch program as a remote control the following
+ command line options are available:
+
+ --kill
+ stop both ircdwatch and ircd
+
+ --rest
+ stop ircdwatch but leave ircd running
+
+ --help
+ list command line arguments
+
+
+COMPILE TIME CONFIGURATION
+==========================
+ you configure ircdwatch by editing config.h in the directory where
+ you build ircd. the configuration parameters available for
+ ircdwatch are those starting with the prefix "IRCDWATCH_". please
+ refer to the config.h file for more information on the parameter
+ settings. most of the defaults should be okay if you want to use
+ ircdwatch though.
+
+
+ADMINISTRATIVIA
+===============
+ ircdwatch was written by Bjorn Borud <borud@guardian.no> and is
+ Copyright (C) 1998 Bjorn Borud <borud@guardian.no>
+
+ the program is released under the GNU General Public License
+
+ the current maintainer can be reached at: <borud@guardian.no>
+
+ please report bugs to <ircd-users@stealth.net>
+ improvements are welcome.
+
diff --git a/contrib/ircdwatch/ircdwatch.8 b/contrib/ircdwatch/ircdwatch.8
new file mode 100644
index 0000000..cc944b1
--- /dev/null
+++ b/contrib/ircdwatch/ircdwatch.8
@@ -0,0 +1,50 @@
+.\" @(#)$Id: ircdwatch.8,v 1.1 1998/06/12 22:57:40 kalt Exp $
+.TH IRCDWATCH 8 "$Date: 1998/06/12 22:57:40 $"
+.SH NAME
+ircdwatch \- Daemon for monitoring ircd and ircd.conf
+.SH SYNOPSIS
+.hy 0
+.IP \fBircdwatch\fP
+[
+.BI \-\-kill
+] [
+.BI \-\-rest
+] [
+.BI \-\-help
+]
+.SH DESCRIPTION
+.LP
+\fIircdwatch\fP is a daemon that periodically checks that the
+\fIircd\fP daemon is running, restarting it of necessary. This
+daemon can also be configured (at compile time) to check for
+changes to the \fIircd\fP configuration file and make \fIircd\fP
+reload its configuration file by sending it a SIGHUP signal.
+.LP
+Given command line arguments \fIircdwatch\fP will serve as a remote
+control for stopping both \fIircdwatch\fP and \fIircd\fP or just
+\fIircdwatch\fP.
+
+.SH OPTIONS
+.TP
+.B \-\-kill
+Stop both \fIircd\fP and \fIircdwatch\fP
+.TP
+.B \-\-rest
+Stop \fIircdwatch\fP but leave \fIircd\fP running
+.TP
+.B \-\-help
+List command line arguments
+.SH COPYRIGHT
+Copyright (C) 1998 Bjorn Borud, <borud@guardian.no>
+.LP
+.RE
+.SH FILES
+ "ircd.conf"
+ "ircd.pid"
+ "ircdwatch.pid"
+.SH "SEE ALSO"
+ircd(8)
+.SH BUGS
+There may be some portability issues. Report bugs to <ircd-users@stealth.net>
+.SH AUTHOR
+Bjorn Borud, <borud@guardian.no>
diff --git a/contrib/ircdwatch/ircdwatch.c b/contrib/ircdwatch/ircdwatch.c
new file mode 100644
index 0000000..c384578
--- /dev/null
+++ b/contrib/ircdwatch/ircdwatch.c
@@ -0,0 +1,499 @@
+/*
+ * Copyright (C) 1998 Bjorn Borud <borud@guardian.no>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: ircdwatch.c,v 1.3 1999/02/21 00:33:44 kalt Exp $";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h> /* atol() */
+#include <unistd.h> /* fork() exec() */
+#include <sys/types.h>
+#include <sys/stat.h> /* stat() */
+#include <signal.h>
+#include <syslog.h>
+#include <string.h> /* strncmp() */
+#include <time.h>
+
+#include "os.h"
+#include "config.h"
+
+/*
+ * Try and find the correct name to use with getrlimit() for setting
+ * the max. number of files allowed to be open by this process.
+ * (borrowed from ircd/s_bsd.c)
+ */
+#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
+
+#define PID_LEN 7 /* overkill, but hey */
+#define MAX_OPEN_FILEDESCRIPTORS_WILD_GUESS 256
+
+static int want_to_quit = 0;
+
+void finalize(int i)
+{
+#ifdef IRCDWATCH_USE_SYSLOG
+ syslog(LOG_NOTICE, "ircdwatch daemon exiting");
+ closelog();
+#endif
+ exit(i);
+}
+
+int daemonize(void)
+{
+ pid_t pid;
+ int i;
+ int open_max;
+
+#ifdef RLIMIT_FD_MAX
+ struct rlimit rlim;
+
+ if (getrlimit(RLIMIT_FD_MAX, &rlim) != 0) {
+ perror("getrlimit");
+ finalize(1);
+ }
+
+ /* if we get a lame answer we just take a wild guess */
+ if (rlim.rlim_max == 0) {
+ open_max = MAX_OPEN_FILEDESCRIPTORS_WILD_GUESS;
+ }
+
+ open_max = rlim.rlim_max;
+
+#else
+
+ /* no RLIMIT_FD_MAX? take a wild guess */
+ open_max = MAX_OPEN_FILEDESCRIPTORS_WILD_GUESS;
+
+#endif
+
+ pid = fork();
+ if (pid < 0) {
+ perror("fork");
+ exit(1);
+ }
+
+ /* parent process dies */
+ if (pid != 0) {
+ exit(0);
+ }
+
+ setsid();
+ umask(0);
+
+ /* close file descriptors */
+ for (i=0; i < open_max; i++) {
+ close(i);
+ }
+
+ return(0);
+}
+
+static void sig_handler (int signo)
+{
+ if (signo == SIGHUP) {
+ want_to_quit = 1;
+ return;
+ }
+
+ if (signo == SIGALRM) {
+
+#ifndef POSIX_SIGNALS
+ (void)signal(SIGALRM, &sig_handler);
+#endif;
+
+ return;
+ }
+}
+
+
+void set_up_signals(void)
+{
+#ifdef POSIX_SIGNALS
+ struct sigaction act;
+
+ act.sa_handler = sig_handler;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+
+ if (sigaction(SIGHUP, &act, NULL) < 0) {
+ perror("sigaction");
+ }
+
+ if (sigaction(SIGALRM, &act, NULL) < 0) {
+ perror("sigaction");
+ }
+#else
+ (void)signal(SIGHUP, &sig_handler);
+ (void)signal(SIGALRM, &sig_handler);
+#endif
+
+ /* ignore it if child processes die */
+ signal(SIGCHLD, SIG_IGN);
+}
+
+int write_my_pid(void)
+{
+ FILE *f;
+
+ f = fopen(IRCDWATCH_PID_FILENAME, "w");
+ if (f == NULL) {
+ return(-1);
+ }
+
+ fprintf(f, "%d\n", getpid());
+ fclose(f);
+
+ return(0);
+}
+
+
+int file_modified(char *s)
+{
+ struct stat st;
+
+ if (stat(s, &st) < 0) {
+ return(-1);
+ }
+ return(st.st_ctime);
+}
+
+
+int spawn (char *cmd)
+{
+ pid_t pid;
+
+ pid = fork();
+
+ if (pid == -1) {
+#ifdef IRCDWATCH_USE_SYSLOG
+ syslog(LOG_ERR, "spawn() unable to fork, errno=%d", errno);
+#endif
+ return(-1);
+ }
+
+ if (pid == 0) {
+ execl("/bin/sh", "sh", "-c", cmd, (char *) NULL);
+ _exit(127);
+ }
+ return(0);
+}
+
+int read_pid(char *pid_filename)
+{
+ FILE *f;
+ char pidbuf[PID_LEN];
+ pid_t pid;
+
+ f = fopen(pid_filename, "r");
+ if (f == NULL) {
+#ifdef IRCDWATCH_USE_SYSLOG
+ syslog(LOG_ERR, "unable to fopen() %s: %s", pid_filename, strerror(errno));
+#endif
+ return(-1);
+ }
+
+ if (fgets(pidbuf, PID_LEN, f) != NULL) {
+ pid = atol(pidbuf);
+ } else {
+#ifdef IRCDWATCH_USE_SYSLOG
+ syslog(LOG_ERR, "fgets() %s: %s", pid_filename, strerror(errno));
+#endif
+ fclose(f);
+ return(-1);
+ }
+
+ fclose(f);
+ return(pid);
+}
+
+int file_exists (char *s)
+{
+ struct stat st;
+ if ((stat(s, &st) < 0) && (errno == ENOENT)) {
+ return(0);
+ }
+ return(1);
+}
+
+/* yeah, I'll get around to these in some later version */
+
+int file_readable (char *s)
+{
+ return(access(s, R_OK) == 0);
+}
+
+int file_writable (char *s)
+{
+ return(access(s, W_OK) == 0);
+}
+
+int file_executable (char *s)
+{
+ int rc;
+ rc = (access(IRCD_PATH, X_OK) == 0);
+ return rc;
+}
+
+int verify_pid(int pid)
+{
+ int res;
+
+ res = kill(pid, 0);
+ if (res < 0 && errno == EPERM) {
+ fprintf(stderr, "Not process owner\n");
+ exit(1);
+ }
+
+ return(res == 0);
+}
+
+int ircdwatch_running () {
+ int pid;
+
+ if (file_exists(IRCDWATCH_PID_FILENAME)) {
+ pid = read_pid(IRCDWATCH_PID_FILENAME);
+ if (pid > 0) {
+ return(verify_pid(pid) == 1);
+ } else {
+ return(-1);
+ }
+ }
+ return(0);
+}
+
+int ircd_running () {
+ int pid;
+
+ if (file_exists(IRCDPID_PATH)) {
+ pid = read_pid(IRCDPID_PATH);
+ if (pid > 0) {
+ return(verify_pid(pid) == 1);
+ } else {
+ return(-1);
+ }
+ }
+ return(0);
+}
+
+void hup_ircd ()
+{
+ int pid;
+ int res;
+
+ if (file_exists(IRCDPID_PATH)) {
+ pid = read_pid(IRCDPID_PATH);
+ if (pid > 0) {
+ res = kill(pid, SIGHUP);
+ if (res < 0 && errno == EPERM) {
+#ifdef IRCDWATCH_USE_SYSLOG
+ syslog(LOG_ERR, "not allowed to send SIGHUP to ircd");
+#endif
+ finalize(1);
+ }
+ }
+ }
+}
+
+
+void daemon_run ()
+{
+ int i;
+ int last_config_time = 0;
+
+ /* is ircdwatch already running? */
+ i = ircdwatch_running();
+ if (i == -1) {
+ /* unable to open pid file. wrong user? */
+ fprintf(stderr, "ircdwatch pid file exists but is unreadable\n");
+ exit(1);
+ } else if (i) {
+ fprintf(stderr, "ircdwatch is already running\n");
+ exit(0);
+ }
+
+ /* is ircd running? */
+ i = ircd_running();
+ if (i == -1) {
+ /* unable to open pid file. wrong user? */
+ fprintf(stderr, "ircdwatch pid file exists but is unreadable\n");
+ exit(1);
+ } else if (!i) {
+ fprintf(stderr, "ircd not running. attempting to start ircd...\n");
+ if (file_exists(IRCD_PATH)) {
+ if (file_executable(IRCD_PATH)) {
+ spawn(IRCD_PATH);
+ } else {
+ fprintf(stderr, "%s not executable\n", IRCD_PATH);
+ exit(1);
+ }
+ } else {
+ fprintf(stderr, "%s does not exist\n", IRCD_PATH);
+ exit(1);
+ }
+ }
+
+ set_up_signals();
+ closelog();
+ /* daemonize(); */
+
+#ifdef IRCDWATCH_USE_SYSLOG
+ openlog(IRCDWATCH_SYSLOG_IDENT,
+ IRCDWATCH_SYSLOG_OPTIONS,
+ IRCDWATCH_SYSLOG_FACILITY);
+
+ syslog(LOG_NOTICE, "starting ircdwatch daemon");
+#endif
+
+ alarm(IRCDWATCH_POLLING_INTERVAL);
+ pause();
+
+ while (!want_to_quit) {
+ if (! ircd_running() ) {
+
+#ifdef IRCDWATCH_USE_SYSLOG
+ syslog(LOG_ERR, "spawning %s", IRCD_PATH);
+#endif
+
+ spawn(IRCD_PATH);
+ }
+
+#ifdef IRCDWATCH_HUP_ON_CONFIG_CHANGE
+ i = file_modified(IRCDCONF_PATH);
+ if (i != -1) {
+
+ if (last_config_time == 0) {
+ last_config_time = i;
+ }
+
+ else if (i > last_config_time) {
+ last_config_time = i;
+ hup_ircd();
+
+#ifdef IRCDWATCH_USE_SYSLOG
+ syslog(LOG_NOTICE, "config change, HUPing ircd");
+#endif
+
+ }
+ }
+#endif
+
+ alarm(IRCDWATCH_POLLING_INTERVAL);
+ pause();
+ }
+ return;
+}
+
+void kill_ircd ()
+{
+ int pid;
+ int res;
+
+ if (file_exists(IRCDPID_PATH)) {
+ pid = read_pid(IRCDPID_PATH);
+ if (pid > 0) {
+ res = kill(pid, SIGTERM);
+ if (res < 0) {
+ perror("ircd kill");
+ finalize(1);
+ } else {
+ fprintf(stderr, "killed ircd\n");
+ }
+ }
+ } else {
+ fprintf(stderr, "File %s does not exist\n", IRCDPID_PATH);
+ }
+}
+
+void kill_ircdwatch ()
+{
+ int pid;
+ int res;
+
+ if (file_exists(IRCDWATCH_PID_FILENAME)) {
+ pid = read_pid(IRCDWATCH_PID_FILENAME);
+ if (pid > 0) {
+ res = kill(pid, SIGHUP);
+ if (res < 0) {
+ perror("ircdwatch kill");
+ finalize(1);
+ } else {
+ fprintf(stderr, "Sent HUP to ircdwatch. it will die soon...\n");
+ }
+ }
+ } else {
+ fprintf(stderr, "File %s does not exist\n", IRCDWATCH_PID_FILENAME);
+ }
+}
+
+
+void usage (void)
+{
+ fprintf(stderr,"\n\
+Usage:\n\
+ ircdwatch [--kill | --rest | --help]\n\
+\n\
+ --kill, stop both ircdwatch and ircd\n\
+ --rest, stop ircdwatch but let ircd alone\n\
+ --help, display this text\n\
+\n\
+%s\n", rcsid);
+}
+
+int
+main (int argc, char **argv) {
+ int i;
+
+#ifdef IRCDWATCH_USE_SYSLOG
+ openlog(IRCDWATCH_SYSLOG_IDENT,
+ IRCDWATCH_SYSLOG_OPTIONS,
+ IRCDWATCH_SYSLOG_FACILITY);
+#endif
+
+ if (argc > 1) {
+ if (strncmp(argv[1], "--rest", 6) == 0) {
+ kill_ircdwatch();
+ exit(0);
+ }
+
+ if (strncmp(argv[1], "--kill", 6) == 0) {
+ kill_ircdwatch();
+ kill_ircd();
+ exit(0);
+ }
+
+ usage();
+ exit(0);
+ }
+
+ daemon_run();
+ finalize(0);
+}
diff --git a/contrib/mkpasswd/README b/contrib/mkpasswd/README
new file mode 100644
index 0000000..a2bb420
--- /dev/null
+++ b/contrib/mkpasswd/README
@@ -0,0 +1,64 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/crypt/README
+ * Copyright (C) 1991 Nelson Minar
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: README,v 1.1 1998/04/07 21:20:59 kalt Exp $
+ *
+ */
+
+The change implemented here is that the operator password in irc.conf
+is no longer stored in plaintext form, but is encrypted the same way
+that user passwords are encrypted on normal UNIX systems. Ie, instead
+of having
+
+ O:*:goodboy:Nelson
+
+in your ircd.conf file, you have
+
+ O:*:sCnvYRmbFJ7oI:Nelson
+
+You still type "/oper Nelson goodboy" to become operator. However, if
+someone gets ahold of your irc.conf file, they can no longer figure
+out what the password is from reading it. There are still other
+security holes, namely server-server passwords, but this closes one
+obvious problem.
+
+So how do you generate these icky looking strings for passwords?
+There's a simple program called mkpasswd to do that for you. Just run
+mkpasswd, and at the prompt type in your plaintext password. It will
+spit out the encrypted password, which you should then just copy into
+the irc.conf file. This should be done only when adding new passwords
+to your irc.conf file. To change over your irc.conf file to use
+encrypted passwords, define CRYPT_OPER_PASSWORD in config.h. You will
+need to recompile your server if you already compiled it with this
+feature disabled. Once compiled, edit the Makefile in this directory
+and chang "IRCDCONF" to your irc.conf file. Then "make install" in this
+directory to replace all the operator passwords in your irc.conf file
+with the encrypted format.
+
+Choose your passwords carefully. Do not choose something in a
+dictionary, make sure its at least 5 characters. Anything past 8
+characters is ignored.
+
+One thing to note about crypt() passwords - for every plaintext, there
+are 4096 different passwords. Some valid encryptions of "goodboy"
+include t1Ub2RhRQHd4g sCnvYRmbFJ7oI and Xr4Z.Kg5tcdy6. The first
+two characters (the "salt") determine which of the 4096 passwords
+you will get. mkpasswd chooses the salt randomly, or alternately
+will let you specify one on the command line.
+
+see also - crypt(3)
diff --git a/contrib/mkpasswd/crypter b/contrib/mkpasswd/crypter
new file mode 100755
index 0000000..4851620
--- /dev/null
+++ b/contrib/mkpasswd/crypter
@@ -0,0 +1,55 @@
+#!/usr/local/bin/perl
+#************************************************************************
+#* IRC - Internet Relay Chat, ircd/crypt/crypter
+#* Copyright (C) 1991 Sean Batt
+#*
+#* This program is free software; you can redistribute it and/or modify
+#* it under the terms of the GNU General Public License as published by
+#* the Free Software Foundation; either version 1, or (at your option)
+#* any later version.
+#*
+#* This program is distributed in the hope that it will be useful,
+#* but WITHOUT ANY WARRANTY; without even the implied warranty of
+#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+#* GNU General Public License for more details.
+#*
+#* You should have received a copy of the GNU General Public License
+#* along with this program; if not, write to the Free Software
+#* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#*
+#* $Id: crypter,v 1.1 1998/04/07 21:21:00 kalt Exp $
+#*
+#*/
+
+#From Sean Batt sean@coombs.anu.edu.au
+#
+#Temporary output file
+#
+$tmpfile = "/tmp/ircd.conf.tmp";
+
+#
+#Original ircd.conf file
+#
+$ircdconf = @ARGV[0];
+
+print "crypting ",$ircdconf,"\n";
+@saltset = ('a' .. 'z', 'A' .. 'Z', '0' .. '9', '.', '/');
+
+umask(0077);
+open ($ircdout, ">/tmp/ircd.conf.tmp") || die "open $!";
+
+while ($text = <>) {
+#if its not an "O" line we can ignore it
+ $text =~ /^o/i || print ($ircdout $text) && next;
+ chop($text);
+ @oline = split(':', $text);
+ $salt = $saltset[rand(time)%64].$saltset[(rand(time)>>6)%64];
+ $oline[2] = crypt(@oline[2], $salt);
+ print ($ircdout join(':',@oline)."\n");
+}
+close ($ircdout);
+close ($ircdin);
+print "/bin/cp ",$tmpfile," ",$ircdconf,"\n";
+(fork()==0) ? exec("/bin/cp", $tmpfile, $ircdconf) : wait;
+
+#unlink($tmpfile);
diff --git a/contrib/mkpasswd/mkpasswd.c b/contrib/mkpasswd/mkpasswd.c
new file mode 100644
index 0000000..8ea8413
--- /dev/null
+++ b/contrib/mkpasswd/mkpasswd.c
@@ -0,0 +1,44 @@
+/* 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>
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: mkpasswd.c,v 1.1 1998/04/07 21:21:00 kalt Exp $";
+#endif
+
+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;
+}
+
diff --git a/contrib/mod_passwd/README b/contrib/mod_passwd/README
new file mode 100644
index 0000000..6aa2352
--- /dev/null
+++ b/contrib/mod_passwd/README
@@ -0,0 +1,30 @@
+$Id: README,v 1.1 1999/03/13 23:06:15 kalt Exp $
+
+This is an example module for the authentication program (iauth) used by
+the IRC server.
+
+* This module demonstrates how a module can access and use the PASS and
+ USER information provided by users. It is *NOT* a finished product. In
+ particular, the actual password validation is not implemented.
+
+* This module also demonstrates how a DSM module should be written. You'll
+ note that it is completely identical to ordinary modules, except for one
+ extra function: "passwd_load()"
+
+To be used, this module needs to be compiled from the normal compilation
+directory. It should be linked as a dynamic library. Methods vary
+depending on the compiler and platform.
+
+$ gcc -c -g -I../iauth -I../common -I. ../contrib/mod_passwd/mod_passwd.c
+$ ld -Bshareable mod_passwd.o -o mod_passwd.so
+$ ls -l mod_passwd.so
+-rwxr--r-- 1 kalt staff 26932 Mar 13 17:59 mod_passwd.so
+$
+
+To be used by iauth, add the following lines to the iauth.conf file:
+
+ extinfo
+ shared passwd /path/to/mod_passwd.so
+ module passwd
+
+See iauth.conf(5) for more information on configuring iauth.
diff --git a/contrib/mod_passwd/mod_passwd.c b/contrib/mod_passwd/mod_passwd.c
new file mode 100644
index 0000000..817a722
--- /dev/null
+++ b/contrib/mod_passwd/mod_passwd.c
@@ -0,0 +1,171 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, mod_passwd.c
+ * Copyright (C) 1999 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: mod_passwd.c,v 1.1 1999/03/13 23:06:15 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "a_defines.h"
+#include "a_externs.h"
+
+/*
+ * passwd_init
+ *
+ * This procedure is called when a particular module is loaded.
+ * Returns NULL if everything went fine,
+ * an error message otherwise.
+ */
+char *
+passwd_init(self)
+AnInstance *self;
+{
+ return NULL;
+}
+
+/*
+ * passwd_release
+ *
+ * This procedure is called when a particular module is unloaded.
+ */
+void
+passwd_release(self)
+AnInstance *self;
+{
+}
+
+/*
+ * passwd_stats
+ *
+ * This procedure is called regularly to update statistics sent to ircd.
+ */
+void
+passwd_stats(self)
+AnInstance *self;
+{
+}
+
+/*
+ * passwd_start
+ *
+ * This procedure is called to start an authentication.
+ * Returns 0 if everything went fine,
+ * +1 if still waiting for some data (username, password)..
+ * -1 otherwise (nothing to be done, or failure)
+ *
+ * It is responsible for sending error messages where appropriate.
+ * In case of failure, it's responsible for cleaning up (e.g. passwd_clean
+ * will NOT be called)
+ */
+int
+passwd_start(cl)
+u_int cl;
+{
+ if (cldata[cl].authuser &&
+ cldata[cl].authfrom < cldata[cl].instance->in)
+ {
+ /*
+ ** another instance preceding this one in the configuration
+ ** has already authenticated the user, no need to bother
+ ** doing anything here then. (the other takes precedence)
+ */
+ return -1;
+ }
+ if ((cldata[cl].state & A_GOTU) == 0)
+ /* haven't received username/password pair from ircd yet */
+ return 1;
+ if ((cldata[cl].state & A_GOTP) == 0)
+ {
+ /* no password to check -> reject user! */
+ cldata[cl].state |= A_DENY;
+ sendto_ircd("K %d %s %u ", cl, cldata[cl].itsip,
+ cldata[cl].itsport);
+ return -1; /* done */
+ }
+ /*
+ **
+ **
+ ** INSERT FUNCTION TO CHECK PASSWORD VALIDITY
+ **
+ **
+ */
+ /* if failure, see above */
+ /* if success: */
+ cldata[cl].state |= A_UNIX;
+ if (cldata[cl].authuser)
+ free(cldata[cl].authuser);
+ cldata[cl].authuser = mystrdup(cldata[cl].user);
+ cldata[cl].authfrom = cldata[cl].instance->in;
+ sendto_ircd("U %d %s %u %s", cl, cldata[cl].itsip, cldata[cl].itsport,
+ cldata[cl].authuser);
+ return -1; /* done */
+}
+
+/*
+ * passwd_work
+ *
+ * This procedure is called whenever there's new data in the buffer.
+ * Returns 0 if everything went fine, and there is more work to be done,
+ * Returns -1 if the module has finished its work (and cleaned up).
+ *
+ * It is responsible for sending error messages where appropriate.
+ */
+int
+passwd_work(cl)
+u_int cl;
+{
+ return -1;
+}
+
+/*
+ * passwd_clean
+ *
+ * This procedure is called whenever the module should interrupt its work.
+ * It is responsible for cleaning up any allocated data, and in particular
+ * closing file descriptors.
+ */
+void
+passwd_clean(cl)
+u_int cl;
+{
+}
+
+/*
+ * passwd_timeout
+ *
+ * This procedure is called whenever the timeout set by the module is
+ * reached.
+ *
+ * Returns 0 if things are okay, -1 if authentication was aborted.
+ */
+int
+passwd_timeout(cl)
+u_int cl;
+{
+}
+
+static aModule Module_passwd =
+ { "passwd", passwd_init, passwd_release, passwd_stats,
+ passwd_start, passwd_work, passwd_timeout, passwd_clean };
+
+aModule *
+passwd_load()
+{
+ return &Module_passwd;
+}
diff --git a/contrib/tkserv/CHANGES b/contrib/tkserv/CHANGES
new file mode 100644
index 0000000..e983ded
--- /dev/null
+++ b/contrib/tkserv/CHANGES
@@ -0,0 +1,37 @@
+1.0.0b8 : Ported TkServ to C.
+1.0.0b8 : It is now possible to QUIT the service via SQUERY.
+1.0.0b9 : Added default expiration if no time value was specified (koopal)
+1.0.0b9 : It is now possible to remove existing tklines "manually" (koopal)
+1.0.0b10: the pwd of the service went to the cmd line (koopal)
+1.0.0 : Official release of TkServ
+1.0.1 : Applied some fixes to make TkServ work under BSDI (primetime)
+1.0.1 : no address of a local var is returned anymore :) (primetime)
+1.0.2 : Added forgotten tkserv.access.example to the package (primetime)
+1.0.2 : IP masks (x.x.x.*) are now also be recognized as IPs (primetime)
+1.0.2 : hostnames are now also possible in the restriction field (primetime)
+1.0.3 : DEBUGGING is now functional and displays all service<->server
+ traffic to the standard output
+1.0.3 : TkServ should now also compile under Irix (Szern)
+1.0.3 : IP restrictions are now also possible in the access file
+ - wildcards are allowed (Szern)
+1.0.3 : Wildcards do now also work in the oper u@h field of the access
+ file (Szern)
+1.0.3 : Replaced FNM_CASEFOLD by FNM_NOESCAPE
+1.0.4 : ':' is not allowed anymore in the TKLINE cmd line (Eumel)
+1.0.4 : Fixed lame bug which kept tklines active altho already expired (Eumel)
+1.0.5 : TkServ should now also compile under Redhat Linux. (Tero)
+1.0.5 : a few changes for ircd/contrib compliancy
+1.0.5 : the semantics for the access file have changed (check out README)
+1.0.5 : it is now possible to disallow tklining of specific hosts (tumble)
+1.0.6 : Added leading colons for the /squery commands (tumble)
+1.0.6 : Added a hint concerning the distribution to the README
+1.0.6 : it's now possible to decide whether a user needs to be opered or
+ not when accessing TkServ
+1.0.7 : TkServ won't crash anymore if a bad lifetime is given (Tero)
+1.0.8 : A few changes to make TkServ fit better into ircd/contrib.
+1.0.8 : TkServ now sends out a hint when it receives an unknown cmd
+ (Fusion & viha)
+1.0.9 : renamed the function logf due to a conflict in *BSD? (Virginie)
+1.0.9 : General rename of some tkserv functions
+1.2 : Password migration from cmd line to conf file (Earthpig)
+1.2 : TkServ now daemonizes itself. (Earthpig)
diff --git a/contrib/tkserv/CREDITS b/contrib/tkserv/CREDITS
new file mode 100644
index 0000000..617fb16
--- /dev/null
+++ b/contrib/tkserv/CREDITS
@@ -0,0 +1,60 @@
+Thanks to the following people, who have contributed in one way or another
+to the development of TkServ:
+
+- Andre 'koopal' Koopal
+ + beta testing
+ + default expiration
+ + removal of tklines before expiration (manual removal)
+ + password migration from config.h to cmd line
+
+- Asu 'primetime' Pala
+ + fix for BSDI
+ + IP recognition bug
+ + forgotten tkserv.access.example file
+ + hostnames in the restriction field of the access file
+
+- 'Szern'
+ + fix for Irix
+ + IPs in the restriction field
+ + wildcards in the u@h oper field of the access file
+
+- Michael 'Eumel' Neumayer
+ + colons are not allowed anymore outside the password parameter
+ + expired tklines do now get removed really automatically
+
+- Tero 'Tero' Saari
+ + RedHat Linux cludge
+ + no crashes anymore when a bad lifetime is given
+
+- Andrew ´Earthpig´ Snare
+ + password back to conf file (more secure)
+ + automatic daemonization
+
+- 'tumble'
+ + possibility to explicitly disallow specific hosts from getting tklined
+ + leading colons for the /squery commands in the README
+
+- Kristian 'Fusion' Bergmann & 'viha'
+ + Sending out of a hint when an unknown command is received
+
+- 'Virginie'
+ + rename of the logf function because of conflict under *BSD?
+
+- 'jbn'
+ + expiration of tklines / default expiration
+
+- The EPIC Software Labs
+ + for their nice ircII-EPIC client from which i took some networking
+ stuff, see http://www.snafu.de/~kl/epic/index.html for more about
+ epic
+
+- Kai 'Oswald' Seidler
+ + for his NoteServ, on which TkServ is based and which has helped me a
+ lot in making TkServ, see http://oswald.pages.de for more
+
+- Christophe 'syrk' Kalt and Vesa 'Vesa' Ruokonen
+ + for giving me the impulse to this kind of service :)
+
+
+And finally thanks to all the Linux people out there for contributing
+to the world's best OS! :-)
diff --git a/contrib/tkserv/INSTALL b/contrib/tkserv/INSTALL
new file mode 100644
index 0000000..9bc69bd
--- /dev/null
+++ b/contrib/tkserv/INSTALL
@@ -0,0 +1,20 @@
+How to install TkServ
+---------------------
+
+Yes, there isn't any configure yet. That's why the compilation on some
+machines could be difficult because you may have to include one or two
+libraries by hand. I'll try to create a configure file in the future.
+
+Up to now, i've only compiled TkServ on Linux, Solaris and Irix. I hope you
+won't get into trouble when trying to compile on another OS. But everyone
+should be running Linux anyway. :-)
+
+So here we go:
+
+1. Unpack and untar the archive. (which you might already have done :)
+2. RTFM. :->
+3. run "./configure" (if you haven't already done so)
+3. Edit the tkconf.h file.
+4. "make tkserv"
+
+Good luck, Kasi
diff --git a/contrib/tkserv/README b/contrib/tkserv/README
new file mode 100644
index 0000000..a7b7c47
--- /dev/null
+++ b/contrib/tkserv/README
@@ -0,0 +1,290 @@
+Welcome to TkServ !
+=+=+=+=+=+=+=+=+=+=
+
+This program is released under the GNU General Public License.
+A copy of this license is included in the distribution.
+
+I) Introduction
+---------------
+
+TkServ is a so-called temporary k-line service.
+
+[If you don't know what a service is, consult the documentation which comes
+along with the irc2.10.x package (if you don't know services, you shouldn't
+be reading this anyway ;).]
+
+This is what TkServ does - roughly: On request, it adds a given k-line
+pattern to the server's k-line list and (sooner or later, see below) then
+removes it. The adding/removing is done via the ircd.conf file.
+
+The purpose/advantages of a temporary k-line service:
+
+ - it facilitates the process of k-lining users
+ - added k-lines disappear automatically (see below)
+ - it allows _also_ remote users (only if they are listed in the access
+ file of the service - see below) to temp k-line users on the respective
+ server
+ - it allows people to specify a duration for each tkline
+ - it is more effective than /kill but practically as easy to use
+ - it could therefore act as a replacement for the /kill command - which in
+ fact is more or less its longtime goal...
+
+
+II) Security concerns
+---------------------
+
+Of course, when allowing remote "access" to the ircd.conf file, the main
+concern of most admins is security. Therefore, here's a list of the
+procedures used by TkServ to ensure that only authorized users may add
+temporary k-lines to the server's conf file [origin == the person who is
+sending a request]:
+
+- the origin's user@host has to match one of the u@h's in the tkserv.access
+ file (case sensitive!)
+- the origin has always to specify a password which has to match the
+ password that belongs to the corresponding user@host in the access file
+ (case sensitive!)
+- the origin has to be opered, if you want to
+- it is possible to allow an authorized user to only tkline given hostnames
+ or TLDs
+
+Especially the third point equals to strong security, because: Could you
+imagine any cracker who has gained O: on some server, wasting his time on
+trying to get access to a remote server's temp k-line list instead of
+playing around with his O: ? See, neither could i. ;-)
+
+
+III) Installation
+-----------------
+
+A) Precondition
+
+ The only thing you need in order to run TkServ is an "ircd.conf" file,
+ an "ircd.pid" file and an IRC server which has been compiled with
+ USE_SERVICES #define'd in the config.h file (!).
+
+B) Editing the configuration file (config.h)
+
+ You have to change the following entries in the config file:
+
+ TKSERV_ADMIN_NAME (your real name)
+ TKSERV_ADMIN_CONTACT (mail address)
+ TKSERV_ADMIN_OTHER (your nick, for example)
+
+ TKSERV_NAME (the name of the service appearing on /SERVLIST)
+ TKSERV_DESC (a neato description :)
+ TKSERV_DIST (the distribution of the service)
+
+| A few words to the distribution of the service. Here are the pros &
+| contras of a global TkServ from my point of view:
+|
+| [contra] It makes the /servlist become unnecessarily big and less handy
+| [contra] You can detect also local services by /trace'ing a server
+| [contra] You can access a local TkServ by setting up a special client
+| on the concerned server (maybe with a special I: line)
+|
+| [pro] A global TkServ is more comfortable to use for remote users.
+| [pro] If you want to see which server is running one (for e.g. to
+| request access to it), you do only have to do a /servlist.
+
+ TKSERV_PATH (the abs. path to your ircd.conf, no trailing slash please!)
+ TKSERV_LOGFILE (the abs. path to your tkserv logfile, no trailing slash)
+ TKSERV_ACCESSFILE (the abs. path to your tkserv access file, ditto)
+
+ TKSERV_DEBUG (for debugging only, displayes traffic to standard output)
+
+C) Compiling the source
+
+TkServ will be compiled along with the irc server.
+
+D) Setting up the access file: tkserv.access
+
+ If anyone should be authorized to use TkServ on your server, he/she has
+ to figure in the access file. The format of it is:
+
+| [!]<user@host.domain.tld><SPACE><password><SPACE>[<FQDN || IP>]<RETURN>
+|
+| Which means:
+| [!]<user@host.domain.tld> <password> [<FQDN || IP>]
+|
+| A '!' before the u@h means that the specified user doesn't need to be
+| opered when accessing TkServ. Before the FQDN/IP, it means that the user
+| is not allowed to tkline that given FQDN/IP. See below.
+|
+| Examples:
+| (1) foo@bar.com foo-pass
+| (2) some@user.on.the.net some.passw1 *.net,207.128.*
+| another@user.foo.com Akfdsv.df *netcom.com,*.ca
+| you@get.the.picture.org ditto. *.org,dialup*.lamer.net,194.44.44.*
+| oper@dialup*.dialup.net pwd1.2 *dialup.net,145.44.*,*.fr
+| (3) !luser@doesnt.need.to.be.opered.org bleh !elite.org,*.org
+| (4) !~luser@no.ident.no.oper.com yo *.com
+|
+| (1) Any oper who is running identd and whose userhost equals to
+| foo@bar.com can tkline everyone if supplied password equals
+| foo-pass.
+| (2) Any oper with identd whose u@h equals to some@user.on.the.net
+| can tkline everyone whose TLD is ".net" or who is IRCing within
+| the IP subnet 207.128.*, if correct password is given.
+| (3) Any luser (no need to be opered) whose u@h/passwd equals can tkline
+| everyone whose TLD is ".org" except the host "elite.org"
+| ("*@elite.org").
+|
+| Generally, you should be aware of the fact that if you put something
+| in the FQDN/IP field, then you automatically restrict the access.
+| Therefore, you must then also indicate all the allowed FQDNs/IPs.
+|
+| The access routines are pretty flexible. So pay attention in what order
+| you allow/disallow what. :)
+|
+| Other examples:
+| !foo@bar.com foo-pass !*.net,*.com,!*.com
+| some@user.on.the.net some.passw1 *.net,207.128.*,!127.0.0.*
+| another@user.foo.com Akfdsv.df *netcom.com,!*trends.ca,*.ca
+|
+| Notice that if you allow "*.de" and after it you forbid "blah.de",
+| this won't work. The oper will still be able to tkline blah.de since
+| "*.de" appears before "!blah.de" in the access field.
+|
+| Are we confused, yet? ;-)
+
+ For some other examples, refer to the tkserv.access.example file, which
+ is included in the package.
+
+ The u@h field for the user can also contain wildcards, as you can see.
+
+| If you specify an FQDN (or several of them in a comma-separated
+| list), the concerned user will only be allowed to tkline users from
+| that FQDN(s). Everything is done via 'wildcard-matching' (if any).
+| I.e. that "home.blah.de" matches only "*@home.blah.de". If you want
+| to allow a whole TLD, you have to do this by putting "*.tld" in the
+| access field.
+
+! An empty FQDN/IP field means that the concerned user can tkline everyone. !
+ [Except *@* that is.]
+
+E) Setting up the S: line in your ircd.conf file
+
+ If you're not yet familiar with S: lines, consult the documentation of
+ the ircd package.
+
+ S:<host>:<password>:<name>:33554432:<class>
+
+ <host> is the FQDN from which the service will connect to the server.
+
+ The service type 33554432 is mandatory! Currently, TkServ will refuse
+ any other service type. [Actually, it won't, but it's good to think that
+ it will... ;-]
+
+ The service class should refer to an existing class (according to the
+ documentation :).
+
+F) Starting TkServ
+
+ The command line syntax of TkServ looks like this:
+
+ tkserv <server> <port> <password>
+ or
+ tkserv <Unix domain socket> <password>
+
+ Example:
+
+ tkserv localhost 6667 my-serv.pass
+
+ Where <server> is the address of your IRC server, <port> the port to
+ which TkServ will connect and <password> the password for the service.
+
+G) Adding temp k-klines (TKLINE)
+
+ Provided that TkServ recognizes you, you can add temporary k-lines via
+ the TKLINE command, which has three different variants:
+
+ (1) :TKLINE <password> <lifetime in hours> <user@host> <reason>
+ (2) :TKLINE <password> <user@host> <reason>
+ (3) :TKLINE <password> -1 <user@host>
+
+ (1) adds a tkline for <u@h> with an expire time of <lifetime> hours and
+ with the reason <reason>.
+ (2) adds a tkline for <u@h> with the default expire time (2 hours) and
+ with the reason <reason>.
+ (3) removes any existing tklines found for <user@host>.
+
+ Examples:
+
+ (1) :TKLINE my.pass 5 lamer@lamers.org dont flood
+ (2) :TKLINE blah. *@foo.com stop spamming
+ (3) :TKLINE my.pass -1 lamer@lamers.org
+
+ <lifetime> must be > 0 and < 168.
+
+| [If your client doesn't support SQUERY, the entire cmd line has to be:
+| "/quote squery <name of tkserv> :tkline ...". If it does support it,
+| then "/squery <name of tkserv> tkline ..." should do it.]
+|
+| [And yes, ircII-EPIC4 supports SQUERY and SERVLIST! ;-)]
+|
+| If a non-opered user tries to use TKLINE without having a matching entry
+| in the access file, he gets "Only IRC-Operators may use this command" as
+| an error message. This is not correct anymore, but i didn't bother to
+| change it (since it may prevent kids from playing around with TkServ :).
+
+H) Online help/info
+
+TkServ does also have a little online help which is accessible via
+"/squery <service name> help".
+
+I) Quitting the service
+
+To make TkServ quit IRC you have to send him the following SQUERY:
+
+QUIT <password>
+
+Where <password> corresponds to password that you indicated at startup.
+Be aware that anyone who knows that password can make your TkServ quit.
+
+J) Debugging
+
+If you #define TKSERV_DEBUG in the config.h file, everything which is sent
+to the server from the service and from the server to the service will be
+displayed to the standard output.
+
+
+IV) Misc, or what goes where
+
+TkServ will create the following permanent files in your ircd directory:
+
+ircd.conf.tkserv (backup of the ircd.conf file)
+tkserv.log (TkServ's log file)
+
+The latter will contain most of the error messages (in case something goes
+wrong - what we all don't hope ;) as well as logs of successful TKLINE
+requests.
+
+The tkserv.access file has to be in the directory specified in the config.h
+file. If no tkserv.access file is found, no one will be able to add temp
+k-lines.
+
+Now and then you should zero your TkServ logfile because this won't happen
+by itself. =)
+
+
+V) Credits
+
+See the CREDITS file.
+
+
+VI) Bugs, comments, suggestions...
+
+Send everything to kl@snafu.de or to Kasi@IRC.
+
+
+VII) The TkServ-mailinglist
+
+There's now a mailinglist for TkServ out there. It is used for general
+announcements (bugs, new releases, etc.) concerning TkServ. Since it's a
+read-only mailinglist, it doesn't have much traffic. You can subscribe to
+it by sending a mail to tkserv@kl.Snafu.DE with "subscribe" in the subject
+or in the body of the mail.
+
+
+Enjoy, -Kasi
diff --git a/contrib/tkserv/proto.h b/contrib/tkserv/proto.h
new file mode 100644
index 0000000..edf23b7
--- /dev/null
+++ b/contrib/tkserv/proto.h
@@ -0,0 +1,24 @@
+void sendto_server(char *buf, ...);
+void sendto_user(char *text, ...);
+void process_server_output(char *line);
+void parse_server_output(char *buffer);
+int server_output(int fd, char *buffer);
+
+void service_pong(void);
+void service_notice(char **args);
+void service_squery(char **args);
+int service_userhost(char *args);
+void squery_help(char **args);
+void squery_tkline(char **args);
+void squery_quit(char **args);
+
+void sendlog(char *text, ...);
+char *ts(void);
+
+int is_opered(void);
+int is_authorized(char *pwd, char *host);
+
+void exec_cmd(char *cmd, ...);
+int add_tkline(char *host, char *user, char *reason, int lifetime);
+int check_tklines(char *host, char *user, int lifetime);
+void rehash(int what);
diff --git a/contrib/tkserv/tkserv.access.example b/contrib/tkserv/tkserv.access.example
new file mode 100644
index 0000000..4269c93
--- /dev/null
+++ b/contrib/tkserv/tkserv.access.example
@@ -0,0 +1,10 @@
+foo@bar.com foo.pass *netcom.com,*.net
+someone@SomeOrg.org aldkf.23 eleet.org,165.55.45.*
+~blah@ppp*.blah.de igh.pass
+user@users.Online.net ukuk.ua1
+some@ip*.user.com blah 204.85.*,194.55.43.*
+you.get@the.picture.com pass ppp*.lame.com,*.org,dialin*.whitehouse.gov,*.net,*.uk
+disallow@something.com bleh !*.de,!*.fr,*.net,*.org,*.com,!195.144.45.*
+disallow@another.host.fr yo !hugo.fr,!admin.irc.fr,*.fr,*.ca,195.55.66.*
+!luser@who.doesnt.need.to.be.opered.de yeh *.de
+
diff --git a/contrib/tkserv/tkserv.c b/contrib/tkserv/tkserv.c
new file mode 100644
index 0000000..92f281d
--- /dev/null
+++ b/contrib/tkserv/tkserv.c
@@ -0,0 +1,1022 @@
+/*
+** Powered by Linux. :-)
+**
+** Copyright (c) 1998 Kaspar 'Kasi' Landsberg, <kl@berlin.Snafu.DE>
+**
+** File : tkserv.c v1.2
+** Author : Kaspar 'Kasi' Landsberg, <kl@snafu.de>
+** Desc. : Temporary K-line Service.
+** For further info see the README file.
+** Location : http://www.snafu.de/~kl/tkserv
+** Usage : tkserv <server> <port>
+** E.g. : tkserv localhost 6667
+**
+** This program is distributed under the GNU General Public License in the
+** hope that it will be useful, but without any warranty. Without even the
+** implied warranty of merchantability or fitness for a particular purpose.
+** See the GNU General Public License for details.
+**
+** Note: The C version of this service is based on parts of the
+** ircII-EPIC IRC client by the EPIC Software Labs and on
+** the NoteServ service by Kai 'Oswald' Seidler - see
+** http://oswald.pages.de for more about NoteServ.
+** Thanks to both. =)
+**
+** PS: Casting rules the world! (doh)
+*/
+
+#include "os.h"
+#undef strcasecmp
+#include "config.h"
+#include "tkconf.h"
+#include "proto.h"
+
+/* Max. kill reason length */
+#define TKS_MAXKILLREASON 128
+
+/* Used max. length for an absolute Unix path */
+#define TKS_MAXPATH 128
+
+/* Max. buffer length (don't change this?) */
+#define TKS_MAXBUFFER 8192
+
+/* don't change this either(?) */
+#define TKS_MAXARGS 250
+
+/* The version information */
+#define TKS_VERSION "Hello, i'm TkServ v1.2."
+
+static char *nuh;
+FILE *tks_logf;
+int fd = -1, tklined = 0;
+
+/*
+** Returns the current time in a formated way.
+** Yes, "ts" stands for "time stamp". I know,
+** this hurts, but i couldn't find any better
+** description. ;->
+*/
+char *tks_ts(void)
+{
+ static char tempus[256];
+ time_t now;
+ struct tm *loctime;
+
+ /* Get the current time */
+ now = time(NULL);
+
+ /* Convert it to local time representation */
+ loctime = localtime(&now);
+
+ strftime(tempus, 256, "@%H:%M %m/%d", loctime);
+
+ return(tempus);
+}
+
+/* logging routine, with timestamps */
+void tks_log(char *text, ...)
+{
+ char txt[TKS_MAXBUFFER];
+ va_list va;
+
+ tks_logf = fopen(TKSERV_LOGFILE, "a");
+ va_start(va, text);
+ vsprintf(txt, text, va);
+
+ if (tks_logf != NULL)
+ fprintf(tks_logf, "%s %s\n", txt, tks_ts());
+ else
+ {
+ perror(TKSERV_LOGFILE);
+ va_end(va);
+ return;
+ }
+
+ va_end(va);
+ fclose(tks_logf);
+}
+
+/* an optimized system() function */
+void exec_cmd(char *cmd, ...)
+{
+ char command[TKS_MAXBUFFER];
+ va_list va;
+
+ va_start(va, cmd);
+ vsprintf(command, cmd, va);
+ system(command);
+ va_end(va);
+}
+
+/* sends a string (<= TKS_MAXBUFFER) to the server */
+void sendto_server(char *buf, ...)
+{
+ char buffer[TKS_MAXBUFFER];
+ va_list va;
+
+ va_start(va, buf);
+ vsprintf(buffer, buf, va);
+ write(fd, buffer, strlen(buffer));
+ va_end(va);
+
+#ifdef TKSERV_DEBUG
+ printf("%s", buffer);
+#endif
+}
+
+/* sends a NOTICE to the SQUERY origin */
+void sendto_user(char *text, ...)
+{
+ char *nick, *ch;
+ char txt[TKS_MAXBUFFER];
+ va_list va;
+
+ nick = (char *) strdup(nuh);
+ ch = (char *) strchr(nick, '!');
+ *ch = '\0';
+
+ va_start(va, text);
+ vsprintf(txt, text, va);
+ sendto_server("NOTICE %s :%s\n", nick, txt);
+ va_end(va);
+}
+
+void process_server_output(char *line)
+{
+ char *ptr;
+ static char *args[TKS_MAXARGS];
+ int i, argc = 0;
+
+ while ((ptr = (char *) strchr(line, ' ')) && argc < TKS_MAXARGS)
+ {
+ args[argc] = line;
+ argc++;
+ *ptr = '\0';
+ line = ptr + 1;
+ }
+
+ args[argc] = line;
+
+ for (i = argc + 1; i < TKS_MAXARGS; i++)
+ args[i] = "";
+
+ /*
+ ** After successfull registering, backup the ircd.conf file
+ ** and set the perms of the log file -- the easy way :)
+ */
+ if ((*args[0] == ':') && (!strcmp(args[1], "SERVSET")))
+ {
+ chmod(TKSERV_ACCESSFILE, S_IRUSR | S_IWRITE);
+ chmod(TKSERV_LOGFILE, S_IRUSR | S_IWRITE);
+ exec_cmd("cp "CPATH" "TKSERV_IRCD_CONFIG_BAK);
+ tks_log("Registration successful.");
+ }
+
+ /* We do only react upon PINGs, SQUERYs and &NOTICES */
+ if (!strcmp(args[0], "PING"))
+ service_pong();
+
+ if ((*args[0] == ':') && (!strcmp(args[1], "SQUERY")))
+ service_squery(args);
+
+ if (!strcmp(args[0], "&NOTICES"))
+ service_notice(args);
+}
+
+/* reformats the server output */
+void parse_server_output(char *buffer)
+{
+ char *ch, buf[TKS_MAXBUFFER];
+ static char tmp[TKS_MAXBUFFER];
+
+ /* server sent an empty line, so just return */
+ if (!buffer && !*buffer)
+ return;
+
+ while ((ch = (char *) strchr(buffer, '\n')))
+ {
+ *ch = '\0';
+
+ if (*(ch - 1) == '\r')
+ *(ch - 1) == '\0';
+
+ sprintf(buf, "%s%s", tmp, buffer);
+ *tmp = '\0';
+ process_server_output(buf);
+ buffer = ch + 1;
+ }
+
+ if (*buffer)
+ strcpy(tmp, buffer);
+}
+
+/* reads and returns output from the server */
+int server_output(int fd, char *buffer)
+{
+ int n = read(fd, buffer, TKS_MAXBUFFER);
+ buffer[n] = '\0';
+
+#ifdef TKSERV_DEBUG
+ printf("%s", buffer);
+#endif
+
+ return(n);
+}
+
+/* is the origin of the /squery opered? */
+int is_opered(void)
+{
+ char *nick, *ch, *token, *u_num, *userh;
+ char buffer[TKS_MAXBUFFER];
+
+ nick = (char *) strdup(nuh);
+ ch = (char *) strchr(nick, '!');
+ *ch = '\0';
+ sendto_server("USERHOST %s\n", nick);
+
+ /* get the USERHOST reply (hopefully) */
+ server_output(fd, buffer);
+
+ token = (char *) strtok(buffer, " ");
+ token = (char *) strtok(NULL, " ");
+ u_num = (char *) strdup(token);
+ token = (char *) strtok(NULL, " ");
+ token = (char *) strtok(NULL, " ");
+ userh = (char *) strdup(token);
+
+ /* if we got the USERHOST reply, perform the check */
+ if (!strcmp(u_num, "302"))
+ {
+ char *ch;
+ ch = (char *) strchr(userh, '=') - 1;
+
+ /* is the origin opered? */
+ if (*ch == '*')
+ {
+ char *old_uh, *new_uh, *ch;
+
+ old_uh = (char *) (strchr(nuh, '!') + 1);
+ new_uh = (char *) (strchr(userh, '=') + 2);
+
+ if (ch = (char *) strchr(new_uh, '\r'))
+ *ch = '\0';
+
+ /* Does the u@h of the USERHOST reply correspond to the u@h of our origin? */
+ if (!strcmp(old_uh, new_uh))
+ return(1);
+ else
+ /*
+ ** race condition == we sent a USERHOST request and got the USERHHOST reply,
+ ** but this reply doesn't correspond to our origin of the SQUERY --
+ ** this should never happen (but never say never ;)
+ */
+ sendto_user("A race condition has occured -- please try again.");
+ }
+ }
+ else
+ /*
+ ** race condition == we sent a USERHOST request but the next message from
+ ** the server was not a USERHOST reply (usually due to lag)
+ */
+ sendto_user("A race condition has occured -- please try again (and ignore the following error message).");
+
+ return(0);
+}
+
+/*
+** Look for an entry in the access file and
+** see if the origin needs to be opered
+*/
+int must_be_opered()
+{
+ FILE *fp;
+
+ /* if the access file exists, check for auth */
+ if ((fp = fopen(TKSERV_ACCESSFILE, "r")) != NULL)
+ {
+ char buffer[TKS_MAXBUFFER];
+ char *access_uh, *token, *uh;
+
+ while (fgets(buffer, TKS_MAXBUFFER, fp))
+ {
+ uh = (char *) (strchr(nuh, '!') + 1);
+ token = (char *) strtok(buffer, " ");
+
+ if (token)
+ access_uh = (char *) strdup(token);
+
+ /* check for access file corruption */
+ if (!access_uh)
+ {
+ tks_log("Corrupt access file. RTFM. :-)");
+
+ return(0);
+ }
+
+ /* do we need an oper? */
+ if (*access_uh == '!')
+ {
+ if (!fnmatch((char *) (strchr(access_uh, '!') + 1), uh, 0))
+ return(0);
+ }
+ }
+ }
+ else
+ tks_log("%s not found.", TKSERV_ACCESSFILE);
+
+ return(1);
+}
+
+/* check whether origin is authorized to use the service */
+int is_authorized(char *pwd, char *host)
+{
+ FILE *fp;
+
+ /* if the access file exists, check for authorization */
+ if ((fp = fopen(TKSERV_ACCESSFILE, "r")) != NULL)
+ {
+ char buffer[TKS_MAXBUFFER];
+ char *access_uh, *access_pwd;
+ char *token, *uh, *ch, *tlds = NULL;
+
+ while (fgets(buffer, TKS_MAXBUFFER, fp))
+ {
+ uh = (char *) (strchr(nuh, '!') + 1);
+ token = (char *) strtok(buffer, " ");
+
+ if (token)
+ access_uh = (char *) strdup(token);
+
+ if (*access_uh == '!')
+ access_uh = (char *) (strchr(access_uh, '!') + 1);
+
+ token = (char *) strtok(NULL, " ");
+
+ if (token)
+ access_pwd = (char *) strdup(token);
+
+ token = (char *) strtok(NULL, " ");
+
+ if (token)
+ tlds = (char *) strdup(token);
+ else
+ if (ch = (char *) strchr(access_pwd, '\n'))
+ *ch = '\0';
+
+ /* check for access file corruption */
+ if (!access_uh || !access_pwd)
+ {
+ tks_log("Corrupt access file. RTFM. :-)");
+
+ return(0);
+ }
+
+ /* check uh, pass and TLD */
+ if (!fnmatch(access_uh, uh, 0))
+ if (!strcmp(pwd, access_pwd))
+ if (!tlds)
+ return(1);
+ else
+ {
+ char *token, *ch;
+
+ /* blah */
+ if (ch = (char *) strchr(tlds, '\n'))
+ *ch = '\0';
+
+ token = (char *) strtok(tlds, ",");
+
+ /* '!' negates the given host/domain -> not allowed to tkline */
+ if (*token == '!')
+ {
+ if (!fnmatch(((char *) strchr(token, '!') + 1), host, 0))
+ {
+ sendto_user("You are not allowed to tkline \"%s\",", host);
+ return(0);
+ }
+ }
+ else if (!fnmatch(token, host, 0))
+ return(1);
+
+ /* walk thru the list */
+ while (token = (char *) strtok(NULL, ","))
+ {
+ if (*token == '!')
+ {
+ if (!fnmatch((char *) (strchr(token, '!') + 1), host, 0))
+ {
+ sendto_user("You are not allowed to tkline \"%s\",", host);
+ return(0);
+ }
+ }
+ else if (!fnmatch(token, host, 0))
+ return(1);
+ }
+
+ sendto_user("You are not allowed to tkline \"%s\".", host);
+ }
+ }
+
+ }
+ else
+ tks_log("%s not found.", TKSERV_ACCESSFILE);
+
+ return(0);
+}
+
+/*************** ircd.conf section ****************/
+
+/* Appends new tklines to the ircd.conf file */
+int add_tkline(char *host, char *user, char *reason, int lifetime)
+{
+ FILE *iconf;
+
+ if (iconf = fopen(CPATH, "a"))
+ {
+ time_t now;
+
+ now = time(NULL);
+ fprintf(iconf, "K:%s:%s:%s:0 # %d %u tkserv\n",
+ host, reason, user, lifetime, now);
+ fclose(iconf);
+ rehash(1);
+ tks_log("K:%s:%s:%s:0 added for %d hour(s) by %s.",
+ host, reason, user, lifetime, nuh);
+
+ return(1);
+ }
+ else
+ tks_log("Couldn't write to "CPATH);
+
+ return(0);
+}
+
+/* Check for expired tklines in the ircd.conf file */
+int check_tklines(char *host, char *user, int lifetime)
+{
+ FILE *iconf, *iconf_tmp;
+
+ if ((iconf = fopen(CPATH, "r")) && (iconf_tmp = fopen(TKSERV_IRCD_CONFIG_TMP, "w")))
+ {
+ int count = 0, found = 0;
+ time_t now;
+ char buffer[TKS_MAXBUFFER];
+ char buf_tmp[TKS_MAXBUFFER];
+
+ /* just in case... */
+ chmod(TKSERV_IRCD_CONFIG_TMP, S_IRUSR | S_IWRITE);
+
+ now = time(NULL);
+
+ while (fgets(buffer, TKS_MAXBUFFER, iconf))
+ {
+ if ((*buffer != 'K') || (!strstr(buffer, "tkserv")))
+ fprintf(iconf_tmp, buffer);
+ else
+ {
+ /*
+ ** If lifetime has a value of -1, look for matching
+ ** tklines and remove them. Otherwise, perform
+ ** the expiration check.
+ */
+ if (lifetime == -1)
+ {
+ char *token;
+ char buf[TKS_MAXBUFFER];
+
+ strcpy(buf, buffer);
+ token = (char *) strtok(buf, ":");
+ token = (char *) strtok(NULL, ":");
+
+ if (!strcasecmp(token, host))
+ {
+ token = (char *) strtok(NULL, ":");
+ token = (char *) strtok(NULL, ":");
+
+ if (!strcasecmp(token, user))
+ {
+ count++;
+ found = 1;
+ }
+ else
+ fprintf(iconf_tmp, buffer);
+ }
+ else
+ fprintf(iconf_tmp, buffer);
+ }
+ else
+ {
+ char *ch, *token;
+ char buf[TKS_MAXBUFFER];
+ unsigned long int lifetime, then;
+
+ strcpy(buf, buffer);
+ ch = (char *) strrchr(buf, '#');
+ token = (char *) strtok(ch, " ");
+ token = (char *) strtok(NULL, " ");
+ lifetime = strtoul(token, NULL, 0);
+ token = (char *) strtok(NULL, " ");
+ then = strtoul(token, NULL, 0);
+
+ if (!(((now - then) / (60 * 60)) >= lifetime))
+ fprintf(iconf_tmp, buffer);
+ else
+ found = 1;
+ }
+ }
+ }
+
+ fclose(iconf);
+ fclose(iconf_tmp);
+ exec_cmd("cp %s %s", TKSERV_IRCD_CONFIG_TMP,CPATH);
+ unlink(TKSERV_IRCD_CONFIG_TMP);
+
+ if (found)
+ rehash(-1);
+
+ return(count);
+ }
+ else
+ tks_log("Error while checking for expired tklines...");
+}
+
+/* reloads the ircd.conf file -- the easy way */
+void rehash(int what)
+{
+ exec_cmd("kill -HUP `cat "PPATH"`");
+
+ if (what != -1)
+ tklined = what;
+}
+
+/*************** end of ircd.conf section **************/
+
+/*************** The service command section *************/
+
+/* On PING, send PONG and check for expired tklines */
+void service_pong(void)
+{
+ sendto_server("PONG %s\n", TKSERV_NAME);
+ check_tklines(NULL, NULL, 0);
+}
+
+/*
+** If we get a rehash, tell the origin that the tklines are active/removed
+** and check for expired tklines...
+*/
+void service_notice(char **args)
+{
+ if ((!strcmp(args[4], "reloading") && (!strcmp(args[5], TKSERV_IRCD_CONF))) ||
+ (!strcmp(args[3], "rehashing") && (!strcmp(args[4], "Server"))))
+ {
+ if (tklined)
+ {
+ sendto_user("TK-line%s.", (tklined > 1) ? "(s) removed" : " active");
+ tklined = 0;
+ }
+ }
+}
+
+/* parse the received SQUERY */
+void service_squery(char **args)
+{
+ char *cmd, *ch;
+
+ nuh = (char *) strdup(args[0] + 1);
+ cmd = (char *) strdup(args[3] + 1);
+
+ if (ch = (char *) strchr(cmd, '\r'))
+ *ch = '\0';
+
+ if (!strcasecmp(cmd, "admin"))
+ {
+ sendto_user(TKSERV_ADMIN_NAME);
+ sendto_user(TKSERV_ADMIN_CONTACT);
+ sendto_user(TKSERV_ADMIN_OTHER);
+ }
+
+ else if (!strcasecmp(cmd, "help"))
+ squery_help(args);
+
+ else if (!strcasecmp(cmd, "info"))
+ {
+ sendto_user("This service is featuring temporary k-lines.");
+ sendto_user("It's available at http://www.snafu.de/~kl/tkserv.");
+ }
+
+ else if (!strcasecmp(cmd, "quit"))
+ squery_quit(args);
+
+ else if (!strcasecmp(cmd, "tkline"))
+ squery_tkline(args);
+
+ else if (!strcasecmp(cmd, "version"))
+ sendto_user(TKS_VERSION);
+
+ else
+ sendto_user("Unknown command. Try HELP.");
+}
+
+/* SQUERY HELP */
+void squery_help(char **args)
+{
+ char *ch, *help_about;
+
+ help_about = args[4];
+
+ if (help_about && *help_about)
+ {
+ if (ch = (char *) strchr(help_about, '\r'))
+ *ch = '\0';
+
+ if (!strcasecmp(help_about, "admin"))
+ sendto_user("ADMIN shows you the administrative info for this service.");
+
+ if (!strcasecmp(help_about, "help"))
+ sendto_user("HELP <command> shows you the help text for <command>.");
+
+ if (!strcasecmp(help_about, "info"))
+ sendto_user("INFO shows you a short description about this service.");
+
+ if (!strcasecmp(help_about, "tkline"))
+ {
+ sendto_user("TKLINE adds a temporary entry to the server's k-line list.");
+ sendto_user("TKLINE is a privileged command.");
+ }
+
+ if (!strcasecmp(help_about, "version"))
+ sendto_user("VERSION shows you the version information of this service.");
+ }
+ else
+ {
+ sendto_user("Available commands:");
+ sendto_user("HELP, INFO, VERSION, ADMIN, TKLINE.");
+ sendto_user("Send HELP <command> for further help.");
+ }
+}
+
+/* SQUERY TKLINE */
+void squery_tkline(char **args)
+{
+ int lifetime, i;
+ char *passwd, *pattern, *host, *ch, *user = "*";
+ char reason[TKS_MAXKILLREASON];
+
+ /* Before we go thru all this, make sure we don't waste our time... */
+ if (must_be_opered())
+ {
+ if (!is_opered())
+ {
+ sendto_user("Only IRC-Operators may use this command.");
+ return;
+ }
+ }
+
+ i = 5;
+
+ while (args[i] && *args[i])
+ {
+ if (strchr(args[i], ':'))
+ {
+ sendto_user("Colons are only allowed in the password.");
+ return;
+ }
+
+ i++;
+ }
+
+ if (args[5] && *args[5])
+ {
+ if (isdigit(*args[5]) || (*args[5] == '-'))
+ lifetime = atoi(args[5]);
+ else
+ {
+ sendto_user("The lifetime may only contain digits.");
+ return;
+ }
+ }
+ else
+ {
+ sendto_user("Usage: TKLINE <password> [<lifetime>] <u@h> <reason>");
+ return;
+ }
+
+ /* TKLINE <pass> <lifetime> <u@h> <reason> */
+ if ((lifetime > 0) && !(args[7] && *args[7]))
+ {
+ sendto_user("Usage: TKLINE <password> <lifetime> <u@h> <reason>");
+ return;
+ }
+
+ /* TKLINE <pass> <u@h> <reason> (default expiration) */
+ if ((lifetime == 0) && !(args[6] && *args[6]))
+ {
+ sendto_user("Usage: TKLINE <password> <u@h> <reason>");
+ return;
+ }
+
+ /* TKLINE <pass> -1 <u@h> (removal of tklines) */
+ if ((lifetime == -1) && !(args[6] && *args[6]))
+ {
+ sendto_user("Usage: TKLINE <password> -1 <u@h>");
+ return;
+ }
+
+ if ((lifetime >= 768) || (lifetime < -1))
+ {
+ sendto_user("<lifetime> must be greater than 0 and less than 768.");
+ return;
+ }
+
+ /* I don't want to get confused, so all this may be a bit redundant */
+
+ if (lifetime > 0)
+ {
+ passwd = args[4];
+ pattern = args[6];
+ strcpy(reason, args[7]);
+ i = 8;
+
+ /* I know... */
+ while(args[i] && *args[i])
+ {
+ strncat(reason, " ", TKS_MAXKILLREASON - strlen(reason) - 1);
+ strncat(reason, args[i], TKS_MAXKILLREASON - strlen(reason) - 1);
+ i++;
+ }
+
+ if (ch = (char *) strchr(reason, '\r'))
+ *ch = '\0';
+ }
+
+ if (lifetime == 0)
+ {
+ if (!(strchr(args[5], '@') || strchr(args[5], '*') ||
+ strchr(args[5], '.')))
+ {
+ sendto_user("<lifetime> must be greater than 0.");
+ return;
+ }
+
+ passwd = args[4];
+ lifetime = 2; /* Default lifetime */
+ pattern = args[5];
+ strcpy(reason, args[6]);
+ i = 7;
+
+ while(args[i] && *args[i])
+ {
+ strncat(reason, " ", TKS_MAXKILLREASON - strlen(reason) - 1);
+ strncat(reason, args[i], TKS_MAXKILLREASON - strlen(reason) - 1);
+ i++;
+ }
+
+ if (ch = (char *) strchr(reason, '\r'))
+ *ch = '\0';
+ }
+
+ if (lifetime == -1)
+ {
+ passwd = args[4];
+ pattern = args[6];
+
+ if (ch = (char *) strchr(pattern, '\r'))
+ *ch = '\0';
+ }
+
+
+ /* Don't allow "*@*" and "*" in the pattern */
+ if (!strcmp(pattern, "*@*") || !strcmp(pattern, "*"))
+ {
+ sendto_user("The pattern \"%s\" is not allowed.", pattern);
+ tks_log("%s tried to tkline/untkline \"%s\".", nuh, pattern);
+ return;
+ }
+
+ /* Split the pattern up into username and hostname */
+ if (ch = (char *) strchr(pattern, '@'))
+ {
+ host = (char *) (strchr(pattern, '@') + 1);
+ user = pattern;
+ *ch = '\0';
+ }
+ else /* user defaults to "*" */
+ host = pattern;
+
+ /*
+ ** Make sure there's a dot in the hostname.
+ ** The reason for this being that i "need" a dot
+ ** later on and that i don't want to perform
+ ** extra checks whether it's there or not...
+ ** Call this lazyness, but it also makes the service faster. ;-)
+ */
+ if (!strchr(host, '.'))
+ {
+ sendto_user("The hostname must contain at least one dot.");
+ return;
+ }
+
+ if (!is_authorized(passwd, host))
+ {
+ sendto_user("Authorization failed.");
+ return;
+ }
+
+ if (lifetime == -1)
+ {
+ int i;
+
+ i = check_tklines(host, user, lifetime);
+ sendto_user("%d tkline%sfor \"%s@%s\" found.", i,
+ (i > 1) ? "s " : " ", user, host);
+
+ if (i > 0)
+ rehash(2);
+ }
+ else
+ if (!add_tkline(host, user, reason, lifetime))
+ sendto_user("Error while trying to edit the "CPATH" file.");
+}
+
+/* SQUERY QUIT
+** Each time we receive a QUIT via SQUERY we check whether
+** the supplied password matches the one in the conf file or not.
+** If not, an error is sent out. If yes, we close the connection to
+** the server.
+*/
+void squery_quit(char **args)
+{
+ char *ch;
+
+ if (ch = (char *) strchr(args[4], '\r'))
+ *ch = '\0';
+
+ if (!strcmp(args[4], TKSERV_PASSWORD))
+ {
+ tks_log("Got QUIT from %s. Terminating.", nuh);
+ sendto_server("QUIT :Linux makes the world go round. :)\n");
+ }
+ else
+ {
+ sendto_user("I refuse to QUIT. Have a look at the log to see why.");
+ tks_log("Got QUIT from %s with wrong password. Continuing.", nuh);
+ }
+}
+
+/**************** End of service command section ***************/
+
+int main(int argc, char *argv[])
+{
+
+ char *host, *port, buffer[TKS_MAXBUFFER], last_buf[TKS_MAXBUFFER];
+ char tmp[TKS_MAXPATH];
+
+ int is_unix = (argv[1] && *argv[1] == '/');
+ int sock_type = (is_unix) ? AF_UNIX : AF_INET;
+ int proto_type = SOCK_STREAM;
+ int eof = 0;
+
+ struct in_addr LocalHostAddr;
+ struct sockaddr_in server;
+ struct sockaddr_in localaddr;
+ struct hostent *hp;
+ struct timeval timeout;
+
+ fd_set read_set;
+ fd_set write_set;
+
+ if ((is_unix) && (argc != 2))
+ {
+ fprintf(stderr, "Usage: %s <server> <port>\n", argv[0]);
+ fprintf(stderr, " %s <Unix domain socket>\n", argv[0]);
+ exit(1);
+ }
+ else if (argc != 3)
+ {
+ fprintf(stderr, "Usage: %s <server> <port>\n", argv[0]);
+ fprintf(stderr, " %s <Unix domain socket>\n", argv[0]);
+ exit(1);
+ }
+
+ if (!strcmp(TKSERV_DIST, "*"))
+ {
+ printf("Your service has a global distribution. Please make sure that\n");
+ printf("you read the part about the service distribution in the README.\n");
+ }
+
+ tks_log("Welcome to TkServ. Lean back and enjoy the show...");
+
+ if ((fd = socket(sock_type, proto_type, 0)) < 0)
+ {
+ perror("socket");
+ exit(1);
+ }
+
+ /* copy the args into something more documentable */
+ host = argv[1];
+
+ if (!is_unix)
+ port = argv[2];
+
+ /* Unix domain socket */
+ if (is_unix)
+ {
+ struct sockaddr_un name;
+ memset(&name, 0, sizeof(struct sockaddr_un));
+ name.sun_family = AF_UNIX;
+ strcpy(name.sun_path, host);
+
+ if (connect(fd, (struct sockaddr *) &name, strlen(name.sun_path) + 2) == -1)
+ {
+ perror("connect");
+ close(fd);
+ exit(1);
+ }
+ }
+
+ memset(&localaddr, 0, sizeof(struct sockaddr_in));
+ localaddr.sin_family = AF_INET;
+ localaddr.sin_addr = LocalHostAddr;
+ localaddr.sin_port = 0;
+
+ if (bind(fd, (struct sockaddr *) &localaddr, sizeof(localaddr)))
+ {
+ perror("bind");
+ close(fd);
+ exit(1);
+ }
+
+ memset(&server, 0, sizeof(struct sockaddr_in));
+ memset(&LocalHostAddr, 0, sizeof(LocalHostAddr));
+
+ if (!(hp = gethostbyname(host)))
+ {
+ perror("resolv");
+ close(fd);
+ exit(1);
+ }
+
+ memmove(&(server.sin_addr), hp->h_addr, hp->h_length);
+ memmove((void *) &LocalHostAddr, hp->h_addr, sizeof(LocalHostAddr));
+ server.sin_family = AF_INET;
+ server.sin_port = htons(atoi(port));
+
+ if (connect(fd, (struct sockaddr *) &server, sizeof(server)) == -1)
+ {
+ perror("connect");
+ exit(1);
+ }
+
+ /* register the service with SERVICE_WANT_NOTICE */
+ sendto_server("PASS %s\n", TKSERV_PASSWORD);
+ sendto_server("SERVICE %s localhost %s 33554432 0 :%s\n", TKSERV_NAME, TKSERV_DIST, TKSERV_DESC);
+ sendto_server("SERVSET 33619968\n");
+
+ timeout.tv_usec = 1000;
+ timeout.tv_sec = 10;
+
+ /* daemonization... i'm sure it's not complete */
+ switch (fork())
+ {
+ case -1:
+ perror("fork()");
+ exit(3);
+ case 0:
+ close(STDIN_FILENO);
+ close(STDOUT_FILENO);
+ close(STDERR_FILENO);
+ if (setsid() == -1)
+ exit(4);
+ break;
+ default:
+ return 0;
+ }
+
+ /* listen for server output and parse it */
+ while (!eof)
+ {
+ FD_ZERO(&read_set);
+ FD_ZERO(&write_set);
+ FD_SET(fd, &read_set);
+
+ if (select(FD_SETSIZE, &read_set, &write_set, NULL, &timeout) == -1)
+ {
+ perror("select");
+ }
+
+ if (!server_output(fd, buffer))
+ {
+ printf("Connection closed.\n");
+ printf("Last server output was: %s\n", last_buf);
+ eof = 1;
+ }
+
+ strcpy(last_buf, buffer);
+ parse_server_output(buffer);
+ }
+
+ close(fd);
+
+ exit(0);
+}
+/* eof */
diff --git a/doc/2.10-New b/doc/2.10-New
new file mode 100644
index 0000000..8903783
--- /dev/null
+++ b/doc/2.10-New
@@ -0,0 +1,18 @@
+ * +a (away) user mode
+ This user mode is used to propagate users' away status between
+ servers.
+
+ * added channel mode +e (exceptions to bans).
+ * added channel mode +I (invitations).
+ * invites can now be used to override channel bans and limit.
+ * banned users cannot speak on channel without +o/+v.
+ * ! channels introduced (can't be collided);
+ A quite detailed technical description can be found on the web:
+ http://www.stealth.net/~kalt/irc/channel.html
+
+ * NJOIN for 2.10 <-> 2.10 communication on connect bursts instead of
+ the combined JOIN/MODE introduced by 2.9 (and now deprecated)
+
+ * a slave process is now used to authenticate incoming connections.
+ The slave's modular design makes it easy to add new authentication
+ modules.
diff --git a/doc/2.9-New b/doc/2.9-New
new file mode 100644
index 0000000..17d78e2
--- /dev/null
+++ b/doc/2.9-New
@@ -0,0 +1,60 @@
+ * +a (anonymous) channel mode
+
+ This channel mode is only allowed on &local channels.
+
+ * +s user mode removed;
+ * &KILLS, &NOTICES, &ERRORS, &CHANNEL, &HASH, &NUMERICS, &SERVERS
+ channels created and used by the server for server notices
+ (comments on what goes where please) and dividing notices up this
+ way was better than using more user modes (they default to the
+ server being on them and +amnt);
+
+ &KILLS : server and oper KILLS
+ &NOTICES : warnings and notices
+ &ERRORS : server errors
+ &LOCAL : notices concerning local clients.
+ &CHANNEL : fake modes
+ &HASH : hash tables growth
+ &NUMERICS : numerics received by the server
+ &SERVERS : servers joining and leaving the net
+
+ * + channels reintroduced (can't have modes);
+ * Config doesn't prompt for cc/includes/libs;
+ * M-line doesn't define port, PORTNUM removed from config.h (must use
+ P-lines or use inetd);
+ * BIND 4.9.2 libresolv stuff included;
+ * USERHOST will return as many id's as requested.
+ * RECONNECT to pickup error'd sserver-server links (not activated)
+ * chooses next bigger prime for hash table sizes rather than
+ needing exact primes
+ * hash tables grow to suit rather than being static in size
+ * adaptive growth of sendq (suggested by msa)
+ * Server parameter in USER message tokenised betweem 2.9 servers
+ * whowas tables grow to suit rather than being static in size
+ * NICK+USER+UMODE combined into NICK for 2.9 <-> 2.9 communication
+ * MODE +ov and JOIN combined into JOIN for 2.9 <-> 2.9 communication
+ on connect bursts
+ * QUIT removed when possible for 2.9 <-> 2.9 communication on split
+ * autoconf'iscated ircd.
+ * userlog has single character appended to show cause of quit.
+ * i lines (user mode +r)
+
+ i lined users have a restricted access: They are forbidden
+ MODE, KICK and TOPIC on #channels. They don't get channel
+ operator status when creating a #channel, and cannot
+ change their nickname once connected.
+
+ * enhanced nick delay to prevent collisions
+
+ The nickname of users splitting away is locked for 15 minutes,
+ and cannot be used by local clients.
+
+ * channel history to prevent op riding
+
+ A user with channel operator status on #foo splitting away
+ means that no local user can re-create the channel #foo during
+ the next 15 minutes. It doesn't stop users from using #foo as
+ as the channel is not empty.
+
+Some transition documentation from 2.8 to 2.9 version can be found in
+ http://www.irc.org/~irc/server/
diff --git a/doc/Authors b/doc/Authors
new file mode 100644
index 0000000..07f8ee0
--- /dev/null
+++ b/doc/Authors
@@ -0,0 +1,180 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, doc/AUTHORS
+ * Copyright (C) 1990
+ *
+ * AUTHORS FILE:
+ * This file attempts to remember all contributors to the IRC
+ * developement. Names can be only added this file, no name
+ * should ever be removed. This file must be included into all
+ * distributions of IRC and derived works.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+The email addresses listed in here may or may not be up to date.
+
+IRC was conceived of and written by Jarkko Oikarinen <jto@tolsun.oulu.fi>.
+IRC was originally written in University of Oulu, Computing Center.
+Jan 1991 - IRC 2.6 jto@tolsun.oulu.fi
+ - Multiple Channels and protocol changes
+
+Contributions were made by a cast of dozens, including the following:
+
+Markku Jarvinen <mta@tut.fi>: Emacs-like editing facility for the client
+
+Kimmo Suominen <kim@kannel.lut.fi>: HP-UX port
+
+Jeff Trim <jtrim@orion.cair.du.edu>: enhancements and advice
+
+Vijay Subramaniam <vijay@lll-winken.llnl.gov>: advice and ruthless publicity
+
+Karl Kleinpaste <karl@cis.ohio-state.edu>: user's manual
+
+Greg Lindahl <gl8f@virginia.edu>: AUTOMATON code, the Wumpus GM automaton,
+myriad bug fixes
+
+Bill Wisner <wisner@hayes.fai.alaska.edu>: numerous bug fixes and code
+enhancements
+
+Tom Davis <conslt16@zeus.unl.edu> and Tim Russell <russell@zeus.unl.edu>:
+VMS modifications
+
+Markku Savela <msa@tel4.tel.vtt.fi>: advice, support, and being the
+incentive to do some of our *own* coding. :)
+
+Tom Hopkins <hoppie@buengf.bu.edu>: bug fixes, quarantine lines,
+consolidation of various patches.
+
+Christopher Davis <ckd@cs.bu.edu>: EFnet/Anet gateway coding,
+many automata ;), documentation fixing.
+
+Helen Rose <hrose@cs.bu.edu>: documentation updating, and fixing.
+
+Tom Hinds <rocker@bucsf.bu.edu>: emacs client updating.
+
+Tim Miller <cerebus@bu-pub.bu.edu>: various server and client-breaking
+features.
+
+Darren Reed <avalon@coombs.anu.edu.au>: various bug fixes and enhancements.
+Introduced nickname and channelname hash tables into the server.
+
+The version 2.2 release was coordinated by Mike Bolotski
+<mikeb@salmon.ee.ubc.ca>.
+
+The version 2.4 release was coordinated by Markku Savela and
+Chelsea Ashley Dyerman
+
+The version 2.5.2 release was coordinated by Christopher Davis, Helen Rose,
+and Tom Hopkins.
+
+The versions 2.6.2, 2.7, 2.8 and 2.9 releases were coordinated by Darren Reed.
+
+Contributions for the 2.8 release from the following people:
+Matthew Green <phone@cairo.anu.edu.au>
+Chuck Kane <ckane@ece.uiuc.edu>
+Matt Lyle <matt@oc.com>
+Vesa Ruokonen <ruokonen@lut.fi>
+
+Markku Savela <Markku.Savela@vtt.fi> / April 1990
+Fixed various bugs in 2.2PL1 release server (2.2msa.4) and changed
+sockets to use non-blocking mode (2.2msa.9). [I have absolutely
+nothing to do with clients :-]
+
+Chelsea Ashley Dyerman <chelsea@earth.cchem.berkeley.edu> / April 1990
+Rewrote the Makefiles, restructuring of source tree. Added libIrcd.a to
+the Makefile macros, numerous reformatting of server text messages, and
+added mkversion.sh to keep track of compilation statistics. Numerous
+bug fixes and enhancements, and co-coordinator of the 2.4 release.
+
+jarlek@ifi.uio.no added mail functions to irc.
+
+Armin Gruner <gruner@informatik.tu-muenchen.de> / May, June 1990:
+* Patched KILL-line feature for ircd.conf, works now.
+ Enhancement: Time intervals can be specified in passwd-field.
+ Result: KILL-Line is only active during these intervals
+* Patched PRIVMSG handling, now OPER can specify masks for sending
+ private messages, advantage: msg to all at a specified server or host.
+* Little tests on irc 2.5 alpha, fixed some little typos in client code.
+ Change: common/debug.c has been moved to ircd/s_debug.c, and a
+ irc/c_debug.c has been created, for the benefit that wrong server msg
+ are displayed if client does not recognize them. (strange, if a server
+ sends an 'unknown command', isn't it?)
+
+Tom Hopkins <hoppie@buengf.bu.edu> / September, October 1990:
+* Patched msa's K lines for servers (Q lines).
+* Consolidated several patches, including Stealth's logging patch.
+* Fixed several minor bugs.
+* Has done lots of other stuff that I can't seem to remember, but he
+ always works on code, so he has to have done alot more than three
+ lines worth. :)
+
+Various modifications, bugreports, cleanups and testing by:
+
+Hugo Calendar <hugo@ucscb.ucsc.edu>
+Bo Adler <thumper@ugcs.caltech.edu>
+Michael Sandrof <mike@uniteq.com>
+Jon Solomon <jsol@cs.bu.edu>
+Jan Peterson <jlp@hamblin.math.byu.edu>
+Nathan Glasser <nathan@brokaw.lcs.mit.edu>
+Helen Rose <hrose@kei.com>
+Mike Pelletier <stealth@caen.engin.umich.edu>
+Basalat Ali Raja <gwydion@gnu.ai.mit.edu>
+Eric P. Scott <eps@toaster.sfsu.edu>
+Dan Goodwin <fornax@wpi.wpi.edu>
+Noah Friedman <friedman@ai.mit.edu>
+
+The 2.9 release brought many improvements to the protocol: adaptive growth
+of sendq, hash tables, whowas table, extended NICK syntax, server tokens,
+extended JOIN syntax, restricted usermode, nick and channel delay,
+suppression of server-server QUITs during splits, suppression of usermode s..
+
+Contributions for the 2.9 release from the following people:
+Vesa Ruokonen <ruokonen@lut.fi>: V configuration lines, many bug fixes.
+Christophe Kalt <kalt@stealth.net>: nick and channel delay, suppressed QUITs
+during netsplits, many bug fixes.
+
+The versions 2.9.3, 2.9.4, 2.9.5 releases were coordinated by Christophe Kalt.
+
+Christophe Kalt <kalt@stealth.net>: server link compression using zlib, added
+B configuration lines, extended IP bans and K lines to work on resolved hosts,
+finished service code, virtual IP support.
+
+Various modifications, bugreports, cleanups and testing by:
+
+Chris Behrens <cbehrens@concentric.net>
+Helmut Springer <delta@RUS.Uni-Stuttgart.DE>
+Magnus Tjernstrom <d92-mtm@oook.campus.luth.se>
+Olivier Galibert <Olivier.Galibert@mines.u-nancy.fr>: service code testing
+Alain Nissen <Alain.Nissen@ulg.ac.be>: source tree restructuration, many
+portability issues, new configure.in
+Roar Thronæs <roart@nvg.ntnu.no> added IPv6 support
+
+The versions 2.10 releases were coordinated by Christophe Kalt.
+
+Christophe Kalt <kalt@stealth.net>: added channel modes e and I, designed and
+implemented !channels, brought away status back to life, added NJOIN message,
+made invitation override bans, wrote iauth.
+
+Various modifications, bugreports, cleanups and testing by:
+
+Helmut Springer <delta@RUS.Uni-Stuttgart.DE>
+Michael 'Eumel' Neumayer <eumel@42.org>
+Kurt Roeckx <Q@ping.be> cleaned up the compression code, among many things
+Roar Thronæs <roart@nvg.ntnu.no> for more IPv6 work
+Piotr Kucharski <chopin@sgh.waw.pl> for his work on the anti socks module
+Michal Svoboda <svobodam@eva.vsp.cz> removed useless anUser linked list
+
+Thanks go to those persons not mentioned here who have added their advice,
+opinions, and code to IRC.
diff --git a/doc/BUGS b/doc/BUGS
new file mode 100644
index 0000000..32e914f
--- /dev/null
+++ b/doc/BUGS
@@ -0,0 +1,13 @@
+# @(#)$Id: BUGS,v 1.14 1999/03/07 22:59:31 kalt Exp $
+
+The list is probably not as scary as it once was.
+Anyone with some free time is welcome to fix those =)
+
+* The server still occasionnally crashes because of some bug
+ in the hash tables. (Vesa already fixed this bug several
+ times but it keeps crashing :^)
+
+* RECONNECT is still in some unknown state. (and deactivated
+ for various reasons)
+
+* The operator count showed by /LUSERS becomes incorrect (negative).
diff --git a/doc/ChangeLog b/doc/ChangeLog
new file mode 100644
index 0000000..9869542
--- /dev/null
+++ b/doc/ChangeLog
@@ -0,0 +1,1956 @@
+2.10.3
+
+1999-08-13 Christophe Kalt
+
+ * channel.c/match_modeid(): logic fix (reported by Michal Svoboda).
+
+ * os.h: added YET ANOTHER KLUDGE for linux and poll().
+
+ * ircd.c: assume "-s" option in CYGWIN environment.
+
+ * configure.in: update for CYGWIN environment.
+
+1999-08-13 Piotr Kucharski
+
+ * mod_socks.c/socks_read(): allow more methods in socks5 check.
+
+1999-08-01 Piotr Kucharski
+
+ * ircd.c/bad_command(): -d command line option no longer exists,
+ while -s was added.
+
+1999-07-28 Christophe Kalt
+
+ * struct_def.h: IsChannelName() macro cannot use cid_ok() for the
+ client.
+
+ * channel.c/m_njoin(): inverse condition prevented modes from
+ being sent to users and 2.9 servers.
+
+1999-07-27 Piotr Kucharski
+
+ * s_id.c/cid_ok(): quite unfortunate typo which made joining
+ !channels impossible (from Michal Svoboda).
+
+1999-07-25 Christophe Kalt
+
+ * channel.c: sanity checks to drop modes on +channels even when
+ received from servers (from Michal Svoboda).
+
+ * struct_def.h, channel.c, s_id.c: added checks to ensure !name
+ validity (from Michal Svoboda).
+
+1999-07-23 Christophe Kalt
+
+ * s_bsd.c/inetport(): fixed test for IPv6 (from KIKUCHI Takahiro).
+
+ * ircd.c:
+ * better casting for sbrk() for OSF 4.0.
+ * setup_me(): fixed syntax for IPv6.
+
+1999-07-21 Piotr Kucharski
+
+ * channel.c/set_mode(): send ERR_UNKNOWNMODE to 'mode O' issued
+ on non-!channels.
+
+1999-07-21 Christophe Kalt
+
+ * s_misc.c/exit_one_client(): generate fake PARTs for users
+ quitting anonymous channels.
+
+ * send.c/sendto_common_channels(): skip anonymous channels.
+
+ * Makefile.in: ircdwatch needs clsupport.o which needs clmatch.o.
+
+ * channel.c: added notices to warn users about +a channels.
+
+1999-07-20 Kurt Roeckx
+
+ * channel.c:
+ * m_njoin: send +v for uniqops in the right case
+ * send_channel_members: send +v inside njoin for ops too
+ * m_invite: send back numerics if the channel doesn't exist
+
+1999-07-18 Piotr Kucharski
+
+ * channel.c/set_mode(), m_kick(): send ERR_NOTONCHANNEL, not
+ ERR_CHANOPRIVSNEEDED, thus disable stealth secret channel probing;
+ furthermore, use rather sptr->name, not parv[0] in sending errors;
+
+1999-07-17 Christophe Kalt
+
+ * ircd.c/setup_me(), s_bsd.c: fixed that really old bug about the
+ I line format to match connections received on the loopback
+ interface (from Eugene L. Vorokov).
+
+ * configure.in: fixed previous changes about poll() (reported by
+ KIKUCHI Takahiro).
+
+1999-07-17 Kurt Roeckx
+
+ * s_user.c/m_kill(): killer could end up < path
+
+1999-07-14 Christophe Kalt
+
+ * configure.in, os.h: use ncurses.h (from KIKUCHI Takahiro).
+
+ * configure.in: SunOS has poll(), but we don't want to use it
+ (reported by KIKUCHI Takahiro).
+
+ * mod_lhex.c: replaced strtoul() with sscanf().
+
+1999-07-11 Christophe Kalt
+
+ * a_defines.h was missing support_def.h (from KIKUCHI Takahiro).
+
+ * Makefile.in: ircdwatch.c uses strerror(), needs clsupport.o
+ (from KIKUCHI Takahiro).
+
+ * config.h.dist, ircd.c, s_debug.c: renamed CONNECTTIMEOUT to
+ ACCEPTTIMEOUT, and changed from 30 to 90.
+
+1999-07-11 Piotr Kucharski
+
+ * mod_socks.c:
+ * socks_write(): a typo made iauth allow open proxies and
+ caused a lot of BADPROTO warnings (from KIKUCHI Takahiro).
+ * socks_init(): buffer overflow with tmpbuf[] being too
+ small to hold too many iauth options (also from Takahiro).
+
+1999-07-09 Christophe Kalt
+
+ * configure.in, os.h, s_bsd.c: IPv6 updates (from KIKUCHI Takahiro).
+
+1999-07-05 Christophe Kalt
+
+ * s_bsd.c/read_message(): can't use iauth_options when USE_IAUTH
+ is undefined.
+
+1999-07-05 Piotr Kucharski
+
+ * channel.c/m_invite(): invite to :-channels was sometimes
+ lost with no error.
+
+1999-07-04 Christophe Kalt
+
+ * a_conf_def.h, a_conf.c, a_io.c: added the "timeout" option.
+
+ * mod_socks.c: added PROXY_BADPROTO & OPT_PROTOCOL to
+ differentiate between unexpected and bad protocol.
+
+ * s_id.c: fixed alphabet_id[] (noted by Michal Svoboda), and
+ rewrote some code.
+
+1999-07-04 Piotr Kucharski
+
+ * s_user.c/m_nick(): fix performance bug introduced in code
+ preventing insidious collisions
+
+ * mod_socks.c/socks_open_proxy(): now reports in logs versions
+ of open proxies found
+
+1999-07-02 Kurt Roeckx
+
+ * configure.in, Makefile.in: Added -I for inet6.
+
+1999-07-02 Christophe Kalt
+
+ * res.c/proc_answer(): portability fix from hybrid6.
+
+ * send.c/sendto_match_butone(): finally looked closely at why this
+ was sending $*.mask to the wrong servers, fixed.
+
+ * struct_def.h, send.c/sendto_match_butone(), list_ext.h,
+ list.c/make_client(), ircd.c/setup_me(), s_misc.c/exit_client(),
+ s_serv.c, s_service.c/m_service(), s_user.c/m_user(): removed old
+ code conditional to NO_USRTOP being undefined.
+
+ * s_user.c:
+ * m_nick(): new delay on nicks to prevent insidious
+ collisions (from Piotr Kucharski).
+ * m_private(): dropped restrictions on mass msg/notices.
+
+ * s_auth.c/read_authports(): can't call set_clean_username with
+ ->auth pointing to ->username (from Piotr Kucharski).
+
+ * mod_socks.c: couple typos.
+
+ * a_conf.c/conf_read(): ->popt wasn't initialized.
+
+1999-06-27 Christophe Kalt
+
+ * s_misc.c/exit_one_client(): made BETTER_NDELAY a little more
+ friendly (from Piotr Kucharski).
+
+ * a_io.c/sendto_ircd(): added error output in write error notice.
+
+ * hash.c/hash_channel_name(): added shortname parameter to disable
+ guess and fix bug (From Q).
+
+ * channel.c/m_join(): reject local user join for duplicates.
+
+ * mod_socks.c: more options, less bugs (from Piotr Kucharski).
+
+ * s_user.c:
+ * m_nick(): kill nicks introduced by server if parc != 8
+ instead of simply sending a notice.
+ * register_user(): static variable wasn't declared as such.
+
+ * ircd.c, s_serv.c: used mybasename();
+
+ * support_ext.h, support.c: added mybasename();
+
+1999-06-20 Christophe Kalt
+
+ * mod_socks.c: added code to allow checks for v5 as well as v4,
+ depending on configuration (from Piotr Kucharski).
+
+ * configure.in, ircd.c/ircd_writetune(), s_serv.c/m_rehash(): use
+ basename, and check if it needs libgen.
+
+ * channel.c/m_njoin(): simple optimization resulting from change
+ to sendto_match_servs_notv() below.
+
+ * send_ext.h, send.c: sendto_serv_{not,}v and
+ sendto_match_servs_{not,}v now return an integer.
+
+1999-06-16 Christophe Kalt
+
+ * iauth.c/main(): send version to ircd upon startup.
+
+ * mod_rfc931.c/rfc931_work(): removed checks on weird chars, let
+ ircd deal with this.
+
+ * s_auth.c:
+ * start_auth(): abort if getpeername() fails (problem
+ reported by Wolfgang Scherer).
+ * added set_clean_username(), used in read_iauth() and
+ read_authports().
+ * read_iauth(): added o message (a->i).
+ * read_iauth(): added V message (a->i).
+
+ * struct_def.h, s_serv.c: added SV_OLDSQUIT, and made m_squit()
+ smarter (ugh, it's a kludge).
+
+1999-06-07 Christophe Kalt
+
+ * s_user.c:
+ * m_nick(): added notice to warn of NICK messages coming
+ from servers with parc != 8.
+ * register_user(): fixed unaccurate notices about iauth.
+
+ * config.h.dist: increased HANGONRETRYDELAY & HANGONGOODLINK values.
+
+1999-06-06 Christophe Kalt
+
+ * struct_def.h, send.c/sendto_match_butone(), list_ext.h,
+ list.c/make_client(), ircd.c/setup_me(), s_misc.c/exit_client(),
+ s_serv.c, s_service.c/m_service(), s_user.c/m_user(): added
+ reorder_client_list() and NO_USRTOP defines. This reduces memory
+ usage (Original code from Michal Svoboda).
+
+ * channel.c/reop_channel(): desynched could be caused by server
+ reops (channel mode +r) (reported by Thomas Kuiper).
+
+1999-05-01 Christophe Kalt
+
+ * s_conf_ext.h, s_conf.c, s_serv.c: added a new list for K/k lines
+ only as an easy way to improve overall performance.
+
+ * service_def.h: updated SERVICE_MASK_ALL.
+
+1999-04-19 Christophe Kalt
+
+ * channel.c/m_njoin(): need to use sendto_match_servs*(); duh!
+
+ * send_ext.h, send.c: added sendto_match_servs_notv().
+
+ * s_serv.c/m_squit(): fixed logic in previous change.
+
+ * packet.c/dopacket(): fixed uncompression code.
+
+1999-04-15 Christophe Kalt
+
+ * service_def.h, channel.c/m_topic(), s_service.c/m_servset():
+ added SERVICE_WANT_TOPIC.
+
+ * s_serv.c/m_squit(): fixed serious and old bug that caused
+ servers to be removed from memory (but not dependants!!!) while
+ squit is going upstream.
+
+ * s_debug.c/send_usage(): divide by zero bugfix (reported by Aaron
+ Campbell).
+
+ * channel.c/m_njoin(): ignore channels with an invalid mask.
+
+ * common/parse.c: extended MSG_NOU to include services.
+
+1999-04-10 Christophe Kalt
+
+ * Makefile.in, a_conf_def.h, a_externs.h, a_conf.c, mod_lhex_ext.h,
+ mod_lhex.c: New module (from Andrew Snare).
+
+ * s_debug.c: increased size of debugbuf[] to avoid overflows (from
+ Eugene L. Vorokov).
+
+ * send.c/send_message(): catch more unlikely errors (from Eugene
+ L. Vorokov).
+
+ * s_bsd.c/set_sock_opts(): silently ignore errors for SO_SNDLOWAT.
+
+ * common/os.h: FreeBSD portability (from KIKUCHI Takahiro).
+
+ * s_bsd.c/read_message():
+ * debug notice format bugfix (from Q).
+ * INET6 fix (from KIKUCHI Takahiro).
+
+ * s_conf.c:
+ * initconf(): allow service type to be in hex in the
+ configuration (from Thomas Kuiper).
+ * find_conf_flags(): case sensitivity fix (from Q).
+
+1999-03-19 Christophe Kalt
+
+ * mod_socks.c/socks_work(): closed proxies would get rejected on
+ first attempt and accepted later as the "closed" status was in the
+ cache.
+
+ * s_user.c/register_user(): fixed iauth failure notice timing bug.
+
+1999-03-13 Christophe Kalt
+
+ * struct_def.h, ircd.c, s_auth.c, s_bsd.c, s_user_ext.h, s_user.c,
+ a_struct_def.h, iauth.c, a_conf.c, a_io.c: added XOPT_EARLYPARSE,
+ `P' message for iauth, `extinfo' option for iauth.
+
+ * a_io.c/next_io(): if xxx_start() returns 1, count module as left.
+
+1999-03-11 Christophe Kalt
+
+ * chkconf.c:
+ * finally shut off MyFree() redefinition warning.
+ * fixed undefined behaviour with ++ operator (effet de bord).
+
+ * a_io.c/init_io(): bzero bugfix (reported by Tomas Edwardsson).
+
+ * a_conf_def.h, a_conf.c:
+ * conf_err(): send conf errors to ircd as well.
+ * conf_match(): extended iauth.conf syntax for hostname
+ and IP matching.
+ * added conf_ipmask() to allow use of a.b.c.d/z format for IP.
+
+ * configure.in: use "cc -Ae" on HPUX (reported by Jens Riecken).
+
+ * ircd.c/main(): iauth's presence needs to be checked before
+ setting up the signal handlers.
+
+1999-03-09 Christophe Kalt
+
+ * a_struct_def.h, a_conf_ext.h, a_conf_def.h, a_conf.c, a_io.c,
+ mod_pipe.c, mod_rfc931.c, mod_socks.c: rewrote next_io() and
+ conf_match() to use new more flexible logic.
+
+ * os.h, a_conf.c, iauth.c, configure.in, Makefile.in, acconfig.h:
+ added DSM support.
+
+1999-03-08 Christophe Kalt
+
+ * struct_def.h, a_conf.c, a_conf_ext.h, iauth.c, ircd.c, s_auth.c,
+ s_auth_ext.h, s_bsd.c, s_user.c, s_user_exit.c: added
+ XOPT_{REQUIRED,NOTIMEOUT,EXTWAIT}, added iauth_spawn counter;
+ removed iauth_required variable.
+
+ * struct_def.h, s_auth.c, s_user.c: added FLAGS_DONEXAUTH to get
+ rid of the approximation from yesterday.
+
+ * s_bsd.c/read_message(): use CLR_READ_EVENT() before modifying fd.
+
+1999-03-07 Christophe Kalt
+
+ * res_comp.c: added missing prototypes.
+
+ * struct_def.h, a_conf.c, a_conf_ext.h, iauth.c, s_auth_ext.h,
+ s_auth.c, s_user.c: added option to reject new user connections if
+ iauth is dead (approximate!).
+
+ * struct_def.h, ircd.c, res.c, s_auth.c, s_bsd.c: removed all
+ references to {Set,Clear,Do}Access macros (unused for a LONG time).
+
+ * ircd.c:
+ * check_pings(): fixed "immediate ping timeout" bug.
+ * main(): check for iauth's presence after changing [ug]id.
+
+ * s_bsd.c/do_dns_async(): notify iauth when no PTR record is found.
+
+ * Makefile.in: fix for M4 file path (Matthew Sullivan).
+
+1999-03-04 Christophe Kalt
+
+ * ircd.c/io_loop(), s_bsd.c/start_iauth(): keep trying to restart
+ iauth (up to once every 90 seconds) to avoid being iauth-less.
+
+ * struct_def.h, mod_socks.c, s_auth.c, s_user.c: added new message
+ type from iauth to ircd to allow denying connections without any
+ message sent to &AUTH; used by the socks module.
+
+1999-02-22 Christophe Kalt
+
+ * s_err.c: RPL_TRACESERVICE changed to show values in hexadecimal
+ (from Thomas Kuiper).
+
+ * s_service.c/m_service(): fixed error message.
+
+1999-02-20 Christophe Kalt
+
+ * configure, configure.in, Makefile.in, config.h.dist, buildm4,
+ send.c, ircd.c, s_bsd.c, s_conf.c, s_misc.c, s_serv.c, s_user.c,
+ chkconf.c, a_conf.c, a_log.c: paths overhaul.
+
+ * c_msg_ext.h, c_msg.c: fixed m_server() prototype.
+
+1999-02-19 Kurt Roeckx
+
+ * packet.c/dopacket(), s_bsd.c/read_packet(): bugfix.
+
+1999-02-18 Christophe Kalt
+
+ * res.c/proc_answer(): fixed T_PTR processing (problem reported by
+ Michal Svoboda).
+
+ * channel.c:
+ * del_modeid(): bugfix when called with NULL.
+ * can_join(): readability (from Q).
+
+ * s_serv.c/check_version():
+ * removed code about 2.10.0[ab]*.
+ * never used NJOIN with 0209* servers (bugfix).
+
+ * s_err.c: removed extraneous %s in RPL_UNIQOPIS.
+
+1999-02-09 Kurt Roeckx
+
+ * hash.c/hash_find_channels(): cleanup.
+
+ * ircd.c/main(), ircd_ext.h: various cleanups.
+
+ * res_comp_ext.h: added prototype for ircd_getshort().
+
+ * s_bsd.c/read_message(): typo fix (=! -> !=).
+
+ * s_conf.c/attach_conf(): stops detecting listen sockets as
+ clients from same IP address.
+
+ * s_err.c: removed / from replies.
+
+ * s_serv.c/m_links(): removed unused variable.
+
+ * s_user.c/who_channel(): removed unused variables.
+
+1999-02-05 Christophe Kalt
+
+ * match.c/match(): removed predictable if's (from Tero Jänkä).
+
+ * s_serv.c/m_server_estab(): flush_connections() called once
+ during burst.
+
+ * s_debug.c: updated.
+
+ * ircd.c/io_loop(), s_bsd.c/read_message(), s_bsd_ext.h, config.h:
+ new logic inspired from irce, removed PREFER_SERVER.
+
+ * s_bsd.c:
+ * added read_listeners().
+ * set_sock_opts() now sets SO_SNDLOWAT.
+ * add_connection() now sends a message to client being
+ reject by the anti-clone crap.
+
+ * send.c: added flush_fdary() function.
+
+ * common_def.h, config.h, send.c: removed SENDQ_ALWAYS define,
+ simplified code for when it was undefined as it is only used by
+ the client now.
+
+2.10.2
+
+1999-02-03 Christophe Kalt
+
+ * mod_rfc931.c/rfc931_work(): get rid of any \n in replies.
+
+ * a_io.c/parse_ircd(): when receiving a "DNS timeout" message,
+ inform ircd if we're already done (otherwise, it keeps waiting
+ until timeout).
+
+ * s_bsd.c/completed_connection(): tell iauth not to wait for DNS
+ information for servers we connect to.
+
+ * s_auth.c/read_iauth():
+ * fixed "Garbage" notices to &AUTH.
+ * send E message to iauth when parsing garbage.
+
+1999-01-28 Christophe Kalt
+
+ * s_serv.c/m_server_estab(): added notices to &DEBUG.
+
+ * struct_def.h, s_auth.c: renamed MotdItem to LineItem and moved
+ around some defines.
+
+ * s_bsd_ext.h: added missing ';' for utmp_open() definition.
+
+ * channel.c/m_list(): !shortname now reports +p/+s channels (but
+ still hides member count and topic for +s channels).
+
+ * match.c/match(): rearranged if test to suppress harmless read
+ overflow errors (reported by Insure++).
+
+ * s_user.c/m_nick(): lp needs to be initialized (reported by Insure++).
+
+ * hash.c/hash_find_channels(): bugfix (spottoed by Q).
+
+ * mod_rfc931.c/rfc931_init(): fix for a silly bug (from Piotr).
+
+1999-01-19 Christophe Kalt
+
+ * resolv_def.h, res_comp.c, res_init.c: updated (BIND 4.9.7-REL).
+
+ * packet.c/dopacket(): don't call unzip_packet() without data at
+ beginning of connection only! (from Q).
+
+ * numeric_def.h, s_err.c, channel.c: added numerics RPL_UNIQOPIS
+ (325), ERR_BANLISTFULL (478) and ERR_UNIQOPPRIVSNEEDED (485).
+
+ * channel.c:
+ * m_njoin(): missing return value (reported by Insure++).
+ * m_mode(): use ERR_RESTRICTED for restricted clients.
+ * m_join(): it's now possible to create !!#foo if #foo exists.
+ * m_list(): now works for !shortname.
+
+ * hash_ext.h, hash.c: added hash_find_channels().
+
+ * configure.in, os.h:
+ * update for autoconf 2.13.
+ * let's trust autoconf to decide to use poll() or not.
+
+ * s_bsd.c: sendto_flags() doesn't exist, it's sendto_flag().
+
+ * mod_rfc931.c:
+ * stats weren't initialized.
+ * added undocumented "protocol" option (it's boring!).
+
+ * mod_socks.c:
+ * fixed never occuring memory leak.
+ * improved stats (from Piotr Kucharski).
+
+ * s_user_ext.h, s_user.c, s_service.c: added a parameter to
+ do_nick_name() [UID].
+
+1999-01-12 Christophe Kalt
+
+ * a_log_def.h, mod_pipe_ext.h, a_externs.h, mod_pipe.c, a_conf.c:
+ finally wrote the pipe module.
+
+ * struct_def.h, a_conf_def.h, a_io_ext.h, iauth.c, mod_rfc931.c,
+ mod_socks.c, s_auth.c, s_auth_ext.h, s_misc.c: iauth now sends
+ statistics to ircd, shown by /stats t.
+
+ * a_conf_def.h, a_conf.c, a_log_def.h, mod_socks.c: SOCKS module
+ overhaul: added caching, rewrote code to use v4 instead of v5, and
+ to be smarter (Based on work from Piotr Kucharski).
+
+ * s_user.c: do_nick_name() now rejects "anonymous".
+
+ * packet.c/dopacket(): don't call unzip_packet() without data.
+
+ * channel.c: extension to del_modeid() from Kaspar Landsberg.
+
+ * s_bsd.c: don't call dopacket() again for compressed links just
+ because the output buffer was filled up.
+
+1998-12-31 Christophe Kalt
+
+ * ircd.c: removed extraneous flush_connections() call in io_loop().
+
+ * ircd.c, s_bsd.c, list.c, list_ext.h: removed unused 'active' code.
+
+ * struct_def.h, parse.c: removed various unused aClient fields.
+
+1998-12-24 Christophe Kalt
+
+ * s_service.c: using FLAGS_CBURST for services has too many
+ implications; reverted.
+
+ * struct_def.h, s_bsd.c, s_zip.c: removed requirement for
+ inflate() to never fill up the uncompression output buffer, an
+ unlikely situation which is now dealt with. (mostly from Q).
+
+1998-12-21 Christophe Kalt
+
+
+ * s_user.c:
+ * [RFC] suppressed an error reply for notices in m_message().
+ * server notices to +n channels were failing. (Reported by Q).
+
+ * a_defines.h: INET6 fix for OSF (from Roar Thronæs).
+
+ * os.h: INET6 fix for OSF (from Roar Thronæs).
+
+ * channel.c: added check against 'duplicate joins' in m_njoin().
+
+1998-12-14 Christophe Kalt
+
+ * channel.c:
+ * yet another +a/+r fix in set_mode().
+ * send_channel_modes() would occasionnally send duplicate
+ bans. (Reported by Robert Martin-Legene <robert@irc.ircnet.dk>)
+
+ * iauth.c, a_io.c: added nonexistant INET6 code.
+
+ * os.h, nameser_def.h, resolv_def.h: OSF portability fix from Roar
+ Thronæs.
+
+ * s_auth.c: added missing INET6 code. (Roar Thronæs)
+
+1998-09-25 Christophe Kalt
+
+ * configure.in: Check for IPv6 system type and update $LIBS (from
+ KIKUCHI Takahiro <kick@kyoto.wide.ad.jp>)
+
+ * bsd.c, os.h, parse.c, struct_def.h, support.c, support_ext.h,
+ c_bsd.c, c_version.c, c_version_ext.h, irc.c, swear.c, channel.c,
+ chkconf.c, ircd.c, nameser_def.h, res.c, res_def.h, res_init.c,
+ resolv_def.h, s_auth.c, s_bsd.c, s_conf.c, s_debug.c, s_misc.c,
+ s_serv.c, s_user.c, acconfig.h, configure.in: merged 2.9.5+IPv6.
+
+1998-04-12 Christophe Kalt
+
+ * configure.in, s_debug.c: vsyslog() isn't necessarely available
+ even if USE_STDARG is defined. (Digital Unix)
+
+1998-04-04 Christophe Kalt
+
+ * c_version_ext.h, c_version.c, irc.c, swear.c: Digital Unix 4.0B
+ port (Roar Thronæs <roart@nvg.ntnu.no>)
+
+1998-12-12 Christophe Kalt
+
+ * channel.c: +a/+r fix for !channels.
+
+1998-11-20 Christophe Kalt
+
+ * irc.c: allocate me.info (fix by Helmut Franzke <hf@rp-online.de>).
+
+2.10.1
+
+1998-11-12 Christophe Kalt
+
+ * Doc references to @stealth.net changed to @irc.org.
+
+ * s_serv.c: report_ping() now sends some extra info to &DEBUG.
+
+ * s_bsd.c: send_ping() window set to 20 minutes (instead of 10),
+ and never close it.
+
+1998-11-03 Christophe Kalt
+
+ * s_serv.c: changed m_trace() to only show unknowns to opers and
+ local clients.
+
+ * a_io.c: fd remap processing bugfix (from Q@ping.be).
+
+ * s_bsd.c: fixed ircd/iauth problem with servers ircd connects to.
+
+1998-10-31 Christophe Kalt
+
+ * parse.c: reordered msgtab[].
+
+ * s_serv.c: added more restrictions to m_links(), m_stats() [t],
+ m_motd() and m_lusers() for remote clients. (*sigh*)
+
+ * channel.c: fixed count_channels() not to count empty channels.
+
+1998-10-28 Christophe Kalt
+
+ * s_user.c: optimized m_whois() (pointed out by several people).
+
+ * s_user.c, channel.c: channel creator flag is now removed on -o.
+
+ * channel.c:
+ * !channel creation is now done with !! rather than !#.
+ * fixed channel counters (affects /lusers & /stats z).
+ * m_njoin(): simple optimization.
+
+Sat Oct 10 18:55:38 1998 Christophe Kalt <kalt@millennium.stealth.net>
+
+ * a_io.c: don't TST_* if cldata[i].?fd <= 0 in loop_io().
+
+ * ircd.s, s_auth.c, s_bsd.c, s_bsd_ext.h: always attempt to
+ restart iauth in start_iauth() after receiving a SIGUSR1.
+
+ * s_service.c: reverted part of last change.
+
+ * s_user.c: last change introduced a bug. (typo, reported by N. Aust)
+
+ * channel.c: fixed match_modeid() to handle remote clients
+ properly now that it's used from can_send().
+
+Thu Oct 8 18:33:50 1998 Christophe Kalt <kalt@millennium.stealth.net>
+
+ * configure.in: always compile with -g flag, and never strip.
+
+ * channel.c:
+ * renamed sub1_from_channel() to free_channel().
+ * always send modes for empty channels during netjoin.
+ * fixed old (2.9.x) memory leak in collect_channel_garbage().
+
+ * s_id.c:
+ * linked list corruption bugfix in collect_chid().
+ * added logic to avoid excessive caching in cache_chid().
+
+ * s_service.c: stdarg bugfix in check_service_butone (from O.G.).
+
+Sun Sep 27 15:12:53 1998 Christophe Kalt <kalt@millennium.stealth.net>
+
+ * s_user.c: prefix bugfix (reported by mrg).
+
+2.10.0p1
+
+Fri Sep 25 22:21:06 1998 Christophe Kalt <kalt@millennium.stealth.net>
+
+ * channel.c: check for +r mode before calling reop_channel().
+
+2.10.0
+
+Wed Sep 23 19:55:14 1998 Christophe Kalt <kalt@millennium.stealth.net>
+
+ * configure.in, os.h: don't trust poll() to work if it exists.
+
+ * channel.c:
+ * removed FULLV2_10 ifdef's
+ * don't send empty NJOIN in m_njoin() (Reported by Beeth).
+
+ * channel.c, s_debug.c, config.h.dist: removed MIRC_KLUDGE.
+
+ * chkconf.c: added warning about old V line format.
+
+ * config.h.dist: OPER_DIE is now defined by default.
+
+ * s_user.c: reverted last change, and hostnames are now truncated.
+
+ * os.h: preprocessor syntax fix.
+
+ * s_conf.c: stupid typo in match_ipmask().
+
+ * s_auth.c: added a new debugging notice.
+
+ * s_debug.c: flags update.
+
+ * ircd.c:
+ * added some debugging info in restart notice.
+ * changed strdup() in mystrdup() (from Andrew Snare).
+
+Sun Sep 20 15:22:25 1998 Christophe Kalt <kalt@millennium.stealth.net>
+
+ * os.h, configure.in: configure now checks for poll() existence to
+ decide if it should be used.
+
+ * res_init.c, s_conf.c: strncpy() bugfixes (from Q).
+
+ * s_auth.c, mod_rfc931.c: '[' is no longer allowed in ident replies.
+
+ * channel.c: don't let chanops set +a on !channels.
+
+ * a_io.c: (weirdbug)fix.
+
+ * s_err.c: numeric 004 update.
+
+ * s_user.c: connections rejected by iauth are now shown as K-lined
+ in &LOCAL.
+
+ * s_bsd.c: new PASS syntax (Q).
+
+Sun Sep 13 20:32:08 1998 Christophe Kalt <kalt@millennium.stealth.net>
+
+ * config.h.dist, ircd.c: removed MYNAME.
+
+ * Makefile.in, config.h.dist: SPATH/APATH cleanup.
+
+ * parse.c: ABW fix (Leon Brouwers <leonb@sci.kun.nl> and purify).
+
+Sat Sep 12 18:53:39 1998 Christophe Kalt <kalt@millennium.stealth.net>
+
+ * ircd.c, s_bsd.c: SIGCHLD handling code to avoid zombies.
+
+ * s_bsd.c:
+ * udpfd used in place of adfd in in read_message().
+ * silently deal with linux accept() way of life.
+
+ * a_io.c: loop_io() bugfix for select() systems.
+
+ * ircd.c:
+ * me.info from ircd.conf was overridden in setup_me().
+ * server_reboot() created a zombie.
+
+ * s_user.c: allow servers to speak on channels (reported by Q).
+
+ * channel.c:
+ * NJOIN bugfix related to unique ops (reported by Q).
+ * removed old core from msa.
+
+ * various little cleanups.
+
+ * res.c: buffer overflow fix. (thanks to Leon Brouwers
+ <leonb@sci.kun.nl> and purify)
+
+Tue Sep 8 21:23:27 1998 Christophe Kalt <kalt@millennium.stealth.net>
+
+ * s_user.c: user mode +a propagation bugfix.
+
+ * ircd.c: die immediately if no listener exists after reading the conf.
+
+ * send_ext.h, send.c, channel.c: backward compatibility fix for eI
+ channel modes (added sendto_match_servs_v()).
+
+Mon Sep 7 18:03:34 1998 Christophe Kalt <kalt@millennium.stealth.net>
+
+ * s_bsd.c: inversed test for -s in start_iauth().
+
+ * channel.c:
+ * keys starting with ':' don't propagate correctly.
+ * m_njoin() didn't send modes properly to clients.
+
+ * s_serv.c:
+ * slightly changed the PASS syntax again.
+ * 2.10 alphas didn't recognize peers as such (reported by Q).
+
+Sun Aug 23 22:16:40 1998 Christophe Kalt <kalt@millennium.stealth.net>
+
+ * struct_def.h, ircd.c, list.c, list_ext.h, s_conf.c, s_serv.c,
+ s_service.c, s_user.c: aClient's info is now dynamically allocated
+ to overcome server handshake limitations.
+
+Sat Aug 22 15:20:10 1998 Christophe Kalt <kalt@millennium.stealth.net>
+
+ * channel.c: fixed ^G bug (only triggered in channel creation)
+
+ * struct_def.h, channel.c, s_err.c, s_user.c: AWAY is back.
+
+Sun Aug 16 16:01:15 1998 Christophe Kalt <kalt@millennium.stealth.net>
+
+ * ircd.c:, s_bsd.c: added -s switch.
+
+Sat Aug 8 14:21:20 1998 Christophe Kalt <kalt@millennium.stealth.net>
+
+ * s_serv.c: Roger's diff broke compression. (reported by Andre Koopal)
+
+ * Makefile.in: iauth didn't know where to find zlib.h (reported
+ by delta)
+
+ * a_log.c: typos in parameter names (reported by delta).
+
+Fri Aug 7 23:54:10 1998 Christophe Kalt <kalt@millennium.stealth.net>
+
+ * mod_rfc931.c: added sanity check on replies.
+
+Fri Aug 7 00:03:45 1998 Christophe Kalt <kalt@millennium.stealth.net>
+
+ * mod_rfc931.c: read RFC 1413 and fixed the reply parser.
+
+ * numeric_def.h, s_err.c, s_auth_ext.h, s_auth.c, s_serv.c: added
+ /stats a to show iauth's configuation.
+
+ * s_auth.c, a_*.[ch], mod_*.c:
+ * SIGUSR2 will cause iauth to close and reopen log file(s).
+ * worked around delayed messages from the iauth caused by
+ ircd's fd remapping habit.
+ * reduced memory usage by dynamically allocating `inbuffer'.
+ * added G message (a->i).
+ * added E message (i->a) and cleaned up errors messages in
+ parse_ircd().
+ * added a/A messages (a->i) to transmist configuration.
+ * revisited next_io() and hopefully fixed the logic.
+
+ * ircd.c, res.c, s_auth.c, s_auth_ext.h, s_bsd.c, s_user.c:
+ * stdarg'ized sendto_iauth().
+ * iauth is now automatically restarted.
+ * fixed bcopy() length in read_iauth().
+ * added notices to track the "" username bug.
+
+Tue Aug 4 21:43:53 1998 Christophe Kalt <kalt@millennium.stealth.net>
+
+ * a_io.c: numerous bug fixes..
+
+ * mod_rfc931.c: fix to prevent crash when receiving data from
+ broken ident servers.
+
+ * a_conf.c, a_conf_def.h, a_externs.h, a_log_def.h: added module
+ `socks'. (Based on a 2.9.5 diff from Jonathan Chapman)
+
+ * a_log.c: added timestamps to `auth' log.
+
+ * s_misc.c: EXITC_AREF is a special case like EXITC_REF.
+
+ * parse.c: penalty bugfix.
+
+ * ircd.c, s_auth.c, s_bsd.c, s_bsd_ext.h:
+ * cleaned up iauth startup procedure, added start_iauth()
+ which is called upon SIGUSR1.
+ * various fixes in read_iauth().
+
+Sun Aug 2 18:34:20 1998 Christophe Kalt <kalt@millennium.stealth.net>
+
+ * s_mist_ext.h, s_misc.c, support_ext.h, support.c: moved
+ myctime() from s_misc.c to support.c.
+
+ * s_bsd.c, a_io.c: added `R' message from ircd to iauth.
+
+ * s_serv.c: updated check_version() not to use NJOIN with 2.9.5 links.
+
+ * parse.c: restricted SQUERY to users.
+
+ * channel.c:
+ * m_njoin(): conversion bugfix (Reported by Q).
+ * added FULLV2_10 #if's.
+
+ * struct_def.h, channel.c, s_err.c, s_misc.c: added channel mode `r'.
+
+ * send.c: reference to NULL pointer in sendto_match_servs()
+ (Reported by Core).
+
+ * sys_def.c, chkconf.c: MyFree() redefinitions (from Core).
+
+ * Makefile.in: "make install-server" path problems.
+
+Sun Jul 19 15:32:48 1998 Christophe Kalt <kalt@millennium.stealth.net>
+
+ * s_conf.c, ircd.c: unitialized K line comment in check_pings().
+
+ * channel.c:
+ * beI modes to multiple channels were corrupted.
+ * mode parameters starting with : don't propagate correctly.
+ * !channel creation propagation was broken (reported by Eumel).
+
+ * send.c, struct_def.h, channel.s, res.c, ircd.c, s_auth.c,
+ s_auth_ext.h, s_bsd.c, s_bsd_ext.h, s_conf.c, s_user.c,
+ Makefile.in, config.h.dist: added iauth.
+
+Fri Jun 12 19:00:03 1998 Christophe Kalt <kalt@millennium.stealth.net>
+
+ * ircd.c: fix for inetd support (from Jonathan Chapman
+ <jonathan@clover.net>).
+
+ * parse.c, s_debug.c: more LOCOP_* fixes (from Michael Neumayer).
+
+ * s_user.c: oper counter bugfix (from Magnus Tjernstrom).
+
+ * channel.c:
+ * fixed join #a,#b,.. desynch bug (reported by viha@vip.fi).
+ * fixed netjoin +p/+s desynch problem (same).
+
+Sun May 31 14:18:41 1998 Christophe Kalt <kalt@millennium.stealth.net>
+
+ * send.c, channel.c: '-' leftovers (Michael Neumayer <eumel@42.org>).
+
+Mon May 25 15:13:51 1998 Christophe Kalt <kalt@millennium.stealth.net>
+
+ * struct_def.h, channel.c, hash.c, s_misc.c: changed new channels
+ prefix to ! (instead of -).
+
+ * parse.c: undefining LOCOP_* had no effect (reported by Eumel).
+
+ * s_service.c: SERVICE_WANT_OPER burst fix (from Jonathan Chapman).
+
+ * s_bsd.c: SO_LINGER patch (from Andrew Snare <ajs@pigpond.com>).
+
+ * configure.in: better logic for --resconf.
+
+ * channel.c:
+ * m_invite() fix for &channels.
+ * add_modeid() always used RPL_BANLIST.
+ * bIe modes coming from a server were rejected
+ add_modeid() if another mode with the same pattern existed.
+
+ * c_debug_ext.h, c_debug.c, chkconf.c, s_misc.c, s_zip.c: fixes
+ for DEBUGMODE (from Andrew Snare <ajs@pigpond.com> & Magnus
+ Tjernstrom <d92-mtm@ludd.luth.se>)
+
+ * hash.c: bigger_prime() useless optimization from Magnus :-)
+
+Tue May 5 19:26:25 1998 Christophe Kalt <kalt@millennium.stealth.net>
+
+ * config.h.dist, Makefile.in, struct_def.h, s_externs.h, send.c,
+ channel.c, hash.c, s_debug.c, s_err.c, s_misc.c, s_serv.c,
+ s_user.c: implemented new channels.
+
+ * struct_def.h, parse.c, channel.c, ircd.c, s_debug.c, s_misc.c,
+ s_serv.c, s_user.c, whowas.c, config.h.dist: replaced BIG_NET #define.
+
+Fri Apr 24 20:30:21 1998 Christophe Kalt <kalt@millennium.stealth.net>
+
+ * irc.c: missing refresh() (from Dave Hill <ddhill@zk3.dec.com>).
+
+ * s_conf.c, s_service.c: portability fixes from Avalon.
+
+ * channel.c, s_user.c: adapted undernet's Bquiet.
+
+Sun Apr 5 17:50:08 1998 Christophe Kalt <kalt@millennium.stealth.net>
+
+ * configure, configure.in, config.h.dist: added --logdir option.
+
+ * s_serv.c:
+ * moved user wallops from #wallops to +wallops.
+ * stricter m_server() check for unregistered users.
+
+ * send.c: wallops were sent to services and unregistered clients.
+
+Sat Apr 4 19:05:26 1998 Christophe Kalt <kalt@millennium.stealth.net>
+
+ * struct_def.h, packet.c, s_bsd.c: (never triggered) link
+ compression bugfix (Roger Espel Llima <espel@llaic.u-clermont1.fr>).
+
+ * config.h.dist, ircd.c, s_debug.c: added PREFER_SERVER #define.
+
+ * s_user.c:
+ * m_oper() notice bug fix (Michael 'Eumel' Neumayer).
+ * completely disabled AWAY.
+
+ * struct_def.h, parse.c, channel.c, ircd.c, s_debug.c, s_misc.c,
+ s_serv.c, s_user.c, whowas.c, config.h.dist: added BIG_NET #define.
+
+ * s_misc.c; Y2K fix.
+
+Tue Mar 31 18:52:41 1998 Christophe Kalt <kalt@millennium.stealth.net>
+
+ * s_serv.c: removed now obsolete USE_NJOIN.
+
+ * numeric_def.h, struct_def.h, channel.c, s_debug.c, s_err.c,
+ s_serv.c: added channel modes +e (EFnet's exceptions to bans) and
+ +I (invitations); raised MAXBANS (should be renamed) to 30.
+
+ * support.c: extended make_version().
+
+ * channel.c:
+ * notify user when a ban is rejected because "redundant".
+ * /invite (from chanop) now overrides bans & limit.
+
+ * s_debug.c, s_serv.c: /stats r no longer restricted to DEBUGMODE.
+
+ * s_bsd.c: getrlimit()/setrlimit() is now used regardless of
+ poll() availibility.
+
+Sun Mar 22 14:01:24 1998 Christophe Kalt <kalt@millennium.stealth.net>
+
+ * channel.c: MIRC_KLUDGE sent bogus modes on channel creation.
+
+ * os.h, support.c, s_bsd.c: CYGWIN32 cleanup from Dave Miller.
+
+ * s_user.c: hunt_server() cleanup.
+
+ * s_conf.c: match_ipmask() choked on a.b.c.d/z (reported by Helmut
+ Springer <delta@RUS.Uni-Stuttgart.DE>).
+
+2.9.5
+
+Tue Feb 17 21:25:02 1998 Christophe Kalt
+
+ * s_bsd.c: w32 doesn't have a working fork().
+
+ * ircd.c: deal with "getpwuid(getuid())" returning NULL.
+
+ * configure.in, os.h, support.c: use our own truncate() when
+ needed (CYGWIN32), and CYGWIN32 portability. (Thanks to Dave
+ Miller <yahoo@molalla.net>).
+
+ * config.guess: update.
+
+ * s_user.c: broadcast restriction wasn't right (Yegg).
+
+ * send.c, ircd.c: removed noisy debugging notices.
+
+Sat Feb 7 09:21:52 1998 Christophe Kalt
+
+ * s_user.c:
+ * oper log is now more verbose.
+ * broadcast messages/notices are now less restricted.
+
+ * hash.c: nitpicking (from Magnus Tjernstrom).
+
+ * configure.in: quoting cleanup (from Alain).
+
+ * send_ext.h, s_debug.h: STDARG prototyping cleanup (from Alain).
+
+Fri Jan 23 17:39:17 1998 Christophe Kalt
+
+ * os.h: linux 2.1 implements poll() but the header files are a
+ mess (what did you expect?), kludge to get it work (from Vesa).
+
+ * channel.c: fixes related to MIRC_KLUDGE.
+
+ * s_conf.c:
+ * find_kill() fix and cleanup (mostly from Vesa).
+ * find_bounce() stricter check and fix (from Vesa).
+
+ * parse.c: m_njoin() is only used by the server.
+
+Fri Jan 23 17:38:36 1998 Christophe Kalt
+
+ * channel.c:
+ * buffer overflow fix.
+ * bugfix from Avalon.
+ * join/invite were propagated for &channels. (reported by DLR)
+ * invite/kick were propagated beyond masks. (reported by DLR)
+ * multiple kicks could desynch channels.
+
+ * s_user.c: stricter check on unregistered NICK changes (Avalon).
+
+ * hash.c: hash_find_server() didn't handle z.stealth.net (1
+ letter) masked by *.stealth.net (DLR).
+
+ * msg_def.h, struct_def.h, channel_ext.h, parse.c, channel.c,
+ s_serv.c: added send_channel_members() and m_njoin().
+
+ * send_ext.h, send.c: added sendto_serv_notv().
+
+ * buidm4: yet another m4 booboo. (fix from Mario)
+
+Wed Jan 7 11:40:59 1998 Christophe Kalt
+
+ * s_user.c: strncpy() lameness.
+
+ * s_conf.c: added match_ipmask() (from Vesa).
+
+ * configure.in, send_ext.h: "checking for working stdarg" always
+ failed because of a quoting problem.
+
+Thu Dec 18 21:48:18 1997 Christophe Kalt
+
+ * channel.c: abusive usage of /names now forbidden.
+
+ * class.c: imposed a minimum of 60 seconds for connect frequencies.
+
+ * struct_def.h, s_misc.c, s_serv.c: check_link() tuning and statistics.
+
+Tue Dec 16 17:12:16 1997 Christophe Kalt
+
+ * s_conf.c: finished D lines.
+
+ * numeric_def.h, struct_def.h, list.c, s_err.c, s_serv.c: added
+ check_link() to prevent server links from being flooded by replies
+ to user requests.
+
+ * s_bsd.c: try to prevent the server from flooding with UDP pings.
+
+ * channel.c: #foo:*.tld modes were always sent during the burst.
+
+Wed Nov 12 21:02:15 1997 Christophe Kalt
+
+ * struct_def.h, s_conf_ext.h, s_conf.c, ircd.c, chkconf.c,
+ numeric_def.h, s_err.c , s_serv.c: added D configuration
+ lines. (/stats h)
+
+ * send.c, s_service.c: allocate more dbufs during a service burst
+ if needed.
+
+ * channel.c: cosmetics, and fixed the use of MAXPENALTY in m_kick().
+
+ * s_debug.c: too many parameters in a call to sendto_one().
+
+2.9.4
+
+Sat Oct 18 09:37:33 1997 Christophe Kalt
+
+ * setup.h.in, configure.in: (Alain Nissen)
+ * additional header files checked.
+ * non-blocking system test fixed.
+
+ * os.h: curses/termcap stuff is now only used for the client (AN).
+
+ * swear_ext.h, swear.c: portability issues (Alain Nissen).
+
+ * c_bsd.c, s_bsd.c, os.h: SELECT_FDSET_TYPE (defined in os.h) used
+ as pointer type in select() calls; HPUX compilation problem
+ fixed. (Alain Nissen)
+
+ * buildm4: typo & missing quote. (again!)
+
+Fri Oct 10 23:48:25 1997 Christophe Kalt
+
+ * s_serv.c: improved m_die() and m_restart() in case a service is
+ used for user log.
+
+ * os.h, acconfig.h, configure.in, res.c, s_bsd.c: (Alain Nissen)
+ * kludge to deal with broken hostent declaration in
+ netdb.h on some linux systems.
+ * test for sigaction & sigset functions added back; signal
+ implementation test fixed.
+
+ * s_conf.c:
+ * more explicit K line message when reason specified in
+ ircd.conf.
+ * extended I lines syntax.
+
+ * s_service_ext.h, s_service.c, s_misc.c: faster split handling is
+ possible now that 2.8.x protocol is history.
+
+ * channel.c:
+ * m_join() was unefficient on net joins.
+ * MIRC_KLUDGE would never show +ov modes.
+
+ * s_user.c:
+ * services can now send to channels (if the modes allow it).
+ * prefixes for restricted connections were gone.
+
+ * buildm4: missing quote.
+
+2.9.4b
+
+Wed Oct 1 21:57:45 1997 Christophe Kalt
+
+ * chkconf.c: added knowledge of B lines.
+
+ * s_debug.c: more info on dbufs for better tuning.
+
+ * channel.c: bans on IP are now matched against resolving clients.
+
+ * s_conf.c: K lines on IP can now be matched against resolving clients.
+
+ * buildm4: update for Y and K line macros, and added macros for
+ B,V,i and k lines (Mario Holbe).
+
+ * s_conf.c: Y global limit per host didn't work.
+
+Wed Sep 24 18:25:45 1997 Christophe Kalt
+
+ * acconfig.h, configure.in, setup.h.in, resolv_def.h, res_init.c:
+ added --resconf=FILE option to configure (Alain Nissen).
+
+ * s_conf.c: fixed bug with Y limits.
+
+Tue Sep 23 11:36:30 1997 Christophe Kalt
+
+ * common_def.h: added CHKCONF_COMPILE statement.
+
+ * bsd_ext.h: incorrect declaration for writeb.
+
+ * support_ext.h, support.c: dumpcore() was broken.
+
+ * class_def.h, class_ext.h, class.c, s_conf.c, s_err.c: it's now
+ possible to combine a limit per host and per user@host for the
+ same class.
+
+ * s_user.c:
+ * RPL_ENDOFWHO wasn't correct.
+ * who_find() / m_whois() didn't always respect +a mode.
+ * @ restriction in username could be bypassed.
+ * unlikely but nonetheless possible ghost generation.
+
+ * ircd.c: setgid() was called after setuid() (reported by Nicole
+ Haywood <kole@mail.usyd.edu.au>)
+
+ * parse.c: avoid a match() call if possible.
+
+Sun Sep 14 19:44:27 1997 Christophe Kalt
+
+ * ircd.c: redundant/useless code commented out.
+
+ * struct_def.h, parse.c, s_err.c, s_serv.c: `stats m' is more verbose.
+
+ * os.h, Makefile.in: zlib.h was missing from includes.
+
+ * s_user.c: 2 fixes (a NULL pointer, and a non reinitialized one).
+
+Thu Sep 11 21:43:20 1997 Christophe Kalt
+
+ * class_def.h, class_ext.h, class.c, s_bsd.c, s_conf.c, s_err.c,
+ s_user.c: added 2 fields to Y lines and implemented [u@]h global
+ limits.
+
+ * service_def.h, channel.c, s_service.c: added SERVICE_WANT_VCHANNEL.
+
+ * channel.c: server channels now have a topic.
+
+ * s_conf.c: negative class numbers are now forbidden.
+
+ * s_conf_ext.h, s_conf.c, s_bsd.c: new B lines format.
+
+Sun Sep 7 20:02:50 1997 Christophe Kalt
+
+ * s_conf.c: B lines now catch "unauthorized connections".
+
+ * s_user.c: m_who() limit wasn't coded. fixed this and rewrote
+ m_who() because recursivity and penalty don't go together.
+
+ * s_err.c: REPL_SERVLIST type field is now in hexa.
+
+ * service_def.h, send.c, s_misc.c, s_user.c: extended services
+ capabilities so they can do logging.
+
+ * s_serv.c, s_user.c: added MD5 support for crypt() (from Urvos Juvan).
+
+ * res.c: hostnames containing * or ? are now rejected.
+
+ * s_conf.c: service type field stripped from optional bits (in S
+ lines).
+
+ * s_serv.c: server token wasn't sent to services in m_server_estab().
+
+ * s_service.c: SERVICE_WANT_PREFIX wasn't honored by m_squery().
+
+ * struct_def.h, parse.c, s_serv.c, s_user.c:
+ * added MyService() macro and updated several tests.
+ * next_client() was ignoring services.
+
+Tue Aug 19 08:38:54 1997 Christophe Kalt
+
+ * channel.c: m_names() could still have a truncated reply.
+
+ * more cleaning from Alain.Nissen@ulg.ac.be:
+
+ * struct_def.h, bsd.c, s_bsd.c: removed references to "pyr".
+ * res_comp.c: removed res_getshort() [never used].
+ * removed all references to VMS.
+
+Mon Aug 11 13:34:15 1997 Christophe Kalt
+
+ * The following changes are from Alain.Nissen@ulg.ac.be
+
+ * all files (in short):
+ * include/ was removed.
+ * all .c have a corresponding _ext.h to declare external
+ variables and functions.
+ * [sc]_externs.h are #includes *_ext.h.
+ * [sc]_defines.h are #includes *_def.h.
+ * all .c have the same list of #include.
+ * os.h has all system #includes and portability tests.
+
+ * Also, several bug and portability fixes:
+
+ * c_bsd.c: move renamed in tcap_move (portability).
+ * c_msg.c:
+ * added test on DOCURSES before including it.
+ * various casts.
+ * edit.c:
+ * return type of suspend_irc() changed to RETSIGTYPE.
+ * added int argument to suspend_irc().
+ * use of signal(SIGTSTP,...) now depends on
+ whether the signal exists rather than the OS.
+ * help.c: helplist rewritten properly.
+ * irc.c:
+ * strdup() replaced with mystrdup().
+ * do_log() takes 2 arguments.
+ * return type of quit_intr() changed to RETSIGTYPE.
+ * added int argument to quit_intr().
+ * screen.c: such a mess
+ * LINES is only present under curses.
+ * idem for refresh().
+ * clear_to_eol() is supposed to take 2 arguments,
+ but what are they?
+ * swear.c: added to clients targets
+ * channel.c: delch renamed in del_ch.
+ * chkconf.c, parse.c: newline renamed in irc_newline.
+ * ircd.c: s_monitor(), s_die(), s_rehash(), s_restart()
+ return type changed from VOIDSIG to RETSIGTYPE.
+ * res.c: now using SOCK_LEN_TYPE.
+ * res_comp.c, res_init.c: various portability changes.
+ * s_auth.c: now using SOCK_LEN_TYPE.
+ * s_bsd.c: now using SOCK_LEN_TYPE.
+ * s_conf.c: several portability fixes.
+ * s_err.c: local_replies[] and local_replies[] rewritten.
+ * s_service.c: changed test on USE_STDARG.
+ * bsd.c:
+ * return type for dummy() is now RETSIGTYPE.
+ * dummy() now takes one int argument.
+ * dbuf.c: removed unused DBUF_INIT.
+ * support.c:
+ * many changes concerning #if tests.
+ * added solaris_gethostbyname() to use instead of
+ Solaris 2.3 broken gethostbyname().
+ * added irc_memcmp() to use if system's memcmp()
+ is broken.
+ * nameser.h: now using WORDS_BIGENDIAN.
+ * configure.in:
+ * simpler solaris 2.x detection when looking for zlib.
+ * added test for cursesX.
+ * added check for sys_errlist definition in sys/errno.h
+ * and more...
+ * Makefile.in: CFLAGS split in S_CFLAGS, C_CFLAGS and
+ CC_CFLAGS (ircd, irc, chkconf).
+
+Fri Aug 8 10:51:24 1997 Christophe Kalt
+
+ * channel.c: m_names() behaviour wasn't consistent with m_who()
+ concerning +p channels (Michael 'Eumel' Neumayer).
+
+ * configure.in: minor changes (Alain Nissen).
+
+ * s_user.c: missing argument to err_str() (Kai Seidler).
+
+ * config.h.dist, h.h, struct.h, common.c, channel.c, s_bsd.c,
+ s_debug.c, s_err.c, s_misc.c, s_serv.c, s_service.c, s_user.c:
+ removed support for 2.8 protocol.
+
+ * config.h.dist, msg.h, channel.c, note.c, s_bsd.c, s_debug.c,
+ s_misd.c, s_user.c: removed NOTE.
+
+ * s_bsd.c: wrong argument to bzero().
+
+ * Makefile.in, buildm4: rev.sh replaced by config.guess and
+ buildm4 wasn't ran by `make install-server'.
+
+2.9.3
+
+Wed Jul 23 11:23:30 1997 Christophe Kalt
+
+ * res.c: queries were never resent when reaching timeout (C. Behrens).
+
+ * acconfig.h, configure.in: better sys_errlist test (A. Nissen).
+
+ * version.c.SH.in: portability (A. Nissen).
+
+ * acconfig.h, configure.in, common.h, config.h.dist: AIX cleanup
+ and optimization flags (A. Nissen).
+
+ * configure.in: typo.
+
+Thu Jul 17 23:04:48 1997 Christophe Kalt
+
+ * c_numeric.c, irc.c: fixes from Vesa.
+
+ * send.c: buffer overflow fix.
+
+ * h.h, res_init.c: portability fixes.
+
+Wed Jul 16 21:35:50 1997 Christophe Kalt
+
+ * s_serv.c: m_die() referenced data after freeing it.
+
+ * support.c, res.c: silly changes to make purify happier.
+
+ * s_bsd.c: fixed memory corruption problem.
+
+ * s_user.c: m_whois() voice flag changed back to + (from !).
+
+ * h.h, support.c, configure.in: reverted back: use inet_* if
+ present, use our own inet* if not. Our functions must be
+ different to avoid some crazy clash when bind 8.x is on installed
+ the system. Should we teach configure.in about -lbind?
+
+Tue Jul 15 00:18:01 1997 Christophe Kalt
+
+ * inet_addr.c moved to support.c, renamed functions (inet_addr,
+ inet_aton, inet_ntoa, inet_netof) to avoid clashes; always used
+ even if the system has it.
+
+ * New configure and Makefile from Alain Nissen. (many many files
+ changed, removed, created, rewritten)
+
+ * buildm4: update (Mario Holbe).
+
+ * struct.h, s_bsd.c: fixed the P line rehash bug(?).
+
+ * h.h, ircd.c: let's be nice to SunOS' cc.
+
+Mon Jun 30 21:41:11 1997 Christophe Kalt
+
+ * dbuf.c, send.c: earlier changes broke the client.
+
+ * config.h.dist, struct.h, dbuf.h, dbuf.c: new magic formula to
+ compute BUFFERPOOL. Added MAXSERVERS for this purpose.
+
+ * s_serv.c: buffer overflow (Chris Behrens).
+
+Thu Jun 26 19:18:24 1997 Christophe Kalt
+
+ * struct.h, channel.c, hash.c, parse.c, send.c, s_misc.c,
+ s_service.c:
+ * cleanup.
+ * added &SERVICES.
+
+ * s_bsd.c: wrong buffer size given to getsockopt().
+
+Thu Jun 19 18:35:37 1997 Christophe Kalt
+
+ * h.h, struct.h, s_debug.c, send.c, dbuf.c:
+ * dbuf stats.
+ * send_message() #ifndef SENDQ_ALWAYS was not uptodate,
+ tried to bring it back up to date.
+
+ * res.c: fixed possible buffer overflow.
+
+ * h.h, s_debug.c, send.c: fixes for STDARG (Olivier Galibert)
+
+ * ircd.c: server_reboot() would crash when called because of "out
+ of memory".
+
+Mon Jun 9 20:49:55 1997 Christophe Kalt
+
+ * config.h.dist, h.h, struct.h, send.c, ircd.c, list.c, s_debug.c,
+ s_serv.c, s_user.c: removed #define KRYS, it is now always `defined'.
+
+ * config.h.dist, h.h, common.h, service.h, sys.h, configure.in,
+ send.c, support.c, s_auth.c, s_service.c, s_debug.c, s_conf.c:
+ removed references to varargs, added support for stdargs.
+ It is controlled by #define USE_STDARG set by configure. (adapted
+ from Olivier Galibert)
+
+ * ircd.c: CHROOT is really called CHROOTDIR.
+
+ * s_user.c:
+ * extended m_message() to accept n!u@h as recipient.
+ * removed notice for bogus PONG.
+
+ * s_serv.c: /SQUIT now requires 2 arguments from opers.
+
+Sun Jun 1 16:57:39 1997 Christophe Kalt
+
+ * dbuf.h, dbuf.c: #define DBUF_TAIL is back.
+
+ * s_conf.c: fixed B lines behaviour, port number is now mandatory.
+
+ * send.c: missing arg to dead_link(). (Olivier Galibert)
+
+ * s_serv.c, numeric.h, s_err.c: added /stats B to see B lines (and
+ fixed /stats V reply).
+
+ * service.h, channel.c, s_misc.c, s_service.c, s_serv.c, s_user.c:
+ * numerous bugfixes related to local services (if
+ USE_SERVICES is defined).
+ * extended services option to allow 2.9 NICK syntax, and
+ let them see tokens if they want. (adapted from O.Galibert)
+
+Wed May 21 21:17:51 1997 Christophe Kalt
+
+ * channel.c, s_service.c, service.h: finished service code (whee).
+
+ * s_serv.c: services were incorrectly sent during burst.
+
+ * s_bsd.c: ident MUST be done before anything else is read from a
+ client.
+
+Thu May 15 16:27:13 1997 Christophe Kalt
+
+ * struct.h, s_conf.h, s_serv.c: created k: lines to be able to
+ deny access based on OTHER ident replies.
+
+ * s_user.c: changed 001 reply to return n!u@h (more zen).
+
+ * s_serv.c:
+ * if A: is bogus, trash it and complain instead of crashing.
+ * get_client_name() is non-reentrant. *sigh*
+
+Wed May 7 22:11:04 1997 Christophe Kalt
+
+ * s_user.c: nick chasing kill bug fix. (Chris Behrens)
+
+ * h.h, ircd.c, s_conf.c, s_user.c: K-lined users now exit
+ displaying the Kline comment, if any.
+
+ * s_conf.c: fixed notice ERR_YOUWILLBEBANNED, and don't disconnect
+ then.
+
+ * inet.h, nameser.h, resolv.h, inet_addr.c, portability.h, res.c,
+ res_comp.c, res_init.c, res_mkquery.c: updated. (BIND 4.9.5-P1)
+
+ * channel.c: notice for service could use free'ed memory.
+
+Sun Apr 27 16:40:08 1997 Christophe Kalt
+
+ * send.c: fixed couple buglets (added by Chris Behrens :^).
+
+ * s_user.c: removed dummy m_note() which was unused and buggy, and
+ would let any oper _broadcast_ NOTE queries to the net.
+
+ * m_note.c: Modified m_note() in note.c not to send any NOTE
+ commands to other servers.
+
+ This is lame, someone help me and port note to be a service.
+ Then, I'll finally take it out of the server !! :-)
+
+Thu Apr 24 18:51:25 1997 Christophe Kalt
+
+ * send.c: better (faster) sendto_common_channel() (from Chris Behrens).
+
+ * s_serv.c: fixed connected burst for services with hostmasks.
+
+ * s_user.c: fixed origin check in m_pong().
+
+ * res.c: added a check on hostnames. (From Darren Reed)
+
+Sun Apr 20 20:30:21 1997 Christophe Kalt
+
+ * s_conf.c: find_bounce() had an inversed test. (how could it work
+ when I tested it??)
+
+ * s_serv.c: SERVER message would occasionnally (and incorrectly)
+ be dropped.
+
+ * s_misc.c: simple optimization in exit_client().
+
+ * s_service.c, s_serv.c: things looked wrong, SERVICE syntax
+ inchorent. Minor memory leak.
+
+ * s_bsd.c, s_misc.c: various "typos" fixed. (UDP & non POLL)
+
+ * send.c, h.h: removed sendto_all_butone(). (unused)
+
+Tue Apr 15 19:41:32 1997 Christophe Kalt
+
+ * sock.h: added a check to make sure FD_SETSIZE is big enough.
+
+ * s_bsd.c, struct.h, s_misc.c: added more UDP stats.
+
+ * s_bsd.c: fixed udp_pfd/res_pfd mess, and cleaned the code. (whee)
+
+ * h.h, struct.h, numeric.h, s_err.c, s_conf.c, s_bsd.c: added B lines.
+
+ * channel.c: defining USE_SERVICE would cause buffer corruption
+ when propagating channel modes to servers. (Found by Michael Neumayer)
+
+Wed Apr 2 15:25:54 1997 Christophe Kalt
+
+ * list.c, s_serv.c: added some error notices for users without server.
+
+ * s_bsd.c: fixed UDP port binding when no IP is given.
+
+ * configure.in: add -cckr to CFLAGS on SGI when using cc(1)
+
+Thu Mar 27 19:03:09 1997 Christophe Kalt
+
+ * h.h, send.c, s_bsd.c, s_user.c, s_serv.c: amount of transferred
+ data added to file logs.
+
+ * config.h.dist: define SVR4 if __svr4__ is there.
+
+ * packet.c: drop server sending an unknown command.
+
+ * s_user.c: changed m_who() for better performance (from Chris
+ Behrens), also put a limit on its number of arguments.
+
+ * h.h, struct.h, list.c: better IsMember (from Chris Behrens).
+
+ * s_serv.c: don't let a user introduce a new server.
+
+Fri Mar 21 19:53:36 1997 Christophe Kalt
+
+ * h.h, struct.h, ircd.c, s_conf.c, s_misc.c, s_serv.c,
+ config.h.dist: server can now cache the MOTD in memory (from Chris
+ Behrens). See CACHED_MOTD #define.
+
+ * service.h, channel.c, s_serv.c, s_service.c, s_user.c: additions
+ for services.
+
+ * s_misc.c: added missing parameter for check_service_butone().
+
+ * INSTALL completed and converted to sgml
+
+ * s_serv.c: MyRealloc(NULL, size) isn't portable.
+
+Tue Mar 18 17:59:26 1997 Christophe Kalt
+
+ * 2.9.3b10
+
+ * channel.c, hash.c, res.c, s_serv.c, s_service.c, s_user.c,
+ whowas.c: penalties tuned again. (added Volker Paulsen's anti SPAM
+ hack).
+
+ * s_err.c, s_serv.c: minor changes to RPL_STATS*
+
+ * s_bsd.c: authclnts[] was not always initialized.
+
+ * ircd.c: buffer in ircd_readtune() lacked initialization.
+
+ * s_service.c: fixed buffer overflow.
+
+ * send.c, support.c: # of arguments cleanup.
+
+ * list.c, res.c, s_service.c: casts to suppress warnings.
+
+ * h.h, dbuf.c: bufalloc, dbufblocks, poolsize now
+ unsigned. (some checks might be needed, poolsize can really get
+ big).
+
+ * s_misc.c: removed duplicate code in exit_client().
+
+ * parse.c:
+
+ * Added more notices when generating SQUITs for unknown
+ servers.
+ * removed bogus else.
+
+Fri Feb 28 09:34:36 1997 Christophe Kalt
+
+ * s_err.c, s_serv.c: Added 2 more fields to RPL_TRACELINK.
+
+Thu Feb 27 14:50:37 1997 Christophe Kalt
+
+ * s_serv.c: /connect by servername didn't work for c lines (from Eumel)
+
+Wed Feb 26 16:48:36 1997 Christophe Kalt
+
+ * s_bsd.c: removed (old) redundant code concerning VIF.
+
+ * config.h.dist: CLONE_MAX and CLONE_PERIOD could be undefined.
+
+ * common.c: match() cleanup.
+
+Thu Feb 13 17:27:53 1997 Christophe Kalt
+
+ * res.c, res_init.c, res_mkquery.c, ircd.c, s_bsd.c: renamed
+ res_init() to ircd_res_init() to avoid conflict (ULTRIX).
+
+ * hash.c, struct.c: cleanup of hashing functions.
+
+ * match.c, parse.c, send.c, common.h, channel.c, hash.c, s_bsd.c,
+ s_misc.c, s_serv.c, s_service.c, s_user.c, note.c, ignore.c:
+
+ * _match() changed to match() and the check for maximum
+ "recursion" slightly changed.
+ * match() and matches() removed (stubs from when match
+ was recursive?).
+ * All occurrences of matches() changed to match().
+ * this saves one function call per match.
+
+ * send.c: Added 2 parameters to sendto_serv_butone().
+
+ * s_err.c, s_serv.c: Added one field to RPL_TRACELINK.
+
+Sun Jan 26 20:02:34 EET 1997 Vesa Ruokonen (ruokonen@aapo.it.lut.fi)
+
+ * 2.9.3b8
+
+ * support.c, h.h, list.c: gcc -Wall cleanups.
+ * h.h, struct.h, chkconf.c, s_conf.c, s_serv.c:
+ created V:lines for checking connecting client parameters.
+ passed as PASS command parameters. A matching V:line.
+ refuses the connection (version number & compile flags).
+ * struct.h, channel.c, s_debug.c:
+ penalty threshold used for limiting KICK params.
+ * struct.h: initial QUEUELEN calculation tuned. (->BUFFERPOOL).
+ * c_msg.c: more verbose m_pong().
+ * channel.c, s_serv.c, s_user.c, whowas.c:
+ penalties tuned for commands generating global bcast.
+ * hash.c: converted multiplication to hashtable lookup to speed.
+ up function calls. (from Core)
+ * ircd.c, s_bsd.c: added truncation for non-appended writes. (_root_)
+ * s_user.c: prefix for voice capability in channel list of WHOIS reply
+ changed from '+' to '!'.
+ * s_user.c: drop PONGs with bad origin.
+ store connection parameters from PASS temporarily to info
+ field in contstant locations.
+ * s_user.c: m_umode() fixed (from Core).
+
+Wed Jan 15 14:42:43 1997 Christophe Kalt
+
+ * s_bsd.c:
+
+ * mysk was initialized by empty password in M line.
+
+Tue Jan 14 24:62:34 EET 1997 Vesa Ruokonen (ruokonen@aapo.it.lut.fi)
+
+ * parse.c, channel.c, s_user.c: cleanup of find_functions(),
+ _nickserv replaced by _service.
+ * h.h, : setup_ping() takes aConfItem pointer as parameter now.
+ * sys.h: #elif expanded to #else #if for compability
+ * s_bsd.c: inetport(P:line) changed to support VIFs better.
+ More info about listening ports into /stats l.
+ UDP ping is initialized from M:line, not anymore from P:line.
+ * s_numeric.c: cleanups in numeric processing.
+ * Makefile.in, Makefile.irc, Makefile.ircd: makedepend fix
+ * configure.in: zlib check moved to end, as it can interfere
+ other checks when libs aren't in default paths.
+
+Mon Jan 13 09:11:04 1997 Christophe Kalt
+
+ * ircd.c:
+
+ * made the display of version (flag -v) more verbose.
+
+ * regenerated configure (with autoconf 2.12; thanks digital).
+
+ * s_user.c:
+
+ * fixed, and extended KILL reasons for `standard'
+ collisions. (both victims u@h are now shown).
+
+ * send.c:
+
+ * fixed the logic when sending mass message/notice to a
+ server mask.
+
+ * configure.in, Makefile.in:
+
+ * fixed detection & use of zlib using the environment
+ variable ZLIB_HOME (from Vesa).
+
+Thu Jan 9 13:09:36 1997 Christophe Kalt
+
+ * struct.h, ircd.c:
+
+ * added -b command line switch to let the server start
+ even if the ircd.tune file is corrupted (mostly from
+ Magnus Tjernstrom).
+
+ * s_conf.c:
+
+ * udp listen was setup even if port was defined to be 0.
+
+Wed Jan 8 12:35:03 1997 Christophe Kalt
+
+ * h.h, s_bsd.c, s_conf.c:
+
+ * port field in M configuration line is used again, now to
+ define on which port the server will listen for UDP pings.
+
+ * hash.c:
+
+ * restricted commands to opers (from Vesa).
+
+ * send.c:
+
+ * sendto_match_butone() had a broken behaviour,
+ brought back the old (2.8.21) behaviour.
+
+ * s_bsd.c:
+
+ * fixed negociation of compression for outgoing
+ connections.
+
+ * moved the "rejected connection" notice to &LOCAL.
+
+ * SLOW_ACCEPT #ifdef's changed to #ifndef's to get what
+ one should expect from the define name !
+
+ * made inetport() more readable, and added check on empty
+ string parameter (from Vesa).
+
+ * highfd isn't defined when _DO_POLL_ is defined, so don't
+ use it in debug notices (from Vesa).
+
+ * break changed to continue because ??? (from Vesa).
+
+ * s_user.c:
+
+ * fixed KILL notice sent on nick collision (was using
+ ident reply for remote clients).
+
+ * allowed oper!user@host.foo to send global message/notice
+ to #*.foo
+
+ * s_serv.c, s_user.c, s_bsd.c, s_debug.c:
+
+ * changed the PASS command semantic (from Vesa).
+
+Fri Jan 3 14:47:52 1997 Christophe Kalt
+
+ * s_bsd.c:
+
+ * completed virtual hosts support (M line).
+
+ * config.h.dist:
+
+ * AIX has poll(), use it.
+
+Mon Dec 30 15:08:20 1996 Christophe Kalt
+
+ * s_bsd.c, h.h:
+
+ * added support for virtual hosts (P line).
+
+Wed Dec 18 12:08:29 1996 Christophe Kalt
+
+ * bsd.c:
+
+ * fixed read_message() bugs resulting from the merge.
+
+ * channel.c:
+
+ * limited the number of possible kicks to MAXMODEPARAMS.
+
+Mon Dec 16 09:36:54 1996 Christophe Kalt
+
+ * list.c:
+
+ * don't free serv->user too early.
+
+ * removed duplicated(?) away memory count.
+
+Fri Dec 13 10:28:43 1996 Christophe Kalt - Hmm, Friday the 13th!
+
+ * config.h.dist, s_auth.c, s_user.c, s_debug.c:
+
+ * minor tuning.
+
+Thu Dec 12 10:34:47 1996 Christophe Kalt
+
+ * struct.h, s_auth.c, s_debug.c:
+
+ * added memory usage stats for ident replies.
+
+ * send.c, s_auth.c, s_misc.c:
+
+ * fixed boundaries problems with long ident replies.
+
+Wed Dec 11 17:42:29 1996 Christophe Kalt
+
+ * struct.h, send.c, s_auth.c, s_bsd.c, list.c, s_conf.c, s_misc.c,
+ s_user.c:
+
+ * added auth field to struct Client to eventually store
+ long `OTHER' ident replies. It is only used in logs, and
+ notices (not in matches against configuration lines).
+
+ * config.h.dist:
+
+ * added #define SLOW_ACCEPT (default).
+
+ * added #define CLONE_CHECK (default).
+
+ * s_bsd.c:
+
+ * fixed config line reference counter.
+
+ * added CLONE_CHECK code (check_clones() from
+ pgoncalves@mail.telepac.pt (Pedro Goncalves)).
+
+ * added SLOW_ACCEPT (previous behaviour) code.
+
+ * merged the 2 versions of read_message(), fixing some
+ (buggy) difference between them.
+
+ * merged two for() in read_message().
+
+
+Mon Dec 2 11:02:54 1996 Christophe Kalt
+
+ * s_user.c:
+
+ * changed error notice
+
+ * send.c:
+
+ * #*.mask messages now propagated to other servers.
+
+ * s_service.c:
+
+ * added missing else.
+
+ * config.h.dist, s_debug.c, channel.c:
+
+ * removed all references to V28PlusOnly
+ * made NoV28Link defined by default
+
+Wed Nov 27 18:09:42 1996 Christophe Kalt
+
+ * struct.h, class.c, ircd.c, s_bsd.c, s_conf.c, s_serv.c:
+
+ * added lowercase c config line
+
+Tue Oct 1 22:29:31 1996 Christophe Kalt
+
+ * added config.h to dependancies in Makefile.ircd
+
+ * config.h.dist, h.h, struct.h, packet.c, send.c, ircd.c, s_bsd.c,
+ s_debug.c, s_serv.c, s_user.c, s_err.c, list.c, Makefile.ircd,
+ configure.in:
+
+ * added #define ZIP_LINKS and s_zip.c.
+ * made configure look for the zlib (-lgz).
+ * implemented server-server zlib compression.
diff --git a/doc/Etiquette b/doc/Etiquette
new file mode 100644
index 0000000..b531954
--- /dev/null
+++ b/doc/Etiquette
@@ -0,0 +1,84 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, doc/etiquette
+ * Copyright (C) 1990, Lea Viljanen and Ari Husa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+HOW TO BEHAVE ON IRC
+
+Authors: Lea Viljanen (LadyBug) viljanen@kreeta.helsinki.fi
+ Ari Husa (luru) so-luru@tolsun.oulu.fi
+Revised, March 1994: Helen Rose (Trillian) hrose@kei.com
+
+1) Language
+
+ The most widely understood and spoken language on IRC is English.
+However! As IRC is used in many different countries, English is by
+no means the only language. If you want to speak some other language
+than English (for example with your friends), go to a separate channel
+and set the topic (with /topic) to indicate that. For example
+ /topic #channelname Finnish only!
+would mean that this channel would be reserved for Finnish discussion.
+On the other hand, you should check the topic (with /list command)
+before you move to a channel to see if there are any restrictions about
+language.
+ On a channel not restricted by /topic, please speak a language
+everybody can understand. If you want to do otherwise, change channels
+and set the topic accordingly.
+
+
+2) Hello/Goodbye
+
+ It's not necessary to greet everybody on a channel personally.
+Usually one "Hello" or equivalent is enough. And don't expect everybody
+to greet you back. On a channel with 20 people that would mean one
+screenful of hellos. It's sensible not to greet, in order not to be rude
+to the rest of the channel. If you must say hello, do it with a private /msg.
+The same applies to goodbyes.
+
+
+3) Discussion
+
+ When you come to a new channel it's advised you to listen
+for a while to get an impression of what's discussed. Please feel free
+to join in, but do not try to force your topic into the discussion
+if that doesn't come naturally.
+
+
+4) {}|[]\
+
+ IRC has quite a lot of people from Scandinavian countries,
+the above characters are letters in their alphabet. This
+has been explained on IRC about a thousand and one times, so
+read the following, do not ask it on IRC:
+
+ { is an A with 2 dots over it
+ } is an A with a small circle above it
+ | is either an O with 2 dots over it or an O with a dash (/) through it
+ [, ], and \ are the preceding three letters in upper case.
+
+ There are a lot of people from Japan as well, who use Kanji characters
+which may look quite exotic as well. As I don't know Kanji I don't
+even try to explain any of the characters.
+
+5) ATTENTION!
+
+ Remember, people on IRC form their opinions about you only by
+your actions, writings and comments on IRC. So think before you type.
+Do not "dump" to a channel or user (send large amounts of unwanted
+information). This is likely to get you /kicked off the channel or
+/killed off from irc. Dumping causes network 'burps', connections going
+down because servers cannot handle the large amount of traffic any more.
diff --git a/doc/INSTALL.appendix b/doc/INSTALL.appendix
new file mode 100644
index 0000000..beeb57a
--- /dev/null
+++ b/doc/INSTALL.appendix
@@ -0,0 +1,86 @@
+Appendix A: Difference between IP addresses and hostnames
+
+
+ There are 2 different types of INTERNET addresses, NAME addresses and
+ NUMERIC addresses. NAME addresses look like ENGLISH words (and indeed
+ they are ENGLISH words that refer to a given host). A NAME address looks
+ like "tolsun.oulu.fi" - and that particular address refers to the machine
+ named TOLSUN in Finland. It is a UNIQUE address because no other machine
+ in the world has its NAME address the same as "tolsun.oulu.fi". Anytime
+ you say "telnet tolsun.oulu.fi" - you would always connect to TOLSUN in
+ Finland. NUMERIC addresses refer to those addresses that are made up of
+ NUMBERS for example "128.214.5.6" is the NUMERIC address for TOLSUN. This
+ address is also UNIQUE in that no other machine in the world will be use
+ those NUMERIC numbers. The NUMERIC address is usually more reliable than
+ the NAME address because not all sites can recognize and translate the
+ NAME address into it's numeric counterpart. NUMERIC always seems to work
+ best, but use a NAME address when you can because it is easier to tell
+ what host you are connected to.
+
+
+ Every Unix machine has a file called "/etc/hosts" on it. This file
+ contains NAME and NUMERIC addresses. When you supply IRC with a NAME
+ address it will at first try to find it in /etc/hosts, and then (if it's
+ really smart), use the local Domain Name Server (DNS) to find the NUMERIC
+ address for the host you want to connect to. Thus if you plan to use NAME
+ addresses keep in mind that on SOME sites the entry for the TARGET machine
+ must be found in /etc/hosts or the NAME address will fail. A typical
+ entry in /etc/hosts looks like this:
+
+ 130.253.1.15 orion.cair.du.edu orion.du.edu orion # BSD 4.3
+
+ This particular example is the Host ORION at the University of Denver.
+ Notice that on the far left is the NUMERIC Address for orion. The
+ next few ENGLISH words are the NAME addresses that can be used for orion,
+ "orion.cair.du.edu", "orion.du.edu", "orion". ALL of these NAME addresses
+ will return the NUMERIC address "130.253.1.15" which IRC will use to
+ connect to the TARGET UNIX. (when I say TARGET UNIX I am refering to the
+ UNIX you want to connect to for IRC). Any futher questions about
+ /etc/hosts should be directed to "man hosts".
+
+
+Appendix B: Enabling Summon Messages
+
+ +-----------------------------------------------------------------------+
+ | E N A B L I N G / S U M M O N M E S S A G E S |
+ +-----------------------------------------------------------------------+
+
+ *NOTE* You must have ROOT or special access to the GROUP tty ('/dev')
+ to do this. If you want to allow users around the world to summon
+ users at your site to irc, then you should make sure that summon works.
+
+ The "IRCD" program needs access to the GROUP of '/dev'. This
+ directory is where user TTY's are stored (as UNIX treats each Terminal
+ as a FILE!) IRCD needs GROUP ACCESS to /dev so that users can be
+ SUMMONED to the program by others users that are *in* the program.
+ This allows people from other Universities around the world to SUMMON
+ your users to IRC so that they can chat with them. Berkeley, SUN, HP-UX
+ and most of the newer versions of UNIX check to see if a USER is
+ accepting MESSAGES via the GROUP access rights on their TTY listing
+ in the /dev directory. For example an entry in '/dev' looks like this:
+
+ (Unix Path on BSD 4.3 UNIX is: /dev/ttyp0)
+
+ crw------- 1 jtrim 20, 0 Apr 29 10:35 ttyp0
+
+ You will note that 'jtrim' OWNS this terminal and can READ/WRITE to this
+ terminal as well (which makes sense because I am ENTERING DATA and
+ RECEIVEING DATA back from the UNIX). I logged into this particular
+ UNIX on "April 29th" at "10:35am" and my TTY is "ttyp0". But further
+ of *note* is that I do not have my MESSAGES ON! (mesg n) -- This is
+ how my terminal would look with MESSAGES ON (mesg y):
+
+ crw--w---- 1 jtrim 20, 0 Apr 29 10:35 ttyp0
+
+ With my MESSAGES ON (mesg y) I can receive TALK(1) requests, use the
+ UNIX WRITE(1) command and other commands that allow users to talk
+ to one another. In IRC this would also allow me to get IRC /SUMMON
+ messages. To set up the "IRCD" program to work with /SUMMON type
+ the following: (using ROOT or an account that has access to '/dev').
+
+ % chgrp tty ircd
+ % chmod 6111 ircd
+
+ The above commands read: "Give IRCD access to GROUP tty (which is /dev)
+ and then when ANYONE runs the IRCD allow SETUID and SETGID priviliges
+ so that they can use the /SUMMON command.
diff --git a/doc/INSTALL.info b/doc/INSTALL.info
new file mode 100644
index 0000000..c74be27
--- /dev/null
+++ b/doc/INSTALL.info
@@ -0,0 +1,1759 @@
+This is Info file INSTALL.info, produced by Makeinfo-1.55 from the
+input file /tmp/sgml2info3035tmp2.
+
+ \input texinfo
+
+
+File: INSTALL.info, Node: Top, Next: Installing IRC-, Prev: (DIR), Up: (DIR)
+
+Installing IRC - The Internet Relay Chat Program
+************************************************
+
+ SGML version by Christophe Kalt
+ $Id: INSTALL.info,v 1.38 1999/08/13 17:22:12 kalt Exp $
+
+ This document describes how to install, and configure IRC 2.10.3.
+
+* Menu:
+
+* Installing IRC-::
+* The config-h file::
+* Editing the Makefile and compiling::
+* The ircd-conf file::
+* Related resources::
+* Reporting a bug::
+
+
+File: INSTALL.info, Node: Installing IRC-, Next: The config-h file, Prev: Top, Up: Top
+
+Installing IRC-
+***************
+
+* Menu:
+
+* The configure script::
+* Notes for Cygwin32 users::
+* Notes concerning IPv6 support::
+
+
+File: INSTALL.info, Node: The configure script, Next: Notes for Cygwin32 users, Up: Installing IRC-
+
+The configure script
+====================
+
+ This package uses a GNU configure script for its configuration. You
+simply need to untar the distribution and run the "configure" script.
+This will run configure which will probe your system for any
+peculiarities it has and setup the Makefile and a file of default
+#define's ($arch/setup.h).
+
+ There are a few options to "configure" to help it out, or change the
+default behaviour:
+`--prefix=DIR'
+ changes the default directory into which ircd will install using
+ "make install". This defaults to /usr/local
+
+`--sbindir=DIR'
+ changes the default directory where the system admin executable
+ files will go. It is important to set this properly. (default is
+ prefix/sbin)
+
+`--logdir=DIR'
+ changes the default directory where the irc log files will go.
+ (default is prefix/var/log/ircd)
+
+`--sysconfdir=DIR'
+ changes the default directory where the irc server configuration
+ files will go. (default is prefix/etc)
+
+`--localstatedir=DIR'
+ changes the default directory where the irc server state files
+ will go. (default is prefix/var/run)
+
+`--resconf=FILE'
+ defines the file to be used by ircd to initialize its resolver.
+ (default is /etc/resolv.conf)
+
+`--zlib-include=DIR'
+ specifies in which directory the include file from the zlib is
+ located.
+
+`--zlib-library=DIR'
+ specifies in which directory the zlib library is located.
+
+`--zlib-prefix=DIR'
+ specifies the prefix for zlib location. It overrides the 2
+ previous options. (The include directory is supposed to be in
+ prefix/include, and the library in prefix/lib).
+
+`--with-zlib'
+ is the default. "configure" looks on your system to find the
+ zlib. If found, ircd will be linked using it. This does NOT mean
+ you can use server link compression, for this you also need to
+ define ZIP_LINKS (see section below).
+
+`--without-zlib'
+ tells "configure" not to look for the zlib. Defining this will
+ keep you from using server link compression.
+
+`--enable-ip6'
+ Enable IPv6 support (See notes below)
+
+`--enable-dsm'
+ Enable Dynamically Shared Modules support for iauth
+
+
+File: INSTALL.info, Node: Notes for Cygwin32 users, Next: Notes concerning IPv6 support, Prev: The configure script, Up: Installing IRC-
+
+Notes for Cygwin32 users
+========================
+
+ The daemon of 2.10.3 release compiles properly on W32 systems which
+have the GNU-Win32 environment () setup. At the time of the release,
+tests were made using the version b20.1 of the Cygwin32 library.
+
+ When compiling on such system, you want to make sure that you have
+carefully followed the Cygwin32 installation notes. In particular, you
+will need to make sure that the following files exist: `/bin/cp.exe',
+`/bin/mv.exe', `/bin/rm.exe' and `/bin/sh.exe'.
+
+ Also, the IRC server needs a `resolv.conf' file in order to
+initialize the resolver. This file can be anywhere (see configure
+options), and is typically in `/etc' on UNIX systems.
+
+ Finally, iauth is automatically disabled. Even though the iauth
+program compiles properly, extra work is required to have a working
+communication channel between the IRC server and the iauth program.
+
+
+File: INSTALL.info, Node: Notes concerning IPv6 support, Prev: Notes for Cygwin32 users, Up: Installing IRC-
+
+Notes concerning IPv6 support
+=============================
+
+ The only part of the software that doesn't use IPv6 is the server
+internal resolver. It relies on the name servers defined in
+"/etc/resolv.conf" to be IPv4 addresses.
+
+ This version was tested on the following IPv6 systems: BSD/OS+KAME,
+Digital Unix, FreeBSD+KAME, Linux, NetBSD+INRIA.
+
+ Because IPv6 numeric addresses contain ":" characters, `the
+separator for the server configuration file was changed to "%"'.
+
+
+File: INSTALL.info, Node: The config-h file, Next: Editing the Makefile and compiling, Prev: Installing IRC-, Up: Top
+
+The config-h file
+*****************
+
+ The second step consists of defining options before the compilation.
+This is done by editing the "config.h" file and changing the various
+#DEFINE's.
+
+* Menu:
+
+* Define what type of UNIX your machine uses-::
+* DEBUGMODE::
+* CPATH MPATH LPATH PPATH TPATH QPATH OPATH::
+* CACHED_MOTD::
+* CHROOTDIR::
+* ENABLE_SUMMON ENABLE_USERS::
+* SHOW_INVISIBLE_LUSERS NO_DEFAULT_INVISIBLE::
+* OPER_KILL OPER_REHASH OPER_RESTART LOCAL_KILL_ONLY::
+* ZIP_LINKS ZIP_LEVEL::
+* SLOW_ACCEPT::
+* CLONE_CHECK::
+* Other #define's::
+
+
+File: INSTALL.info, Node: Define what type of UNIX your machine uses-, Next: DEBUGMODE, Up: The config-h file
+
+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.
+
+
+File: INSTALL.info, Node: DEBUGMODE, Next: CPATH MPATH LPATH PPATH TPATH QPATH OPATH, Prev: Define what type of UNIX your machine uses-, Up: The config-h file
+
+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. Defining
+this induces a large overhead for the server as it does a large amount
+of self diagnostics whilst running.
+
+ `This should only be defined for test purposes, and never used on a
+production server.'
+
+
+File: INSTALL.info, Node: CPATH MPATH LPATH PPATH TPATH QPATH OPATH, Next: CACHED_MOTD, Prev: DEBUGMODE, Up: The config-h file
+
+CPATH MPATH LPATH PPATH TPATH QPATH OPATH
+=========================================
+
+ Define CPATH to be the directory path to the "ircd.conf" file. This
+path is usually /usr/local/lib/ircd/ircd.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 ircd 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 automatically 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.
+
+ Define QPATH to be the directory path to the "iauth.conf" file. This
+path is usually /usr/local/lib/ircd/iauth.conf. The format of this
+file is described by a manual page.
+
+ The OPATH #define should be set to "/dev/null" unless you plan to
+debug the iauth program. Note that the logfile grows very quickly.
+
+
+File: INSTALL.info, Node: CACHED_MOTD, Next: CHROOTDIR, Prev: CPATH MPATH LPATH PPATH TPATH QPATH OPATH, Up: The config-h file
+
+CACHED_MOTD
+===========
+
+ The server sends the "motd" to every client connecting. Every time,
+it reads it from the disk. This is quite intensive and can be
+undesirable for busy servers.
+
+ Defining CACHED_MOTD will make the server store the "motd" in
+memory, and only read it again from the disk when rehashing if the file
+has changed.
+
+
+File: INSTALL.info, Node: CHROOTDIR, Next: ENABLE_SUMMON ENABLE_USERS, Prev: CACHED_MOTD, Up: The config-h file
+
+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 "IRCDDIR" (in Makefile).
+
+
+File: INSTALL.info, Node: ENABLE_SUMMON ENABLE_USERS, Next: SHOW_INVISIBLE_LUSERS NO_DEFAULT_INVISIBLE, Prev: CHROOTDIR, Up: The config-h file
+
+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.
+
+
+File: INSTALL.info, Node: SHOW_INVISIBLE_LUSERS NO_DEFAULT_INVISIBLE, Next: OPER_KILL OPER_REHASH OPER_RESTART LOCAL_KILL_ONLY, Prev: ENABLE_SUMMON ENABLE_USERS, Up: The config-h file
+
+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.
+
+
+File: INSTALL.info, Node: OPER_KILL OPER_REHASH OPER_RESTART LOCAL_KILL_ONLY, Next: ZIP_LINKS ZIP_LEVEL, Prev: SHOW_INVISIBLE_LUSERS NO_DEFAULT_INVISIBLE, Up: The config-h file
+
+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.
+
+
+File: INSTALL.info, Node: ZIP_LINKS ZIP_LEVEL, Next: SLOW_ACCEPT, Prev: OPER_KILL OPER_REHASH OPER_RESTART LOCAL_KILL_ONLY, Up: The config-h file
+
+ZIP_LINKS ZIP_LEVEL
+===================
+
+ As of the 2.9.3 version of the server, server-server connections may
+be compressed using the zlib. In order to compile the server with this
+feature, you MUST have the zlib package (version 1.0 or higher) already
+compiled and define ZIP_LINKS in the config.h file. Compression use for
+server-server connections is separately configured in the ircd.conf
+file for each server-server link. ZIP_LEVEL allows you to control the
+compression level that will be used. Values above 5 will noticeably
+increase the CPU used by the server.
+
+ The zlib package may be found at . The data format used by the zlib
+library is described by RFCs (Request for Comments) 1950 to 1952 in the
+files (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip
+format). These documents are also available in other formats from
+
+
+File: INSTALL.info, Node: SLOW_ACCEPT, Next: CLONE_CHECK, Prev: ZIP_LINKS ZIP_LEVEL, Up: The config-h file
+
+SLOW_ACCEPT
+===========
+
+ This option is defined by default and is needed on some OSes. It
+creates an artificial delay in processing incoming connections. On a
+given port, no more than 1 connection per 2 seconds will be processed.
+
+ Undefining this will let the server process connections as fast as
+it can which can cause problems on some OSes (such as SunOS) and be
+abused (fast massive join of clonebots..), for these reasons, if you
+decide to undefine SLOW_ACCEPT you MUST define CLONE_CHECK.
+
+
+File: INSTALL.info, Node: CLONE_CHECK, Next: Other #define's, Prev: SLOW_ACCEPT, Up: The config-h file
+
+CLONE_CHECK
+===========
+
+ This option acts as a wrapper, by checking incoming connections
+early before starting ident query. By default, the server will not
+accept more than 2 connections from the same host within 10 seconds.
+
+
+File: INSTALL.info, Node: Other #define's, Prev: CLONE_CHECK, Up: The config-h file
+
+Other #define's
+===============
+
+ 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.
+
+
+File: INSTALL.info, Node: Editing the Makefile and compiling, Next: The ircd-conf file, Prev: The config-h file, Up: Top
+
+Editing the Makefile and compiling
+**********************************
+
+ This package now uses GNU autoconf to probe your system and generate
+the correct Makefile. However you need to edit it to specify specific
+information, such as "prefix", "irc_mode", "ircd_mode" and "ircd_dir".
+
+ Now to build the package, type "make all". If everything goes will,
+you can then install it by typing "make install".
+
+ If you have trouble compiling ircd, copy Makefile.in to Makefile and
+edit Makefile as appropriate.
+
+
+File: INSTALL.info, Node: The ircd-conf file, Next: Related resources, Prev: Editing the Makefile and compiling, Up: Top
+
+The ircd-conf file
+******************
+
+ After installing the ircd and irc programs, edit the ircd.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 (See INSTALL.appendix) describes the differences between
+IP addresses and host names. If you are unfamiliar with this, you
+should probably scan through it before proceeding.
+
+ The ircd.conf file contains various records that specify
+configuration options. The record types are as follows:
+ 1. Machine information (M)
+
+ 2. Administrative info (A)
+
+ 3. Port connections (P)
+
+ 4. Connection Classes (Y)
+
+ 5. Client connections (I,i)
+
+ 6. Operator privileges (O)
+
+ 7. Restrict lines (R)
+
+ 8. Excluded accounts (K,k)
+
+ 9. Server connections (C,c,N)
+
+ 10. Deny auto-connections (D)
+
+ 11. Hub connections (H)
+
+ 12. Leaf connections (L)
+
+ 13. Version limitations (V)
+
+ 14. Excluded machines (Q)
+
+ 15. Service connections (S)
+
+ 16. Bounce server (B)
+
+ 17. Default local server (U)
+
+ Except for types "M" and "A", you are allowed to have multiple
+records of the same type. In some cases, you can have concurrent
+records. `It is important to note that the last matching record will
+be used'. This is especially useful when setting up I records (client
+connections).
+
+* Menu:
+
+* Machine information::
+* Administrative info::
+* Port connections::
+* Connection Classes::
+* Client connections::
+* Operator priviliges::
+* Restrict connections::
+* Excluded accounts::
+* Server connections::
+* Deny auto-connections::
+* Hub connections::
+* Leaf connections::
+* Version limitations::
+* Excluded machines::
+* Service connections::
+* Bounce server::
+* Default local server (for local clients) `*OBSOLETED*'::
+
+
+File: INSTALL.info, Node: Machine information, Next: Administrative info, Up: The ircd-conf file
+
+Machine information
+===================
+
+`Introduction'
+ 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:
+
+`Format'
+ M:<Server NAME>:<YOUR Internet IP#>:<Geographic Location>:<Port>
+
+`M'
+ "M" specifies a Machine description line
+
+`Server NAME'
+ The name of YOUR server adding any Internet DOMAINNAME that might
+ also be present. If this hostname can be resolved, the IP# found
+ will be used to for outgoing connections. Otherwise the default
+ interface address of the host is used. The server name may not be
+ FQDN of another host. (This means all outgoing connections will
+ be done from the same IP#, even if your host has several IP#).
+
+`YOUR Internet IP#'
+ If the machine on which you run the server has several IP
+ addresses, you can define which IP# to use for outgoing
+ connections. This overrides overrides the "Server NAME".
+
+ See Also the "Port Connections" section.
+
+`Geographic Location'
+ Geographic Location is used to say WHERE YOUR SERVER 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".
+
+`Port'
+ Defines the port on which your server will listen for UDP pings
+ from other servers. This should be the port were other servers
+ are set to autoconnect. (Also see the port field description in
+ connect lines).
+
+`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".
+
+ 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".
+
+
+File: INSTALL.info, Node: Administrative info, Next: Port connections, Prev: Machine information, Up: The ircd-conf file
+
+Administrative info
+===================
+
+`Introduction'
+ The "A" line 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.
+
+`Format'
+ A:<Your Name/Location>:<Your Electronic Mailing Addr>:<other>::
+
+`A'
+ This specifies an Admin record.
+
+`Your Name & Location'
+ 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.
+
+`Your Electronix Mailing Addr'
+ 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.
+
+`Other'
+ This is really an OTHER field - you can add what you want here.
+
+`Example'
+ (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.
+
+
+File: INSTALL.info, Node: Port connections, Next: Connection Classes, Prev: Administrative info, Up: The ircd-conf file
+
+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.
+
+`Format'
+ P:<Internet IP#>:<*>:<Internet IP Mask>:<Port>:
+ P:<Directory>:<*>:<*>:<Port>:
+
+ * Internet Ports
+ `Internet IP#'
+ If the host on which the server runs has several IP
+ addresses, you can define for which IP address connections
+ will be accepted. If no is defined here, server will bind to
+ all interfaces (INADDR_ANY). See also MACHINE CONFIGURATION
+ section to properly configure outgoing connections.
+
+ P:192.168.1.194:::6664:
+
+ `Internet IP# Mask'
+ This 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 isn't 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.
+
+ `Port'
+ The port number field tells the server which port number it
+ should listen on for incoming connections.
+
+ * Unix Socket Ports.
+ `Directory'
+ The path set in this field 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.
+
+ `Port'
+ The port field when used in combination with a pathname in a
+ P-line is the filename created in the directory set in the
+ first field.
+
+ `Example'
+ P:/tmp/.ircd:::6667:
+
+ Creates a unix socket in the /tmp/.ircd directory called
+ "6667". The unix socket (file) must be a numerical.
+
+`Note'
+ You need at least one P line.
+
+
+File: INSTALL.info, Node: Connection Classes, Next: Client connections, Prev: Port connections, Up: The ircd-conf file
+
+Connection Classes
+==================
+
+`Introduction'
+ To enable more efficient use of MAXIMUM_LINKS, connection classes
+ were implemented. All clients belong to a connection class.
+
+ 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
+ ircd.conf file. This enables you to define the ping frequency,
+ connection frequency (for servers) and maximum number of links
+ that class should have.
+
+ Currently, the Y: line `MUST' appear in the ircd.conf file
+ `BEFORE' it is used in any other way.
+
+`Format'
+ Y:<Class>:<Ping Frequency>:<Connect freq>:<Max
+ Links>:<SendQ>:<Local Limit>:<Global Limit>
+
+`Y'
+ This specifies a Class record.
+
+`Class'
+ This is the class number which gains the following attributes and
+ should match that which is on the end of the C/c/N/I/O/S line.
+
+`Ping Frequency'
+ 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.
+
+`Connect Frequency'
+ 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.
+
+`Max Links'
+ This field defines the maximum number of links this class will
+ allow from automatic connections (C lines). Using /CONNECT
+ overrides this feature. Also defines the maximum number of users
+ in this class for I/O lines per I/O line.
+
+`SendQ'
+ This field defines the "SendQ" value for this class. If this
+ field is not present, the default (from config.h) is assigned.
+
+`Local limit'
+ This field is used to limit the number of local concurrent
+ connections. The format is <x>.<y>
+ * x: defines the maximum number of clients from the same host
+ (IP) will be allowed.
+
+ * y: defines the maximum number of clients from the same
+ user@host (IP) will be allowed. Read note below.
+
+ Only x or y may be set, any unset value defaults to zero.
+
+`Global limit'
+ This field has the same use as the "Local limit" field. But, the
+ connection counts are done for all clients present on the net
+ instead of only counting local clients.
+
+`Note'
+ leaving any of the fields (except SendQ) out means their value is
+ 0 (ZERO)!! The SendQ field default value is dynamically
+ determined.
+
+`Note'
+ If you plan to use the local user@host limit, please read the
+ following very carefully. The "user" value is the ident reply for
+ the connection. If no reply was given then it defaults to
+ "unknown" and thus the effective limit will be per host, not per
+ user@host. Also, some ident servers return encrypted data which
+ changes for every connection making the limit void.
+
+`Note'
+ Only the local limitation is accurate.
+
+`Note'
+ If you define a gobal limit, you should also define a local limit
+ (same or lower) as it won't take more CPU and will make the global
+ limit more accurate.
+
+`Note'
+ The local and global limits only affect users (I lines), not
+ servers nor services.
+
+`Example'
+ Y:23:120:300:5:100000:0:0: (server class)
+
+ This defines 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. The SendQ is set to 100000 bytes.
+
+ 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.
+
+ Y:1:60:0:50:20000:2:5: (client class)
+
+ In case of a client class, the fields are interpreted a bit
+ differently. This class (number 1) can be used by up to 50 users.
+ The connections are allowed to remain silent for 60 seconds
+ before a PING is set. The SendQ is set to 20000 bytes. A new
+ connection in this class will only be allowed if there aren't more
+ than 2 other local connections from the same IP address, or more
+ than 5 other connections on the net from the same hostname.
+
+ Y:2:60:0:50:20000:2.1:5: (client class)
+
+ In case of a client class, the fields are interpreted a bit
+ differently. This class (number 1) can be used by up to 50 users.
+ The connections are allowed to remain silent for 60 seconds
+ before a PING is set. The SendQ is set to 20000 bytes. A new
+ connection in this class will only be allowed if there aren't more
+ than 2 other local connections from the same IP address, 1 other
+ local connection from the same user from the same IP address, or
+ more than 5 other connections on the net from the same hostname.
+
+
+File: INSTALL.info, Node: Client connections, Next: Operator priviliges, Prev: Connection Classes, Up: The ircd-conf file
+
+Client connections
+==================
+
+ How to let clients connect to your IRCD.
+`Introduction'
+ A client is a program that connects to the ircd daemon (ircd).
+ There are clients written in C, GNU Emacs Lisp and many other
+ languages. The "irc" program is the C client. Each person that
+ talks via IRC is running their own client.
+
+ The ircd.conf files contains entries that specify which clients
+ are allowed to connect to your irc daemon. Obviously you want to
+ allow your own 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.
+
+`Format'
+ I:<TARGET Host Addr>:<Password>:<TARGET Hosts NAME>:<Port>:<Class>
+ i:<TARGET Host Addr>:<Password>:<TARGET Hosts NAME>:<Port>:<Class>
+
+`TARGET Host Addr'
+ Specifies the IP address(es) of the machine(s) that are allowed to
+ connect. If "user@" prefixes the actual IP address the server
+ will require that the remote username returned by the ident server
+ be the same as the one given before the "@". Wildcards are
+ permitted unless using a bitmask (e.g. 1.2.3.0/24).
+
+`Password'
+ The password that must be given by the client to be allowed on the
+ server.
+
+`TARGET Host NAME'
+ Specifies the host name(s) of the machines allowed to connect to
+ the server. If "user@" prefixes the actual IP address the server
+ will require that the remote username returned by the ident server
+ be the same as the one given before the "@". Wildcards are
+ permitted.
+
+ This field can be empty, it then has a special meaning. See Below.
+
+`Port'
+ Specifies the port number for which this configuration line is
+ valid. An empty field, or "0" matches all ports.
+
+`Class'
+ This field should refer to an existing class. Connections classes
+ are usefull to limit the number of users allowed on the server.
+
+`Note'
+ The server first checks if the client hostname (or any aliases)
+ matches the `TARGET Host NAME' field. If a match is found, the
+ client is accepted. If not, the server checks if the IP address
+ of the client matches the `TARGET Host Addr' field. The matching
+ field is used to set the name of the client: for example, if the
+ client matches the `TARGET Host Addr' field, it will show on IRC
+ with a numerical address (even if this address is resolvable). If
+ the `TARGET Host NAME' field is empty, then the host name is
+ always used (when available).
+
+`Examples'
+ 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:x::tolsun.oulu.fi::1
+
+ If you wanted to let remote clients connect, you could add the
+ following lines:
+
+ I:x::*.du.edu::1
+
+ Allow any clients from machines whose names end in ".du.edu" to
+ connect with no password.
+
+ I:128.214.6.100::nic.funet.fi::1
+
+ Allow clients from a machine with that IP number to connect.
+ Numeric match is enough, name is not required anymore.
+
+ I:x:secret:*.tut.fi::1
+
+ Allow clients from machines matching "*.tut.fi" to connect with
+ the password "secret".
+
+ I:*::*::1
+
+ 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).
+
+ I:x::*.fi:6667:1
+
+ Allow clients from machines matching "*.fi" to connect on the port
+ 6667.
+
+ I:135.11.35.*::*.net::1
+
+ Allows clients from machines which host name matches "*.net" or
+ which IP address matches "135.11.35.*" to connect to the server.
+ If the host name does not match "*.net" then the IP address is
+ used for these clients, even if the host name is known.
+
+ I:135.11.35.*::::1
+
+ Allows clients from machines which IP address matches
+ "135.11.35.*" to connect to the server. If the host name is
+ known, is it used as address for these clients.
+
+`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).
+
+`NEW!!!'
+ As of the 2.9.1 version of the server, i lines are introduced.
+ They work the same way as I lines, but the clients matching an i
+ line will have a restricted connection. (no nick/mode change, no
+ kick). Such users will have their username prefixed by +, = or -
+ depending on the ident reply.
+
+
+File: INSTALL.info, Node: Operator priviliges, Next: Restrict connections, Prev: Client connections, Up: The ircd-conf file
+
+Operator priviliges
+===================
+
+ How to become the IRC administrator on your site
+`Introduction'
+ To become an IRC Administrator, IRC must know who is authorized to
+ become an operator and what their "Nickname" and "Password" is.
+
+`Format'
+ O:<TARGET Host NAME>:<Password>:<Nickname>:<Port>:<Class>
+
+`O'
+ 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.
+
+`TARGET Host NAME'
+ 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.
+
+`Password'
+ 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 "ircd.conf" file protected from all
+ of the other users.
+
+`Nickname'
+ The Nickname you usually go by - but you can make this what you
+ want.
+
+`Port'
+ Unused.
+
+`Class'
+ 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::1
+
+ 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".
+
+
+File: INSTALL.info, Node: Restrict connections, Next: Excluded accounts, Prev: Operator priviliges, Up: The ircd-conf file
+
+Restrict connections
+====================
+
+ Let an external program decide if a client should be allowed or not.
+`Introduction'
+ R lines provide a convenient way to handle user access to the
+ server with an external program. The outside program given three
+ parameters: the client's username (set by the USER command), the
+ client's hostname, and the client's ident reply ("unknown" if
+ none).
+
+ It is expected to return a reply line where the first word is
+ either "Y" or "N" meaning `Yes Let them in" or "No don't let them
+ in". If the first word begins with neither "Y" or "N" the default
+ is to let the person on.
+
+`Format'
+ R:<Target Host Name>:<Program>:<User>:::
+
+`R'
+ This specifies a restrict record.
+
+`Target Host Name'
+ In this field you specify the Hostname that the user is connecting
+ from. If you wanted to restrict connects to IRC from
+ "orion.cair.du.edu" then you would want to enter
+ "orion.cair.du.edu".
+
+`Program'
+ This is the external program to run to know if the user is allowed
+ on your server.
+
+`User'
+ The Username of the user you want removed from IRC. For example
+ "root".
+
+
+File: INSTALL.info, Node: Excluded accounts, Next: Server connections, Prev: Restrict connections, Up: The ircd-conf file
+
+Excluded accounts
+=================
+
+ Remove an errant user from IRC on your site.
+`Introduction'
+ 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.
+
+`Format'
+ K:<Host Name>:<time interval(s)|comment>:<User>:<port>:
+
+`Format'
+ k:<Host Name>:<time interval(s)|comment>:<Auth>:<port>:
+
+`K'
+ "K" tells the IRCD that you are making a KILL USER command entry.
+
+`Host Name'
+ In this field you specify the Hostname or the IP address (Single
+ IP, Wildcard notation or bitmask notation) 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 ?
+
+ If you specify an IP address, IP mask, or an IP bitmask, it will
+ match clients connecting from the matching addresses, no matter if
+ they resolve or not.
+
+ You can prefix an IP address, an IP mask, or IP bitmask by "=" in
+ which case only non resolving matching hosts will be banned.
+
+`time interval(s)|comment'
+ Either leave this field empty or put a comment, then the line
+ active continuously for the specified user/host machine. You may
+ also specify intervals during the line should be active, see
+ examples below.
+
+`User'
+ The USERNAME of the user you want removed from IRC. For example
+ "root".
+
+`Auth'
+ If the user's ident server replies with the OTHER type (as opposed
+ to the UNIX type), the reply is not used to set the user's
+ username. (lowercase) k lines can be used in these case to reject
+ users based on their ident reply.
+
+ This field will be matched against the ident server reply. It is
+ important to note that OTHER replies are prefixed with a "-" by
+ the ircd, while UNIX replies are not.
+
+`Port'
+ The port on which the Kill line will be effective. 0 means all
+ ports.
+
+`Examples'
+ K:orion.cair.du.edu::jtrim:0:
+
+ If user "jtrim" connects to IRC from host "orion.cair.du.edu" then
+ IMMEDIATELY REMOVE HIM from my IRCD.
+
+ k:*.stealth.net::-43589:0:
+
+ If a user connects from any host that has the suffix "stealth.net"
+ and if that host ident server returns "-43589" - then IMMEDIATELY
+ REMOVE THEM from my IRCD.
+
+ K:*.cair.du.edu::root:0:
+
+ 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:0:
+
+ 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:*:0:
+
+ 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 before).
+
+ K:192.11.35.*::*:0:
+
+ This line disallows all hosts whose IP address matches
+ "192.11.35.*" to login to the ircd.
+
+ K:=192.11.35.*::*:0:
+
+ This line disallows all hosts whose IP address matches
+ "192.11.35.*" and which didn't resolve to login to the ircd.
+
+
+File: INSTALL.info, Node: Server connections, Next: Deny auto-connections, Prev: Excluded accounts, Up: The ircd-conf file
+
+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:
+ 1. to save your server from causing extra load and delays to users
+
+ 2. to save internet from extra network traffic (remember the old
+ rwho program with traffic problems when the number of machines
+ increased).
+
+`Format'
+ C:<TARGET Host Addr>:<Password>:<TARGET Host NAME>:<TARGET
+ PORT>:<Class>
+
+ for example:
+
+ C:nic.funet.fi:passwd:nic.funet.fi:6667:1
+
+ - or -
+
+ C:128.214.6.100:passwd:nic.funet.fi:6667:1
+
+ - or -
+
+ C:root@nic.funet.fi:passwd:nic.funet.fi:6667:1
+
+ Each field is separated with a ":" charcter:
+
+`C'
+ This field tells the IRC program which option is being configured.
+ "C" corresponds to a server Connect option.
+
+`TARGET Host Addr'
+ 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 "@".
+
+`Password'
+ The password of the other host. A password must always be present
+ for the line to be recognized.
+
+`TARGET Host NAME'
+ 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.
+
+`TARGET PORT'
+ 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. The port field can contain 2 ports, separated by a
+ . In this case, the first port is used when auto-connecting, the
+ second port is used for the UDP pings to the targer server.
+
+`Class'
+ The class field should refer to an existing class and determines
+ the maximum number of simultaneous uses of the C-line allowable
+ through the max. links field in the Y-line.
+
+`NEW!!!'
+ As of the 2.9.3 version of the server, server connections can be
+ compressed with the zlib library. To define a compressed
+ connection, you must have compiled the server with ZIP_LINKS
+ defined (cf 2.h), and use a _lowercase_ C line.
+
+ Some examples:
+ * C:nic.funet.fi::nic.funet.fi:6667:1 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:1 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:1 This reads: do not attempt to
+ connect to "irc.nada.kth.se", 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:1
+C:irc.nada.kth.se::irc.nada.kth.se:6667:1
+C:nic.funet.fi::nic.funet.fi:6667:1
+
+ 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.
+
+`Format'
+ The format for the NOCONNECT entry in the "ircd.conf" is:
+ N:<TARGET Host Addr>:<Password>:<TARGET Host NAME>:<Domain
+ Mask>:<Class>
+
+ 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".
+
+`N'
+ "N" corresponds to a server Noconnect option.
+
+`TARGET Host Addr'
+ 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 "@".
+
+`Password'
+ The password of the other host. A password must always be present
+ for the line to be recognized. If CRYPT_LINK_PASSWORD is defined
+ in config.h, this password must be crypted.
+
+`TARGET Host NAME'
+ 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.
+
+`Domain Mask'
+ Domain masking, see below.
+
+`Class'
+ The class field should refer to an existing class.
+
+`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 "Domain Mask" 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.
+
+
+File: INSTALL.info, Node: Deny auto-connections, Next: Hub connections, Prev: Server connections, Up: The ircd-conf file
+
+Deny auto-connections
+=====================
+
+`Introduction'
+ D lines were implemented to give server administrators more
+ control on how auto connections are done. This will most likely
+ only be useful for big networks which have complex configurations.
+
+`Format'
+ D:<Denied Server Mask>:Denied Class:<Server Name>:Server Class:
+
+`Denied Server Mask'
+ This field is matched against all servers currently present on the
+ network.
+
+`Denied Class'
+ If this field contains a class number, it will match if any server
+ in that class is currently present on the network. Note that this
+ can be true for any server, even the ones not directly connected.
+
+`Server Mask'
+ This field is matched against the server name that the server
+ wants to auto connect to.
+
+`Server Class'
+ This field is used to match against the class to which belong the
+ servers for which an autoconnect is set.
+
+`Examples'
+ D:*.edu::*.fi::
+
+ Don't auto-connect to any "*.fi" server if any server present on
+ the network matches "*.edu".
+
+ D::2:eff.org:3:
+
+ Do now auto-connect to "eff.org", or any server in class "3" if a
+ server defined to be in class "2" is currently present on the
+ network.
+
+
+File: INSTALL.info, Node: Hub connections, Next: Leaf connections, Prev: Deny auto-connections, Up: The ircd-conf file
+
+Hub connections
+===============
+
+`Introduction'
+ 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.
+
+`Format'
+ H:<Server Mask>:*:<Server Name>::
+
+`Server Mask'
+ All servers that are allowed via this H-line must match the mask
+ given in this field.
+
+`Server Name'
+ 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::
+
+ Allows "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::
+
+
+File: INSTALL.info, Node: Leaf connections, Next: Version limitations, Prev: Hub connections, Up: The ircd-conf file
+
+Leaf connections
+================
+
+`Introduction'
+ 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.
+
+`Format'
+ L:<Server Mask>:*:<Server Name>:<Max Depth>:
+
+`Server Mask'
+ 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).
+
+`Server Name'
+ The name of the server connected to you that for which you want to
+ enforce leaf-like attributes upon.
+
+`Max Depth'
+ 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.
+
+
+File: INSTALL.info, Node: Version limitations, Next: Excluded machines, Prev: Leaf connections, Up: The ircd-conf file
+
+Version limitations
+===================
+
+`Introduction'
+ V-lines are used to restrict server connecting to you based on
+ their version and on compile time options.
+
+`Format'
+ V:<Version Mask>:<Flags>:<Server Mask>::
+
+`Version Mask'
+ The matching version number strings will be rejected.
+
+`Flags'
+ If any flag specified in this field is found in the peer's flags
+ string, it will be rejected.
+
+`Server Mask'
+ This field is used to match server names. The V line will be used
+ for servers matching the mask given in this field.
+
+`Server Type'
+ Both the `Version Mask' and the `Flags' should be prefixed with
+ the server type identification. This implementation uses the id
+ "`IRC"' (starting with version 2.10).
+
+`Examples'
+ V:IRC/021001*::*::
+
+ Disallows any "IRC" server which version is 2.10.1* to connect.
+
+ V:IRC/021001*:IRC/D:*::
+
+ Disallows any "IRC" server which version is 2.10.1* or which has
+ been compiled with DEBUGMODE defined to connect.
+
+ V:*/0209*::::
+
+ Disallows any server using the 2.9 protocol to connect.
+
+`Note'
+ It is possible to have and use multiple V-lines for the one server
+ mask.
+
+ V:IRC/021001*::*::
+
+ V:IRC/021002*::*::
+
+ is allowed.
+
+`Protocol Version'
+ Only the 4 first digit of the `Version Number' are standard: they
+ define the protocol version. The remaining of the string is
+ implementation dependant; matches on this part should be used with
+ particular identification.
+
+`Flags'
+ are not standard. Therefore, this field `should always' contain a
+ specific identification.
+
+
+File: INSTALL.info, Node: Excluded machines, Next: Service connections, Prev: Version limitations, Up: The ircd-conf file
+
+Excluded machines
+=================
+
+ Disallowing SERVERS in your irc net.
+`Introduction'
+ 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.
+
+
+File: INSTALL.info, Node: Service connections, Next: Bounce server, Prev: Excluded machines, Up: The ircd-conf file
+
+Service connections
+===================
+
+`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 are not intended for interactive usage, and are better
+ suited for automated clients.
+
+`Format'
+ S:<TARGET Host Mask>:<Password>:<Service Name>:<Service
+ Type>:<Class>
+
+`TARGET Host Mask'
+ The host mask should be set to match the host(s) from which the
+ service will be connecting from. This may be either an IP# or full
+ name (prefered).
+
+`Password'
+ This is the password which must be passed in the SERVICE command.
+
+`Service Name'
+ The name used by the service. Services don't have nicknames, but a
+ static name defined by the S line.
+
+`Service Type'
+ The type of service. It defines the priviledges given to the
+ service. Be very careful in the types you allow. The types can be
+ found in include/service.h
+
+`Class'
+ The class field should refer to an existing class.
+
+`Notes'
+ 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 are rejected upon sending an unknown or unallowed
+ command. Services however, are not affected by flood control and
+ can be granted special privileges. It is therefore `wise to
+ oversee the use of S-lines with much care.'
+
+
+File: INSTALL.info, Node: Bounce server, Next: Default local server (for local clients) `*OBSOLETED*', Prev: Service connections, Up: The ircd-conf file
+
+Bounce server
+=============
+
+`Introduction'
+ This provides you a way to bounce clients to another server. This
+ information is provided to clients which are denied connection,
+ either because their connection class is full, or the server is
+ full, or they are not authorized to connect.
+
+`Format'
+ B:<Class|Host Mask>::<Server Name>:<Port>:
+
+`B'
+ This specifies a Bounce record.
+
+`Class|Host Mask'
+ This field specifies to which client this configuration line
+ applies to. It can be either a connection class number, a host
+ mask to be matched against the client's hostname, or an IP
+ address/mask/bitmask to be matched against the client's IP address.
+
+ When the server is completely full, it rejects clients with the
+ "All connections in use" message. In this case, the server
+ doesn't process the connections at all, and has no knowledge of
+ the client's host name, or class number. For these cases, this
+ field must be empty.
+
+`Server Name'
+ This specifies the IRC server hostname that the client should use.
+
+`Port'
+ This specifies the IRC server port that the client should connect
+ to.
+
+`Example'
+ B:2::irc.stealth.net:6660:
+
+ Rejected clients in class 2 are advised to use "irc.stealth.net"
+ on port 6660.
+
+ B:*.fi::irc.funet.fi:6667:
+
+ Finnish client should use irc.funet.fi when they cannot be taken
+ anymore.
+
+ B:::irc2.stealth.net:6667:
+
+ When the server is completely full, clients should use the
+ secondary server.
+
+
+File: INSTALL.info, Node: Default local server (for local clients) `*OBSOLETED*', Prev: Bounce server, Up: The ircd-conf file
+
+Default local server (for local clients) `*OBSOLETED*'
+======================================================
+
+`Introduction'
+ 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).
+
+`Format'
+ U:<TARGET Host addr>:<Password>:<TARGET Host NAME>:<Internet Port>
+
+`Examples'
+ 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.
+
+
+File: INSTALL.info, Node: Related resources, Next: Reporting a bug, Prev: The ircd-conf file, Up: Top
+
+Related resources
+*****************
+
+`Mailing list'
+ A list is dedicated to the people using ircd. If you have trouble
+ running ircd, or wish to discuss the future, you can subscribe by
+ sending an email to , with "`subscribe ircd-users"' in the body.
+
+ If you just have a question and don't want to subscribe to the
+ list, mail to . Be sure to indicate which version you are using.
+
+`Development'
+ Technical discussions and development are carried on
+ ircd-dev@irc.org. People interested in very early testing, and/or
+ working on the source code are welcome. This is done by sending
+ an email to , with "`subscribe ircd-dev"' in the body.
+
+`FAQ'
+ It can be found on the WWW, at .
+
+`WWW 2.9'
+ Vesa Ruokonen has also put serveral pages related to the 2.9
+ servers on the WWW: .
+
+
+File: INSTALL.info, Node: Reporting a bug, Prev: Related resources, Up: Top
+
+Reporting a bug
+***************
+
+ If you encounter a bug in the software, here is how and where to
+report it.
+
+* Menu:
+
+* How to report a bug::
+* Where to send a bug report::
+
+
+File: INSTALL.info, Node: How to report a bug, Next: Where to send a bug report, Up: Reporting a bug
+
+How to report a bug
+===================
+
+ To save everyone time, make sure that your e-mail contains all the
+information related to your problem. In particular, we need to know:
+`Package version'
+ The IRC software version you are using: please include the output
+ obtained by running "irc -v" for the client, and/or "ircd -v" for
+ the server.
+
+ Also, let us know if you have applied any patch to the package or
+ if it is the vanilla version.
+
+`OS'
+ Please, indicate which OS version you are running.
+
+`Configuration'
+ If it is related to a configuration problem with the server,
+ include the relevant parts of the configuration file.
+
+`Backtrace'
+ If the bug results in a crash, please include the backtrace.
+ (This can be done, for example, by running "gdb" on the core file,
+ and typing "where").
+
+`Fix'
+ If you have a fix, don't forget to include it.
+
+
+File: INSTALL.info, Node: Where to send a bug report, Prev: How to report a bug, Up: Reporting a bug
+
+Where to send a bug report
+==========================
+
+ Reports should be sent to . Your report will be reviewed and
+forwarded to the appropriate mailing list.
+
+
+
+Tag Table:
+Node: Top122
+Node: Installing IRC-630
+Node: The configure script855
+Node: Notes for Cygwin32 users3143
+Node: Notes concerning IPv6 support4196
+Node: The config-h file4794
+Node: Define what type of UNIX your machine uses-5466
+Node: DEBUGMODE5866
+Node: CPATH MPATH LPATH PPATH TPATH QPATH OPATH6530
+Node: CACHED_MOTD7758
+Node: CHROOTDIR8234
+Node: ENABLE_SUMMON ENABLE_USERS8558
+Node: SHOW_INVISIBLE_LUSERS NO_DEFAULT_INVISIBLE9094
+Node: OPER_KILL OPER_REHASH OPER_RESTART LOCAL_KILL_ONLY9777
+Node: ZIP_LINKS ZIP_LEVEL10409
+Node: SLOW_ACCEPT11420
+Node: CLONE_CHECK12038
+Node: Other #define's12378
+Node: Editing the Makefile and compiling12703
+Node: The ircd-conf file13343
+Node: Machine information15375
+Node: Administrative info17471
+Node: Port connections19506
+Node: Connection Classes21716
+Node: Client connections27167
+Node: Operator priviliges32680
+Node: Restrict connections34800
+Node: Excluded accounts36115
+Node: Server connections40081
+Node: Deny auto-connections48520
+Node: Hub connections49893
+Node: Leaf connections51109
+Node: Version limitations53192
+Node: Excluded machines54949
+Node: Service connections56256
+Node: Bounce server57849
+Node: Default local server (for local clients) `*OBSOLETED*'59551
+Node: Related resources60434
+Node: Reporting a bug61372
+Node: How to report a bug61632
+Node: Where to send a bug report62645
+
+End Tag Table
diff --git a/doc/INSTALL.sgml b/doc/INSTALL.sgml
new file mode 100644
index 0000000..b24e36f
--- /dev/null
+++ b/doc/INSTALL.sgml
@@ -0,0 +1,1388 @@
+<!doctype linuxdoc system>
+
+<article>
+
+<title>Installing IRC - The Internet Relay Chat Program
+<author>SGML version by Christophe Kalt
+<date>$Id: INSTALL.sgml,v 1.38 1999/08/13 17:19:52 kalt Exp $
+<abstract>
+This document describes how to install, and configure IRC 2.10.3.
+</abstract>
+
+<sect>Installing IRC.
+<sect1>The configure script
+<p>
+This package uses a GNU configure script for its configuration.
+You simply need to untar the distribution and run the
+``configure'' script. This will run configure which will probe
+your system for any peculiarities it has and setup the Makefile
+and a file of default &num;define's (&dollar;arch/setup.h).
+<p>
+There are a few options to ``configure'' to help it out, or
+change the default behaviour:
+<descrip>
+<tag/--prefix=DIR/ changes the default directory into which
+ircd will install using ``make install''. This defaults
+to /usr/local
+<tag/--sbindir=DIR/ changes the default directory where the
+system admin executable files will go. It is important to
+set this properly. (default is prefix/sbin)
+<tag/--logdir=DIR/ changes the default directory where the
+irc log files will go. (default is prefix/var/log/ircd)
+<tag/--sysconfdir=DIR/ changes the default directory where
+the irc server configuration files will go. (default is prefix/etc)
+<tag/--localstatedir=DIR/ changes the default directory
+where the irc server state files will go. (default is prefix/var/run)
+<tag/--resconf=FILE/ defines the file to be used by ircd to
+initialize its resolver. (default is /etc/resolv.conf)
+<tag/--zlib-include=DIR/ specifies in which directory the
+include file from the zlib is located.
+<tag/--zlib-library=DIR/ specifies in which directory the
+zlib library is located.
+<tag/--zlib-prefix=DIR/ specifies the prefix for zlib
+location. It overrides the 2 previous options. (The
+include directory is supposed to be in prefix/include, and
+the library in prefix/lib).
+<tag/--with-zlib/ is the default. ``configure'' looks on your
+system to find the zlib. If found, ircd will be linked using
+it. This does NOT mean you can use server link compression,
+for this you also need to define ZIP_LINKS (see section below).
+<tag/--without-zlib/ tells ``configure'' not to look for the zlib.
+Defining this will keep you from using server link compression.
+<tag/--enable-ip6/ Enable IPv6 support (See notes below)
+<tag/--enable-dsm/ Enable Dynamically Shared Modules support for iauth
+</descrip>
+
+<sect1>Notes for Cygwin32 users
+<p>
+The daemon of 2.10.3 release compiles properly on W32
+systems which have the GNU-Win32 environment (<url
+url="http://www.cygnus.com/misc/gnu-win32/">) setup. At the
+time of the release, tests were made using the version b20.1
+of the Cygwin32 library.
+<p>
+When compiling on such system, you want to make sure that
+you have carefully followed the Cygwin32 installation
+notes. In particular, you will need to make sure that the
+following files exist: <bf>/bin/cp.exe</bf>,
+<bf>/bin/mv.exe</bf>, <bf>/bin/rm.exe</bf> and
+<bf>/bin/sh.exe</bf>.
+<p>
+Also, the IRC server needs a <bf>resolv.conf</bf> file in
+order to initialize the resolver. This file can be anywhere
+(see configure options), and is typically in <bf>/etc</bf>
+on UNIX systems.
+<p>
+Finally, iauth is automatically disabled. Even though the
+iauth program compiles properly, extra work is required to
+have a working communication channel between the IRC server
+and the iauth program.
+
+<sect1>Notes concerning IPv6 support
+<p>
+The only part of the software that doesn't use IPv6 is the
+server internal resolver. It relies on the name servers
+defined in ``/etc/resolv.conf'' to be IPv4 addresses.
+<p>
+This version was tested on the following IPv6 systems:
+BSD/OS+KAME, Digital Unix, FreeBSD+KAME, Linux, NetBSD+INRIA.
+<p>
+Because IPv6 numeric addresses contain ``:'' characters,
+<bf>the separator for the server configuration file was
+changed to ``%''</bf>.
+
+<sect>The config.h file
+<p>
+The second step consists of defining options before the
+compilation. This is done by editing the ``config.h'' file
+and changing the various &num;DEFINE's.
+
+<sect1>Define what type of UNIX your machine uses.
+<p>
+Pick the machine type which best describes your machine and
+change the &num;undef to &num;define (if needed).Some
+flavours of Unix require no &num;define and in such cases
+all others should be &num;undef'd.
+
+<sect1>DEBUGMODE
+<p>
+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. Defining this induces a large
+overhead for the server as it does a large amount of self
+diagnostics whilst running.
+<p>
+<bf>This should only be defined for test purposes, and never
+used on a production server.</bf>
+
+<sect1>CPATH, MPATH, LPATH, PPATH, TPATH, QPATH, OPATH
+<p>
+Define CPATH to be the directory path to the ``ircd.conf''
+file. This path is usually /usr/local/lib/ircd/ircd.conf. The
+format of this file will be discussed later.
+<p>
+The LPATH &num;define should be set to ``/dev/null'' unless
+you plan to debug the ircd program. Note that the logfile grows
+very quickly.
+<p>
+Define MPATH to be the path to the ``motd'' (message of the
+day) file for the server. Keep in mind this is
+automatically displayed whenever anyone signs on to your
+server.
+<p>
+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.
+<p>
+Define QPATH to be the directory path to the ``iauth.conf''
+file. This path is usually /usr/local/lib/ircd/iauth.conf.
+The format of this file is described by a manual page.
+<p>
+The OPATH &num;define should be set to ``/dev/null'' unless
+you plan to debug the iauth program. Note that the logfile grows
+very quickly.
+
+<sect1>CACHED_MOTD
+<p>
+The server sends the ``motd'' to every client connecting.
+Every time, it reads it from the disk. This is quite
+intensive and can be undesirable for busy servers.
+<p>
+Defining CACHED_MOTD will make the server store the ``motd''
+in memory, and only read it again from the disk when
+rehashing if the file has changed.
+
+<sect1>CHROOTDIR
+<p>
+To use the CHROOTDIR feature, make sure it is &num;define'd
+and that the server is being run as root. The server will
+chroot to the directory name provded by ``IRCDDIR'' (in
+Makefile).
+
+<sect1>ENABLE_SUMMON, ENABLE_USERS
+<p>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.
+
+<sect1>SHOW_INVISIBLE_LUSERS, NO_DEFAULT_INVISIBLE
+<p>
+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.
+
+<sect1>OPER_KILL, OPER_REHASH, OPER_RESTART, LOCAL_KILL_ONLY
+<p>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.
+
+<sect1>ZIP_LINKS, ZIP_LEVEL
+<p>
+As of the 2.9.3 version of the server, server-server
+connections may be compressed using the zlib. In order to
+compile the server with this feature, you MUST have the zlib
+package (version 1.0 or higher) already compiled and define
+ZIP_LINKS in the config.h file. Compression use for
+server-server connections is separately configured in the
+ircd.conf file for each server-server link. ZIP_LEVEL
+allows you to control the compression level that will be
+used. Values above 5 will noticeably increase the CPU used
+by the server.
+<p>
+The zlib package may be found at <url
+url="http://www.cdrom.com/pub/infozip/zlib/">. The data format used
+by the zlib library is described by RFCs (Request for
+Comments) 1950 to 1952 in the files <url
+url="ftp://ds.internic.net/rfc/rfc1950.txt"> (zlib format),
+rfc1951.txt (deflate format) and rfc1952.txt (gzip
+format). These documents are also available in other formats
+from <url url="ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html">
+
+<sect1>SLOW_ACCEPT
+<p>
+This option is defined by default and is needed on some
+OSes. It creates an artificial delay in processing incoming
+connections. On a given port, no more than 1 connection per
+2 seconds will be processed.
+<p>
+Undefining this will let the server process connections as
+fast as it can which can cause problems on some OSes (such
+as SunOS) and be abused (fast massive join of clonebots..),
+for these reasons, if you decide to undefine SLOW_ACCEPT you
+MUST define CLONE_CHECK.
+
+<sect1>CLONE_CHECK
+<p>
+This option acts as a wrapper, by checking incoming
+connections early before starting ident query. By default,
+the server will not accept more than 2 connections from the
+same host within 10 seconds.
+
+<sect1>Other &num;define's
+<p>
+The rest of the user changable &num;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.
+
+<sect>Editing the Makefile, and compiling
+<p>
+This package now uses GNU autoconf to probe your system and
+generate the correct Makefile. However you need to edit it
+to specify specific information, such as ``prefix'',
+``irc_mode'', ``ircd_mode'' and ``ircd_dir''.
+<p>
+Now to build the package, type ``make all''. If everything
+goes will, you can then install it by typing ``make install''.
+<p>
+If you have trouble compiling ircd, copy Makefile.in to
+Makefile and edit Makefile as appropriate.
+
+<sect>The ircd.conf file
+<p>
+After installing the ircd and irc programs, edit the
+ircd.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.
+<p>
+Appendix A (See INSTALL.appendix) describes the differences
+between IP addresses and host names. If you are unfamiliar
+with this, you should probably scan through it before
+proceeding.
+<p>
+The ircd.conf file contains various records that specify
+configuration options. The record types are as follows:
+<enum>
+<item>Machine information (M)
+<item>Administrative info (A)
+<item>Port connections (P)
+<item>Connection Classes (Y)
+<item>Client connections (I,i)
+<item>Operator privileges (O)
+<item>Restrict lines (R)
+<item>Excluded accounts (K,k)
+<item>Server connections (C,c,N)
+<item>Deny auto-connections (D)
+<item>Hub connections (H)
+<item>Leaf connections (L)
+<item>Version limitations (V)
+<item>Excluded machines (Q)
+<item>Service connections (S)
+<item>Bounce server (B)
+<item>Default local server (U)
+</enum>
+<p>
+Except for types ``M'' and ``A'', you are allowed to have
+multiple records of the same type. In some cases, you can
+have concurrent records. <bf>It is important to note that
+the last matching record will be used</bf>. This is
+especially useful when setting up I records (client
+connections).
+
+<sect1>Machine information
+<p>
+<descrip>
+<tag/Introduction/
+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:
+<tag/Format/
+<verb>M:&lt;Server NAME&gt;:&lt;YOUR Internet IP&num;&gt;:&lt;Geographic Location&gt;:&lt;Port&gt;</verb>
+<tag/M/
+``M'' specifies a Machine description line
+<tag/Server NAME/
+The name of YOUR server adding any Internet DOMAINNAME that
+might also be present. If this hostname can be resolved, the
+IP&num; found will be used to for outgoing connections.
+Otherwise the default interface address of the host is used.
+The server name may not be FQDN of another host. (This
+means all outgoing connections will be done from the same
+IP&num;, even if your host has several IP&num;).
+<tag/YOUR Internet IP&num;/
+If the machine on which you run the server has several IP
+addresses, you can define which IP&num; to use for outgoing
+connections. This overrides overrides the ``Server NAME''.
+<p>See Also the ``Port Connections'' section.
+<tag/Geographic Location/
+Geographic Location is used to say WHERE YOUR SERVER 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: &lt;CITY&gt; &lt;STATE&gt;, USA. Like for
+Denver I say: ``Denver Colorado, USA''. Finnish sites (like
+tolsun.oulu.fi generally say something like ``Oulu,
+Finland''.
+<tag/Port/
+Defines the port on which your server will listen for UDP
+pings from other servers. This should be the port were
+other servers are set to autoconnect. (Also see the port
+field description in connect lines).
+<tag/Example:/
+M:tolsun.oulu.fi::Oulu, Finland:6667:
+<p>
+This line reads: My Host's name is ``tolsun.oulu.fi'' and my
+site is located in ``Oulu, Finland''.
+<p>
+M:orion.cair.du.edu::Denver Colorado, USA:6667:
+<p>
+This line reads: My Hosts name is ``orion.cair.du.edu'' and
+my site is located in ``Denver Colorado, USA''.
+</descrip>
+<p>
+
+<sect1>Administrative info
+<p>
+<descrip>
+<tag/Introduction/ The ``A'' line 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.
+<tag/Format/<verb>A:&lt;Your Name/Location&gt;:&lt;Your Electronic Mailing Addr&gt;:&lt;other&gt;::</verb>
+<tag/A/This specifies an Admin record.
+<tag/Your Name &amp; Location/ 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.
+<tag/Your Electronix Mailing Addr/ 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.
+<tag/Other/ This is really an OTHER field - you can add what
+you want here.
+<tag/Example/
+(the line is just one line in the confuration file, here it
+is cut into two lines to make it clearer to read):
+<p>
+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?;)::
+<p>
+Would look like this when printed out with the /admin command:
+<p>
+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? ;)
+<p>
+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.
+</descrip>
+
+<Sect1>Port connections
+<p>
+<descrip>
+<tag/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.
+<tag/Format/<verb>P:&lt;Internet IP&num;&gt;:&lt;*&gt;:&lt;Internet IP Mask&gt;:&lt;Port&gt;:
+P:&lt;Directory&gt;:&lt;*&gt;:&lt;*&gt;:&lt;Port&gt;:</verb>
+</descrip>
+<itemize>
+<item>Internet Ports
+<descrip>
+<tag/Internet IP&num;/ If the host on which the server runs has
+several IP addresses, you can define for which IP address
+connections will be accepted. If no is defined here, server
+will bind to all interfaces (INADDR_ANY). See also MACHINE
+CONFIGURATION section to properly configure outgoing
+connections.
+<p>
+P:192.168.1.194:::6664:
+<tag/Internet IP&num; Mask/ This 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>
+<verb>P:::128.2.*:6664:
+P:::128.2.0.0:6664:
+</verb>
+<p>
+The incoming isn't matched against the mask, rather the ip&num;
+string is decoded and compared segment by segment. Thus
+<p>
+P:::128.2*.1.2:6664:
+<p>
+will not match 128.20.1.2.
+<tag/Port/ The port number field tells the server which port
+number it should listen on for incoming connections.
+</descrip>
+<item> Unix Socket Ports.
+<descrip>
+<tag/Directory/ The path set in this field 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.
+<tag/Port/ The port field when used in combination with a
+pathname in a P-line is the filename created in the
+directory set in the first field.
+<tag/Example/ P:/tmp/.ircd:::6667:
+<p>
+Creates a unix socket in the /tmp/.ircd directory called
+``6667''. The unix socket (file) must be a numerical.
+</descrip>
+</itemize>
+<descrip>
+<tag/Note/ You need at least one P line.
+</descrip>
+
+<sect1>Connection Classes
+<p>
+<descrip>
+<tag/Introduction/ To enable more efficient use of
+MAXIMUM_LINKS, connection classes were implemented. All
+clients belong to a connection class.
+<p>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.
+<p>To define a connection class, you need to include a Y:
+line in the ircd.conf file. This enables you to define the
+ping frequency, connection frequency (for servers) and
+maximum number of links that class should have.
+<p>Currently, the Y: line <bf>MUST</bf> appear in the
+ircd.conf file <bf>BEFORE</bf> it is used in any other way.
+<tag/Format/<verb>Y:&lt;Class&gt;:&lt;Ping Frequency&gt;:&lt;Connect freq&gt;:&lt;Max Links&gt;:&lt;SendQ&gt;:&lt;Local Limit&gt;:&lt;Global Limit&gt;</verb>
+<tag/Y/ This specifies a Class record.
+<tag/Class/ This is the class number which gains the following
+attributes and should match that which is on the end of the
+C/c/N/I/O/S line.
+<tag/Ping Frequency/ 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.
+<tag/Connect Frequency/ 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.
+<tag/Max Links/ This field defines the maximum number of
+links this class will allow from automatic connections (C
+lines). Using /CONNECT overrides this feature. Also
+defines the maximum number of users in this class for I/O
+lines per I/O line.
+<tag/SendQ/ This field defines the ``SendQ'' value for this
+class. If this field is not present, the default (from
+config.h) is assigned.
+<tag/Local limit/ This field is used to limit the number
+of local concurrent connections. The format is
+&lt;x&gt;.&lt;y&gt;
+<itemize>
+<item> x: defines the maximum number of clients from the
+same host (IP) will be allowed.
+<item> y: defines the maximum number of clients from the
+same user@host (IP) will be allowed. Read note below.
+</itemize>
+Only x or y may be set, any unset value defaults to zero.
+<tag/Global limit/ This field has the same use as the
+``Local limit'' field. But, the connection counts are done
+for all clients present on the net instead of only counting
+local clients.
+<tag/Note/ leaving any of the fields (except SendQ) out
+means their value is 0 (ZERO)!! The SendQ field default
+value is dynamically determined.
+<tag/Note/ If you plan to use the local user@host limit,
+please read the following very carefully. The ``user''
+value is the ident reply for the connection. If no reply
+was given then it defaults to ``unknown'' and thus the
+effective limit will be per host, not per user@host. Also,
+some ident servers return encrypted data which changes for
+every connection making the limit void.
+<tag/Note/ Only the local limitation is accurate.
+<tag/Note/ If you define a gobal limit, you should also
+define a local limit (same or lower) as it won't take more
+CPU and will make the global limit more accurate.
+<tag/Note/ The local and global limits only affect users (I
+lines), not servers nor services.
+<tag/Example/ Y:23:120:300:5:100000:0:0: (server class)
+<p>
+This defines 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. The SendQ is set to 100000
+bytes.
+<p>
+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.
+<p>
+Y:1:60:0:50:20000:2:5: (client class)
+<p>
+In case of a client class, the fields are interpreted a bit
+differently. This class (number 1) can be used by up to 50
+users. The connections are allowed to remain silent for 60
+seconds before a PING is set. The SendQ is set to 20000
+bytes. A new connection in this class will only be allowed
+if there aren't more than 2 other local connections from the
+same IP address, or more than 5 other connections on the net
+from the same hostname.
+<p>
+Y:2:60:0:50:20000:2.1:5: (client class)
+<p>
+In case of a client class, the fields are interpreted a bit
+differently. This class (number 1) can be used by up to 50
+users. The connections are allowed to remain silent for 60
+seconds before a PING is set. The SendQ is set to 20000
+bytes. A new connection in this class will only be allowed
+if there aren't more than 2 other local connections from the
+same IP address, 1 other local connection from the same user
+from the same IP address, or more than 5 other connections
+on the net from the same hostname.
+</descrip>
+
+<sect1>Client connections
+<p>
+How to let clients connect to your IRCD.
+<descrip>
+<tag/Introduction/ A client is a program that connects to
+the ircd daemon (ircd). There are clients written in C, GNU
+Emacs Lisp and many other languages. The ``irc'' program is
+the C client. Each person that talks via IRC is running
+their own client.
+<p>
+The ircd.conf files contains entries that specify which
+clients are allowed to connect to your irc daemon.
+Obviously you want to allow your own 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.
+<tag/Format/
+<verb>I:&lt;TARGET Host Addr&gt;:&lt;Password&gt;:&lt;TARGET Hosts NAME&gt;:&lt;Port&gt;:&lt;Class&gt;
+i:&lt;TARGET Host Addr&gt;:&lt;Password&gt;:&lt;TARGET Hosts NAME&gt;:&lt;Port&gt;:&lt;Class&gt;</verb>
+<tag/TARGET Host Addr/Specifies the IP address(es) of the
+machine(s) that are allowed to connect. If ``user@''
+prefixes the actual IP address the server will require that
+the remote username returned by the ident server be the same
+as the one given before the ``@''. Wildcards are permitted
+unless using a bitmask (e.g. 1.2.3.0/24).
+<tag/Password/The password that must be given by the client
+to be allowed on the server.
+<tag/TARGET Host NAME/Specifies the host name(s) of the
+machines allowed to connect to the server. If ``user@''
+prefixes the actual IP address the server will require that
+the remote username returned by the ident server be the same
+as the one given before the ``@''. Wildcards are permitted.
+<p>
+This field can be empty, it then has a special meaning. See
+Below.
+<tag/Port/Specifies the port number for which this
+configuration line is valid. An empty field, or ``0''
+matches all ports.
+<tag/Class/This field should refer to an existing class.
+Connections classes are usefull to limit the number of users
+allowed on the server.
+<tag/Note/The server first checks if the client hostname (or
+any aliases) matches the <bf>TARGET Host NAME</bf> field.
+If a match is found, the client is accepted. If not, the
+server checks if the IP address of the client matches the
+<bf>TARGET Host Addr</bf> field. The matching field is used
+to set the name of the client: for example, if the client
+matches the <bf>TARGET Host Addr</bf> field, it will show on
+IRC with a numerical address (even if this address is
+resolvable). If the <bf>TARGET Host NAME</bf> field is
+empty, then the host name is always used (when available).
+<tag/Examples/
+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:
+<p>
+I:x::tolsun.oulu.fi::1
+<p>
+If you wanted to let remote clients connect, you could add
+the following lines:
+<p>
+I:x::*.du.edu::1
+<p>
+Allow any clients from machines whose names end in
+``.du.edu'' to connect with no password.
+<p>
+I:128.214.6.100::nic.funet.fi::1
+<p>
+Allow clients from a machine with that IP number to
+connect. Numeric match is enough, name is not required
+anymore.
+<p>
+I:x:secret:*.tut.fi::1
+<p>
+Allow clients from machines matching ``*.tut.fi'' to connect
+with the password ``secret''.
+<p>
+I:*::*::1
+<p>
+Allow anyone from anywhere to connect your server.
+<p>
+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).
+<p>
+I:x::*.fi:6667:1
+<p>
+Allow clients from machines matching ``*.fi'' to connect on
+the port 6667.
+<p>
+I:135.11.35.*::*.net::1
+<p>
+Allows clients from machines which host name matches
+``*.net'' or which IP address matches ``135.11.35.*'' to
+connect to the server. If the host name does not match
+``*.net'' then the IP address is used for these clients,
+even if the host name is known.
+<p>
+I:135.11.35.*::::1
+<p>
+Allows clients from machines which IP address matches
+``135.11.35.*'' to connect to the server. If the host name
+is known, is it used as address for these clients.
+<tag/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).
+<tag/NEW!!!/ As of the 2.9.1 version of the server, i lines
+are introduced. They work the same way as I lines, but the
+clients matching an i line will have a restricted
+connection. (no nick/mode change, no kick). Such users will
+have their username prefixed by +, = or - depending on the
+ident reply.
+</descrip>
+
+<sect1>Operator priviliges
+<p>
+How to become the IRC administrator on your site
+<descrip>
+<tag/Introduction/ To become an IRC Administrator, IRC must
+know who is authorized to become an operator and what their
+``Nickname'' and ``Password'' is.
+<tag/Format/<verb>O:&lt;TARGET Host NAME&gt;:&lt;Password&gt;:&lt;Nickname&gt;:&lt;Port&gt;:&lt;Class&gt;</verb>
+<tag/O/ 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.
+<tag/TARGET Host NAME/ 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.
+<tag/Password/ 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
+``ircd.conf'' file protected from all of the other users.
+<tag/Nickname/ The Nickname you usually go by - but you can
+make this what you want.
+<tag/Port/ Unused.
+<tag/Class/ 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.
+<tag/Example/ O:orion.cair.du.edu:pyunxc:Jeff::1
+<p>
+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''.
+</descrip>
+
+<sect1>Restrict connections
+<p>
+Let an external program decide if a client should be allowed
+or not.
+<descrip>
+<tag/Introduction/ R lines provide a convenient way to
+handle user access to the server with an external program.
+The outside program given three parameters: the client's
+username (set by the USER command), the client's hostname,
+and the client's ident reply (``unknown'' if none).
+<p>It is expected to return a reply line where the first
+word is either ``Y'' or ``N'' meaning `Yes Let them in'' or
+``No don't let them in''. If the first word begins with
+neither ``Y'' or ``N'' the default is to let the person on.
+<tag/Format/
+<verb>R:&lt;Target Host Name&gt;:&lt;Program&gt;:&lt;User&gt;:::</verb>
+<tag/R/This specifies a restrict record.
+<tag/Target Host Name/ In this field you specify the
+Hostname that the user is connecting from. If you wanted to
+restrict connects to IRC from ``orion.cair.du.edu'' then you
+would want to enter ``orion.cair.du.edu''.
+<tag/Program/ This is the external program to run to know if
+the user is allowed on your server.
+<tag/User/ The Username of the user you want removed from
+IRC. For example ``root''.
+</descrip>
+
+<sect1>Excluded accounts
+<p>
+Remove an errant user from IRC on your site.
+<descrip>
+<tag/Introduction/
+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.
+<tag/Format/<verb>K:&lt;Host Name&gt;:&lt;time interval(s)|comment&gt;:&lt;User&gt;:&lt;port&gt;:</verb>
+<tag/Format/<verb>k:&lt;Host Name&gt;:&lt;time interval(s)|comment&gt;:&lt;Auth&gt;:&lt;port&gt;:</verb>
+<tag/K/``K'' tells the IRCD that you are making a KILL USER
+command entry.
+<tag/Host Name/ In this field you specify the Hostname or
+the IP address (Single IP, Wildcard notation or bitmask
+notation) 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 ?
+<p>
+If you specify an IP address, IP mask, or an IP bitmask,
+it will match clients connecting from the matching
+addresses, no matter if they resolve or not.
+<p>
+You can prefix an IP address, an IP mask, or IP bitmask by
+``='' in which case only non resolving matching hosts will
+be banned.
+<tag/time interval(s)|comment/ Either leave this field empty
+or put a comment, then the line active continuously for the
+specified user/host machine. You may also specify intervals
+during the line should be active, see examples below.
+<tag/User/ The USERNAME of the user you want removed from
+IRC. For example ``root''.
+<tag/Auth/ If the user's ident server replies with the OTHER
+type (as opposed to the UNIX type), the reply is not used to
+set the user's username. (lowercase) k lines can be used in
+these case to reject users based on their ident reply.
+<p>
+This field will be matched against the ident server reply.
+It is important to note that OTHER replies are prefixed with
+a ``-'' by the ircd, while UNIX replies are not.
+<tag/Port/ The port on which the Kill line will be
+effective. 0 means all ports.
+<tag/Examples/ K:orion.cair.du.edu::jtrim:0:
+<p>
+If user ``jtrim'' connects to IRC from host
+``orion.cair.du.edu'' then IMMEDIATELY REMOVE HIM from my
+IRCD.
+<p>
+k:*.stealth.net::-43589:0:
+<p>
+If a user connects from any host that has the suffix
+``stealth.net'' and if that host ident server returns
+``-43589'' - then IMMEDIATELY REMOVE THEM from my IRCD.
+<p>
+K:*.cair.du.edu::root:0:
+<p>
+If user ``root'' connects to IRC from any host that has the
+suffix ``cair.du.edu'' - then IMMEDIATELY REMOVE THEM from
+my IRCD.
+<p>
+K:*::vijay:0:
+<p>
+This line reads ``I don't care WHAT HOST user ``vijay'' is
+on, I will NEVER allow username ``vijay'' to login to my
+IRCD.''
+<p>
+K:*.oulu.fi:0800-1200,1400-1900:*:0:
+<p>
+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
+before).
+<p>
+K:192.11.35.*::*:0:
+<p>
+This line disallows all hosts whose IP address matches
+``192.11.35.*'' to login to the ircd.
+<p>
+K:=192.11.35.*::*:0:
+<p>
+This line disallows all hosts whose IP address matches
+``192.11.35.*'' and which didn't resolve to login to the
+ircd.
+</descrip>
+
+<sect1>Server connections
+<p>
+How to connect to other servers, How other servers can connect to you
+<p>
+<bf>WARNING:</bf>
+The hostnames used as examples are really only examples and
+not meant to be used (simply because they don't work) in
+real life.
+<p>
+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:
+<itemize>
+<item>``garfield.mit.edu'' - Tertiary Connection
+<item>``irc.nada.kth.se'' - Secondary Connection
+<item>``nic.funet.fi'' - Primary Connection
+</itemize>
+<p>
+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.
+<p>
+PLEASE limit the number of hosts you will attempt to connect
+to down to 3. This is because of two main reasons:
+<enum>
+<item> to save your server from causing extra load and
+delays to users
+<item> to save internet from extra network traffic (remember
+the old rwho program with traffic problems when the number
+of machines increased).
+</enum>
+<p>
+<descrip>
+<tag/Format/ <verb>C:&lt;TARGET Host Addr&gt;:&lt;Password&gt;:&lt;TARGET Host NAME&gt;:&lt;TARGET PORT&gt;:&lt;Class&gt;</verb>
+<p>
+for example:
+<p>
+C:nic.funet.fi:passwd:nic.funet.fi:6667:1
+<p>
+ - or -
+<p>
+C:128.214.6.100:passwd:nic.funet.fi:6667:1
+<p>
+ - or -
+<p>
+C:root@nic.funet.fi:passwd:nic.funet.fi:6667:1
+<p>
+Each field is separated with a ":" charcter:
+<tag/C/ This field tells the IRC program which option is
+being configured. "C" corresponds to a server Connect
+option.
+<tag/TARGET Host Addr/ 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 ``@''.
+<tag/Password/ The password of the other host. A password
+must always be present for the line to be recognized.
+<tag/TARGET Host NAME/ 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.
+<tag/TARGET PORT/ 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.
+The port field can contain 2 ports, separated by a . In this
+case, the first port is used when auto-connecting, the
+second port is used for the UDP pings to the targer server.
+<tag/Class/ The class field should refer to an existing
+class and determines the maximum number of simultaneous uses
+of the C-line allowable through the max. links field in the
+Y-line.
+<tag/NEW!!!/ As of the 2.9.3 version of the server, server connections can be compressed with the zlib library. To define a compressed connection, you must have compiled the server with ZIP_LINKS defined (cf 2.h), and use a _lowercase_ C line.
+</descrip>
+<p>
+Some examples:
+<itemize>
+<item>C:nic.funet.fi::nic.funet.fi:6667:1
+<p>
+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.
+<item>C:18.72.0.252:Jeff:garfield.mit.edu:6667:1
+<p>
+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.
+<item>C:irc.nada.kth.se::irc.nada.kth.se:1
+<p>
+This reads: do not attempt to connect to
+``irc.nada.kth.se'', if ``irc.nada.kth.se'' requests a
+connection, allow it to connect.
+</itemize>
+<p>
+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
+<bf>reverse</bf> order of how we could want to connect to
+them.
+<p>
+Here's how it would look if we connected ``nic.funet.fi'' first:
+<p>
+C:garfield.mit.edu::garfield.mit.edu:6667:1
+C:irc.nada.kth.se::irc.nada.kth.se:6667:1
+C:nic.funet.fi::nic.funet.fi:6667:1
+<p>
+Ircd will attempt to connect to nic.funet.fi first, then to
+irc.nada and finally to garfield.
+<p>
+<bf>Reciprocal entries:</bf>
+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.
+<p>
+<descrip>
+<tag/Format/ The format for the NOCONNECT entry in the ``ircd.conf'' is:
+<verb>N:&lt;TARGET Host Addr&gt;:&lt;Password&gt;:&lt;TARGET Host NAME&gt;:&lt;Domain Mask&gt;:&lt;Class&gt;</verb>
+<p>
+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:
+<p>
+N:garfield.mit.edu:golden:garfield.mit.edu::
+<p>
+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''.
+<p>
+N:18.72.0.252::garfield.mit.edu::
+<p>
+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''.
+<tag/N/ ``N'' corresponds to a server Noconnect option.
+<tag/TARGET Host Addr/ 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 ``@''.
+<tag/Password/ The password of the other host. A password
+must always be present for the line to be recognized. If
+CRYPT_LINK_PASSWORD is defined in config.h, this password
+must be crypted.
+<tag/TARGET Host NAME/ 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.
+<tag/Domain Mask/ Domain masking, see below.
+<tag/Class/ The class field should refer to an existing class.
+<tag/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:
+<p>
+*.de - a domain name matching all machines in Germany.
+<p>
+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.
+<p>
+So wildcard domains are a great help, but how to use them ?
+<p>
+They can be defined in the N-line for a given connection, in
+place of ``Domain Mask'' you write a magic number called
+wildcard count.
+<p>
+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.
+<p>
+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 <bf>collision</bf> (*.fi matches
+nic.funet.fi).
+<p>
+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.
+</descrip>
+<p>
+
+<sect1>Deny auto-connections
+<p>
+<descrip>
+<tag/Introduction/ D lines were implemented to give server
+administrators more control on how auto connections are
+done. This will most likely only be useful for big networks
+which have complex configurations.
+<tag/Format/<verb>D:&lt;Denied Server Mask&gt;:Denied Class:&lt;Server Name&gt;:Server Class:
+</verb>
+<tag/Denied Server Mask/ This field is matched against all
+servers currently present on the network.
+<tag/Denied Class/ If this field contains a class number,
+it will match if any server in that class is currently
+present on the network. Note that this can be true for any
+server, even the ones not directly connected.
+<tag/Server Mask/ This field is matched against the server
+name that the server wants to auto connect to.
+<tag/Server Class/ This field is used to match against the
+class to which belong the servers for which an autoconnect
+is set.
+<tag/Examples/D:*.edu::*.fi::
+<p>
+Don't auto-connect to any ``*.fi'' server if any server
+present on the network matches ``*.edu''.
+<p>
+D::2:eff.org:3:
+<p>
+Do now auto-connect to ``eff.org'', or any server in class
+``3'' if a server defined to be in class ``2'' is currently
+present on the network.
+</descrip>
+
+<sect1>Hub connections
+<p>
+<descrip>
+<tag/Introduction/ 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.
+<tag/Format/<verb>H:&lt;Server Mask&gt;:*:&lt;Server Name&gt;::
+</verb>
+<tag/Server Mask/ All servers that are allowed via this
+H-line must match the mask given in this field.
+<tag/Server Name/ This field is used to match exactly
+against a server name, wildcards being treated as literal
+characters.
+<tag/Examples/H:*.edu::*.bu.edu::
+<p>
+Allows a server named ``*.bu.edu'' to introduce only servers
+that match the ``*.edu'' name mask.
+<p>
+H:*::eff.org::
+<p>
+Allows ``eff.org'' to introduce (and act as a hub for) any
+server.
+<tag/Note/ It is possible to have and use multiple H-lines
+(or L-lines) for the one server. eg:
+<p>
+<verb>H:*.edu:*:*.bu.edu::
+H:*.au:*:*.bu.edu::
+</verb>
+<p>
+is allowed as is
+<p>
+<verb>L:*.edu:*:*.au::
+L:*.com:*:*.au::
+</verb>
+</descrip>
+
+<sect1>Leaf connections
+<p>
+<descrip>
+<tag/Introduction/ 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.
+<tag/Format/<verb>L:&lt;Server Mask&gt;:*:&lt;Server Name&gt;:&lt;Max Depth&gt;:</verb>
+<tag/Server Mask/ 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).
+<tag/Server Name/ The name of the server connected to you
+that for which you want to enforce leaf-like attributes
+upon.
+<tag/Max Depth/ 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.
+</descrip>
+
+<sect1>Version limitations
+<p>
+<descrip>
+<tag/Introduction/ V-lines are used to restrict server
+connecting to you based on their version and on compile time
+options.
+<tag/Format/<verb>V:&lt;Version Mask&gt;:&lt;Flags&gt;:&lt;Server Mask&gt;::</verb>
+<tag/Version Mask/ The matching version number strings will be rejected.
+<tag/Flags/ If any flag specified in this field is found in
+the peer's flags string, it will be rejected.
+<tag/Server Mask/ This field is used to match server names.
+The V line will be used for servers matching the mask given
+in this field.
+<tag/Server Type/ Both the <bf>Version Mask</bf> and the
+<bf>Flags</bf> should be prefixed with the server type
+identification. This implementation uses the id
+``<bf>IRC</bf>'' (starting with version 2.10).
+<tag/Examples/V:IRC/021001*::*::
+<p>
+Disallows any ``IRC'' server which version is 2.10.1* to connect.
+<p>
+V:IRC/021001*:IRC/D:*::
+<p>
+Disallows any ``IRC'' server which version is 2.10.1* or
+which has been compiled with DEBUGMODE defined to connect.
+<p>
+V:*/0209*::::
+<p>
+Disallows any server using the 2.9 protocol to connect.
+<tag/Note/ It is possible to have and use multiple V-lines
+for the one server mask.
+<p>
+V:IRC/021001*::*::
+<p>
+V:IRC/021002*::*::
+<p>
+is allowed.
+<tag/Protocol Version/ Only the 4 first digit of the
+<bf>Version Number</bf> are standard: they define the
+protocol version. The remaining of the string is
+implementation dependant; matches on this part should be
+used with particular identification.
+<tag/Flags/ are not standard. Therefore, this field
+<bf>should always</bf> contain a specific identification.
+</descrip>
+
+<sect1>Excluded machines
+<p>
+Disallowing SERVERS in your irc net.
+<descrip>
+<tag/Introduction/ 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
+<bf>your server</bf> disconnects the link. Note that just
+placing Q-lines to your server probably results in <bf>your
+server</bf> being left alone, unless other servers have
+agreed to have the same Q-line in their ircd configuration
+files as well.
+<tag/Example/Q::of the security holes:foo.bar.baz::
+<p>
+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.
+</descrip>
+
+<sect1>Service connections
+<p>
+<descrip>
+<tag/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.
+<p>
+Services are not intended for interactive usage, and are
+better suited for automated clients.
+<tag/Format/<verb>S:&lt;TARGET Host Mask&gt;:&lt;Password&gt;:&lt;Service Name&gt;:&lt;Service Type&gt;:&lt;Class&gt;</verb>
+<tag/TARGET Host Mask/ The host mask should be set to match
+the host(s) from which the service will be connecting
+from. This may be either an IP&num; or full name (prefered).
+<tag/Password/ This is the password which must be passed in
+the SERVICE command.
+<tag/Service Name/ The name used by the service. Services
+don't have nicknames, but a static name defined by the S
+line.
+<tag/Service Type/ The type of service. It defines the
+priviledges given to the service. Be very careful in the
+types you allow. The types can be found in
+include/service.h
+<tag/Class/ The class field should refer to an existing class.
+<tag/Notes/ 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 are rejected upon sending
+an unknown or unallowed command. Services however, are not
+affected by flood control and can be granted special
+privileges. It is therefore <bf>wise to oversee the use of
+S-lines with much care.</bf>
+</descrip>
+
+<sect1>Bounce server
+<p>
+<descrip>
+<tag/Introduction/ This provides you a way to bounce clients
+to another server. This information is provided to clients
+which are denied connection, either because their connection
+class is full, or the server is full, or they are not
+authorized to connect.
+<tag/Format/<verb>B:&lt;Class|Host Mask&gt;::&lt;Server Name&gt;:&lt;Port&gt;:</verb>
+<tag/B/ This specifies a Bounce record.
+<tag/Class|Host Mask/ This field specifies to which client
+this configuration line applies to. It can be either a
+connection class number, a host mask to be matched against
+the client's hostname, or an IP address/mask/bitmask to be
+matched against the client's IP address.
+<p>
+When the server is completely full, it rejects clients with
+the ``All connections in use'' message. In this case, the
+server doesn't process the connections at all, and has no
+knowledge of the client's host name, or class number. For
+these cases, this field must be empty.
+<tag/Server Name/ This specifies the IRC server hostname
+that the client should use.
+<tag/Port/ This specifies the IRC server port that the
+client should connect to.
+<tag/Example/B:2::irc.stealth.net:6660:
+<p>
+Rejected clients in class 2 are advised to use
+``irc.stealth.net'' on port 6660.
+<p>
+B:*.fi::irc.funet.fi:6667:
+<p>
+Finnish client should use irc.funet.fi when they cannot be
+taken anymore.
+<p>
+B:::irc2.stealth.net:6667:
+<p>
+When the server is completely full, clients should use the
+secondary server.
+</descrip>
+
+<sect1>Default local server (for local clients) <bf>*OBSOLETED*</bf>
+<p>
+<descrip>
+<tag/Introduction/ 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).
+<tag/Format/<verb>U:&lt;TARGET Host addr&gt;:&lt;Password&gt;:&lt;TARGET Host NAME&gt;:&lt;Internet Port&gt;</verb>
+<tag/Examples/
+U:tolsun.oulu.fi::tolsun.oulu.fi:6667<p>
+U:128.214.5.6::tolsun.oulu.fi:6667<p>
+U:tolsun.oulu.fi::tolsun.oulu.fi
+<p>
+If the port number is omitted, irc will default to using 6667.
+</descrip>
+
+<sect>Related resources
+<p>
+<descrip>
+<tag/Mailing list/ A list is dedicated to the people using
+ircd. If you have trouble running ircd, or wish to discuss
+the future, you can subscribe by sending an email to
+<htmlurl url="mailto:majordomo@irc.org"
+name="majordomo@irc.org">, with ``<bf>subscribe
+ircd-users</bf>'' in the body.
+<p>
+If you just have a question and don't want to subscribe to
+the list, mail to <htmlurl url="mailto:ircd-users@irc.org"
+name="ircd-users@irc.org">. Be sure to indicate which
+version you are using.
+<tag/Development/ Technical discussions and development are
+carried on ircd-dev@irc.org. People interested in very
+early testing, and/or working on the source code are
+welcome. This is done by sending an email to <htmlurl
+url="mailto:majordomo@irc.org"
+name="majordomo@irc.org">, with ``<bf>subscribe
+ircd-dev</bf>'' in the body.
+<tag/FAQ/ It can be found on the WWW, at <url
+url="http://www.stealth.net/~kalt/irc/faq.html">.
+<tag/WWW 2.9/ Vesa Ruokonen has also put serveral pages
+related to the 2.9 servers on the WWW: <url
+url="http://www.irc.org/~irc/server/">.
+</descrip>
+
+<sect>Reporting a bug
+<p>
+If you encounter a bug in the software, here is how and
+where to report it.
+
+<sect1>How to report a bug
+<p>
+To save everyone time, make sure that your e-mail contains
+all the information related to your problem. In particular,
+we need to know:
+<descrip>
+<tag/Package version/
+The IRC software version you are using: please include the
+output obtained by running ``irc -v'' for the client, and/or
+``ircd -v'' for the server.
+<p>
+Also, let us know if you have applied any patch to the
+package or if it is the vanilla version.
+<tag/OS/
+Please, indicate which OS version you are running.
+<tag/Configuration/
+If it is related to a configuration problem with the server,
+include the relevant parts of the configuration file.
+<tag/Backtrace/
+If the bug results in a crash, please include the
+backtrace. (This can be done, for example, by running
+``gdb'' on the core file, and typing ``where'').
+<tag/Fix/
+If you have a fix, don't forget to include it.
+</descrip>
+
+<sect1>Where to send a bug report
+<p>
+Reports should be sent to <htmlurl url="mailto:ircd-bugs@irc.org"
+name="ircd-bugs@irc.org">. Your report will be reviewed
+and forwarded to the appropriate mailing list.
+
+</article>
diff --git a/doc/INSTALL.txt b/doc/INSTALL.txt
new file mode 100644
index 0000000..b8dbc63
--- /dev/null
+++ b/doc/INSTALL.txt
@@ -0,0 +1,1716 @@
+ Installing IRC - The Internet Relay Chat Program
+ SGML version by Christophe Kalt
+ $Id: INSTALL.txt,v 1.38 1999/08/13 17:22:12 kalt Exp $
+
+ This document describes how to install, and configure IRC 2.10.3.
+
+ 11.. IInnssttaalllliinngg IIRRCC..
+
+ 11..11.. TThhee ccoonnffiigguurree ssccrriipptt
+
+ This package uses a GNU configure script for its configuration. You
+ simply need to untar the distribution and run the ``configure''
+ script. This will run configure which will probe your system for any
+ peculiarities it has and setup the Makefile and a file of default
+ #define's ($arch/setup.h).
+
+ There are a few options to ``configure'' to help it out, or change the
+ default behaviour:
+
+ ----pprreeffiixx==DDIIRR
+ changes the default directory into which ircd will install using
+ ``make install''. This defaults to /usr/local
+
+ ----ssbbiinnddiirr==DDIIRR
+ changes the default directory where the system admin executable
+ files will go. It is important to set this properly. (default is
+ prefix/sbin)
+
+ ----llooggddiirr==DDIIRR
+ changes the default directory where the irc log files will go.
+ (default is prefix/var/log/ircd)
+
+ ----ssyyssccoonnffddiirr==DDIIRR
+ changes the default directory where the irc server configuration
+ files will go. (default is prefix/etc)
+
+ ----llooccaallssttaatteeddiirr==DDIIRR
+ changes the default directory where the irc server state files
+ will go. (default is prefix/var/run)
+
+ ----rreessccoonnff==FFIILLEE
+ defines the file to be used by ircd to initialize its resolver.
+ (default is /etc/resolv.conf)
+
+ ----zzlliibb--iinncclluuddee==DDIIRR
+ specifies in which directory the include file from the zlib is
+ located.
+
+ ----zzlliibb--lliibbrraarryy==DDIIRR
+ specifies in which directory the zlib library is located.
+
+ ----zzlliibb--pprreeffiixx==DDIIRR
+ specifies the prefix for zlib location. It overrides the 2
+ previous options. (The include directory is supposed to be in
+ prefix/include, and the library in prefix/lib).
+
+ ----wwiitthh--zzlliibb
+ is the default. ``configure'' looks on your system to find the
+ zlib. If found, ircd will be linked using it. This does NOT
+ mean you can use server link compression, for this you also need
+ to define ZIP_LINKS (see section below).
+
+ ----wwiitthhoouutt--zzlliibb
+ tells ``configure'' not to look for the zlib. Defining this
+ will keep you from using server link compression.
+
+ ----eennaabbllee--iipp66
+ Enable IPv6 support (See notes below)
+
+ ----eennaabbllee--ddssmm
+ Enable Dynamically Shared Modules support for iauth
+
+
+ 11..22.. NNootteess ffoorr CCyyggwwiinn3322 uusseerrss
+
+ The daemon of 2.10.3 release compiles properly on W32 systems which
+ have the GNU-Win32 environment ( <http://www.cygnus.com/misc/gnu-
+ win32/>) setup. At the time of the release, tests were made using the
+ version b20.1 of the Cygwin32 library.
+
+ When compiling on such system, you want to make sure that you have
+ carefully followed the Cygwin32 installation notes. In particular,
+ you will need to make sure that the following files exist:
+ //bbiinn//ccpp..eexxee, //bbiinn//mmvv..eexxee, //bbiinn//rrmm..eexxee and //bbiinn//sshh..eexxee.
+
+ Also, the IRC server needs a rreessoollvv..ccoonnff file in order to initialize
+ the resolver. This file can be anywhere (see configure options), and
+ is typically in //eettcc on UNIX systems.
+
+ Finally, iauth is automatically disabled. Even though the iauth
+ program compiles properly, extra work is required to have a working
+ communication channel between the IRC server and the iauth program.
+
+
+ 11..33.. NNootteess ccoonncceerrnniinngg IIPPvv66 ssuuppppoorrtt
+
+ The only part of the software that doesn't use IPv6 is the server
+ internal resolver. It relies on the name servers defined in
+ ``/etc/resolv.conf'' to be IPv4 addresses.
+
+ This version was tested on the following IPv6 systems: BSD/OS+KAME,
+ Digital Unix, FreeBSD+KAME, Linux, NetBSD+INRIA.
+
+ Because IPv6 numeric addresses contain ``:'' characters, tthhee sseeppaarraattoorr
+ ffoorr tthhee sseerrvveerr ccoonnffiigguurraattiioonn ffiillee wwaass cchhaannggeedd ttoo ````%%''''.
+
+
+ 22.. TThhee ccoonnffiigg..hh ffiillee
+
+ The second step consists of defining options before the compilation.
+ This is done by editing the ``config.h'' file and changing the various
+ #DEFINE's.
+
+
+ 22..11.. DDeeffiinnee wwhhaatt ttyyppee ooff UUNNIIXX yyoouurr mmaacchhiinnee uusseess..
+
+ 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.
+
+
+ 22..22.. DDEEBBUUGGMMOODDEE
+
+ 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. Defining
+ this induces a large overhead for the server as it does a large amount
+ of self diagnostics whilst running.
+
+ TThhiiss sshhoouulldd oonnllyy bbee ddeeffiinneedd ffoorr tteesstt ppuurrppoosseess,, aanndd nneevveerr uusseedd oonn aa
+ pprroodduuccttiioonn sseerrvveerr..
+ 22..33.. CCPPAATTHH,, MMPPAATTHH,, LLPPAATTHH,, PPPPAATTHH,, TTPPAATTHH,, QQPPAATTHH,, OOPPAATTHH
+
+ Define CPATH to be the directory path to the ``ircd.conf'' file. This
+ path is usually /usr/local/lib/ircd/ircd.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 ircd 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 automatically 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.
+
+ Define QPATH to be the directory path to the ``iauth.conf'' file. This
+ path is usually /usr/local/lib/ircd/iauth.conf. The format of this
+ file is described by a manual page.
+
+ The OPATH #define should be set to ``/dev/null'' unless you plan to
+ debug the iauth program. Note that the logfile grows very quickly.
+
+
+ 22..44.. CCAACCHHEEDD__MMOOTTDD
+
+ The server sends the ``motd'' to every client connecting. Every time,
+ it reads it from the disk. This is quite intensive and can be
+ undesirable for busy servers.
+
+ Defining CACHED_MOTD will make the server store the ``motd'' in
+ memory, and only read it again from the disk when rehashing if the
+ file has changed.
+
+
+ 22..55.. CCHHRROOOOTTDDIIRR
+
+ 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 ``IRCDDIR'' (in Makefile).
+
+
+ 22..66.. EENNAABBLLEE__SSUUMMMMOONN,, EENNAABBLLEE__UUSSEERRSS
+
+ 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.
+
+
+ 22..77.. SSHHOOWW__IINNVVIISSIIBBLLEE__LLUUSSEERRSS,, NNOO__DDEEFFAAUULLTT__IINNVVIISSIIBBLLEE
+
+ 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.
+
+
+
+
+
+ 22..88.. OOPPEERR__KKIILLLL,, OOPPEERR__RREEHHAASSHH,, OOPPEERR__RREESSTTAARRTT,, LLOOCCAALL__KKIILLLL__OONNLLYY
+
+ 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.
+
+
+ 22..99.. ZZIIPP__LLIINNKKSS,, ZZIIPP__LLEEVVEELL
+
+ As of the 2.9.3 version of the server, server-server connections may
+ be compressed using the zlib. In order to compile the server with
+ this feature, you MUST have the zlib package (version 1.0 or higher)
+ already compiled and define ZIP_LINKS in the config.h file.
+ Compression use for server-server connections is separately configured
+ in the ircd.conf file for each server-server link. ZIP_LEVEL allows
+ you to control the compression level that will be used. Values above
+ 5 will noticeably increase the CPU used by the server.
+
+ The zlib package may be found at
+ <http://www.cdrom.com/pub/infozip/zlib/>. The data format used by the
+ zlib library is described by RFCs (Request for Comments) 1950 to 1952
+ in the files <ftp://ds.internic.net/rfc/rfc1950.txt> (zlib format),
+ rfc1951.txt (deflate format) and rfc1952.txt (gzip format). These
+ documents are also available in other formats from
+ <ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html>
+
+
+ 22..1100.. SSLLOOWW__AACCCCEEPPTT
+
+ This option is defined by default and is needed on some OSes. It
+ creates an artificial delay in processing incoming connections. On a
+ given port, no more than 1 connection per 2 seconds will be processed.
+
+ Undefining this will let the server process connections as fast as it
+ can which can cause problems on some OSes (such as SunOS) and be
+ abused (fast massive join of clonebots..), for these reasons, if you
+ decide to undefine SLOW_ACCEPT you MUST define CLONE_CHECK.
+
+
+ 22..1111.. CCLLOONNEE__CCHHEECCKK
+
+ This option acts as a wrapper, by checking incoming connections early
+ before starting ident query. By default, the server will not accept
+ more than 2 connections from the same host within 10 seconds.
+
+
+ 22..1122.. OOtthheerr ##ddeeffiinnee''ss
+
+ 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.
+
+
+ 33.. EEddiittiinngg tthhee MMaakkeeffiillee,, aanndd ccoommppiilliinngg
+
+ This package now uses GNU autoconf to probe your system and generate
+ the correct Makefile. However you need to edit it to specify specific
+ information, such as ``prefix'', ``irc_mode'', ``ircd_mode'' and
+ ``ircd_dir''.
+
+ Now to build the package, type ``make all''. If everything goes will,
+ you can then install it by typing ``make install''.
+
+
+ If you have trouble compiling ircd, copy Makefile.in to Makefile and
+ edit Makefile as appropriate.
+
+
+ 44.. TThhee iirrccdd..ccoonnff ffiillee
+
+ After installing the ircd and irc programs, edit the ircd.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 (See INSTALL.appendix) describes the differences between IP
+ addresses and host names. If you are unfamiliar with this, you should
+ probably scan through it before proceeding.
+
+ The ircd.conf file contains various records that specify configuration
+ options. The record types are as follows:
+
+ 1. Machine information (M)
+
+ 2. Administrative info (A)
+
+ 3. Port connections (P)
+
+ 4. Connection Classes (Y)
+
+ 5. Client connections (I,i)
+
+ 6. Operator privileges (O)
+
+ 7. Restrict lines (R)
+
+ 8. Excluded accounts (K,k)
+
+ 9. Server connections (C,c,N)
+
+ 10.
+ Deny auto-connections (D)
+
+ 11.
+ Hub connections (H)
+
+ 12.
+ Leaf connections (L)
+
+ 13.
+ Version limitations (V)
+
+ 14.
+ Excluded machines (Q)
+
+ 15.
+ Service connections (S)
+
+ 16.
+ Bounce server (B)
+
+ 17.
+ Default local server (U)
+
+ Except for types ``M'' and ``A'', you are allowed to have multiple
+ records of the same type. In some cases, you can have concurrent
+ records. IItt iiss iimmppoorrttaanntt ttoo nnoottee tthhaatt tthhee llaasstt mmaattcchhiinngg rreeccoorrdd wwiillll
+ bbee uusseedd. This is especially useful when setting up I records (client
+ connections).
+
+ 44..11.. MMaacchhiinnee iinnffoorrmmaattiioonn
+
+
+ IInnttrroodduuccttiioonn
+ 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:
+
+ FFoorrmmaatt
+
+ M:<Server NAME>:<YOUR Internet IP#>:<Geographic Location>:<Port>
+
+
+
+ MM ``M'' specifies a Machine description line
+
+ SSeerrvveerr NNAAMMEE
+ The name of YOUR server adding any Internet DOMAINNAME that
+ might also be present. If this hostname can be resolved, the IP#
+ found will be used to for outgoing connections. Otherwise the
+ default interface address of the host is used. The server name
+ may not be FQDN of another host. (This means all outgoing
+ connections will be done from the same IP#, even if your host
+ has several IP#).
+
+ YYOOUURR IInntteerrnneett IIPP##
+ If the machine on which you run the server has several IP
+ addresses, you can define which IP# to use for outgoing
+ connections. This overrides overrides the ``Server NAME''.
+
+ See Also the ``Port Connections'' section.
+
+ GGeeooggrraapphhiicc LLooccaattiioonn
+ Geographic Location is used to say WHERE YOUR SERVER 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''.
+
+ PPoorrtt
+ Defines the port on which your server will listen for UDP pings
+ from other servers. This should be the port were other servers
+ are set to autoconnect. (Also see the port field description in
+ connect lines).
+
+ EExxaammppllee::
+ 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''.
+
+ 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''.
+
+
+
+ 44..22.. AAddmmiinniissttrraattiivvee iinnffoo
+
+
+ IInnttrroodduuccttiioonn
+ The ``A'' line 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.
+ FFoorrmmaatt
+
+ A:<Your Name/Location>:<Your Electronic Mailing Addr>:<other>::
+
+
+
+ AA This specifies an Admin record.
+
+ YYoouurr NNaammee && LLooccaattiioonn
+ 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.
+
+ YYoouurr EElleeccttrroonniixx MMaaiilliinngg AAddddrr
+ 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.
+
+ OOtthheerr
+ This is really an OTHER field - you can add what you want here.
+
+ EExxaammppllee
+ (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.
+
+
+ 44..33.. PPoorrtt ccoonnnneeccttiioonnss
+
+
+ IInnttrroodduuccttiioonn
+ 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.
+
+ FFoorrmmaatt
+
+ P:<Internet IP#>:<*>:<Internet IP Mask>:<Port>:
+ P:<Directory>:<*>:<*>:<Port>:
+
+
+
+
+ +o Internet Ports
+
+ IInntteerrnneett IIPP##
+ If the host on which the server runs has several IP addresses,
+ you can define for which IP address connections will be
+ accepted. If no is defined here, server will bind to all
+ interfaces (INADDR_ANY). See also MACHINE CONFIGURATION section
+ to properly configure outgoing connections.
+
+ P:192.168.1.194:::6664:
+
+ IInntteerrnneett IIPP## MMaasskk
+ This 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 isn't 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.
+
+ PPoorrtt
+ The port number field tells the server which port number it
+ should listen on for incoming connections.
+
+ +o Unix Socket Ports.
+
+ DDiirreeccttoorryy
+ The path set in this field 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.
+
+ PPoorrtt
+ The port field when used in combination with a pathname in a P-
+ line is the filename created in the directory set in the first
+ field.
+
+ EExxaammppllee
+ P:/tmp/.ircd:::6667:
+
+ Creates a unix socket in the /tmp/.ircd directory called
+ ``6667''. The unix socket (file) must be a numerical.
+
+
+ NNoottee
+ You need at least one P line.
+
+
+ 44..44.. CCoonnnneeccttiioonn CCllaasssseess
+
+
+ IInnttrroodduuccttiioonn
+ To enable more efficient use of MAXIMUM_LINKS, connection
+ classes were implemented. All clients belong to a connection
+ class.
+
+ 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 ircd.conf file. This enables you to define the ping
+ frequency, connection frequency (for servers) and maximum number
+ of links that class should have.
+
+ Currently, the Y: line MMUUSSTT appear in the ircd.conf file BBEEFFOORREE
+ it is used in any other way.
+
+ FFoorrmmaatt
+
+ Y:<Class>:<Ping Frequency>:<Connect freq>:<Max Links>:<SendQ>:<Local Limit>:<Global Limit>
+
+
+
+ YY This specifies a Class record.
+
+ CCllaassss
+ This is the class number which gains the following attributes
+ and should match that which is on the end of the C/c/N/I/O/S
+ line.
+
+ PPiinngg FFrreeqquueennccyy
+ 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.
+
+ CCoonnnneecctt FFrreeqquueennccyy
+ 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.
+
+ MMaaxx LLiinnkkss
+ This field defines the maximum number of links this class will
+ allow from automatic connections (C lines). Using /CONNECT
+ overrides this feature. Also defines the maximum number of
+ users in this class for I/O lines per I/O line.
+
+ SSeennddQQ
+ This field defines the ``SendQ'' value for this class. If this
+ field is not present, the default (from config.h) is assigned.
+
+ LLooccaall lliimmiitt
+ This field is used to limit the number of local concurrent
+ connections. The format is <x>.<y>
+
+ +o x: defines the maximum number of clients from the same host (IP)
+ will be allowed.
+
+ +o y: defines the maximum number of clients from the same user@host
+ (IP) will be allowed. Read note below.
+
+ Only x or y may be set, any unset value defaults to zero.
+
+ GGlloobbaall lliimmiitt
+ This field has the same use as the ``Local limit'' field. But,
+ the connection counts are done for all clients present on the
+ net instead of only counting local clients.
+
+ NNoottee
+ leaving any of the fields (except SendQ) out means their value
+ is 0 (ZERO)!! The SendQ field default value is dynamically
+ determined.
+
+ NNoottee
+ If you plan to use the local user@host limit, please read the
+ following very carefully. The ``user'' value is the ident reply
+ for the connection. If no reply was given then it defaults to
+ ``unknown'' and thus the effective limit will be per host, not
+ per user@host. Also, some ident servers return encrypted data
+ which changes for every connection making the limit void.
+
+ NNoottee
+ Only the local limitation is accurate.
+
+ NNoottee
+ If you define a gobal limit, you should also define a local
+ limit (same or lower) as it won't take more CPU and will make
+ the global limit more accurate.
+
+ NNoottee
+ The local and global limits only affect users (I lines), not
+ servers nor services.
+
+ EExxaammppllee
+ Y:23:120:300:5:100000:0:0: (server class)
+
+ This defines 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. The SendQ is set to 100000 bytes.
+
+ 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.
+
+ Y:1:60:0:50:20000:2:5: (client class)
+
+ In case of a client class, the fields are interpreted a bit
+ differently. This class (number 1) can be used by up to 50
+ users. The connections are allowed to remain silent for 60
+ seconds before a PING is set. The SendQ is set to 20000 bytes.
+ A new connection in this class will only be allowed if there
+ aren't more than 2 other local connections from the same IP
+ address, or more than 5 other connections on the net from the
+ same hostname.
+
+ Y:2:60:0:50:20000:2.1:5: (client class)
+
+ In case of a client class, the fields are interpreted a bit
+ differently. This class (number 1) can be used by up to 50
+ users. The connections are allowed to remain silent for 60
+ seconds before a PING is set. The SendQ is set to 20000 bytes.
+ A new connection in this class will only be allowed if there
+ aren't more than 2 other local connections from the same IP
+ address, 1 other local connection from the same user from the
+ same IP address, or more than 5 other connections on the net
+ from the same hostname.
+
+
+ 44..55.. CClliieenntt ccoonnnneeccttiioonnss
+
+ How to let clients connect to your IRCD.
+
+ IInnttrroodduuccttiioonn
+ A client is a program that connects to the ircd daemon (ircd).
+ There are clients written in C, GNU Emacs Lisp and many other
+ languages. The ``irc'' program is the C client. Each person
+ that talks via IRC is running their own client.
+
+ The ircd.conf files contains entries that specify which clients
+ are allowed to connect to your irc daemon. Obviously you want
+ to allow your own 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.
+
+ FFoorrmmaatt
+
+ I:<TARGET Host Addr>:<Password>:<TARGET Hosts NAME>:<Port>:<Class>
+ i:<TARGET Host Addr>:<Password>:<TARGET Hosts NAME>:<Port>:<Class>
+
+
+
+ TTAARRGGEETT HHoosstt AAddddrr
+ Specifies the IP address(es) of the machine(s) that are allowed
+ to connect. If ``user@'' prefixes the actual IP address the
+ server will require that the remote username returned by the
+ ident server be the same as the one given before the ``@''.
+ Wildcards are permitted unless using a bitmask (e.g.
+ 1.2.3.0/24).
+
+ PPaasssswwoorrdd
+ The password that must be given by the client to be allowed on
+ the server.
+
+ TTAARRGGEETT HHoosstt NNAAMMEE
+ Specifies the host name(s) of the machines allowed to connect to
+ the server. If ``user@'' prefixes the actual IP address the
+ server will require that the remote username returned by the
+ ident server be the same as the one given before the ``@''.
+ Wildcards are permitted.
+
+ This field can be empty, it then has a special meaning. See
+ Below.
+
+ PPoorrtt
+ Specifies the port number for which this configuration line is
+ valid. An empty field, or ``0'' matches all ports.
+
+ CCllaassss
+ This field should refer to an existing class. Connections
+ classes are usefull to limit the number of users allowed on the
+ server.
+
+ NNoottee
+ The server first checks if the client hostname (or any aliases)
+ matches the TTAARRGGEETT HHoosstt NNAAMMEE field. If a match is found, the
+ client is accepted. If not, the server checks if the IP address
+ of the client matches the TTAARRGGEETT HHoosstt AAddddrr field. The matching
+ field is used to set the name of the client: for example, if the
+ client matches the TTAARRGGEETT HHoosstt AAddddrr field, it will show on IRC
+ with a numerical address (even if this address is resolvable).
+ If the TTAARRGGEETT HHoosstt NNAAMMEE field is empty, then the host name is
+ always used (when available).
+
+ EExxaammpplleess
+ 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:x::tolsun.oulu.fi::1
+ If you wanted to let remote clients connect, you could add the
+ following lines:
+
+ I:x::*.du.edu::1
+
+ Allow any clients from machines whose names end in ``.du.edu''
+ to connect with no password.
+
+ I:128.214.6.100::nic.funet.fi::1
+
+ Allow clients from a machine with that IP number to connect.
+ Numeric match is enough, name is not required anymore.
+
+ I:x:secret:*.tut.fi::1
+
+ Allow clients from machines matching ``*.tut.fi'' to connect
+ with the password ``secret''.
+
+ I:*::*::1
+
+ 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).
+
+ I:x::*.fi:6667:1
+
+ Allow clients from machines matching ``*.fi'' to connect on the
+ port 6667.
+
+ I:135.11.35.*::*.net::1
+
+ Allows clients from machines which host name matches ``*.net''
+ or which IP address matches ``135.11.35.*'' to connect to the
+ server. If the host name does not match ``*.net'' then the IP
+ address is used for these clients, even if the host name is
+ known.
+
+ I:135.11.35.*::::1
+
+ Allows clients from machines which IP address matches
+ ``135.11.35.*'' to connect to the server. If the host name is
+ known, is it used as address for these clients.
+
+ NNEEWW!!!!!!
+ 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).
+
+ NNEEWW!!!!!!
+ As of the 2.9.1 version of the server, i lines are introduced.
+ They work the same way as I lines, but the clients matching an i
+ line will have a restricted connection. (no nick/mode change, no
+ kick). Such users will have their username prefixed by +, = or -
+ depending on the ident reply.
+
+ 44..66.. OOppeerraattoorr pprriivviilliiggeess
+
+ How to become the IRC administrator on your site
+
+ IInnttrroodduuccttiioonn
+ To become an IRC Administrator, IRC must know who is authorized
+ to become an operator and what their ``Nickname'' and
+ ``Password'' is.
+
+ FFoorrmmaatt
+
+ O:<TARGET Host NAME>:<Password>:<Nickname>:<Port>:<Class>
+
+
+
+ OO 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.
+
+ TTAARRGGEETT HHoosstt NNAAMMEE
+ 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.
+
+ PPaasssswwoorrdd
+ 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 ``ircd.conf'' file protected from
+ all of the other users.
+
+ NNiicckknnaammee
+ The Nickname you usually go by - but you can make this what you
+ want.
+
+ PPoorrtt
+ Unused.
+
+ CCllaassss
+ 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.
+
+ EExxaammppllee
+ O:orion.cair.du.edu:pyunxc:Jeff::1
+
+ 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''.
+
+
+ 44..77.. RReessttrriicctt ccoonnnneeccttiioonnss
+
+ Let an external program decide if a client should be allowed or not.
+
+ IInnttrroodduuccttiioonn
+ R lines provide a convenient way to handle user access to the
+ server with an external program. The outside program given
+ three parameters: the client's username (set by the USER
+ command), the client's hostname, and the client's ident reply
+ (``unknown'' if none).
+
+ It is expected to return a reply line where the first word is
+ either ``Y'' or ``N'' meaning `Yes Let them in'' or ``No don't
+ let them in''. If the first word begins with neither ``Y'' or
+ ``N'' the default is to let the person on.
+
+ FFoorrmmaatt
+
+ R:<Target Host Name>:<Program>:<User>:::
+
+
+
+ RR This specifies a restrict record.
+
+ TTaarrggeett HHoosstt NNaammee
+ In this field you specify the Hostname that the user is
+ connecting from. If you wanted to restrict connects to IRC from
+ ``orion.cair.du.edu'' then you would want to enter
+ ``orion.cair.du.edu''.
+
+ PPrrooggrraamm
+ This is the external program to run to know if the user is
+ allowed on your server.
+
+ UUsseerr
+ The Username of the user you want removed from IRC. For example
+ ``root''.
+
+
+ 44..88.. EExxcclluuddeedd aaccccoouunnttss
+
+ Remove an errant user from IRC on your site.
+
+ IInnttrroodduuccttiioonn
+ 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.
+
+ FFoorrmmaatt
+
+ K:<Host Name>:<time interval(s)|comment>:<User>:<port>:
+
+
+
+ FFoorrmmaatt
+
+ k:<Host Name>:<time interval(s)|comment>:<Auth>:<port>:
+
+
+
+ KK ``K'' tells the IRCD that you are making a KILL USER command
+ entry.
+
+ HHoosstt NNaammee
+ In this field you specify the Hostname or the IP address (Single
+ IP, Wildcard notation or bitmask notation) 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 ?
+
+ If you specify an IP address, IP mask, or an IP bitmask, it will
+ match clients connecting from the matching addresses, no matter
+ if they resolve or not.
+
+ You can prefix an IP address, an IP mask, or IP bitmask by ``=''
+ in which case only non resolving matching hosts will be banned.
+
+ ttiimmee iinntteerrvvaall((ss))||ccoommmmeenntt
+ Either leave this field empty or put a comment, then the line
+ active continuously for the specified user/host machine. You
+ may also specify intervals during the line should be active, see
+ examples below.
+
+ UUsseerr
+ The USERNAME of the user you want removed from IRC. For example
+ ``root''.
+
+ AAuutthh
+ If the user's ident server replies with the OTHER type (as
+ opposed to the UNIX type), the reply is not used to set the
+ user's username. (lowercase) k lines can be used in these case
+ to reject users based on their ident reply.
+
+ This field will be matched against the ident server reply. It
+ is important to note that OTHER replies are prefixed with a
+ ``-'' by the ircd, while UNIX replies are not.
+
+ PPoorrtt
+ The port on which the Kill line will be effective. 0 means all
+ ports.
+
+ EExxaammpplleess
+ K:orion.cair.du.edu::jtrim:0:
+
+
+ If user ``jtrim'' connects to IRC from host
+ ``orion.cair.du.edu'' then IMMEDIATELY REMOVE HIM from my IRCD.
+
+ k:*.stealth.net::-43589:0:
+
+ If a user connects from any host that has the suffix
+ ``stealth.net'' and if that host ident server returns ``-43589''
+ - then IMMEDIATELY REMOVE THEM from my IRCD.
+
+ K:*.cair.du.edu::root:0:
+
+ 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:0:
+
+ 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:*:0:
+
+ 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 before).
+ K:192.11.35.*::*:0:
+
+ This line disallows all hosts whose IP address matches
+ ``192.11.35.*'' to login to the ircd.
+
+ K:=192.11.35.*::*:0:
+
+ This line disallows all hosts whose IP address matches
+ ``192.11.35.*'' and which didn't resolve to login to the ircd.
+
+
+ 44..99.. SSeerrvveerr ccoonnnneeccttiioonnss
+
+ How to connect to other servers, How other servers can connect to you
+
+ WWAARRNNIINNGG:: 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:
+
+ +o ``garfield.mit.edu'' - Tertiary Connection
+
+ +o ``irc.nada.kth.se'' - Secondary Connection
+
+ +o ``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:
+
+ 1. to save your server from causing extra load and delays to users
+
+ 2. to save internet from extra network traffic (remember the old rwho
+ program with traffic problems when the number of machines
+ increased).
+
+
+ FFoorrmmaatt
+
+ C:<TARGET Host Addr>:<Password>:<TARGET Host NAME>:<TARGET PORT>:<Class>
+
+
+
+ for example:
+
+ C:nic.funet.fi:passwd:nic.funet.fi:6667:1
+
+ - or -
+
+ C:128.214.6.100:passwd:nic.funet.fi:6667:1
+
+ - or -
+
+ C:root@nic.funet.fi:passwd:nic.funet.fi:6667:1
+
+ Each field is separated with a ":" charcter:
+
+ CC This field tells the IRC program which option is being
+ configured. "C" corresponds to a server Connect option.
+
+ TTAARRGGEETT HHoosstt AAddddrr
+ 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 ``@''.
+
+ PPaasssswwoorrdd
+ The password of the other host. A password must always be
+ present for the line to be recognized.
+
+ TTAARRGGEETT HHoosstt NNAAMMEE
+ 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.
+
+ TTAARRGGEETT PPOORRTT
+ 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. The port field can contain 2 ports,
+ separated by a . In this case, the first port is used when auto-
+ connecting, the second port is used for the UDP pings to the
+ targer server.
+
+ CCllaassss
+ The class field should refer to an existing class and determines
+ the maximum number of simultaneous uses of the C-line allowable
+ through the max. links field in the Y-line.
+
+ NNEEWW!!!!!!
+ As of the 2.9.3 version of the server, server connections can be
+ compressed with the zlib library. To define a compressed
+ connection, you must have compiled the server with ZIP_LINKS
+ defined (cf 2.h), and use a _lowercase_ C line.
+
+ Some examples:
+
+ +o C:nic.funet.fi::nic.funet.fi:6667:1
+
+ 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.
+
+ +o C:18.72.0.252:Jeff:garfield.mit.edu:6667:1
+
+ 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.
+
+ +o C:irc.nada.kth.se::irc.nada.kth.se:1
+
+ This reads: do not attempt to connect to ``irc.nada.kth.se'', 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 rreevveerrssee 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:1
+ C:irc.nada.kth.se::irc.nada.kth.se:6667:1
+ C:nic.funet.fi::nic.funet.fi:6667:1
+
+ Ircd will attempt to connect to nic.funet.fi first, then to irc.nada
+ and finally to garfield.
+
+ RReecciipprrooccaall eennttrriieess:: 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.
+
+
+
+ FFoorrmmaatt
+ The format for the NOCONNECT entry in the ``ircd.conf'' is:
+
+ N:<TARGET Host Addr>:<Password>:<TARGET Host NAME>:<Domain Mask>:<Class>
+
+
+
+ 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''.
+
+ NN ``N'' corresponds to a server Noconnect option.
+
+ TTAARRGGEETT HHoosstt AAddddrr
+ 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 ``@''.
+
+ PPaasssswwoorrdd
+ The password of the other host. A password must always be
+ present for the line to be recognized. If CRYPT_LINK_PASSWORD is
+ defined in config.h, this password must be crypted.
+
+ TTAARRGGEETT HHoosstt NNAAMMEE
+ 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.
+
+ DDoommaaiinn MMaasskk
+ Domain masking, see below.
+
+
+ CCllaassss
+ The class field should refer to an existing class.
+
+ WWiillddccaarrddss ddoommaaiinnss
+ 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 ``Domain Mask'' 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 ccoolllliissiioonn (*.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.
+
+
+
+ 44..1100.. DDeennyy aauuttoo--ccoonnnneeccttiioonnss
+
+
+ IInnttrroodduuccttiioonn
+ D lines were implemented to give server administrators more
+ control on how auto connections are done. This will most likely
+ only be useful for big networks which have complex
+ configurations.
+
+ FFoorrmmaatt
+
+ D:<Denied Server Mask>:Denied Class:<Server Name>:Server Class:
+
+
+
+ DDeenniieedd SSeerrvveerr MMaasskk
+ This field is matched against all servers currently present on
+ the network.
+
+ DDeenniieedd CCllaassss
+ If this field contains a class number, it will match if any
+ server in that class is currently present on the network. Note
+ that this can be true for any server, even the ones not directly
+ connected.
+
+
+ SSeerrvveerr MMaasskk
+ This field is matched against the server name that the server
+ wants to auto connect to.
+
+ SSeerrvveerr CCllaassss
+ This field is used to match against the class to which belong
+ the servers for which an autoconnect is set.
+
+ EExxaammpplleess
+ D:*.edu::*.fi::
+
+ Don't auto-connect to any ``*.fi'' server if any server present
+ on the network matches ``*.edu''.
+
+ D::2:eff.org:3:
+
+ Do now auto-connect to ``eff.org'', or any server in class ``3''
+ if a server defined to be in class ``2'' is currently present on
+ the network.
+
+
+ 44..1111.. HHuubb ccoonnnneeccttiioonnss
+
+
+ IInnttrroodduuccttiioonn
+ 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.
+
+ FFoorrmmaatt
+
+ H:<Server Mask>:*:<Server Name>::
+
+
+
+ SSeerrvveerr MMaasskk
+ All servers that are allowed via this H-line must match the mask
+ given in this field.
+
+ SSeerrvveerr NNaammee
+ This field is used to match exactly against a server name,
+ wildcards being treated as literal characters.
+
+ EExxaammpplleess
+ H:*.edu::*.bu.edu::
+
+ Allows a server named ``*.bu.edu'' to introduce only servers
+ that match the ``*.edu'' name mask.
+
+ H:*::eff.org::
+
+ Allows ``eff.org'' to introduce (and act as a hub for) any
+ server.
+
+ NNoottee
+ 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::
+
+
+
+
+ 44..1122.. LLeeaaff ccoonnnneeccttiioonnss
+
+
+ IInnttrroodduuccttiioonn
+ 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.
+
+ FFoorrmmaatt
+
+ L:<Server Mask>:*:<Server Name>:<Max Depth>:
+
+
+
+ SSeerrvveerr MMaasskk
+ 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).
+
+ SSeerrvveerr NNaammee
+ The name of the server connected to you that for which you want
+ to enforce leaf-like attributes upon.
+
+ MMaaxx DDeepptthh
+ 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.
+
+
+ 44..1133.. VVeerrssiioonn lliimmiittaattiioonnss
+
+
+ IInnttrroodduuccttiioonn
+ V-lines are used to restrict server connecting to you based on
+ their version and on compile time options.
+
+ FFoorrmmaatt
+
+
+ V:<Version Mask>:<Flags>:<Server Mask>::
+
+
+
+ VVeerrssiioonn MMaasskk
+ The matching version number strings will be rejected.
+
+ FFllaaggss
+ If any flag specified in this field is found in the peer's flags
+ string, it will be rejected.
+
+ SSeerrvveerr MMaasskk
+ This field is used to match server names. The V line will be
+ used for servers matching the mask given in this field.
+
+ SSeerrvveerr TTyyppee
+ Both the VVeerrssiioonn MMaasskk and the FFllaaggss should be prefixed with the
+ server type identification. This implementation uses the id
+ ``IIRRCC'' (starting with version 2.10).
+
+ EExxaammpplleess
+ V:IRC/021001*::*::
+
+ Disallows any ``IRC'' server which version is 2.10.1* to
+ connect.
+
+ V:IRC/021001*:IRC/D:*::
+
+ Disallows any ``IRC'' server which version is 2.10.1* or which
+ has been compiled with DEBUGMODE defined to connect.
+
+ V:*/0209*::::
+
+ Disallows any server using the 2.9 protocol to connect.
+
+ NNoottee
+ It is possible to have and use multiple V-lines for the one
+ server mask.
+
+ V:IRC/021001*::*::
+
+ V:IRC/021002*::*::
+
+ is allowed.
+
+ PPrroottooccooll VVeerrssiioonn
+ Only the 4 first digit of the VVeerrssiioonn NNuummbbeerr are standard: they
+ define the protocol version. The remaining of the string is
+ implementation dependant; matches on this part should be used
+ with particular identification.
+
+ FFllaaggss
+ are not standard. Therefore, this field sshhoouulldd aallwwaayyss contain a
+ specific identification.
+
+
+ 44..1144.. EExxcclluuddeedd mmaacchhiinneess
+
+ Disallowing SERVERS in your irc net.
+
+ IInnttrroodduuccttiioonn
+ 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 yyoouurr
+ sseerrvveerr disconnects the link. Note that just placing Q-lines to
+ your server probably results in yyoouurr sseerrvveerr being left alone,
+ unless other servers have agreed to have the same Q-line in
+ their ircd configuration files as well.
+
+ EExxaammppllee
+ 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.
+
+
+ 44..1155.. SSeerrvviiccee ccoonnnneeccttiioonnss
+
+
+ IInnttrroodduuccttiioonn
+ 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 are not intended for interactive usage, and are better
+ suited for automated clients.
+
+ FFoorrmmaatt
+
+ S:<TARGET Host Mask>:<Password>:<Service Name>:<Service Type>:<Class>
+
+
+
+ TTAARRGGEETT HHoosstt MMaasskk
+ The host mask should be set to match the host(s) from which the
+ service will be connecting from. This may be either an IP# or
+ full name (prefered).
+
+ PPaasssswwoorrdd
+ This is the password which must be passed in the SERVICE
+ command.
+
+ SSeerrvviiccee NNaammee
+ The name used by the service. Services don't have nicknames, but
+ a static name defined by the S line.
+
+ SSeerrvviiccee TTyyppee
+ The type of service. It defines the priviledges given to the
+ service. Be very careful in the types you allow. The types can
+ be found in include/service.h
+
+ CCllaassss
+ The class field should refer to an existing class.
+
+ NNootteess
+ 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 are rejected upon sending an unknown or
+ unallowed command. Services however, are not affected by flood
+ control and can be granted special privileges. It is therefore
+ wwiissee ttoo oovveerrsseeee tthhee uussee ooff SS--lliinneess wwiitthh mmuucchh ccaarree..
+
+
+
+
+ 44..1166.. BBoouunnccee sseerrvveerr
+
+
+ IInnttrroodduuccttiioonn
+ This provides you a way to bounce clients to another server.
+ This information is provided to clients which are denied
+ connection, either because their connection class is full, or
+ the server is full, or they are not authorized to connect.
+
+ FFoorrmmaatt
+
+ B:<Class|Host Mask>::<Server Name>:<Port>:
+
+
+
+ BB This specifies a Bounce record.
+
+ CCllaassss||HHoosstt MMaasskk
+ This field specifies to which client this configuration line
+ applies to. It can be either a connection class number, a host
+ mask to be matched against the client's hostname, or an IP
+ address/mask/bitmask to be matched against the client's IP
+ address.
+
+ When the server is completely full, it rejects clients with the
+ ``All connections in use'' message. In this case, the server
+ doesn't process the connections at all, and has no knowledge of
+ the client's host name, or class number. For these cases, this
+ field must be empty.
+
+ SSeerrvveerr NNaammee
+ This specifies the IRC server hostname that the client should
+ use.
+
+ PPoorrtt
+ This specifies the IRC server port that the client should
+ connect to.
+
+ EExxaammppllee
+ B:2::irc.stealth.net:6660:
+
+ Rejected clients in class 2 are advised to use
+ ``irc.stealth.net'' on port 6660.
+
+ B:*.fi::irc.funet.fi:6667:
+
+ Finnish client should use irc.funet.fi when they cannot be taken
+ anymore.
+
+ B:::irc2.stealth.net:6667:
+
+ When the server is completely full, clients should use the
+ secondary server.
+
+
+ 44..1177.. DDeeffaauulltt llooccaall sseerrvveerr ((ffoorr llooccaall cclliieennttss)) **OOBBSSOOLLEETTEEDD**
+
+
+ IInnttrroodduuccttiioonn
+ 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).
+
+
+ FFoorrmmaatt
+
+ U:<TARGET Host addr>:<Password>:<TARGET Host NAME>:<Internet Port>
+
+
+
+ EExxaammpplleess
+ 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.
+
+
+ 55.. RReellaatteedd rreessoouurrcceess
+
+
+ MMaaiilliinngg lliisstt
+ A list is dedicated to the people using ircd. If you have
+ trouble running ircd, or wish to discuss the future, you can
+ subscribe by sending an email to majordomo@irc.org, with
+ ``ssuubbssccrriibbee iirrccdd--uusseerrss'' in the body.
+
+ If you just have a question and don't want to subscribe to the
+ list, mail to ircd-users@irc.org. Be sure to indicate which
+ version you are using.
+
+ DDeevveellooppmmeenntt
+ Technical discussions and development are carried on ircd-
+ dev@irc.org. People interested in very early testing, and/or
+ working on the source code are welcome. This is done by sending
+ an email to majordomo@irc.org, with ``ssuubbssccrriibbee iirrccdd--ddeevv'' in
+ the body.
+
+ FFAAQQ
+ It can be found on the WWW, at
+ <http://www.stealth.net/~kalt/irc/faq.html>.
+
+ WWWWWW 22..99
+ Vesa Ruokonen has also put serveral pages related to the 2.9
+ servers on the WWW: <http://www.irc.org/~irc/server/>.
+
+
+ 66.. RReeppoorrttiinngg aa bbuugg
+
+ If you encounter a bug in the software, here is how and where to
+ report it.
+
+
+ 66..11.. HHooww ttoo rreeppoorrtt aa bbuugg
+
+ To save everyone time, make sure that your e-mail contains all the
+ information related to your problem. In particular, we need to know:
+
+ PPaacckkaaggee vveerrssiioonn
+ The IRC software version you are using: please include the
+ output obtained by running ``irc -v'' for the client, and/or
+ ``ircd -v'' for the server.
+
+ Also, let us know if you have applied any patch to the package
+ or if it is the vanilla version.
+
+ OOSS Please, indicate which OS version you are running.
+
+ CCoonnffiigguurraattiioonn
+ If it is related to a configuration problem with the server,
+ include the relevant parts of the configuration file.
+
+ BBaacckkttrraaccee
+ If the bug results in a crash, please include the backtrace.
+ (This can be done, for example, by running ``gdb'' on the core
+ file, and typing ``where'').
+
+ FFiixx
+ If you have a fix, don't forget to include it.
+
+
+ 66..22.. WWhheerree ttoo sseenndd aa bbuugg rreeppoorrtt
+
+ Reports should be sent to ircd-bugs@irc.org. Your report will be
+ reviewed and forwarded to the appropriate mailing list.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/doc/Juped/Advertisement b/doc/Juped/Advertisement
new file mode 100644
index 0000000..585c467
--- /dev/null
+++ b/doc/Juped/Advertisement
@@ -0,0 +1,39 @@
+ The Internet Relay Chat Program - IRC
+
+ Author: Jeff Trim, April '89
+ Revised: Greg Lindahl, Oct '90 (gl8f@virginia.edu)
+ Re-Revised: Helen Rose, March '94 (hrose@kei.com)
+
+Have you ever wanted to talk with computer users in other parts of the
+world? Well guess what? You can! The network is called IRC and it is
+networked much over North America, Europe, and Asia, Oceania, and parts of
+Africa. This program is a substitution for talk(1), ytalk(1) and many
+other multiple talk programs you might have read about. When you are
+talking in IRC, everything you type will instantly be transmitted around
+the world to other users that might be watching their terminals at the
+time - they can then type something and RESPOND to your messages - and
+vise versa. I should warn you that the program can be very addictive once
+you begin to make friends and contacts on IRC ;-) especially when you
+learn how to cuss in 14 languages.
+
+Topics of discussion on IRC are varied, just like the topics of Usenet
+newsgroups are varied. Technical and political discussions are popular,
+especially when world events are in progress. IRC is also a way to expand
+your horizons, as people from many countries and cultures are on, 24 hours
+a day. Most conversations are in English, but there are always places to
+chat in German, Japanese, and Finnish, and occasionally other languages.
+
+ How To Get IRC (technical)
+
+IRC is a fully-distributed client-server system, much like
+NNTP-Usenet, with several clients availble in C and elisp. You may ftp
+documentation and clients from any of the following sites:
+
+many kinds of clients (C, elisp, X11, VMS, REXX for VM, MSDOS, Macintosh):
+cs.bu.edu:/irc/clients
+ftp.acsu.buffalo.edu:/pub/irc
+ftp.funet.fi:/pub/unix/irc
+coombs.anu.edu.au:/pub/irc
+
+If you have any questions about IRC installation, write to hrose@kei.com.
+
diff --git a/doc/Juped/ChangeLog.common b/doc/Juped/ChangeLog.common
new file mode 100644
index 0000000..f6b10ae
--- /dev/null
+++ b/doc/Juped/ChangeLog.common
@@ -0,0 +1,91 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, lib/ircd/ChangeLog
+ * Copyright (C) 1990 Mike Bolotski
+ *
+ * This program is free software; you can 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.
+ */
+
+Mon Sep 02 17:08:43 1991 Darren Reed <avalon@coombs.anu.edu.au>
+
+ * general comments:
+
+ various files now have dependencies depending on whether it is the
+ client or server the files are being compiled for.
+
+ * parse.c
+
+ find_*() routines changed to use hash table lookup.
+
+ * send.c
+
+ changed to maximize presence of the local client array.
+ sendto_ops_butone() fixed back to not broadcast wallops.
+
+Sun Jun 30 23:21:50 1991 Armin Gruner <gruner@informatik.tu-muenchen.de>
+
+ * parse.c
+ Changed from->name to sender; Maybe double search can be removed
+
+ * send.c
+ LOOP detected!!
+ Fixed sendto_channel_butone() as suggested by msa.
+ send.c needs TOTAL cleanup.
+
+ * bsd.c
+ Final fixes of inet_netof() and inet_nota()
+
+ * send.c
+ Changed some SendMessage() into sendto_one() (code duplication ;))
+
+Wed Jun 20 11:25:54 1990 Jarkko Oikarinen (jto@tolsun.oulu.fi)
+
+ Added gruner's patches.
+ Patches to make string channels work done as well to some files.
+
+Sun Jun 17 21:29:04 1990 Armin Gruner (gruner@informatik.tu-muenchen.de)
+
+ * parse.c
+ In case that a server sends an unknown command to a client (!!),
+ debug() is called, as client handles debug outputs now.
+
+Thu May 10 17:15:12 1990 Jarkko Oikarinen (jto@tolsun.oulu.fi)
+
+ * dbuf.c
+ Fixed memcpy and bcopy problems in different machines
+
+Sat Jan 6 15:14:14 1990 Mike Bolotski (mikeb at coho.ee.ubc.ca)
+
+ * config.h
+ Added Poohbear's cleanup changes.
+ Added #undef SYSV if mips is defined (as per jlp@hamblin.byu.edu)
+
+
+Sat Dec 16 16:06:17 1989 Mike Bolotski (mikeb at coho.ee.ubc.ca)
+
+ * config.h
+
+ Changed NOTTY to TTYON, and reversed the logic everywhere.
+ Now TTYON has to be explicitly defined in order to produce
+ tty output.
+
+
+Thu Dec 14 12:50:36 1989 Mike Bolotski (mikeb at coho.ee.ubc.ca)
+
+ * version.c
+ Added a version.c file to contain the version numbers and
+ prompt strings. Removed the old #ifdef MAIN style definition
+
+
+
diff --git a/doc/Juped/ChangeLog.doc b/doc/Juped/ChangeLog.doc
new file mode 100644
index 0000000..538d791
--- /dev/null
+++ b/doc/Juped/ChangeLog.doc
@@ -0,0 +1,90 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, doc/ChangeLog
+ * Copyright (C) 1990, Mike Bolotski
+ *
+ * This program is free software; you can 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.
+ */
+
+
+Tue Mar 22 17:32:33 1994 Helen T. Rose Davis (hrose@rocza.kei.com)
+
+ * Re-rewrite of documentation to coincide with 2.8.17 release.
+
+Mon Mar 29 01:26:16 1993
+
+ * INTSALL updated.
+ * m4macros added.
+
+Fri Jan 22 22:49:20 1993
+
+ * INTSALL updated.
+
+Thu Dec 17 19:41:19 1992 Darren Reed <avalon@coombs.anu.edu.au>
+
+ * general Well, these docs were updated for 2.7, nobody
+ documented it - must be a general distaste for
+ documentation I'd say :)
+
+ Work on 2.8 documentation slowly creaping along.
+
+Mon Sep 02 17:12:41 1991 Darren Reed <avalon@coombs.anu.edu.au>
+
+ * Documentation brought upto date with new features to 2.6.2
+
+
+Mon Aug 26 16:51:01 1991 Helen Trillian Rose (hrose@eff.org)
+
+ * Rewrite of documentation (again) to coincide with the 2.6.2
+ release.
+
+Wed Oct 31 18:05:12 1990 Jarkko Oikarinen
+
+ * Added hrose@cs.bu.edu's patches to irc2.6
+ - Documentation rewrites...
+ - patches
+
+Fri Jun 29 18:54:40 1990 Armin Gruner (gruner@informatik.tu-muenchen.de)
+
+ * NETWORKING
+
+ Added some sites in Germany
+
+Sat Dec 16 15:56:41 1989 Mike Bolotski (mikeb at coho.ee.ubc.ca)
+
+ * INSTALL
+
+ Modified the installation document as per Valdis's nitpicking.
+ Improved the grammer and speling of a lot of dokumentation.
+ Removed lots and lots of informal wording, eh? and especially
+ the long run on sentences that try to say a lot but really don't
+ and are present only to show the author's superiority, especially
+ when quoting from a prestigious work like Webster's New Collegiate
+ Dictionary, gosh, specifically the 1979 version (ISBN
+ 0-87779-3580-1), which I guess I should run out and purchase
+ immediately, for otherwise I might be considered ignorant by
+ wise men who have written a great deal of code in VS/Pascal and
+ even IBM Assembler and still can't manage not to avoid including
+ .QUIT in every goddam mail message.
+
+
+ * HISTORY
+
+ Added a recent history of the version numbers and the new
+ patchlevel mechanism.
+
+
+ * BugList
+
+ Added a BugList file including the notation of bug numbers.
diff --git a/doc/Juped/ChangeLog.include b/doc/Juped/ChangeLog.include
new file mode 100644
index 0000000..481b39b
--- /dev/null
+++ b/doc/Juped/ChangeLog.include
@@ -0,0 +1,85 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/ChangeLog
+ * 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.
+ */
+
+Sat Jul 25 05:52:43 1992
+ * common.h Dynix (sequent) doesnt have malloc.h but it appears
+ Dynix/PTX does. Blah.
+
+Fri Jul 24 18:43:35 1992
+ * config.h, sys.h, common.h
+ Applied patches from Adrian Hall for compiling on
+ Dynix/PTX (email: csc260@central1.lancaster.ac.uk).
+
+Mon Sep 02 17:06:59 1991 Darren Reed <avalon@coombs.anu.edu.au>
+
+ * config.h
+ added MAXCONNECTIONS (see config.h for details)
+ added NICKNAMEHISTORYLENGTH
+
+ * hash.h
+ Added to support for ../ircd/hash.c
+
+ * msg.h
+ Commands reordered in (hopefully) order of useage.
+ All commands now marked for flood protection.
+
+Tue Jul 02 11:10:26 1991 Armin Gruner <gruner@informatik.tu-muenchen.de>
+
+ * config.h
+ changed MSG_MAIL to MSG_NOTE as requested by the author.
+
+Mon Jul 01 20:37:38 1991 Armin Gruner <gruner@informatik.tu-muenchen.de>
+
+ * config.h
+ #define WALL a priori. WALL should be go away in future version.
+
+ * numeric.h
+ ERR_TOOMANYTARGETS added.
+
+Mon Dec 03 13:56:36 1990 Armin Gruner <gruner@informatik.tu-muenchen.de>
+
+ * config.h
+ Switches for NEED_* added.
+
+Mon Nov 26 10:33:43 1990 Armin Gruner <gruner@informatik.tu-muenchen.de>
+
+ * sys.h[.SH]
+ declaration of dummy() and restart() depending on configuration
+ process.
+
+Sat Nov 10 18:00:44 1990 Armin Gruner <gruner@informatik.tu-muenchen.de>
+
+ * New header file: common.h, should be included into all source
+ files. Created sys.h.SH, Makefile.SH, config.h.SH; these files
+ are extracted by running Configure.
+
+ * Added some function declarations
+ Removed Makefile (do we need one here ?).
+
+Wed Jun 20 11:44:00 1990 Jarkko Oikarinen (jto@tolsun.oulu.fi)
+
+ * config.h
+ MAIL changes to config.h
+ * struct.h
+ Numerous changes to file to make string channels work
+
+Thu May 10 22:37:23 1990 Jarkko Oikarinen (jto@tolsun.oulu.fi)
+
+ * config.h
+ Added UPHOST into config.h (Who removed it ?)
diff --git a/doc/Juped/ChangeLog.irc b/doc/Juped/ChangeLog.irc
new file mode 100644
index 0000000..18a86b7
--- /dev/null
+++ b/doc/Juped/ChangeLog.irc
@@ -0,0 +1,77 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/ChangeLog
+ * Copyright (C) 1990 Mike Bolotski
+ *
+ * This program is free software; you can 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.
+ */
+
+Mon Dec 9 06:38:57 1991 Darren Reed <avalon@coombs.anu.edu.au>
+ * All files
+ Updated to work properly with 2.7. Its early and I'm cold.
+
+Sun Jun 30 14:45:59 1991 Armin Gruner <gruner@informatik.tu-muenchen.de>
+
+ * irc.c
+ Removed MSG protocol command. Kludge to get channel msgs working.
+ * msg.c
+ Reformatted WHOERPLY output :)
+
+Wed Nov 28 20:45:42 1990 Armin Gruner <gruner@informatik.tu-muenchen.de>
+
+ * c_msg.c
+ Fixed abuf[123] overflow. (by using mybuf and removing the buffers)
+
+Sat Nov 10 17:59:29 1990 Armin Gruner <gruner@informatik.tu-muenchen.de>
+
+ * Added #include "common.h" into all source files, moved "common"
+ and regularly used declarations to include/common.h
+
+Wed Jun 20 11:45:30 1990 Jarkko Oikarinen (jto@tolsun.oulu.fi)
+
+ String channel fixes to files, added some numerics.
+
+Sun Jun 17 17:12:14 1990 Armin Gruner (gruner@informatik.tu-muenchen.de)
+
+ * c_debug.c
+ New created file, for the benefit of wrong server stuff output
+ if client does not recognize it. common/debug.c has been removed.
+
+ * c_numeric.c
+ Changed output of YOUWILLBEBANNED and YOUREBANNEDCREEP, now only
+ the first digits (== minutes) of the msg will be inserted.
+
+ * irc.c
+ Defined debuglevel to DEBUG_ERROR, now more error
+ conditions are displayed.
+
+
+Sat Jan 6 14:48:34 1990 Mike Bolotski (mikeb at coho.ee.ubc.ca)
+
+ * screen.c
+
+ Changed insert = ~insert to be insert = !insert.
+ Gotta be careful about those bitwise operators, WiZ.
+
+ * swear.c
+
+ Changed scroll to scroll_ok. Changed extern/static definitions
+ of tgoto, getenv to work with ANSI C compilers.
+
+ * edit.c
+
+ Changed #if HPUX to #if HPUX || defined(mips)
+
+
+
diff --git a/doc/Juped/ChangeLog.ircd b/doc/Juped/ChangeLog.ircd
new file mode 100644
index 0000000..228ce0d
--- /dev/null
+++ b/doc/Juped/ChangeLog.ircd
@@ -0,0 +1,458 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/ChangeLog
+ * Copyright (C) 1990 Mike Bolotski
+ *
+ * This program is free software; you can 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.
+ */
+
+Tue Sep 1 20:16:42 1992
+ * s_bsd.c, s_bsd.c, s_serv.c
+ * TRACE/STATS now show logfiles if logging is enabled.
+
+Tue Sep 1 03:56:21 1992
+ * channel.c * bug found in set_mode() - length of strings when
+ setting/clearing chanop was possibly incorrect.
+ * a few optimizations have hopefully been added as
+ well.
+
+ * s_bsd.c, s_auth.c
+ * RFC913 (authd) / TAP code separated from s_bsd,c to
+ s_auth.c
+
+ * s_misc.c, s_debug.c
+ * various code/routines removed from s_misc.c and put
+ in s_debug.c where it truely belongs.
+
+Tue Aug 25 16:07:01 1992
+ * ircd.c * chroot(2) option from Seth added to work along
+ with SET_UID & SET_GID for servers running as
+ root. (seth@ctr.columbia.edu)
+
+Thu Aug 13 18:46:53 1992
+ * channel.c * Bug in send_channel_modes() fixed which causes
+ trashed +b's to be sent on server rejoins.
+
+Thu Aug 13 17:40:47 1992
+ * channel.c * Added channel passwords (keys).
+
+Tue Aug 11 14:05:12 1992
+ * channel.c * JOIN bug giving chanop on wrong channels fixed.
+ Reported by Rogue_F.
+
+Tue Aug 4 04:38:23 1992
+ * s_bsd.c, s_serv.c, s_conf.c
+ * Username authentication for servers completed.
+ Username now required in host portion of the
+ C/N lines for a connection to be completed.
+
+Tue Aug 4 03:45:54 1992
+ * IDENT changes finally debugged.
+
+Tue Aug 4 02:16:42 1992
+ * s_bsd.c, s_user.c, s_serv.c, ircd.c
+ * IDENT code now written such that it works in a
+ similar manner to the DNS async code and thus should
+ stop the server hanging (if at all).
+
+ * authuser.c * Removed. (redundant).
+
+Fri Jul 31 01:05:57 1992
+ * s_user.c * m_whois() changes to stop people abusing /whois *
+ and kiling other links to/from that server.
+
+Sat Jul 25 07:33:20 1992
+ * s_user.c * m_oper() fixed so it doesnt core dump when it
+ calls send_umode(). send_umode_toservs() added.
+
+Sat Jul 25 05:51:01 1992
+ * s_bsd.c * Patches for little endian systems (ie sequents :)
+ completed. (Fixing of RPL_MYPORTIS)
+
+Fri Jul 24 18:43:35 1992
+ * s_bsd.c, s_conf.c, ircd.c, s_misc.c
+ * Applied patches from Adrian Hall for compiling on
+ Dynix/PTX (email: csc260@central1.lancaster.ac.uk).
+
+Fri Jul 24 00:07:41 1992
+ Its been busy with other things so these comments
+ apply over a few days.
+
+ * general Compiles cleanly under ultrix 4.2 and AIX 3.1
+
+ * s_user.c O-lines host field changed to user@host.
+ This change could sweep across to other lines yet.
+
+ * s_serv.c L-lines host field made functional.
+
+ * s_bsd.c I-lines also take user@host as the host now :)
+
+Tue Jul 14 03:51:04 1992
+ * s_msg.c, s_serv.c, s_user.c
+ - THE BIG SPLIT occured! s_msg.c split into two files:
+ s_serv.c and s_user.c
+
+Mon Jul 13 03:08:03 1992 Darren Reed <avalon@coombs.anu.edu.au>
+ * s_conf.c, class.c
+ - added MAXSENDQ. field for classes.
+
+Sun Jul 12 10:41:48 1992 Darren Reed <avalon@coombs.anu.edu.au>
+ * s_msg.c - added m_close
+
+Sat Jul 11 01:01:09 1992 Darren Reed <avalon@coombs.anu.edu.au>
+ * s_err.c - Created, debuged and Added.
+ * general - Generic creation of ERR and RPL numerics from routines
+ in s_err.c. The use of these is optional.
+ * channel.c - Changed NAMES, LIST to be able to query remote
+ servers.
+ - NAMES, LIST, TOPIC all understand channel name lists
+ using a comma (,) as a name separator.
+
+Sat Jul 4 22:40:35 1992 Darren Reed <avalon@coombs.anu.edu.au>
+ * s_bsd.c, ircd.c, s_conf.c, s_msg.c
+ - Changed DIE/RESTART/REHASH to be signal activated or
+ optionally allow operators to issue REHASH/RESTART.
+
+Sat Jul 4 04:12:43 1992 Darren Reed <avalon@coombs.anu.edu.au>
+ * s_bsd.c, res.c
+ - fixed automatic lookup of hostnames returned by a
+ lookup of the IP#.
+
+Fri Jul 3 16:15:39 1992 Darren Reed <avalon@coombs.anu.edu.au>
+ * channel.c - added comments to the KICK command.
+ * s_msg.c - rewrote WHOIS, optimized sending of JOIN channels at
+ net splits.
+ * general - checked to make sure all replies had a ':' in the
+ reply to mark the last parameter being sent.
+
+Thu Jul 2 07:56:46 1992 Darren Reed <avalon@coombs.anu.edu.au>
+ * channel.c - imposed 256 character limit on channel names for
+ clients local to the server.
+
+Thu Jul 2 03:41:15 1992 Darren Reed <avalon@coombs.anu.edu.au>
+ * s_msg.c - changed numeric reply 200 from TRACE. Now shows next
+ server in the reply line (extra arg).
+
+Tue Jun 30 04:53:11 1992 Darren Reed <avalon@coombs.anu.edu.au>
+ * s_bsd.c - split up check_server() to accomodate the name lookup
+ in the middle of it for access checking.
+ * s_msg.c - split up m_server to work with the splitup of
+ check_server().
+
+Mon Jun 29 23:46:32 1992 Darren Reed <avalon@coombs.anu.edu.au>
+ * whowas.c - added RPL_ENDOFWHOWAS to the whowas reply chain.
+
+Sun Jun 28 21:31:20 1992 Darren Reed <avalon@coombs.anu.edu.au>
+ * channel.c, send.c
+ - channel name masks using ":mask" completed along with
+ removal of # significance. '%' channel prefix is
+ local to server.
+
+ + The removal of the # significance was temporary due to
+ too many problems with the nickname/channelname space
+ problems.
+
+ * s_bsd.c, res.c, s_conf.c
+ - hostname and ip number lookup working asynchronously.
+ * s_bsd.c - udp port created. echo's any data sent to it.
+
+Sun Dec 1 Greg Lindahl <gl8f@virginia.edu>
+ * general - gee, avalon, you could at least try. as of pre16
+ numerics restored to old values. MSG_NOTE code
+ removed, because it does not pass Saber C.
+ * support.c - ctype macros now give values for EOF.
+ * dbuf.c - test for bozo compilers
+ * example.conf- more documentation
+ * s_msg.c - pjg's patch to fix m_server
+ * ircd.c - print message when debugging off and debugtty set
+ * config.h - remove many dead crufty options.
+
+Sun Dec 1 13:41:11 1991 Darren Reed <avalon@coombs.anu.edu.au>
+ * all files - There have been so many changes and bug fixes going
+ into 2.7 that it would be impossible to list them all.
+
+Mon Nov 4 14:35:07 1991 Darren Reed <avalon@coombs.anu.edu.au>
+ * s_msg.c - installed msa's patch to m_nick
+
+Mon Nov 4 01:03:45 1991 Darren Reed <avalon@coombs.anu.edu.au>
+ * all files - changed all functions to have "function_name" style
+ names. All macros now MacroName.
+ * general - lots of various different work in preparation for 2.7
+
+Thu Sep 19 14:55:24 1991 Darren Reed <avalon@coombs.anu.edu.au>
+ * s_msg.c, channel.c
+ - moved m_topic() and m_invite() from s_msg.c to
+ channel.c
+ - changed m_topic() to now process # channel topics
+
+Mon Sep 02 16:27:53 1991 Darren Reed <avalon@coombs.anu.edu.au>
+ (lost previous ChangeLog which had accurate dates of additions
+ for 2.6.2. Following is changes from 2.6.1 to 2.6.2).
+
+ * s_conf.c - added L-line handling for Leaf Enforcement.
+ (Courtesy Wumpus (Greg Lindhal))
+ - added det_I_lines_butfirst to make sure each client
+ connection only ever has (at most) 1 I-line attached
+ to it.
+
+ * channel.c - fixed ghost ChanOp problem from earlier versions.
+ - painful ^G mode bug fixed for 2.6.1
+
+ * ircd.c - some problems with TryConnections fixed.
+
+ * s_bsd.c, ircd.c, s_msg.c
+ - local clients are now stored and referenced with an
+ array of pointers. This has a fixed size :/
+
+ * s_msg.c, list.c
+ - client list is now a double linked list.
+ - moved some code to list.c to create addition/deletion
+ routines to add/delete client records from the list.
+
+ * list.c - added NICKNAMEHISTORYLENGTH to replace the 'magic' 200.
+
+ * s_msg.c - Added following commands:
+ USERHOST <nickname> [n.[n.[n.[n.]]]]
+ ISON <nickname> [nickname...]
+
+ * hash.c, s_msg.c, channel.c
+ - (finally) added hash tables for nickname, server and
+ channel name lookup. Nicknames and servers share the
+ same table.
+
+Thu Jul 04 20:31:10 1991 Armin Gruner <gruner@informatik.tu-muenchen.de>
+
+ * s_numeric.c
+ Changed sptr->name to parv[0]; use strtoken() for loop.
+
+Tue Jul 02 11:11:15 1991 Armin Gruner <gruner@informatik.tu-muenchen.de>
+
+ * ircd.c, channel.c, s_msg.c
+ changed MSG_MAIL to MSG_NOTE as requested by the author
+ Fixed m_links(); remote LINKS should work now.
+ * mail.c
+ Removed mail.c, replaced by new version 1.3pre8, now note.c
+
+Mon Jul 01 20:35:40 1991 Armin Gruner <gruner@informatik.tu-muenchen.de>
+
+ * s_msg.c
+ m_notice(), m_text(), m_privmsg() merged to one function.
+ m_wall() changed. Default is WALL. Should be eliminated
+ anyways in next version.
+
+ * channel.c
+ Changed error msgs when parameters from 'l' are missing.
+
+Sun Jun 30 14:53:42 1991 Armin Gruner <gruner@informatik.tu-muenchen.de>
+
+ * s_msg.c
+ Major cleanups; Server/host mask msgs moved to NOTICEs.
+ m_whois changed. For nonexistent nickname an error is created now.
+
+Sat Jun 29 15:46:35 1991 Armin Gruner <gruner@informatik.tu-muenchen.de>
+
+ * s_msg.c
+ Fixed m_summon error bug
+ Applied msa'a patches. Fixes ExitOneClient().
+
+ * channel.c
+ Fixed join ctrl-g bug
+
+Sat Apr 6 19:47:00 1991 Jarkko Oikarinen <jto@tolsun.oulu.fi>
+
+ * Added destination parameter to /links (a'la /whois)
+
+Thu Apr 4 16:01:16 1991 Armin Gruner <gruner@informatik.tu-muenchen.de>
+
+ * ircd.c, s_bsd.c
+ Fix SIGHUP - SIGHUP to ircd causes a rehash() finally.
+
+ * c_msg.c
+ Fix KILL from an OPER - pre19 with wildcard match didn't pro-
+ pagate the correct sender. Server kills behind *-domains are
+ still unsolved.
+
+Sun Mar 31 08:57:12 1991 Jarkko Oikarinen <jto@tolsun.oulu.fi>
+
+ * WALL placed under #ifdef. Default is no WALL
+ * Fixed JOIN mode option to accept more parameters
+ like userlimit.
+
+Sun Mar 24 07:43:00 1991 Jarkko Oikarinen <jto@tolsun.oulu.fi>
+
+ * A couple minor bug fixes.
+ * Channel name to ERR_CHANOPRIVSNEEDED and ERR_NOTONCHANNEL.
+
+Sun Mar 17 09:50:12 1991 Jarkko Oikarinen <jto@tolsun.oulu.fi>
+
+ * m_who() numeric RPL_ENDOFWHO (315) for all queries
+ * RPL_ENDOFWHOIS (316) reply added
+ * RPL_ENDOFWHO (315) and RPL_ENDOFWHOIS (316) return
+ the query parameter now as well.
+ * RPL_WHOISIDLE (317) returns the idle time of a particular user.
+ * RPL_NOTOPIC (331), RPL_TOPIC (332) return channel name as a
+ paramater (this has been already added to RPL_CHANNELMODEIS (324))
+ * Limited trace (won't show users on a server) available now for
+ all users
+ * Fix to HuntServer() to make sure loops do not happen.
+ * Added new numeric, ERR_CHANOPRIVSNEEDED (482) which replaces
+ *all* ERR_NOPRIVILEGES (481) messages where the missing privileges
+ were channel operator privileges.
+ * KICK to user not existant on irc now generates
+ ERR_NOTONCHANNEL (442) error reply.
+ * ERR_NOSUCHSERVER (402) returns the server name as a parameter.
+ * ERR_CANNOTSENDTOCHAN (404) now returns the channel name you couldn't
+ send to.
+
+Mon Feb 25 16:08:51 1991 Armin Gruner <gruner@informatik.tu-muenchen.de>
+
+ * s_msg.c
+ 'Fixed' K:-line behaviour of m_user(). Now, the connection
+ is not closed; USER-msg is distributed with K:-line remark, and
+ user isn't introduced locally, so user gets 'You have not registered
+ as a user'.
+
+ * ircd.c
+ SIGHUP generates rehash() now.
+
+Mon Feb 11 18:57:56 1991 Armin Gruner <gruner@informatik.tu-muenchen.de>
+
+ * s_msg.c
+ Fixed m_server(). The domain matching was done against the
+ return value of GetClientName(), but this never matches
+ if the servername differs from the host name, because
+ [real socketname] is added to 'inpath'.
+
+Fri Jan 12 12:34:21 1991 Jarkko Oikarinen (jto@tolsun.oulu.fi)
+
+ * more ircd options at startup...
+
+Mon Dec 03 13:54:25 1990 Armin Gruner <gruner@informatik.tu-muenchen.de>
+
+ * class.c, s_msg.c, s_bsd.c
+ Fixes from Avalon. Sigh.
+
+Wed Nov 28 14:07:11 1990 Armin Gruner <gruner@informatik.tu-muenchen.de>
+
+ * class.c, s_bsd.c (CloseConnection)
+ Fixes from avalon (DEBUG stuff)
+
+Tue Nov 27 11:24:56 1990 Armin Gruner <gruner@informatik.tu-muenchen.de>
+
+ * s_msg.c, s_bsd.c, ircd.c, class.c
+ Isolated the implementation of 'classes' to class.c (by using
+ macros for accessing the structure members) -- we should start
+ using this everywhere -- especially with this linear list of
+ clients!!
+
+ * channel.h (new file)
+ prototyping, 'channel'-misc, try to isolate channel implemen-
+ tation to channel.h and channel.c
+
+Sun Nov 25 16:13:42 1990 Armin Gruner <gruner@informatik.tu-muenchen.de>
+
+ * class.c, class.h
+ New files for class-handling. Applied Avalon's patches.
+ Change some code into more readable one (MIN).
+
+Tue Nov 13 11:44:28 1990 Armin Gruner <gruner@informatik.tu-muenchen.de>
+
+ * s_msg.c
+ Fixed Invite bug.
+
+ * s_bsd.c
+ Fixed overhead of check_access.
+ New function to get qualified (local) domain name: AddLocalDomain()
+
+Mon Nov 12 20:42:44 1990 Armin Gruner <gruner@informatik.tu-muenchen.de>
+
+ * channel.c
+ Fixed 2.6 MODE_NOPRIVMSG bug
+
+ * Added mkversion.sh into self configuration extraction,
+ now version.c.SH
+
+Sat Nov 10 19:10:33 1990 Armin Gruner <gruner@informatik.tu-muenchen.de>
+
+ * Removed getlongtime() everywhere.
+
+ * s_bsd.c
+ Removed some ULTRIX sidesteps.
+
+ * s_conf.c
+ Changed the return values of find_kill().
+
+ * ircd.c
+ Avalon's cleanup's.
+ Change close() to shutdown() (restart()).
+
+Wed Oct 31 18:20:00 1990 Jarkko Oikarinen (jto@tolsun.oulu.fi)
+
+ * 2.6:
+ - multichannels
+ - wildcard servers
+ - more fun stuff I don't remember anymore but which should
+ be in documentation...
+
+Sun Oct 21 18:53:02 1990 Christopher Davis (ckd at bucsd)
+
+ * Makefile
+ - Added IRCDLIBS and IRCDMODE variables
+
+Wed Jun 20 11:53:00 1990 Jarkko Oikarinen (jto@tolsun.oulu.fi)
+
+ numerous files changed and functions moved around to make
+ string channels work...
+
+Sun Jun 17 16:52:39 1990 Armin Gruner (gruner@informatik.tu-muenchen.de)
+
+ * s_debug.c
+ New created file, common/debug.c has been moved to it because
+ now we handle also debug outputs in client code
+
+ * s_conf.c
+ Added the prefix character into all reply-strings.
+ MSGs never appeared on client site because parse() didn't
+ recognize it as a prefix (numeric) message
+ Changed the test of time-interval, now a specified interval
+ that begins before midnight and ends after should also work
+
+ * s_bsd.c
+ Added setdtablesize() for sequents OS Dynix,
+ default was 20; allows more socket connections.
+
+Sat May 12 22:50:13 1990 Jarkko Oikarinen (jto@tolsun.oulu.fi)
+
+ * s_msg.c
+ Added newline removal from the end of string ctime()
+ returns (m_info() and m_stats())
+ * s_whowas.c
+ Added newline removal from the end of string ctime()
+ returns (m_whowas())
+ * s_conf.f
+ Added close() into init_conf()
+ Was obviously forgotten from there
+
+Thu May 10 17:17:13 1990 Jarkko Oikarinen (jto@tolsun.oulu.fi)
+
+ * whowas.c
+ Fixed memcpy and bcopy problems
+
+Sat Jan 6 17:36:28 1990 Mike Bolotski (mikeb at coho.ee.ubc.ca)
+
+ * date.c
+
+ Added HPUX-specific code since it lacks the timezone() function.
+
+
diff --git a/doc/Juped/INSTALL b/doc/Juped/INSTALL
new file mode 100644
index 0000000..8ec35ff
--- /dev/null
+++ b/doc/Juped/INSTALL
@@ -0,0 +1,1167 @@
+/************************************************************************
+ * 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) Installing IRC
+ 2) The config.h file
+ 3) Editing the Makefile, and compiling
+ 4) The ircd.conf file
+ 5) Mailing list
+
+1) So that ircd/irc will compile and work correctly with your version of
+ Unix, it is necessary that you run "make" first. This will run
+ configure which will probe your system for any peculiarities it has
+ and setup the Makefile and a file of default #define's ($arch/setup.h).
+ To change the default directory into which ircd will install using
+ "make install", invoke "make" using the "CONFIGARGS=--prefix=/dir"
+ command line option.
+
+2) Edit the "config.h" file and make changes to the various #DEFINE's:
+
+ a) 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.
+
+ b) 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. Defining
+ this induces a large overhead for the server as it does a large amount
+ of self diagnostics whilst running.
+
+ c) SPATH, CPATH, MPATH, LPATH, PPATH, TPATH
+
+ 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 "ircd.conf" file.
+ This path is usually /usr/local/lib/ircd.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.
+
+ Define TPATH to be the directory path to the "ircd.tune" file.
+ This path is usually /usr/local/lib/ircd.tune. This file is used
+ by the server to optimize memory use.
+
+ d) 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 IRCDDIR (in Makefile).
+
+ e) 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.
+
+ f) 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.
+
+ g) 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.
+
+ h) ZIP_LINKS, ZIP_LEVEL
+
+ As of the 2.9.3 version of the server, server-server connections
+ may be compressed using the zlib. In order to compile the server
+ with this feature, you MUST have the zlib package (version 1.0 or higher)
+ already compiled and define ZIP_LINKS in the config.h file. Compression
+ use for server-server connections is separately configured in the
+ ircd.conf file for each server-server link. ZIP_LEVEL allows you to
+ control the compression level that will be used. Values above 5 will
+ noticeably increase the CPU used by the server.
+
+ The zlib package may be found at http://quest.jpl.nasa.gov/zlib/
+ The data format used by the zlib library is described by RFCs (Request
+ for Comments) 1950 to 1952 in the files
+ ftp://ds.internic.net/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate
+ format) and rfc1952.txt (gzip format). These documents are also
+ available in other formats from
+ ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html
+
+ i) SLOW_ACCEPT
+
+ This option is defined by default and is needed on some OSes. It
+ creates an artificial delay in processing incoming connections. On a
+ given port, no more than 1 connection per 2 seconds will be processed.
+
+ Undefining this will let the server process connections as fast as
+ it can which can cause problems on some OSes (such as SunOS) and be
+ abused (fast massive join of clonebots..), for these reasons, if you
+ decide to undefine SLOW_ACCEPT you MUST define CLONE_CHECK.
+
+ j) CLONE_CHECK
+
+ This option acts as a wrapper, by checking incoming connections
+ early before starting ident query. By default, the server will not
+ accept more than 2 connections from the same host within 10 seconds.
+
+ k) 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) Editting Makefile and compilation.
+
+ Once configure has been run, it is safe to edit the Makefile. You
+ will most likely need to uncomment the correct IRCDLIBS, IRCLIBS and
+ IRCDDIR lines.
+
+ To now build and install the server, type "make && make install".
+
+ If you have trouble compiling ircd, copy Makefile.in to Makefile and
+ edit Makefile as appropriate.
+
+4) The ircd.conf file.
+
+ After installing the ircd and irc programs, edit the ircd.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 ircd.conf file contains various records that specify configuration
+ options. The record types are as follows:
+
+ 1. Server connections (C,c,N)
+ 2. Machine information (M)
+ 3. Client connections (I,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)
+ 14. Version limitations (V)
+
+
+ 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 "ircd.conf" is:
+
+ C:<TARGET Host Addr>:<Password>:<TARGET Host NAME>:<TARGET PORT>:<Class>
+Field: 1 2 3 4 5 6
+
+ for example:
+
+ C:nic.funet.fi:passwd:nic.funet.fi:6667:1
+
+ - or -
+
+ C:128.214.6.100:passwd:nic.funet.fi:6667:1
+
+ - or -
+
+ C:root@nic.funet.fi:passwd:nic.funet.fi:6667:1
+
+
+ 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.
+ The port field can contain 2 ports, separated by a .
+ In this case, the first port is used when auto-connecting,
+ the second port is used for the UDP pings to the targer
+ server.
+
+ Field 6: The class field should refer to an existing class and
+ determines the maximum number of simultaneous uses of the
+ C-line allowable through the max. links field in the Y-line.
+
+ NEW!!!
+ As of the 2.9.3 version of the server, server connections can be
+ compressed with the zlib library. To define a compressed connection,
+ you must have compiled the server with ZIP_LINKS defined (cf 2.h), and
+ use a _lowercase_ C line.
+
+ Some examples:
+
+ C:nic.funet.fi::nic.funet.fi:6667:1
+
+ 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:1
+
+ 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:1
+
+ 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:1
+ C:irc.nada.kth.se::irc.nada.kth.se:6667:1
+ C:nic.funet.fi::nic.funet.fi:6667:1
+
+ 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.
+
+ The format for the NOCONNECT entry in the "ircd.conf" is:
+
+ N:<TARGET Host Addr>:<Password>:<TARGET Host NAME>:<Domain Mask>:<Class>
+Field: 1 2 3 4 5 6
+
+ 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".
+
+ Explanation:
+
+ Each field is separated with a ":" charcter:
+
+ Field 1: "N" corresponds to a server Noconnect 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. If CRYPT_LINK_PASSWORD
+ is defined in config.h, this password must be crypted.
+
+ 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: Domain masking, see below.
+
+ Field 6: The class field should refer to an existing class.
+
+ 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
+
+ Introduction.
+ 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:<Server NAME>:<YOUR Internet IP#>:<Geographic Location>:<Port>
+ Field: 1 2 3 4 5
+
+ Explanation:
+
+ Field 1: "M" specifies a Machine description line
+
+ Field 2: The name of YOUR server adding any Internet DOMAINNAME that
+ might also be present. If this hostname can be resolved,
+ the IP# found will be used to for outgoing connections.
+ Otherwise the default interface address of the host is used.
+ The server name may not be FQDN of another host.
+ (This means all outgoing connections will be done from the
+ same IP#, even if your host has several IP#).
+
+ Field 3: If the machine on which you run the server has several IP
+ addresses, you can define which IP# to use for outgoing
+ connections. This overrides field 2.
+ See Also the "Port Connections" section.
+
+ Field 4: Geographic Location is used to say WHERE YOUR SERVER 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: Defines the port on which your server will listen for udp
+ pings from other servers. This should be the port were other
+ servers are set to autoconnect. (Also see the port field
+ description in connect lines).
+
+ 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".
+
+ 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".
+
+ 3. CLIENT CONNECTIONS - How to let clients connect to your IRCD.
+
+ Introduction.
+ A client is a program that connects to the ircd daemon (ircd).
+ There are clients written in C, GNU Emacs Lisp and many other languages.
+ The "irc" program is the C client. Each person that talks via IRC is
+ running their own client.
+
+ The ircd.conf files contains entries that specify which clients are
+ allowed to connect to your irc daemon. Obviously you want to allow your
+ own 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>:<Port>:<Class>
+ Field:1 2 3 4 5 6
+ i:<TARGET Host Addr>:<Password>:<TARGET Hosts NAME>:<Port>:<Class>
+
+
+ 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:x::tolsun.oulu.fi::1
+
+ If you wanted to let remote clients connect, you could add the
+ following lines:
+
+ I:x::*.du.edu::1
+
+ Allow any clients from machines whose names end in "du.edu" to connect
+ with no password.
+
+ I:128.214.6.100::nic.funet.fi::1
+
+ Allow clients from a machine with that IP number to connect.
+ Numeric match is enough, name is not required anymore.
+
+ I:x:secret:*.tut.fi::1
+
+ Allow clients from machines matching *.tut.fi to connect
+ with the password 'secret'.
+
+ I:*::*::1
+
+ 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).
+
+ I:x::*.fi:6667:1
+
+ Allow clients from machines matching *.fi to connect on the port
+ 6667.
+
+ I:*@*::*@*::1
+
+ Allow clients from anywhere to connect your server.
+ If the client machine does not reply to your server ident query,
+ the client's username will be prefixed by ~
+
+ 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).
+
+ NEW!!!
+ As of the 2.9.1 version of the server, i lines are introduced. They
+ work the same way as I lines, but the clients matching an i line
+ will have a restricted connection. (no nick/mode change, no kick)
+ Such users will have their username prefixed by +, = or - depending
+ on the ident reply.
+
+ 4. DEFAULT HOSTS (for local clients) *obsoleted*
+
+ Introduction.
+ 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
+
+ Introduction.
+ 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 "ircd.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 "ircd.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::1
+
+ 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
+
+ Introduction.
+ 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.
+
+ Introduction.
+ 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)|comment>:<User>:<port>:
+ Field: 1 2 3 4 5
+
+ 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 or put a comment, then the line
+ 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'.
+
+ Field 5: The port on which the Kill line will be effective.
+ 0 means all ports.
+
+
+ Some Examples:
+ K:orion.cair.du.edu::jtrim:0:
+
+ If user 'jtrim' connects to IRC from host "orion.cair.du.edu"
+ then IMMEDIATELY REMOVE HIM from my IRCD.
+
+ K:*.cair.du.edu::root:0:
+
+ 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:0:
+
+ 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:*:0:
+
+ 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.
+
+ Introduction.
+ 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.
+
+ Introduction.
+ 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 ircd.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 ircd.conf file BEFORE it is used in any other way.
+
+ The format for the line is:
+
+ Y:<CLASS>:<PING FREQUENCY>:<CONNECT FREQ|MAX IP>:<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/I/O 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: This field has a different meaning depending on the use of the
+ Y line:
+ For servers: 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.
+ For clients: Positive value: defines the maximum number of
+ clients from the same host (IP)
+ will be allowed.
+ Negative value: defines the maximum number of
+ clients from the same user@host (IP)
+ will be allowed. Read note below.
+
+ Field 5: This field defines the maximum number of links this class
+ will allow from automatic connections (C lines). Using /CONNECT
+ overrides this feature. Also defines the maximum number of
+ users in this class (I/O lines).
+
+ 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)!!
+
+ NOTE: If you plan to use the user@host limit, please read the following
+ very carefully. The `user' value is the ident reply for the
+ connection. If no reply was given then it defaults to "unknown"
+ and thus the effective limit will be per host, not per user@host.
+ Also, some ident servers return encrypted data which changes for
+ every connection making the limit void.
+
+ 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.
+
+ Introduction.
+ 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: 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: the name of the server connected to you that for which you
+ want to enforce leaf-like attributes upon.
+
+ Field 5: 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 Fully Implemented Yet)
+
+ 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. The following line can be added to your ircd.conf file
+ to enable a service:
+
+ S:<TARGET Host Mask>:<password>:<service_name>:<service type>:<class>
+ Field: 1 2 3 4 5 6
+
+ 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 name used by the service. Services don't have nicknames, but
+ a static name defined by the S line.
+
+ Field 5: The type of service. It defines the priviledges given to the
+ service. Be very careful in the types you allow.
+ The types can be found in include/service.h
+
+ Field 6: The class field should refer to an existing class.
+
+ 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 done by sending a SERVICE command to the
+ server:
+
+ SERVICE servicename servername distribution servicetype 0 :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
+ are rejected upon sending an unknown or unallowed command. Services
+ however, are not affected by flood control and can be granted special
+ priviledges. It is therefore wise to oversee the use of S-lines with
+ much care.
+
+ Services can be listed using the SERVLIST command, and can be sent
+ messages using the SQUERY command.
+
+ 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#>:<*>:<Internet IP Mask>:<PORT>:
+Field: 1 2 3 4 5
+
+or
+
+ P:<Directory>:<*>:<*>:<PORT>:
+Field: 1 2 3 4 5
+
+ Explanation:
+ Internet Ports
+ Field 2
+ If the host on which the server runs has several IP addresses, you can
+ define for which IP address connections will be accepted. If no
+ is defined here, server will bind to all interfaces (INADDR_ANY).
+ See also MACHINE CONFIGURATION section to properly configure outgoing
+ connections.
+
+ P:192.168.1.194:::6664:
+
+ Field 4
+ 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 isn't 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.
+
+ NOTE: You need at least one P line.
+
+ 13. Hub Connections
+
+ Introduction.
+ 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::
+
+ 14. Version limitations
+
+ Introduction.
+ 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:
+
+ V:<VERSION MASK>:<FLAGS>:<SERVER NAME>::
+Field: 1 2 3 4
+
+ Explanation:
+ Field 2
+ Server is not allowed to connect if its version string matches the mask
+ given in this field.
+
+ Field 3
+ This field should contained flags as defined in ircd/s_debug.c
+ This flags show up in RPL_VERSION.
+ If any of the flags present in this field are found in the RPL_VERSION
+ of a server, this server will be denied connection.
+ This must be used with care.
+
+ Field 4:
+ This field is used to match server names. The V line will be used
+ for servers matching the mask given in this field.
+
+ Examples:
+
+ V:020901*::*::
+
+ Disallows any server which version is 2.9.1* to connect.
+
+ V:020901*:D:*::
+
+ Disallows any server which version is 2.9.1* or which has been
+ compiled with DEBUGMODE defined to connect.
+
+ Note: It is possible to have and use multiple V-lines for the one server
+ mask.
+
+ H:020901:*:*::
+ V:020902:*:*::
+
+ is allowed.
+
+
+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.
+
+
+6) ircd-users
+
+A mailing list is dedicated to the people using ircd. If you have trouble
+running ircd, or wish to discuss the future, you can subscribe by sending
+an email to majordomo@stealth.net, with "subscribe ircd-users" in the body.
diff --git a/doc/Juped/US-Admin/Networking b/doc/Juped/US-Admin/Networking
new file mode 100644
index 0000000..e8dc186
--- /dev/null
+++ b/doc/Juped/US-Admin/Networking
@@ -0,0 +1,156 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, doc/NETWORKING
+ * Copyright (C) 1994, Helen Rose <hrose@kei.com>
+ *
+ * This program is free software; you can 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.
+ */
+
+ Author: Helen Rose
+ hrose@kei.com
+ Date: 3 March, 1994
+
+*** Please read this before doing any connecting or writing to ask for
+connections. The information contained in this section is crucial to the
+way IRC is run.
+
+Note that any old documentation referring to ANet vs EFnet is out of date
+and no longer applies. ANet died so long ago that nobody can remember
+*when* it died.
+
+
+To qualify for a link on the irc network, several criteria must be
+met. These criteria include (but are not limited to):
+
+* A well established local irc userbase. A total of 100-150 local irc
+ users. An average of 15-20 irc users over a 24 hour period is also
+ acceptable. Note, these user counts are *unique, local* users. So
+ one person running fifteen clients doesn't count, and one local
+ person plus fifteen offsite people doesn't count. These are not
+ arbitrary numbers, it takes at least this many users to equate the
+ traffic of adding another server to the irc network.
+
+* A userbase that uses irc *all the time* (15 users on at once but
+ just for a 3 hour period per day is not sufficient).
+
+* A good, fast, internet link. Absolutely *NO* SLIP lines. 56k lines
+ are marginal, they usually cause more trouble than they are worth,
+ so we recommend a T1 or better.
+
+It is well established that having a local irc server does not attract
+local irc users. Often, your best bet is to set up a local client that is
+accessible by everyone at your site, connect it to a nearby offsite
+server, and then see if the usage level goes up. (See appendix for list of
+open-client servers).
+
+To see how many users you have, on irc do /m x@monitor.us show site.name
+where site.name is your two-part domain name (eg "kei.com" or "bu.edu" or
+"mit.edu"). monitor will tell you how many users you have. Once this
+number gets over 125 or so, put the level it has reached in your note to
+operlist-request@kei.com.
+
+If you are in the United States and need a link, please mail to
+"operlist-request@kei.com" supplying the information listed below.
+
+(1) Find out if your system has /etc/ping (sometimes /usr/etc/ping) and
+ ping the following hosts:
+
+ server/machine name IP address Geographical Location
+ csa.bu.edu 129.197.10.3 Boston, MA
+ irc-2.mit.edu 18.180.0.2 Cambridge, MA
+ polaris.ctr.columbia.edu 128.59.68.10 New York, NY
+ poe.acc.virginia.edu 128.143.83.132 Charlottesville, VA
+ irc.iastate.edu 129.186.150.1 Ames, IA
+ dewey.cc.utexas.edu 128.83.135.3 Austin, TX
+ irc.netsys.com 198.175.9.8 Palo Alto, CA
+ w6yx.stanford.edu 36.55.0.50 Stanford, CA
+ goren.u.washington.edu 140.142.63.1 Seattle, WA
+
+These are results of the typical /etc/ping command:
+
+(note that the machine I am running this from runs SunOS so I have to use
+ping -s ):
+
+3:59pm hrose@csa : ~ % ping -s polaris.ctr.columbia.edu
+PING polaris.ctr.columbia.edu: 56 data bytes
+64 bytes from polaris.ctr.columbia.edu (128.59.68.10): icmp_seq=0. time=137. ms
+64 bytes from polaris.ctr.columbia.edu (128.59.68.10): icmp_seq=1. time=163. ms
+64 bytes from polaris.ctr.columbia.edu (128.59.68.10): icmp_seq=2. time=110. ms
+64 bytes from polaris.ctr.columbia.edu (128.59.68.10): icmp_seq=3. time=111. ms
+64 bytes from polaris.ctr.columbia.edu (128.59.68.10): icmp_seq=4. time=78. ms
+64 bytes from polaris.ctr.columbia.edu (128.59.68.10): icmp_seq=5. time=82. ms
+64 bytes from polaris.ctr.columbia.edu (128.59.68.10): icmp_seq=7. time=83. ms
+64 bytes from polaris.ctr.columbia.edu (128.59.68.10): icmp_seq=8. time=91. ms
+64 bytes from polaris.ctr.columbia.edu (128.59.68.10): icmp_seq=9. time=159. ms
+[...]
+^^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^ ^^^^^^^
+Size of packet hostname IP address packet number trip time
+
+
+----polaris.ctr.columbia.edu PING Statistics----
+25 packets transmitted, 25 packets received, 0% packet loss
+round-trip (ms) min/avg/max = 78/136/327
+
+
+When you send pings to operlist-request, please only send the results
+(the above three lines)--we *don't* need each packet's time.
+
+
+Guidelines:
+
+Avg Time Connection is
+======== =============
+0-20ms Optimal
+20-40ms Excellent
+40-70ms Very Good
+70-90ms Average
+90-110ms Acceptable
+110ms-150ms Below Average
+150ms-200ms Bad
+200ms-300ms You're on a very slow link and it is unlikely you will be
+ able to support a server successfully.
+
+
+** *** WHERE TO FIND HELP!!! ***
+**
+** If you have any other questions about connecting to an irc server, please
+** mail to operlist-request@kei.com. If you have problems mailing there,
+** try mailing hrose@kei.com.
+**
+** *** WHERE TO FIND HELP!!! ***
+
+Appendix
+========
+
+Open client servers.
+
+USA:
+ csa.bu.edu
+ irc.colorado.edu
+ irc.uiuc.edu
+
+Canada:
+ ug.cs.dal.ca
+
+Europe:
+ irc.funet.fi
+ cismhp.univ-lyon1.fr
+ disuns2.epfl.ch
+ irc.nada.kth.se
+ sokrates.informatik.uni-kl.de
+ bim.itc.univie.ac.at
+
+Australia:
+ jello.qabc.uq.oz.au
+
diff --git a/doc/LICENSE b/doc/LICENSE
new file mode 100644
index 0000000..9a17037
--- /dev/null
+++ b/doc/LICENSE
@@ -0,0 +1,249 @@
+
+ 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.
+
+ 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.
+
+ 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.
+
+ 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
+
+ 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!
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644
index 0000000..20b82e4
--- /dev/null
+++ b/doc/Makefile
@@ -0,0 +1,39 @@
+#************************************************************************
+#* IRC - Internet Relay Chat, Makefile
+#* Copyright (C) 1990, Jarkko Oikarinen
+#*
+#* This program is free software; you can redistribute it and/or modify
+#* it under the terms of the GNU General Public License as published by
+#* the Free Software Foundation; either version 1, or (at your option)
+#* any later version.
+#*
+#* This program is distributed in the hope that it will be useful,
+#* but WITHOUT ANY WARRANTY; without even the implied warranty of
+#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+#* GNU General Public License for more details.
+#*
+#* You should have received a copy of the GNU General Public License
+#* along with this program; if not, write to the Free Software
+#* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#*
+#* $Id: Makefile,v 1.3 1997/08/08 14:44:13 kalt Exp $
+#*
+#*/
+
+MANDIR=/usr/local/man
+
+all:
+
+sgml: service doc
+
+doc: INSTALL.sgml
+ sgml2txt INSTALL.sgml
+ sgml2info INSTALL.sgml
+
+service: SERVICE.sgml
+ sgml2txt SERVICE.sgml
+
+install: all
+ -${INSTALL} -c -m 644 ircd.8 ${MANDIR}/man8
+ -${INSTALL} -c -m 644 irc.1 ${MANDIR}/man1
+
diff --git a/doc/Nets/Europe/CoordEBIC b/doc/Nets/Europe/CoordEBIC
new file mode 100644
index 0000000..80ee042
--- /dev/null
+++ b/doc/Nets/Europe/CoordEBIC
@@ -0,0 +1,86 @@
+############################################################################
+list updated the 8.11.1996
+############################################################################
+
+ If you like in future to establish a link inside the EBIC area,
+ please contact the coordinator of the affected toplevel domain.
+ This coordinator will discuss the link with affected local server
+ admins and inform other EBIC members about new links. Also a good
+ idea is to join #EU-Opers and discuss the new link there.
+
+############################################################################
+ These toplevel domains are currently participating EBIC:
+############################################################################
+
+ at be ch zc de dk fi fr hr hu is it nl no pl ru(/su) se si sk uk
+
+############################################################################
+ The following national coordinators have been choosen for '95:
+############################################################################
+
+*.at EASINET, ACONET
+ 1. Fingwe, Bernhard Lorenz <Bernhard.Lorenz@wu-wien.ac.at>
+
+*.be BELNET
+ 1. Frans Francis Vanhemmens <vanhemme@ulb.ac.be>
+ 2. mro Marc Roger <Marc.Roger@belnet.be>
+
+*.ch SWITCH, EUNET/CH
+ 1. ksa Karim Saouli <Karim.Saouli@span.ch>
+
+*.cz CESNET, PASNET
+ 1. Kratz Tomas Kraus <xkraus@sun.felk.cvut.cz>
+
+*.de WIN, BelWue <irc-oper@leo.org>
+ 1. YeggMan Volker Paulsen <Volker.Paulsen@gmd.de>
+ 2. Haegar Thomas Thissen <tici@uni-paderborn.de>
+
+*.dk DENET, DKNET
+ 1. karthy Karsten Thygesen <karthy@sunsite.auc.dk>
+
+*.fi FUNET
+ 1. Vesa Vesa Ruokonen <Vesa.Ruokonen@lut.fi>
+
+*.fr EASINET/ROCAD, RENATER <irc-fr@ifens01.insa-lyon.fr>
+ 1. Nono Arnaud Girsch <Arnaud.Girsch@insa-lyon.fr>
+ 2. Dumpty Marie-Laure Bruneton <brunetom@poly.polytechnique.fr>
+
+*.hr CARNET
+ 1. Mozz Mario Mikocevic <mozgy@smile.srce.hr>
+
+*.hu HUNGARNET
+ 1. keksz Revoly Andras <cakes@sch.bme.hu>
+
+*.is ISnet
+ 1. ra Richard Allen <ra@rhi.hi.is>
+
+*.it CILEA <ebic-it@ccii.unipi.it>
+ 1. Francesco Francesco Messineo <frank@nowhere.ccii.unipi.it>
+ 2. Coccy Cosimo Riglietti <pez0004@cdc715_3.cdc.polimi.it>
+
+*.nl SURFNET/NLNET
+ 1. cor Cor Bosman <cor@xs4all.nl>
+ 2. Steven Steven Hessing <steven@nijenrode.nl>
+
+*.no UNINETT
+ 1. Veggen Vegard Engen <Vegard.Engen@uninett.no>
+
+*.pl POLIP
+ 1. Krzysio Krzysztof Mlynarski <krzysio@hydra.mimuw.edu.pl>
+
+*.ru (*.su) DEMOS
+ 1. mishania Mikhail Alekseevitch Sokolov <mishania@demos.net>
+
+*.se SUNET
+ 1. Ace95 Adam Rappner <ace@LoneStar.rsn.hk-r.se>
+
+*.sk UAKOM
+ 1. Koleso Tibor Weis <tibor@uvt.tuzvo.sk>
+
+*.si
+ 1. Iztok Iztok Umek <Iztok.Umek@uni-lj.si>
+
+*.uk JANET, JIPS
+ 1. jim_bob James R. Grinter <jrg@doc.ic.ac.uk>
+
+
diff --git a/doc/Nets/Europe/IRCNO b/doc/Nets/Europe/IRCNO
new file mode 100644
index 0000000..6fafd8d
--- /dev/null
+++ b/doc/Nets/Europe/IRCNO
@@ -0,0 +1,171 @@
+ European Board of IRC Coordinators - Norway
+
+Email: op-no@nvg.unit.no
+Versjon: 1.01-001
+Dokument: IRCNO-ORRO 06.07.93 - 03:51
+File: flode.nvg.unit.no:/pub/irc/ircno/english
+
+--------------------------------------------------------------------------------
+
+ IRCNO in English.
+
+IRCNO is the Norwegian name for EBIC - Norway.
+
+Introduction
+~~~~~~~~~~~
+The purpose of IRCNO is to make IRC in Norway as effective as
+possible. To achieve this, it has to seperate components, an
+administrative and a techincal.
+
+The administrative component enforces compliance with the IRC rules in
+Norway. The purpose of the rules is not to make operators net-police,
+but action must nonetheless be taken when rules are not complied with.
+Furthermore, we create national statistics on servers and users
+connection time. (This info is however only available to the operators).
+We also document IRC in Norway, and keep information files updated.
+Finally, we give heavy user-support. All documentation, information
+files, and user-support files are in the Norwegian language.
+The technical component consist mainly of ensuring the proper and
+reliable functioning of Norwegian servers and links, so that IRC in
+Norway is compatible with the rest of the EBIC IRC Net.
+
+IRCNO also has its own email adress for any inquiries: op-no@nvg.unit.no
+
+IRCNO has official support from the Norwegian academic network provider
+- UNINETT.
+
+
+IRCNO tasks
+~~~~~~~~~~
+Here is a list that defines IRCNO's tasks.
+
+1) Take care of the Norwegian IRC servers.
+2) Enforce the rules for IRC use in Norway.
+3) Be responsible toward UNINETT.
+4) Make statistics.
+5) Document IRC in Norway.
+6) User support.
+
+
+Rules of IRC use in Norway
+~~~~~~~~~~~~~~~~~~~~~~~~~
+We have 3 kinds of rules, user-bot, operator and server-admin.
+Here is a short translation of the rules
+
+USER-RULES - The following is not allowed:
+ 1) Fake userids, or trying to hide the real user-id.
+ 2) Being intentionally offensive to another user.
+ 3) Dumping a lot of text to a public channel.
+ 4) Constant beeping on a channel.
+ 5) Anything that will reduce the techincal functionality of IRC.
+ 6) Harrasement defined by Norwegian Civil Law.
+ 7) Using offencive words in channel topics on public channels.
+ 8) Destroys the integrity of information.
+ 9) Compromise private communication.
+
+
+BOT-RULES - The following guidelines must be followed:
+ 1) Bots must not have fake userid unless given permission.
+ 2) Bots must not send a message to a user not activating it.
+ 3) Bots must be invisible unless they perform a good "irc-deed".
+ 4) Bots must only answer to PRIVMSG by using NOTICE.
+
+Dispensation from some of the bot-rules may be given under certain
+circumstances.
+
+
+OPERATOR RULES
+ This guide gives guidelines on what is not good and what is good.
+
+ Stuff that is not allowed:
+ - Using SQUIT / CONNECT to gain channel-operator-status.
+ - Mindless use of KILL.
+ - Using TRACE to find invisible users.
+
+ Stuff that is allowed:
+ - Using SQUIT / CONNECT to "fix" the net. This is normally not
+ allowed and should be used with care. The IRCNO tries to make
+ efficient use of automatic routing.
+ - KILL should only be used when a user ask to be killed. KILL can
+ also be used if it's based in a certain paragraph of the USER
+ rule file.
+
+
+SERVER RULES
+ Following is the EBIC-Rules conserning linking. For domestic
+ linking we have our own rules.
+
+ 1) To get a server connect to the Norwegian IRC-net:
+ a. New servers must only be leafs.
+ b. New servers must have one primary- and one secondary link.
+ c. New servers should only have one active link at a time.
+ d. The new server must have enough users.
+ 2) New server connections should be discussed among the existing oper/admins.
+ 3) Any link should follow the physical net-topology.
+ 4) A server that is not close to a regional UNINETT net center should not
+ perform as a HUB server.
+ 5) Every server in Norway takes part in the national user-staistic.
+ 6) If hostmasking is to be used, every server behind a mask must be able
+ to connect to the up-host.
+
+
+ADMIN RULES
+ 1) An irc-admin must be available by email, unless he/she notifies IRCNO
+ about any longer planned absence.
+ 2) A server-admin's duty is to have his/her server perform well for
+ the end-users and other servers on the irc-net.
+ 3) An irc-admin must upgrade his/her server and tune it according to
+ something suitable as soon as a server-release is known to be
+ relatively stable.
+ 4) An irc-admin that is not following these rules can loose his/her links
+ if 100% of IRCNO agrees.
+
+
+
+Persons in IRCNO
+~~~~~~~~~~~~~~~
+We do not have any leader or jobs, but we do preform certain tasks.
+Every decision is taken by discussion and voting. We do not have any
+problem with this, and no nasty disagreements occur. This we belive
+is because of our Norwegian Nature :-)
+Who is Who is documentet in the file called irc-no. Norwegian titles
+in paranthesis.
+
+IRCNO secretary (IRCNO sekret{r)
+ Keeps track and system of all docs that are produced within IRCNO.
+ The updating of the various documents is left to the one who has
+ the administrative job with the document.
+
+Filearchive (Filarkiv)
+ Keeps the anonymous FTP archie at flode.nvg.unit.no up-to date.
+ The archive is also accessible by FSP. The archive consist of
+ IRCNO docs, IRC docs in general, and IRC software.
+ This person also administrate the two mailinglists that exist (IRCNO
+ and a IRC-user list)
+
+Statistics: (Statistikk)
+ Does the monthly stats of IRC-use in Norway.
+
+EBIC contact (EBIC kontakt)
+ This task is defined in the EBIC-rules.
+
+Link master (Link ansvarlig)
+ Job is to find the best links for Norwegian servers, and how they
+ should connect to each other. In link-matters this person often
+ has the last word. The link master write a link-report from time
+ to time (found on the archive as "links"). This report is the only
+ english document beside this one. This person must have good
+ knowlege on net-structure in Norway and how the server-linking works.
+
+UNINETT contact (UNINETT kontakt)
+ UNINETT want one contact person. This person will likely aslo be
+ known as the one who is "responsible for IRC in Norway".
+
+
+Other stuff
+~~~~~~~~~~~
+For a list of servers and their associated persons, see the file irc-no
+under "servere in IRCNO".
+
+This document is proof-read by Espen Anneling (anneling@uiowa.edu)
+
diff --git a/doc/Nets/Europe/InfoEBIC b/doc/Nets/Europe/InfoEBIC
new file mode 100644
index 0000000..1956910
--- /dev/null
+++ b/doc/Nets/Europe/InfoEBIC
@@ -0,0 +1,48 @@
+InfoEBIC - General information about European IRC //941115
+
+Online information sources in Europe
+====================================
+- By IRC
+#EU-Opers is an adminstrative channel for European IRC networking.
+
+- Help automatons in the IRC net (based on ircII help pages)
+Help_EU, Help_UK Send PRIVMSG, receive NOTICE
+Help_IT Requires DCC Chat
+
+- By WWW
+http://www.funet.fi/~irc/
+http://irc.pages.de/
+http://www.nvg.unit.no/irc/IRCNO-page.html
+
+Public IRC servers in Europe
+============================
+- Open for all domains
+irc.funet.fi Finland
+irc.Univ-Lyon1.FR France
+
+- Open for national and some neighbouring domains
+irc.cdc.polimi.it Italy
+irc.span.ch Switzerland
+irc.ludd.luth.se Sweden
+irc.nvg.unit.no Norway
+irc.sci.kun.nl Netherlands
+irc.uni-stuttgart.de Germany
+stork.doc.ic.ac.uk United Kingdom
+
+Anonymous FTP archives with IRC software in Europe
+==================================================
+ftp.funet.fi:/pub/unix/irc
+ftp.informatik.tu-muenchen.de:/pub/comp/networking/irc
+hplyot.obspm.fr:/irc
+src.doc.ic.ac.uk:/packages/irc
+
+Mailing list
+============
+There is administrative mailing list for european IRC networking.
+The list address is irc-eu@ifens01.insa-lyon.fr. This list is run by
+an automated mailing-list manager tool, so all requests concerning
+the list should be mailed to listserv@ifens01.insa-lyon.fr. To get help,
+send "help" in mail message to the listserv address, and you will
+get help file in reply.
+
+
diff --git a/doc/Nets/Europe/RulesEBIC b/doc/Nets/Europe/RulesEBIC
new file mode 100644
index 0000000..8e693ff
--- /dev/null
+++ b/doc/Nets/Europe/RulesEBIC
@@ -0,0 +1,90 @@
+ ########################################################################
+ ##### RULES FOR ESTABLISHING NEW IRC SERVERS IN EUROPE (v1.1) #####
+ ########################################################################
+
+
+ 1.) Establishing a new server and inner domain linking should be
+ a local toplevel domain (country) decision.
+
+ Guidelines:
+
+ + New servers should be leafed until their admin(s)
+ have sufficient experience to handle their server
+ responsibly. (This avoids routing disasters).
+
+ + Only a link for ONE server should be given to the new
+ server site, that means the new site shouldn't be able to
+ connect test-servers to other than its own server.
+ (This avoids confusion about linking hierarchy).
+
+ + Be sure that if a toplevel domain hostmask link is given,
+ all hubs of that domain can connect the masked server!
+ (this should avoid disagreement between serveral hub
+ admins in one domain).
+
+
+ 2.) All other links between toplevel domains (countries) should be
+ dicussed between the major link coordinators of each toplevel
+ domain (country). These coordinators are called European Board
+ of IRC Coordinators (EBIC).
+
+ Guidelines:
+
+ + Major link coordinators of each toplevel domain (country)
+ should be published with the server sourcecode in
+ directory ./doc/Europe
+
+ + Each toplevel domain (country) participating in the
+ European IRC net must have a coordinator, who is
+ responsible for country-internal connections AND
+ represents the country in contacts with the rest of the
+ world. This person(s) is (are) chosen by their domain,
+ but must be approved by the EBIC.
+
+ + The EBIC is the only executive in charge of European
+ interconnections and of connections from Europe to the
+ rest of the world. They will decide linking issues
+ WITH the affected local admins.
+
+ + For establishing new links between several toplevel
+ domains the affected EBIC coordinators should be
+ consulted. If further coordination is needed it should
+ be discussed within the EBIC.
+
+ + Additional note: International links should also take
+ care of the network topology, so even if several national
+ opers agree on a same international link, they might be
+ wrong and use unecessary network ressources. The EBIC
+ should avoid such linking.
+
+ + Any major linking change should be announced in the
+ european mailing list:
+ IRC-Operators Europe <irc-eu@grasp.insa-lyon.fr>
+
+
+ 3.) Cracked servers are the concern of EBIC, overiding all local
+ interests.
+
+ Guidelines:
+
+ + In a server with non-standard source code which breaks
+ the current irc protocol (especially the incorrect
+ manipulation of channel modes and user/hostname authen-
+ tication) EBIC will take action.
+
+ + The recommended action is permanent withdrawl of the
+ server from the IRC-net by removal from all its uplinks
+ configuration files.
+
+
+ 4.) A prerequisite for getting a NEW server connection within
+ Europe is an understanding of and compliance to the above
+ rules.
+
+ Guideline:
+
+ + All new admins should get a copy of these rules.
+
+
+############################################################################
+
diff --git a/doc/Nets/Europe/links.eu b/doc/Nets/Europe/links.eu
new file mode 100644
index 0000000..0d77ac7
--- /dev/null
+++ b/doc/Nets/Europe/links.eu
@@ -0,0 +1,70 @@
+Written by Per Persson <pp@pfawww.pp.se>, last update: 1996-06-18
+
+1) Europe should always be a separate net from the other parts of
+ (what was formerly known as) "EFNet". For example; Netherlands
+ with leafs and Sweden/Finland (with leafs) should always be
+ connected to eachother. There are a few times when that wont work
+ though... NORDUnet might have fuckups from time to time and in
+ those few cases we have to use more then one link to USA.
+
+2) Europe "should" be connected this way;
+
+ * irc.nada.kth.se is the primary HUB for northern Europe as well
+ as some southern European servers (.at). irc.nada.kth.se is
+ also the primary European HUB for connections to US.
+ * warszawa.irc.pl is the primary .pl HUB, primary uplink for .pl
+ is .se with .fi/.at as secondary
+ (.pl is almost never connected to "EFNet" right now)
+ * ircd.funet.fi is the primary .fi HUB and irc.cs.hut.fi is the
+ backup.
+ * irc.pvv.unit.no is the primary .no HUB and irc.ifi.uio.no is
+ the backup, primary uplink for .no is .se with .fi as secondary.
+ * irc.ru is the primary .ru HUB, primary uplink is .fi with .se as
+ secondary.
+ * irc.isnet.is's primary uplink is .fi, irc.ludd.luth.se is secondary
+ * sunsite.auc.dk's primary uplink is irc.nada.kth.se
+ * irc.ccii.unipi.it is the primary HUB for Italy, primary uplink is
+ .se with .nl/.uk as secondary.
+ * irc.felk.cvut.cz is the primary .cz HUB, primary uplink is .se.
+ * irc.sanet.sk's primary uplink is .cz.
+
+ * irc.nijnerode.nl is the primary HUB for sourthern Europe and .uk.
+ Primary uplink is irc.ludd.luth.se(irc.nada.kth.se) with .fi as
+ secondary
+ * irc.univ-lyon1.fr is the primary .fr HUB and
+ sil.polytechnique.fr is the backup. primary uplink for .fr is
+ irc.ludd.luth.se and secondary uplink for .fr is irc.cerf.net.
+ * stork.doc.ic.ac.uk is the primary .uk HUB and serv.eng.abdn.ac.uk
+ is the backup. Primary uplink is .nl with .se/.fi as secondary.
+ (.uk also has a .net server, as well as a netcom.net.uk server which
+ uses a bit different uplinks--the rest of the .uk servers are
+ connected to those on occasions as well)
+ * irc.belnet.be is the primary .be HUB, primary uplink for .be is
+ .uk with .fr/.nl as secondary.
+ * irc.wu-wien.ac.at is the primary .at HUB, primary uplink for
+ .at is .fr with .se as secondary.
+ * irc.uni-paderborn.de is the primary .de HUB, primary uplink for
+ .de is .nl with .fi as secondary.
+ (.de isn't often connected, as they have sloooow links)
+ * irc.arnes.si's primary uplink is .nl, secondary uplink is .se.
+
+ * The primary link for Europe to USA is; .se - USA
+ backups are; .fi/.nl - USA
+ (USA can be one of the following; cs-pub.bu.edu, ircd.stealth.net
+ eff.org, bazooka.rutgers.edu or irc.cerf.net. irc.cerf.net
+ is the prefered one nowadays with ircd.stealth.net as secondary)
+
+3) The ASCII map of all this, to make things "easier to comprehend".
+
+
+ (.no .dk .pl .it) __ .se __ .fi __ (.is .ru)
+ /|\
+ .uk __ .nl __/ | \__ .cz __ (.sk)
+ | | |
+ (.be) | .fr __ (.at)
+ |
+ (.si .ch .de)
+
+ ()'s marks leafs
+\ _ /'s marks links
+
diff --git a/doc/Nets/Europe/rules b/doc/Nets/Europe/rules
new file mode 100644
index 0000000..4ad34dc
--- /dev/null
+++ b/doc/Nets/Europe/rules
@@ -0,0 +1,55 @@
+Rules for IRC networking - Ratified July 6th 1994
+
+1.) The establishment of new servers and intra-domain linking should
+ be a local toplevel domain (IE: country) decision.
+
+ Guidelines:
+
+ + Only a link for ONE server should be given to the new
+ server site, that means the new site shouldn't be able to
+ connect test-servers to other than its own server.
+ (This avoids confusion about linking hierachy).
+
+ + If a toplevel domain hostmask link is given, ensure that all
+ hubs of that domain have connect access to the masked server
+ (this should avoid disagreements between hub admins within a
+ domain).
+
+2.) Hacked or cracked servers (and the machines they run on) are the
+ concern of all Admins, and override all local interests.
+
+ Guidelines:
+
+ + In a server with non-standard source code which breaks
+ the current irc protocol (especially the incorrect
+ manipulation of channel modes and user/hostname authen-
+ tication) Admins will take action, this includes the
+ testing of these patches.
+
+ + The recommended action is permanent withdrawl of the
+ server from the IRC-net by removal from all its uplinks
+ configuration files.
+
+3.) The Admins are responsible for all operator access.
+ IRC Administrators should therefore be approved by the
+ machine and network admins for the site in question.
+
+4.) Operator power may be used only on server and network
+ maintenance purposes. KILL may be used only when other
+ methods to fix a problem don't exist.
+
+Infringement of the rules as outlined above should lead to
+operator and/or admin changes on the offending server.
+Responsibility for these changes is primarily that of the uplink
+server administrators.
+
+In the event of continued transgression, further action may be
+taken by remote IRC Administrators 24 hours after the problem
+has been identified and all responsible parties have been
+notified.
+
+All intended additions to this document must be announced to IRC
+Administrators for at least one week prior to ratification.
+
+--
+Edited June 29th by #EU-Opers
diff --git a/doc/Nets/IRCNet b/doc/Nets/IRCNet
new file mode 100644
index 0000000..eaa7396
--- /dev/null
+++ b/doc/Nets/IRCNet
@@ -0,0 +1,17 @@
+The IRC Net Mailing List
+
+The IRC Net Mailing List is meant for discussion about issues concerning the
+IRC Net network. It is currently an open mailing list and you can subscribe
+by typing the following in a shell:
+
+ echo subscribe ircnet | mail majordodo@modeemi.cs.tut.fi
+
+And to see who is on the mailing list you just need to type the following:
+
+ echo who ircnet | mail majordodo@modeemi.cs.tut.fi
+
+All messages to the mailing list itself are to be sent to:
+
+ ircnet@modeemi.cs.tut.fi
+
+http://www.irc.at/bic/
diff --git a/doc/README b/doc/README
new file mode 100644
index 0000000..0567db9
--- /dev/null
+++ b/doc/README
@@ -0,0 +1,40 @@
+# @(#)$Id: README,v 1.5 1999/03/08 17:31:42 kalt Exp $
+
+This directory contains the documentation related to this package.
+
+
+
+The files relevant to the software compilation and configuration are:
+
+RELEASE_NOTES - useful information for people upgrading from a previous
+ version
+INSTALL.txt - detailed information about compilation and configuration
+example.conf - server configuration example file (useful complement to
+ INSTALL)
+
+
+
+Other files of interest:
+
+LICENSE - license agreement
+ChangeLog - log of source changes
+BUGS - list of known bugs
+2.10-New - transition documentation from 2.9 to 2.10 version
+Etiquette - IRC Etiquette
+irc.1 - man page for the client
+ircd.8 - man page for the server
+iauth.8 - man page for iauth
+iauth.conf.5 - man page for the iauth.conf file
+Authors - irc contributors
+Nets/ - documentation about various IRC networks
+Juped/ - old/obsolete documentation files
+alt-irc-faq - alt.irc faq
+m4macros - note on m4 macros for the server configuration file
+2.9-New - old transition documentation from 2.8 to 2.9 version
+
+
+
+related documents on the World Wide Web:
+
+ http://www.stealth.net/~kalt/irc/faq.html
+ http://www.irc.org/~irc/server/
diff --git a/doc/RELEASE_LOG b/doc/RELEASE_LOG
new file mode 100644
index 0000000..f3b20c6
--- /dev/null
+++ b/doc/RELEASE_LOG
@@ -0,0 +1,23 @@
+# @(#)$Id: RELEASE_LOG,v 1.6 1999/08/13 19:53:11 kalt Exp $
+
+990813 2.10.3
+990203 2.10.2
+981112 2.10.1
+980927 2.10.0
+980613 2.9.5+IPv6
+980218 2.9.5
+971020 2.9.4
+970724 2.9.3
+961109 2.9.2
+960707 2.9.1
+941203 2.8.21
+940610 2.8.20
+931109 2.8.16
+930914 2.8.14
+930807 2.8.12
+930626 2.8.10
+930405 2.7.2h
+920811 2.7.2g
+920514 2.7.2
+920114 2.7.1
+910906 2.6.2
diff --git a/doc/RELEASE_NOTES b/doc/RELEASE_NOTES
new file mode 100644
index 0000000..ee6b2e3
--- /dev/null
+++ b/doc/RELEASE_NOTES
@@ -0,0 +1,120 @@
+# @(#)$Id: RELEASE_NOTES,v 1.34 1999/08/13 17:55:01 kalt Exp $
+
+This is version 2.10.3 of the IRC software.
+
+===============================================================================
+
+New features in 2.10.3:
+ * new options for iauth.conf to better control iauth behaviour
+ * iauth now supports dynamically shared modules.
+ * socks module now checks for both v4 and v5 of the SOCKS protocol.
+ * iauth has a new module: LHEx, see ftp://ftp.irc.org/irc/server/LHEx
+
+Important changes in 2.10.3 (since 2.10.2):
+ * default PATHs have changed, see INSTALL file and Makefile.
+ * V line code was fixed, and format slightly changed again.
+
+------
+
+Because of the many changes concerning iauth, it is recommended that this new
+version of the iauth program not be used with older version of the IRC daemon.
+
+===============================================================================
+
+Version 2.10.2 of the software adds support for IPv6.
+
+Important changes in 2.10.2 (since 2.10.1):
+ * iauth's socks module now uses an internal cache.
+ * iauth's socks module now checks for SOCKSv4 (rather than v5) proxies.
+
+===============================================================================
+
+2.10 uses a new (server-server) protocol.
+
+New features in 2.10.0:
+
+ * slave process handles authentication (ident lookups, ..).
+ * creation of a collision proof type of channels (prefix !).
+ * opless !channels may be reoped by the server (mode +r).
+ * added channel mode +e (EFnet's exceptions to bans).
+ * added channel mode +I (invitations).
+ * /invite can now be used to override channel bans & limit.
+ * away status is propagated again. (away messages are not).
+ * users need +o (or +v) to speak on a channel where they're banned.
+
+Important configuration changes between 2.9.x and 2.10.x:
+
+ * The V line format has changed!
+
+------
+
+If the irc daemon is unable to bind any socket to listen to for incoming
+connections, it will die rather than stay alive.
+
+===============================================================================
+
+New feature in 2.9.5:
+ * D lines created.
+
+------
+
+2.9.5 is taking steps to suppress the usage of the 2.9 JOIN
+format (:nickname JOIN #channel^Gov). Future versions will
+not generate such joins anymore. In order to make the
+transition smooth, it is imperative that all servers on the
+IRC network be upgraded to 2.9.5 when the JOIN syntax is
+abandonned. Not doing so will result in a considerable
+increase of the amount of bandwidth used during netjoins.
+
+As a result, MIRC_KLUDGE is now defined by default in config.h
+
+------
+
+2.9.5 can be compiled on a W32 system using the Cygwin32
+library (http://www.cygnus.com/misc/gnu-win32/).
+
+===============================================================================
+
+2.9.4 doesn't support 2.8 links anymore. A 2.8.x server cannot
+be directly linked to a 2.9.4 server. They can however coexist
+on the same IRC network.
+
+------
+
+Configuration changes between 2.9.3 and 2.9.4:
+
+ * The format for I lines was extended.
+ * The format for B lines has slightly changed.
+ * The format for Y lines has changed ([user@]host limits).
+ * K lines on IP addresses now match resolving hosts by default.
+
+------
+
+As announced with the 2.9.3 release, the NOTE feature has been removed.
+A replacement has been written as an independant package, and can be found
+at the following location: ftp://ftp.cs.tu-berlin.de/pub/net/irc/noteserv/
+
+===============================================================================
+
+2.9.3 doesn't support 2.7 protocol anymore. Don't run 2.9.3
+and 2.7 servers on the same IRC network.
+
+------
+
+New features in 2.9.3:
+
+ * compression of server links.
+ * virtual IP support.
+ * B lines created. (client redirection)
+ * k lines created. (OTHER ident)
+ * V lines created. (restrict peers' compile time options)
+ * new type of client: services.
+
+------
+
+Important configuration changes between 2.9.2 and 2.9.3:
+
+ * M and P lines format has changed since 2.9.2, it is important
+ to update your ircd.conf !
+ * kill lines are now case sensitive (K: and k: are different)
+
diff --git a/doc/SERVICE.sgml b/doc/SERVICE.sgml
new file mode 100644
index 0000000..ad72843
--- /dev/null
+++ b/doc/SERVICE.sgml
@@ -0,0 +1,285 @@
+<!doctype linuxdoc system>
+
+<article>
+
+<title>IRC Services
+<author>Christophe Kalt
+<date>$Id: SERVICE.sgml,v 1.6 1999/04/15 21:55:52 kalt Exp $
+<abstract>
+The IRC protocol described in RFC 1459 defines two types of
+connections (client, and server). A third type was
+introduced with version 2.9 of the IRC software: service
+connections. This document describes what services are, and
+how to use them.
+</abstract>
+
+<sect>A new type of connection
+<p>
+A service connection is something between a client and a
+server connection. It is not closer from any, as a matter
+of fact, the scope is pretty broad.
+<sect1>A bit client
+<p>
+services are similar to clients because they cannot:
+<itemize>
+<item> introduce other clients, services, or servers.
+<item> change the global state of the net. (kill, squit..)
+</itemize>
+<sect1>A bit server
+<p>
+services are similar to servers because:
+<itemize>
+<item> they cannot join channels.
+<item> they are not limited by flood control or penalty.
+<item> they can see all users, servers, services.
+<item> they can see all channel names.
+<item> they cannot freely connect to a server.
+<item> they may optionally receive a connection burst.
+</itemize>
+<sect1>Really unique
+<p>
+services are unique because:
+<itemize>
+<item> they are not subject to collisions.
+<item> they can be local to one, or more servers, or global.
+<item> they can only send notices, not private messages.
+<item> they can only be contacted by the use of SQUERY.
+</itemize>
+<p>
+Services are not meant to be used interactively, but provide
+adequate support for automatons, statistic gathering,
+monitoring.
+
+<sect>What users see
+<p>
+This section covers the aspects visible to the users.
+<sect1>&amp;SERVICES
+<p>
+This is a special channel, similar to &amp;SERVERS, on which
+are sent notices when a service connects to or quit the net.
+<sect1>SERVLIST
+<p>
+This new command gives the list of services currently
+present on the IRC network. It can take two arguments.
+<enum>
+<item> a mask to limit the output to the services which
+names matches the mask.
+<item> a type to list only services of a specific type.
+</enum>
+It returns a list of servers using numeric 234, the
+different fields are:
+<itemize>
+<item> The service name.
+<item> The name of the server which introduced it on the
+net.
+<item> The <ref id="dist" name="distribution"> mask.
+<item> The service <ref id="type" name="type">.
+<item> The hop count between you and the service.
+<item> A comment.
+</itemize>
+<sect1>SQUERY
+<p>
+This new command stands for ``Service Query''. The first
+argument is the service name, and the second the text to be
+sent to the service.
+
+<sect>How to set up a service
+<sect1>Compile time option for the server
+<p>
+First of all, it is important to note that in order to be
+able to connect a service to a server, this server must have
+been compiled with ``<bf>USE_SERVICES</bf>'' defined in the
+config.h file. To know if your server has been compiled
+with this option, check the version:
+<p>
+351 Server irc.stealth.net: 2.9.3. AaCeEFiIkMu$_V1
+<p>
+351 Server irc.pvv.unit.no: 2.9.3. AaeEFHiKMp<bf>s</bf>tuYZ_V1
+<p>
+Here, only ``irc.pvv.unit.no'' was compiled with the
+``USE_SERVICES'' defined as the lowercase ``s'' shows in the
+version string.
+<p>
+As they are special clients, services need to be allowed
+access to the server in the configuration file. Each
+service needs its own access to be setup. This is gone by
+adding an S: line to the configuration file. This lines
+defines the name of the service, as well as the type.
+<sect1>Glossary
+<p>
+Services have two main characteristics:
+<descrip>
+<label id="type">
+<tag/Type/ This is a misleading name. The type is actually
+a bit mask which defines what information the service can
+see. The server configuration file limits the type allowed
+for a service. The meaning of the bits is defined in the
+service.h file coming with the IRC software:
+<verb>
+SERVICE_WANT_SERVICE 0x00000001 /* other services signing on/off */
+SERVICE_WANT_OPER 0x00000002 /* operators, included in umodes too */
+SERVICE_WANT_UMODE 0x00000004 /* user modes, iow + local modes */
+SERVICE_WANT_AWAY 0x00000008 /* away isn't propaged anymore.. */
+SERVICE_WANT_KILL 0x00000010 /* KILLs */
+SERVICE_WANT_NICK 0x00000020 /* all NICKs (new user, change) */
+SERVICE_WANT_USER 0x00000040 /* USER signing on */
+SERVICE_WANT_QUIT 0x00000080 /* all QUITs (users signing off) */
+SERVICE_WANT_SERVER 0x00000100 /* servers signing on */
+SERVICE_WANT_WALLOP 0x00000200 /* wallops */
+SERVICE_WANT_SQUIT 0x00000400 /* servers signing off */
+SERVICE_WANT_RQUIT 0x00000800 /* regular user QUITs (these which
+ are also sent between servers) */
+SERVICE_WANT_MODE 0x00001000 /* channel modes (not +ov) */
+SERVICE_WANT_CHANNEL 0x00002000 /* channel creations/destructions */
+SERVICE_WANT_VCHANNEL 0x00004000 /* channel joins/parts */
+SERVICE_WANT_TOPIC 0x00008000 /* channel topics */
+
+SERVICE_WANT_ERRORS 0x01000000 /* &amp;ERRORS */
+SERVICE_WANT_NOTICES 0x02000000 /* &amp;NOTICES */
+SERVICE_WANT_LOCAL 0x04000000 /* &amp;LOCAL */
+SERVICE_WANT_NUMERICS 0x08000000 /* &amp;NUMERICS */
+
+SERVICE_WANT_USERLOG 0x10000000 /* FNAME_USERLOG */
+SERVICE_WANT_CONNLOG 0x20000000 /* FNAME_CONNLOG */
+</verb>
+<label id="dist">
+<tag/Distribution/ This controls the propagation of the
+service. The distribution is checked against server names,
+the service will only be on servers which names matches the
+distribution.
+<p>
+It also eventually limits the information received by the
+service (depending on the service type). A service will not
+have any information concerning users or services connected
+to a server which name does not match the distribution.
+<p>
+Examples:
+<descrip>
+<tag/irc.funet.fi/Using a server name as distribution makes
+the service local to the particular server.
+<tag/*.fr/This would match any server in the toplevel ``fr''.
+<tag/*/This is the distribution to be used to make the
+service global.
+</descrip>
+<p>
+It is important to note that the path between the service
+and a server <bf>must</bf> be composed of servers which have
+matching names:
+<verb>
+trondheim.irc.no <----> ircd.funet.fi <-----> oslo.irc.no
+ ^ ^
+ | |
+ | +------> bergen.irc.no
+ |
+ +-------[MyService - Distribution *.no]
+</verb>
+As shown above, if two ``*.no'' servers have a non ``*.no''
+(for example here a ``*.fi'') server connected between them,
+in this case the information related to ``MyService'' will
+not propagate to ``oslo.irc.no''.
+<p>
+This means that the service will see information concerning
+the ``3 *.no'' servers, but ``oslo.irc.no'' will have no
+knowledge of the presence of ``MyService''. Also, the
+service is unable to send anything thru ``ircd.funet.fi''.
+</descrip>
+<sect1>Signing on as a service
+<p>
+Once the S: line setup on the server, the service connects
+by sending the password (PASS command), and then issuing a
+``SERVICE'' command:
+<p>
+SERVICE servicename servername distribution servicetype 0 :Information
+<descrip>
+<tag/servicename/ This is the name of the service as configured
+by the S line.
+<tag/servername/ This is ignored by the server.
+<tag/distribution/ This is the distribution mask for this
+connection.
+<tag/servicetype/ This is the service type as configured by
+the S line. (It must match)
+<tag/Information/ This is any information. It will be sent
+in ``SERVLIST'' replies and should be a short description of
+the service.
+</descrip>
+<p>
+A successfull registering of a service at the server will
+result in a RPL_YOURESERVICE (383) being sent back to
+the service. Any other reply as a result of sending service
+indicates an error has occured.
+<sect1>Requesting data from the server
+<p>
+Once the connection is established, the service needs to
+issue a ``SERVSET'' command to receive the data it wants:
+<p>
+SERVSET mask1 mask2
+<descrip>
+<tag/mask1/ It is a subset of the service type. It defines
+what the kind of information the service wants to receive
+for this particular connection.
+<p>
+This mask can also have the following bits set, regardless
+of what the S line setting is:
+<verb>
+SERVICE_WANT_PREFIX 0x10000 /* to receive n!u@h instead of n */
+SERVICE_WANT_TOKEN 0x20000 /* use server token instead of name */
+SERVICE_WANT_EXTNICK 0x40000 /* user extended NICK syntax */
+</verb>
+<tag/mask2/ It is optional. It is a subset of mask1 that
+defines which information the service wants to receive in a
+``connection burst''. The information is similar to a
+server ``connection burst'', it describe the current set of
+the network. The service can therefore store the
+information in memory and update it.
+<tag/Note/The ``SERVSET'' command can only be issued once.
+</descrip>
+
+<sect>General notes for server and service administrators
+<sect1>User privacy
+<p>
+Services can see almost as much information as a server.
+This means that granting a service connection should be
+considered with as much care as granting a server
+connection. In particular, the service type should be
+limited to the strict minimum needed for the service to be
+operational. In most cases, a service type of 0 is enough.
+<p>
+A great care should be taken to make sure that a service
+cannot be (ab)used to obtain information not normally
+accessible to users (such as showing invisible
+users). <bf>Administrators must remember that the privacy of
+the users is at stake</bf>.
+<sect1>Guidelines
+<p>
+To avoid confusion, it is a good idea to obey the following
+simple rules:
+<descrip>
+<tag/Name/The name should be descriptive, and if possible
+unique on the network.
+<tag/Information/The service ``information'' should be short
+and descriptive.
+<tag/Mandatory queries/The service must reply to at least 2
+queries:
+<descrip>
+<tag/ADMIN/Name and e-mail address of the administrator.
+<tag/HELP/List of queries understood by the service. Each
+query should also have an help.
+</descrip>
+<tag/Basic queries/These queries should also be understood
+by the service:
+<descrip>
+<tag/INFO/This should be a short text explaining what the
+service and its purpose are.
+<tag/VERSION/The version of the running code.
+</descrip>
+</descrip>
+<sect1>Flood control
+<p>
+Also, since services are not affected by flood control, they
+can easily flood the IRC network with information. They
+should be conceived so this does not happen.
+<p>
+Services should implement their own flood control (for
+outgoing traffic) to be safe.
+
+</article>
diff --git a/doc/SERVICE.txt b/doc/SERVICE.txt
new file mode 100644
index 0000000..fa07c3a
--- /dev/null
+++ b/doc/SERVICE.txt
@@ -0,0 +1,330 @@
+ IRC Services
+ Christophe Kalt
+ $Id: SERVICE.txt,v 1.7 1999/04/15 21:56:53 kalt Exp $
+
+ The IRC protocol described in RFC 1459 defines two types of connec-
+ tions (client, and server). A third type was introduced with version
+ 2.9 of the IRC software: service connections. This document describes
+ what services are, and how to use them.
+
+ 11.. AA nneeww ttyyppee ooff ccoonnnneeccttiioonn
+
+ A service connection is something between a client and a server
+ connection. It is not closer from any, as a matter of fact, the scope
+ is pretty broad.
+
+ 11..11.. AA bbiitt cclliieenntt
+
+ services are similar to clients because they cannot:
+
+ +o introduce other clients, services, or servers.
+
+ +o change the global state of the net. (kill, squit..)
+
+ 11..22.. AA bbiitt sseerrvveerr
+
+ services are similar to servers because:
+
+ +o they cannot join channels.
+
+ +o they are not limited by flood control or penalty.
+
+ +o they can see all users, servers, services.
+
+ +o they can see all channel names.
+
+ +o they cannot freely connect to a server.
+
+ +o they may optionally receive a connection burst.
+
+ 11..33.. RReeaallllyy uunniiqquuee
+
+ services are unique because:
+
+ +o they are not subject to collisions.
+
+ +o they can be local to one, or more servers, or global.
+
+ +o they can only send notices, not private messages.
+
+ +o they can only be contacted by the use of SQUERY.
+
+ Services are not meant to be used interactively, but provide adequate
+ support for automatons, statistic gathering, monitoring.
+
+
+ 22.. WWhhaatt uusseerrss sseeee
+
+ This section covers the aspects visible to the users.
+
+ 22..11.. &&SSEERRVVIICCEESS
+
+ This is a special channel, similar to &SERVERS, on which are sent
+ notices when a service connects to or quit the net.
+
+
+
+ 22..22.. SSEERRVVLLIISSTT
+
+ This new command gives the list of services currently present on the
+ IRC network. It can take two arguments.
+
+ 1. a mask to limit the output to the services which names matches the
+ mask.
+
+ 2. a type to list only services of a specific type.
+
+ It returns a list of servers using numeric 234, the different
+ fields are:
+
+ +o The service name.
+
+ +o The name of the server which introduced it on the net.
+
+ +o The ``distribution'' mask.
+
+ +o The service ``type''.
+
+ +o The hop count between you and the service.
+
+ +o A comment.
+
+ 22..33.. SSQQUUEERRYY
+
+ This new command stands for ``Service Query''. The first argument is
+ the service name, and the second the text to be sent to the service.
+
+
+ 33.. HHooww ttoo sseett uupp aa sseerrvviiccee
+
+ 33..11.. CCoommppiillee ttiimmee ooppttiioonn ffoorr tthhee sseerrvveerr
+
+ First of all, it is important to note that in order to be able to
+ connect a service to a server, this server must have been compiled
+ with ``UUSSEE__SSEERRVVIICCEESS'' defined in the config.h file. To know if your
+ server has been compiled with this option, check the version:
+
+ 351 Server irc.stealth.net: 2.9.3. AaCeEFiIkMu$_V1
+
+ 351 Server irc.pvv.unit.no: 2.9.3. AaeEFHiKMpsstuYZ_V1
+
+ Here, only ``irc.pvv.unit.no'' was compiled with the ``USE_SERVICES''
+ defined as the lowercase ``s'' shows in the version string.
+
+ As they are special clients, services need to be allowed access to the
+ server in the configuration file. Each service needs its own access
+ to be setup. This is gone by adding an S: line to the configuration
+ file. This lines defines the name of the service, as well as the
+ type.
+
+ 33..22.. GGlloossssaarryy
+
+ Services have two main characteristics:
+
+
+ TTyyppee
+ This is a misleading name. The type is actually a bit mask
+ which defines what information the service can see. The server
+ configuration file limits the type allowed for a service. The
+ meaning of the bits is defined in the service.h file coming with
+ the IRC software:
+
+
+ SERVICE_WANT_SERVICE 0x00000001 /* other services signing on/off */
+ SERVICE_WANT_OPER 0x00000002 /* operators, included in umodes too */
+ SERVICE_WANT_UMODE 0x00000004 /* user modes, iow + local modes */
+ SERVICE_WANT_AWAY 0x00000008 /* away isn't propaged anymore.. */
+ SERVICE_WANT_KILL 0x00000010 /* KILLs */
+ SERVICE_WANT_NICK 0x00000020 /* all NICKs (new user, change) */
+ SERVICE_WANT_USER 0x00000040 /* USER signing on */
+ SERVICE_WANT_QUIT 0x00000080 /* all QUITs (users signing off) */
+ SERVICE_WANT_SERVER 0x00000100 /* servers signing on */
+ SERVICE_WANT_WALLOP 0x00000200 /* wallops */
+ SERVICE_WANT_SQUIT 0x00000400 /* servers signing off */
+ SERVICE_WANT_RQUIT 0x00000800 /* regular user QUITs (these which
+ are also sent between servers) */
+ SERVICE_WANT_MODE 0x00001000 /* channel modes (not +ov) */
+ SERVICE_WANT_CHANNEL 0x00002000 /* channel creations/destructions */
+ SERVICE_WANT_VCHANNEL 0x00004000 /* channel joins/parts */
+ SERVICE_WANT_TOPIC 0x00008000 /* channel topics */
+
+ SERVICE_WANT_ERRORS 0x01000000 /* &ERRORS */
+ SERVICE_WANT_NOTICES 0x02000000 /* &NOTICES */
+ SERVICE_WANT_LOCAL 0x04000000 /* &LOCAL */
+ SERVICE_WANT_NUMERICS 0x08000000 /* &NUMERICS */
+
+ SERVICE_WANT_USERLOG 0x10000000 /* FNAME_USERLOG */
+ SERVICE_WANT_CONNLOG 0x20000000 /* FNAME_CONNLOG */
+
+
+
+ DDiissttrriibbuuttiioonn
+ This controls the propagation of the service. The distribution
+ is checked against server names, the service will only be on
+ servers which names matches the distribution.
+
+ It also eventually limits the information received by the
+ service (depending on the service type). A service will not
+ have any information concerning users or services connected to a
+ server which name does not match the distribution.
+
+ Examples:
+
+ iirrcc..ffuunneett..ffii
+ Using a server name as distribution makes the service local
+ to the particular server.
+
+ **..ffrr
+ This would match any server in the toplevel ``fr''.
+
+ ** This is the distribution to be used to make the service
+ global.
+
+ It is important to note that the path between the service and a
+ server mmuusstt be composed of servers which have matching names:
+
+ trondheim.irc.no <----> ircd.funet.fi <-----> oslo.irc.no
+ ^ ^
+ | |
+ | +------> bergen.irc.no
+ |
+ +-------[MyService - Distribution *.no]
+
+
+ As shown above, if two ``*.no'' servers have a non ``*.no'' (for
+ example here a ``*.fi'') server connected between them, in this
+ case the information related to ``MyService'' will not propagate to
+ ``oslo.irc.no''.
+
+ This means that the service will see information concerning the ``3
+ *.no'' servers, but ``oslo.irc.no'' will have no knowledge of the
+ presence of ``MyService''. Also, the service is unable to send
+ anything thru ``ircd.funet.fi''.
+
+ 33..33.. SSiiggnniinngg oonn aass aa sseerrvviiccee
+
+ Once the S: line setup on the server, the service connects by sending
+ the password (PASS command), and then issuing a ``SERVICE'' command:
+
+ SERVICE servicename servername distribution servicetype 0 :Information
+
+ sseerrvviicceennaammee
+ This is the name of the service as configured by the S line.
+
+ sseerrvveerrnnaammee
+ This is ignored by the server.
+
+ ddiissttrriibbuuttiioonn
+ This is the distribution mask for this connection.
+
+ sseerrvviicceettyyppee
+ This is the service type as configured by the S line. (It must
+ match)
+
+ IInnffoorrmmaattiioonn
+ This is any information. It will be sent in ``SERVLIST''
+ replies and should be a short description of the service.
+
+ A successfull registering of a service at the server will result in a
+ RPL_YOURESERVICE (383) being sent back to the service. Any other reply
+ as a result of sending service indicates an error has occured.
+
+ 33..44.. RReeqquueessttiinngg ddaattaa ffrroomm tthhee sseerrvveerr
+
+ Once the connection is established, the service needs to issue a
+ ``SERVSET'' command to receive the data it wants:
+
+ SERVSET mask1 mask2
+
+ mmaasskk11
+ It is a subset of the service type. It defines what the kind of
+ information the service wants to receive for this particular
+ connection.
+
+ This mask can also have the following bits set, regardless of
+ what the S line setting is:
+
+ SERVICE_WANT_PREFIX 0x10000 /* to receive n!u@h instead of n */
+ SERVICE_WANT_TOKEN 0x20000 /* use server token instead of name */
+ SERVICE_WANT_EXTNICK 0x40000 /* user extended NICK syntax */
+
+
+
+ mmaasskk22
+ It is optional. It is a subset of mask1 that defines which
+ information the service wants to receive in a ``connection
+ burst''. The information is similar to a server ``connection
+ burst'', it describe the current set of the network. The
+ service can therefore store the information in memory and update
+ it.
+
+ NNoottee
+ The ``SERVSET'' command can only be issued once.
+
+
+ 44.. GGeenneerraall nnootteess ffoorr sseerrvveerr aanndd sseerrvviiccee aaddmmiinniissttrraattoorrss
+
+ 44..11.. UUsseerr pprriivvaaccyy
+
+ Services can see almost as much information as a server. This means
+ that granting a service connection should be considered with as much
+ care as granting a server connection. In particular, the service type
+ should be limited to the strict minimum needed for the service to be
+ operational. In most cases, a service type of 0 is enough.
+
+ A great care should be taken to make sure that a service cannot be
+ (ab)used to obtain information not normally accessible to users (such
+ as showing invisible users). AAddmmiinniissttrraattoorrss mmuusstt rreemmeemmbbeerr tthhaatt tthhee
+ pprriivvaaccyy ooff tthhee uusseerrss iiss aatt ssttaakkee.
+
+ 44..22.. GGuuiiddeelliinneess
+
+ To avoid confusion, it is a good idea to obey the following simple
+ rules:
+
+ NNaammee
+ The name should be descriptive, and if possible unique on the
+ network.
+
+ IInnffoorrmmaattiioonn
+ The service ``information'' should be short and descriptive.
+
+ MMaannddaattoorryy qquueerriieess
+ The service must reply to at least 2 queries:
+
+ AADDMMIINN
+ Name and e-mail address of the administrator.
+
+ HHEELLPP
+ List of queries understood by the service. Each query should
+ also have an help.
+
+ BBaassiicc qquueerriieess
+ These queries should also be understood by the service:
+
+ IINNFFOO
+ This should be a short text explaining what the service and
+ its purpose are.
+
+ VVEERRSSIIOONN
+ The version of the running code.
+
+ 44..33.. FFlloooodd ccoonnttrrooll
+
+ Also, since services are not affected by flood control, they can
+ easily flood the IRC network with information. They should be
+ conceived so this does not happen.
+
+ Services should implement their own flood control (for outgoing
+ traffic) to be safe.
+
+
+
+
+
+
+
+
+
+
+
diff --git a/doc/alt-irc-faq b/doc/alt-irc-faq
new file mode 100644
index 0000000..3a5bdb5
--- /dev/null
+++ b/doc/alt-irc-faq
@@ -0,0 +1,293 @@
+(1) What is IRC?
+
+ IRC stands for "Internet Relay Chat". It was originally
+written by Jarkko Oikarinen (jto@tolsun.oulu.fi) in 1988. Since starting
+in Finland, it has been used in over 60 countries around the world. It
+was designed as a replacement for the "talk" program but has become much
+much more than that. IRC is a multi-user chat system, where people convene
+on "channels" (a virtual place, usually with a topic of conversation) to
+talk in groups, or privately. IRC is constantly evolving, so the way
+things to work one week may not be the way they work the next. Read the
+MOTD (message of the day) every time you use IRC to keep up on any new
+happenings or server updates.
+
+ IRC gained international fame during the 1991 Persian Gulf War,
+where updates from around the world came accross the wire, and most irc
+users who were online at the time gathered on a single channel to hear
+these reports. IRC had similar uses during the coup against Boris Yeltsin
+in September 1993, where IRC users from Moscow were giving live reports
+about the unstable situation there.
+
+(2) How is IRC set up?
+
+ The user runs a "client" program (usually called 'irc') which
+connects to the IRC network via another program called a "server".
+Servers exist to pass messages from user to user over the IRC network.
+
+(3) How do I use a client?
+
+ First, check to see if irc is installed on your system. Type
+"irc" from your prompt. If this doesn't work, ask your local systems
+people if irc is already installed. This will save you the work of
+installing it yourself.
+
+ If an IRC client isn't already on your system, you either
+compile the source yourself, have someone else on your machine compile
+the source for you, or use the TELNET client.
+"telnet ircclient.itc.univie.ac.at 6668". Please only use the latter when
+you have no other way of reaching IRC, as this resource is quite
+limited, slow, and *very* unreliable.
+
+(4) Where can I get source for an IRC client?
+
+ You can anonymous ftp to any of the following sites (use the
+one closest to you): *** If you don't know what anonymous ftp is, ask
+your local systems people to show you ***
+
+UNIX client-> cs.bu.edu /irc/clients
+ ftp.acsu.buffalo.edu /pub/irc
+ ftp.funet.fi /pub/unix/irc
+ coombs.anu.edu.au /pub/irc
+ (NB. if there is something related to IRC and it can't
+ be found under coombs.anu.edu.au:/pub/irc then it isn't
+ worth having).
+ ftp.informatik.tu-muenchen.de /pub/comp/networking/irc/clients
+ slopoke.mlb.semi.harris.com /pub/irc
+ there is also a client avaliable with the server code.
+EMACS elisp-> cs.bu.edu /irc/clients/elisp
+ ftp.funet.fi /pub/unix/irc/Emacs
+ ftp.informatik.tu-muenchen.de /pub/comp/networking/irc/clients
+ slopoke.mlb.semi.harris.com /pub/irc/emacs
+ cs.hut.fi /pub/irchat
+X11 client-> catless.ncl.ac.uk /pub
+ harbor.ecn.purdue.edu /pub/tcl/code
+VMS -> cs.bu.edu /irc/clients/vms
+ coombs.anu.edu.au /pub/irc/vms
+ ftp.funet.fi /pub/unix/irc/vms
+ ftp.informatik.tu-muenchen.de /pub/net/irc
+REXX client for VM-> cs.bu.edu /irc/clients/rxirc
+ ftp.informatik.uni-oldenburg.de /pub/irc/rxirc
+ ftp.informatik.tu-muenchen.de /pub/net/irc/VM
+ coombs.anu.edu.au /pub/irc/rxirc
+ ftp.funet.fi /pub/unix/irc/rxirc
+MSDOS-> cs.bu.edu /irc/clients/msdos
+ ftp.funet.fi /pub/unix/irc/msdos
+Macintosh-> cs.bu.edu /irc/clients/macintosh
+ sumex-aim.stanford.edu /info-mac/comm
+ ftp.funet.fi /pub/unix/irc/mac
+ ftp.ira.uka.de /pub/systems/mac
+
+(5) Which server do I connect to?
+
+ It's usually best to try and connect to one geographically
+close, even though that may not be the best. You can always ask when you
+get on IRC. Here's a list of servers avaliable for connection:
+
+USA:
+ cs-pub.bu.edu
+ irc.colorado.edu
+ irc-2.mit.edu
+
+Canada:
+ ug.cs.dal.ca
+
+Europe:
+ irc.funet.fi
+ cismhp.univ-lyon1.fr
+ disuns2.epfl.ch
+ irc.nada.kth.se
+ sokrates.informatik.uni-kl.de
+ bim.itc.univie.ac.at
+
+Australia:
+ jello.qabc.uq.oz.au
+
+
+This is, by no means, a comprehensive list, but merely a start. Connect
+to the closest of these servers and join the channel #Twilight_Zone
+When you get there, immediately ask what you want. Don't say "I have a
+question" because then hardly anyone will talk.
+
+(6) OK, I've got a client and I'm connected to a server, now what?
+
+ It's probably best to take a look around and see what you want
+to do first. All IRC commands start with a "/", and most are one word.
+Typing /help will get you help information. /names will get you a list
+of names, etc.
+
+The output of /names is typically something like this->
+
+Pub: #hack zorgo eiji Patrick fup htoaster
+Pub: #Nippon @jircc @miyu_d
+Pub: #nicole MountainD
+Pub: #hottub omar liron beer Deadog moh pfloyd Dode greywolf SAMANTHA
+
+(Note there are LOTS more channels than this, this is just sample
+output -- one way to stop /names from being too large is doing /names
+-min 20 which will only list channels with 20 or more people on it,
+but you can only do this with the ircII client).
+
+"Pub" means public (or "visible") channel. "hack" is the channel name.
+"#" is the prefix. A "@" before someone's nickname indicates he/she is the
+"Channel operator" (see #7) of that channel. A Channel Operator is someone
+who has control over a specific channel. It can be shared or not as the
+first Channel Operator sees fit. The first person to join the channel
+automatically receives Channel Operator status, and can share it with
+anyone he/she chooses (or not). Another thing you might see is "Prv"
+which means private. You will only see this if you are on that private
+channel. No one can see Private channels except those who are on that
+particular private channel.
+
+(7) What is a channel operator? What is an IRC operator?
+
+ A channel operator is someone with a "@" by their nickname in
+a /names list, or a "@" by the channel name in /whois output. Channel
+operators are kings/queens of their channel. This means they can kick
+you out of their channel for no reason. If you don't like this, you
+can start your own channel and become a channel operator there.
+
+ An IRC operator is someone who maintains the IRC network. They
+cannot fix channel problems. They cannot kick someone out of a channel
+for you. They cannot /kill (kick someone out of IRC temporarily)
+someone just because you gave the offender channel operator privileges
+and said offender kicked *you* off.
+
+(8) What is a "bot"?
+
+ "bot" is short for "robot". It is a script run from an ircII
+client or a separate program (in perl, C, and sometimes more obscure
+languages). StarOwl@uiuc.edu (Michael Adams) defined bots very well: "A
+bot is a vile creation of /lusers to make up for lack of penis length".
+IRC bots are generally not needed. See (10) below about "ownership" of
+nicknames and channels.
+
+ It should be noted that many servers (especially in the USA) have
+started to ban ALL bots. Some ban bots so much that if you run a bot on
+their server, you will be banned from using that server (see segment below
+on K: lines).
+
+(9) What are good channels to try while using IRC?
+
+ #hottub and #initgame are almost always teeming with people.
+#hottub is meant to simulate a hot tub, and #initgame is a non-stop game
+of "inits" (initials). Just join and find out!
+
+ To get a list of channels with their names and topics, do
+/list -min 20 (on ircII) which will show you channels with 20 or more
+members. You can also do this for smaller numbers.
+
+ Many IRC operators are in #Twilight_Zone ... so if you join
+that channel be prepared for a lot of senseless dribble, more like what
+you find on the other channels listed above (#hottub). What was once a
+place of people who could help you has turned into just another place
+for those who have nothing better to do with themselves than just be
+there. If you find other documents saying go there to ask questions,
+ignore them. They should be considered to be out of date.
+
+(10) Someone is using my nickname, can anyone do anything about it?
+ Someone is using my channel, can anyone do anything about it?
+
+ There are not enough nicknames to have nickname ownership. If
+someone takes your nickname while you are not on IRC, you can ask for
+them to give it back, but you can not *demand* it, nor will IRC operators
+/kill for nickname ownership. If you goto #Twilight_zone, you will find
+a bunch of people who will refuse to do this for you, yet they will do it
+for themselves or their friends or use /kill for even less reasonable uses.
+
+ There are, literally, millions of possible channel names, so if
+someone is on your usual channel, just go to another. You can /msg them
+and ask for them to leave, but you can't *force* them to leave.
+
+(11) There aren't any channel operators on my channel, now what?
+
+ Channel operators are the owner(s) of their respective channels.
+Keep this in mind when giving out channel operator powers (make sure to
+give them to enough people so that all of the channel operators don't
+unexpectedly leave and the channel is stuck without a channel operator).
+
+ On the other hand, do not give out channel operator to
+*everyone*. This causes the possibility of mass-kicking, where the
+channel would be stuck without any channel operators.
+
+ You have one option. You can ask everyone to leave and rejoin
+the channel. This is a good way to get channel operator back. It
+doesn't work on large channels or ones with bots, for obvious reasons.
+
+(12) What if someone tells me to type something cryptic?
+
+ Never type anything anyone tells you to without knowing what it
+is. There is a problem with typing certain commands with the ircII
+client that give anyone immediate control of your client (and thus can
+gain access to your account).
+
+(13) What does "*** Ghosts are not allowed on IRC." mean?
+
+ On IRC, you cannot be banned from every single server.
+Server-banning exists only on a per-server basis (being banned on one
+server does not mean you are automatically banned from another). "Ghosts
+are not allowed on IRC" means that you are banned from using that server.
+The banning is in one of three forms:
+
+ * You are banned specifically, you yourself. Only you can be responsible
+ for this (if you are using a shared account, this obviously does not
+ apply). Thus the responsibility lies completely with you and you have
+ noone to complain to.
+
+ * Your machine is banned. Chances are it wasn't you who committed the
+ wrongdoing. Try using another machine on campus and seeing if you can
+ use that particular irc server then.
+
+ * Your whole site is banned (where "site" == "school", "company",
+ "country"). This almost certainly wasn't your fault. And chances are
+ you won't be able to get the server-ban lifted. Try using another
+ server.
+
+ The most general answer is "use another server", but if it bothers
+you, try writing to the irc administrator of that site -->
+/admin server.name.here -- plead your case. It might even get somewhere!
+
+(14) Where can I find GIF archives of IRC people?
+
+ GIF archives of IRC people are available:
+
+ ftp.funet.fi:/pub/pics/people/misc/irc (NORDUnet only)
+ ftp.informatik.tu-muenchen.de /pub/comp/networking/irc/RP
+
+(15) Where can I learn more?
+
+ The best, basic, IRC user's manual is the IRC Primer,
+available in plain text, PostScript, and LaTeX from
+cs-pub.bu.edu:/irc/support ... Another good place to start might be
+downloading the IRC tutorials. They're avaliable via anonymous ftp
+from cs-pub.bu.edu in /irc/support/tutorial.*
+
+ You can also join various IRC related mailing lists:
+
+ * "operlist" is a list that discusses current (and past) server code,
+ routing, and protocol. *WARNING* this mailling list has a *LOT* of
+ flame traffic from those who think they know everything but in reality
+ have no better idea than you. You can join by mailing
+ operlist-request@kei.com.
+
+ * "irchat" is an elisp client. You can join the irchat mailing list by
+ mailing irchat-request@cc.tut.fi.
+
+ * "ircd-three" is a list that exists to discuss protocol revisions
+ for the 3.0 release of the ircd (irc server), currently in
+ planning. Mail ircd-three-request@kei.com to be added.
+
+ * "vmsirc" is a list for the questions, problems, and discussions
+ related to the vms IRC clients. Mail vmsirc-request@vax1.elon.edu
+ (with "subscribe" in the message body).
+
+NOTE! These are not "Help me, where can I get started?" lists. For
+that information, read the IRCprimer noted above.
+
+ Those looking for more technical information can get the IRC
+RFC (rfc1459) available at all RFC ftp sites, as well as
+cs-pub.bu.edu:/irc/support/rfc1459.txt
+
+(16) What do I do if I'm still confused or have additions to this document?
+
+ email hrose@kei.com or avalon@coombs.anu.edu.au
+
diff --git a/doc/example.conf b/doc/example.conf
new file mode 100644
index 0000000..afcc9c2
--- /dev/null
+++ b/doc/example.conf
@@ -0,0 +1,531 @@
+# IRC - Internet Relay Chat, doc/example.conf
+# Copyright (C) 1994, Helen Rose
+#
+# $Id: example.conf,v 1.11 1999/07/14 16:17:23 kalt Exp $
+#
+# some changes for 295 and cleaning, delta, Sat Jun 13 01:09:25 MES 1998
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 1, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+# This is an example configuration file for the IRC server.
+# It's highly suggested that you also read INSTALL.* in doc/ and talk with
+# your uplinks if linking to an already existent IRC network.
+#
+# You only need an ircd.conf (IRC server configuration file) if you are
+# running an IRC server. If you are running a standalone client this file
+# is not necessary.
+#
+# This file will explain the various lines in the IRC server
+# configuration file. Not all lines are mandatory. You can check to make
+# sure that your configuration file is correct by using the program
+# "chkconf", provided in the server distribution (and when you do "make
+# install" this program will be installed in the same directory as the irc
+# server).
+#
+# The options for whether a line is needed or not are:
+# MANDATORY: you absolutely MUST have this line
+# NETWORKED: you must have this line if you are connecting this irc
+# server to any other server (servers can run standalone).
+# SUGGESTED: it is HIGHLY suggested that you use this line
+# OPTIONAL: it's completely up to you whether to define this or not
+# DISCOURAGED: you really really should not use this line if at all
+# possible.
+# NOT NECESSARY: an old or out of date line that isn't needed.
+#
+#
+# ========================================================================
+# NOTE! this entire configuration file is read UPSIDE-DOWN! So if you have
+# to put something in a specific order (for example, client-connection
+# lines), put them in reverse order!
+# ========================================================================
+#
+#
+############################
+# M: [MANDATORY]. This line sets your server's name, description and port
+# the server listens for UDP pings (used to determine the fastest link in a
+# class when autoconnecting)
+#
+# M:<Server NAME>:<YOUR Internet IP#>:<Geographic Location>:<Port>
+#
+# Note that 'server name' refers to the name of the irc-server which needs
+# not to be the same as the hostname of the machine it's running on.
+#
+# this let's ircd use the primary ip of your host to establish connections
+M:csa.bu.edu::Boston University Computer Science Department:6667
+#
+# this let's ircd use the ip 128.197.13.20 to establish connections, useful
+# if you're running virtual interfaces
+#M:csa.bu.edu:128.197.13.20:Boston University Computer Science Department:6667
+#
+#
+############################
+# A: [MANDATORY]. This line lists your administrative information
+# (contact address, etc). To view this information, /admin (server) will
+# show it to you.
+#
+# A:<Your Name/Location>:<Your Electronic Mailing Addr>:<other information>::
+#
+A:Boston University CS Department:Helen Rose <hrose@cs.bu.edu>:Client Server::
+#
+#
+############################
+# P: [MANDATORY]. This field allows the server to listen on various ports
+# for connections. Any internet domain port that is below 1024 means the
+# ircd has to be run as root, or from inetd. The server can listen to ports
+# in the UNIX domain or the internet domain. If you wish to create a port
+# in the UNIX domain you must compile with UNIXPORT defined in config.h.
+#
+# P:<YOUR Internet IP#>:<*>:<Internet IP Mask>:<Port>:
+# P:<Directory>:<*>:<*>:<Port>:
+#
+# Note that it's a good idea to open some more ports than 6667 for
+# server-server connections and local clients in case some running wild
+# client blocks the default 6667.
+#
+# the default, an internet domain socket on port 6667 listening on all
+# ip addresses of the machine running ircd
+P::::6667:
+#
+# an internet domain socket listening on port 6668 on address 206.252.192.20
+# (again useful if you're running virtual interfaces)
+P:206.252.192.20:::6668:
+#
+# an internet domain socket listening on port 6669 for connections from
+# addresses matching 147.210.18.* :
+P:::147.210.18.*:6669:
+#
+# This line is an example of a UNIX domain socket in /tmp
+P:/tmp/.ircd:*:*:6666:
+#
+#
+############################
+# Y: [SUGGESTED]. These lines define connection classes. Connection
+# classes allow you to fine-tune your client and server connections.
+# Since the fields have different meanings for server and client classes
+# you shouldn't mix them, and if you have lots of server connections (if
+# you do have lots of servers you shouldn't be reading this file :-) each
+# set of servers (defined arbitrarily by you) should have its own class.
+# If you have clients coming in from lots of different sites, you may want
+# to seperate them out into classes. For instance, you may want to put
+# local users in one class, with remote users in another class. You may also
+# want to put limits on some client classes (one client only for indials
+# for example). In any larger network you definitely want to do this.
+#
+# For SERVER CLASSES, the fields are:
+# Y:<Class>:<Ping Frequency>:<Connect freq>:<Max Links>:<SendQ>::
+# 1 2 3 4 5 67
+# 1 class number
+# 2 ping frequency (in seconds)
+# 3 connect frequency (in seconds)
+# 4 maximum number of automatically initiated links in this class
+# 5 sendq (this overrides any MAXSENDQLENGTH set in config.h)
+# 6 unused for server classes
+# 7 unused for server classes
+#
+# The class numbers are not arbitrary. In auto-connecting servers -- that is,
+# servers that you have a port number (e.g. 6667) on the end of the C: line
+# (see below) the higher the number the higher the priority in auto-connecting.
+#
+# Note that it is a good idea to have ping frequency the same at both ends
+# of the link.
+#
+# this is a normal server connection (normal as of October, 1997)
+# Y:<Class>:<Ping Frequencys>:<Connect freq>:<Max Links>:<SendQ>::
+Y:2:90:300:1:4000000
+#
+#
+# For CLIENT CLASSES, the fields are:
+# Y:<Class>:<Ping Frequency>::<Max Links>:<SendQ>:<Local Limit>:<Global Limit>
+# 1 2 3 4 5 6 7
+# 1 class number
+# 2 ping frequency (in seconds)
+# 3 unused for client classes
+# 4 maximum number of links in this class (per I line)
+# 5 sendQ for each client
+# 6 maximum number of links from this [user@]host on the server
+# 7 maximum number of links from this [user@]host on the net
+#
+# local and global limits have the format <x>.<y> where x defines the maximum
+# number of clients from the same host (IP) whereas y defines the maximum
+# number of clients from the same user@host (IP) allowed to connect. the
+# latter uses the identd replies to identify a user, falling back to an
+# @host limit if no identd runs on the client and fails for identds generating
+# dynamical answers.
+#
+# Note that any unset values default to zero which means 'unlimited'.
+#
+# Y:<Class>:<Ping Frequency>::<Max Links>:<SendQ>:<Local Limit>:<Global Limit>
+# this is a class for multiuser systems allowing 10 local clients per host
+Y:10:90::100:512000:10:32
+#
+# this is a class for multiuser systems running a trustworthy identd
+Y:11:90::100:512000:0.1:0.2
+#
+# this is a class for single user systems (PCs, most indials, ...)
+Y:12:90::100:512000:1:3
+#
+# this is a class for remote systems you want to allow as fallback only
+# (if you run an open server in a net you might really want this)
+Y:13:90::100:512000:1:1
+#
+#
+############################
+# i/I: [MANDATORY]. The I: lines are client-authorization lines. Without
+# these lines, no clients will be able to connect to your server.
+# Wildcards ("*") are permitted. Passwords are also possible (clients can
+# be configured to send passwords) but optional. 'I' allows full access,
+# 'i' sets restricted mode which forbids nick changes and channel op status.
+#
+# I:<TARGET Host Addr>:<Password>:<TARGET Hosts NAME>:<Port>:<Class>
+# i:<TARGET Host Addr>:<Password>:<TARGET Hosts NAME>:<Port>:<Class>
+#
+# NOTE that ircd matches on the *right-most* match and doesn't stop matching
+# after the <TARGET Hosts NAME> didn't match (see also examples below).
+#
+# Not that if <TARGET Hosts NAME> is empty ircd will show clients matching
+# the <TARGET Host Addr> and do resolve as user@host. if an I:-line has both
+# NAME and Addr defined and a client matches only the Addr part it will be
+# shown as user@ip-address regardless if it does resolv or not.
+#
+# this would allow access for any client reaching this line which doesn't
+# already have at least one connection to the net. if you run an open server
+# in a net this might be the right choice, talk to your uplinks first anyway.
+# resolving clients matching this line would be shown as user@host since
+# the field <TARGET Hosts NAME> is empty.
+# Note listing this i: line first, it will be read *last*, meaning it is
+# the "fall-through".
+#i:*@*::::13
+# With the password 'foobar'
+#i:*@*:foobar:::13
+# Note that I:*::*.bu.edu:10 would also allow _all_ clients regardless
+# if they're from *.bu.edu or not since ircd doesn't stop matching after the
+# <TARGET Hosts NAME> didn't match.
+#
+# this would allow access for any client coming from *.net, *.org, *.com or
+# other 3 char TLD
+#i:::*@*.???:13
+#
+# this allows access for any client from the ip block 192.168.0.0/16
+# regardless of its domain. if it's resolvable it will be shown as
+# user@host since the field <TARGET Hosts NAME> is empty (useful to
+# allow whole provider's blocks).
+I:*@192.168.*::::12
+#
+# This is a standard vanilla I: line which will permit anyone with an IP
+# address starting with 128.197 OR with a hostname ending in .bu.edu to
+# connect to the server. NOTE, the ircd matches on the *right-most* match,
+# so if I connect as hrose@csa.bu.edu (which is hrose@128.197.10.3) I will
+# show up on irc as hrose@csa.bu.edu since that is the first match it
+# found. (Even though the second match is valid).
+I:*@128.197.*::*@*.bu.edu::10
+#
+# and you can even specify just certain usernames as long as the client's
+# site is running a trustworthy ident daemon:
+I:::hrose@csa.bu.edu::10
+#
+# this will limit access for indials to one client per host
+I:::*@ppp*.bu.edu::12
+I:::*@indial*.bu.edu::12
+#
+#
+############################
+# O: [OPTIONAL]. These lines define operator access. You do not need to
+# have an operator to run a server. A well configured leaf site should not
+# need an operator online, if it's connections are well defined, the irc
+# administrator can use 'kill -HUP' on the ircd to reload the configuration
+# file.
+#
+# O:<TARGET Host NAME>:<Password>:<Nickname>:<Port>:<Class>
+#
+# If the person in "Nickname" is not coming from the hostname defined in
+# the first field then the person will get the error message "No O: lines
+# for your host".
+#
+# Note that you don't need to use 'Nickname' to become operator, if you're
+# using some other nick at that moment '/op Nickname' will do also.
+#
+O:*.bu.edu:Zaphod:Trillian::10
+#
+# and this line forces ident match:
+O:hrose@csa.bu.edu:Zaphod:Trillian::10
+#
+# This line is a "local operator", it is specified with a lower-case "o"
+#
+# this line permits the nickname "jhs" with the password of "ITBites" to
+# be a local operator only (be able to issue commands locally -- can /kill
+# and /squit and /connect -- but *only* locally)
+#
+o:*.bu.edu:ITBites:jhs::10
+#
+# a crypted password line (NOTE that if you have crypted passwords, *all*
+# of you passwords must be crypted! In fact, if you are getting an error
+# "Incorrect Password" it may well be because crypted passwords are
+# defined and you have used plaintext. So my example of plaintext and
+# crypted strings in the same IRC server configuration file is an
+# impossibility (but it is just theoretical, which is why I explained both).
+#
+O:rocker@csa.bu.edu:T0eiVgHrqeKTQ:Rocker::10
+#
+#
+############################
+# c/C: [NETWORKED]. These lines define what servers your server tries to
+# connect to. 'c' means your server will support compression for this link
+# if you've compiled with zlib, 'C' will enforce an uncompressed link.
+# N: [NETWORKED]. These lines define what servers your server permits
+# to connect.
+#
+# c/N lines MUST be used in pairs. You cannot have one without the other.
+#
+# C:<TARGET Host Addr>:<Password>:<TARGET Server NAME>:<TARGET PORT>:<Class>
+# c:<TARGET Host Addr>:<Password>:<TARGET Server NAME>:<TARGET PORT>:<Class>
+#
+# if the target server listens on different ports you can use for <TARGET PORT>
+# <port_to_connect_to>.<port_target_server_listens_for_udp_pings>.
+# <TARGET Host Addr> can be also an ip address or CNAME.
+#
+# N:<TARGET Host Addr>:<Password>:<TARGET Server NAME>:<Domain Mask>:<Class>
+#
+# "domain mask" is the number of parts in *your* hostname to mask to. For
+# instance, with my servername being "csa.bu.edu", if I wanted to present
+# my servername to be "*.bu.edu" I would have a host-mask portion of "1".
+#
+# it is *strongly* advised that your c/N line passwords be different for
+# security's sake.
+#
+# ident is allowed in the server's hostname part of the field.
+# these lines tell the server to automatically (note the port number, that
+# means automatic connection) connect to cs-ftp.bu.edu:
+C:hrose@cs-ftp.bu.edu:bigspark:cs-ftp.bu.edu:6667:2
+N:hrose@cs-ftp.bu.edu:bigalpha:cs-ftp.bu.edu::2
+#
+# This server's connection lines are more vanilla, masking the host to
+# *.bu.edu (as described above):
+C:irc-2.mit.edu:camelsrk00l:irc-2.mit.edu::2
+N:irc-2.mit.edu:andsoarellamas:irc-2.mit.edu:1:2
+#
+# If you have defined ZIP_LINKS and wish the connection to irc-2.mit.edu to
+# be compressed, you need to use a lowercase c. If the other server refuses
+# or doesn't support compression it will fall back to an uncompressed link.
+c:irc-2.mit.edu:camelsrk00l:irc-2.mit.edu::2
+N:irc-2.mit.edu:andsoarellamas:irc-2.mit.edu:1:2
+#
+#
+############################
+# K: [OPTIONAL]. These lines define user@host patterns to be banned from
+# this particular server (with an optional time field). Note that K: lines
+# are *not* global, and if you ban a user they can still use any other IRC
+# server (unless they have specifically been banned there as well).
+# 'K' uses the the type unix reply from the client's identd if available or
+# the USER information supplied by the client if not. 'k' uses the reply from
+# the client's identd also if it's type other (it's prefixed with '-' then).
+#
+# K:<Host Name or IP>:<time interval(s)|comment>:<User>:<port>:
+# k:<Host Name or IP>:<time interval(s)|comment>:<Auth>:<port>:
+#
+# wildcards are permitted in any one of the fields, in other words, you can
+# K:*::* if you wanted (but your server wouldn't be used much ;-)
+#
+# Note that if you specify an IP address, or IP mask, it will match clients
+# connecting from the matching addresses, no matter if they resolve or not.
+# You can prefix an IP address or IP mask by '=' in which case only non
+# resolving matching hosts will be banned.
+#
+# This k: line bans the username "FSSPR" (the wildcard is used to make
+# sure that any ident-checking character will match) on any machine from
+# the University of Alaska.
+k:*.alaska.edu::*FSSPR:0
+#
+# This K: line bans any users from acs*.bu.edu between the hours of 8am
+# and 12pm and 1pm and 5pm (the time is always the server's local time):
+# Note that 24 hour time is used (no "AM" or "PM").
+K:acs*.bu.edu:0800-1200,1300-1700:*:0
+#
+# This K: line bans any users from *foo.edu sending them the notice
+# "Use server irc.bar" instead of the default notice
+# "You are not welcome to this server"
+K:*foo.edu:Use server irc.bar:*:0
+#
+# This K: line bans any users from *toto.fr from using the port 6667,
+# and tells them to use port 6666 instead.
+K:*toto.fr:Use port 6666:*:6667:
+#
+# This K: line bans any user from 129.69.0.0/16 as long the host doesn't run
+# identd (no matter if it replies type unix or other) from all ports.
+k:129.69.*:identd (rfc1413) required:unknown::
+#
+# This does the same but only for unresolvable clients
+k:=129.69.*:identd (rfc1413) required:unknown::
+#
+#
+############################
+# L: [OPTIONAL]. These lines "Leaf" specified servers. They are only
+# useful if you are a non-leaf site yourself. There are two ways you can
+# use L: lines. The first will limit one particular site to a particular
+# tree depth (including 0, which would mean the server has to connect with
+# no servers linked behind it otherwise the connection will fail). The
+# second will allow you to be selective about which other servers you wish
+# the connecting server to behave as a leaf towards.
+#
+# The fields are as follows:
+# L:disallow connections to this hostmask::server name:depth
+# For example, this will force kaja.gi.alaska.edu to connect only as a
+# leaf (if it is not a leaf, the link will be dropped):
+L:::kaja.gi.alaska.edu::
+# This line will force cm5.eng.umd.edu to have a depth of only 1 below it
+# (that is, it is allowed to have only leaves connected to it):
+L:::cm5.eng.umd.edu:1:
+#
+# This line will prohibit anything matching *.edu to be connected behind
+# any server matching *.au:
+L:*.edu::*.au::
+#
+#
+############################
+# H: [OPTIONAL]. These lines define who you permit to act as a "hub" to
+# you (that is, who you permit to connect non-leafed servers to you).
+#
+# the first field may use wildcards, the third field *must* be an exact
+# match for a server's name (NOT a server's hostname, if they differ, the
+# server's name must be used). If the servername is a wildcard (e.g. *.au)
+# that is an acceptable name for the third field.
+#
+# The fields are as follows:
+# H:servers which are permitted entry::hub server
+#
+# Example, permit cs-ftp.bu.edu to allow any servers behind it to connect:
+H:*::cs-ftp.bu.edu::
+#
+# Example, permit irc-2.mit.edu to allow any MIT servers behind it to
+# connect:
+H:*.mit.edu::irc-2.mit.edu::
+#
+#
+############################
+# D: [OPTIONAL]. Control how auto connections are done. This will be mostly
+# useful for networks with complex configurations.
+#
+# D:<Denied Server Mask>:<Denied Class>:<Server Mask>:<Server Class>:
+# 1 2 3 4
+#
+# If a server matching <Denied Server Mask> or a server in <Denied Class>
+# is present ircd won't auto connect to any server matching <Server Mask>
+# or being in <Server Class> although auto connect for those is active.
+#
+# Example, don't auto connect to *.fi if some server of *.edu is already
+# linked
+D:*.edu::*.fi::
+#
+# Example, don't auto connect to *.fi or any server in class '3' if a
+# server from our class '2' is already present
+D::2:*.fi:3:
+#
+#
+############################
+# V: [OPTIONAL]. These lines define restrictions on servers connecting to
+# you.
+#
+# The first and third fields accept wildcards. The fields are as follow:
+# V:<Version Mask>:<Flags>:<Server Mask>::
+#
+# Example, you believe 2.9.1 is a really old version, and you want your
+# peers to upgrade:
+V:020901*::*::
+#
+# If you are running a production network, you most likely don't want to
+# allow servers compiled in DEBUGMODE which is a threat for the net
+# as well as for the privacy of the users:
+V:*:D:*::
+#
+# Finally, you don't want *.edu servers to be version 2.9.2 *OR* to be
+# compiled with remote oper kills enabled:
+V:020902*:K:*.edu::
+#
+#
+############################
+# B: [SUGGESTED]. These lines define the alternate servers that the users
+# will be redirected to if your server is full.
+#
+# The fiels are as follow:
+# B:<Class|Host Mask>::<Server Name>:<Port>:
+#
+# For example, if you want to redirect your users to irc.stealth.net on port
+# 6667 when your server is full, use:
+B:-1::irc.stealth.net:6667:
+#
+# To redirect *.fi users when your server cannot accept any new user with
+# a hostname matching *.fi, use:
+B:*.fi::irc.funet.fi:6667:
+#
+#
+############################
+# S: [OPTIONAL]. These lines define services allowed to connect to your
+# server. Each service needs a separate line which only allows him to
+# connect once. Remember to compile the ircd with #define USE_SERVICES
+# in config.h, otherwise you can't use services.
+#
+# The fields are as follow:
+# S:<TARGET Host Mask>:<Password>:<Service Name>:<Service Type>:<Class>
+#
+# Example, you want to allow a local information service:
+S:eep.local.net:thisisapassword:EepInfo:0:1
+#
+# Another example, ircd versions since 04/10/1999 support also a hex
+# mask. This is a temporary kline service (tkserv) as you can find it in
+# contrib/tkserv :
+S:eep.local.net:thisisapassword:TkEep:0x2000000:1
+#
+#
+############################
+# U: [NOT NECESSARY]. This line defines the default server for the IRC
+# client that ships with the server -- the default client is in irc/irc
+# You should not use U: lines but instead use the UPHOST definition in
+# config.h
+U:csa.bu.edu:foobar:csa.bu.edu
+#
+#
+############################
+# R: [DISCOURAGED]. These lines restrict user access based on a more
+# stringent checking system than is available in the K: line. It looks for
+# a match (based on hostname and username) and then runs an outside
+# program (which MUST be specified using a full pathname). The output of
+# the program should be a string in the form "Y <message>" (which permits
+# access for the user) or "N <message>" (which denies access for the
+# user). If "Y <message>" is received by the server, the server ignores
+# the message and permits access for the user. If "N <message>" is
+# returned, the server tells the user that he/she is not permitted to
+# access that irc server, and gives the reason.
+#
+# Again, like K: lines, R: lines are local and thus not very effective in
+# blocking certain machines from having IRC access.
+#
+# Use of R: requires that you have defined R_LINES in config.h
+#
+# The fields are as follows:
+# R:hostmask:/full/path/to/program:username
+# you can use wildcards in either the hostmask or username portion
+#
+R:csl.bu.edu:/home/hrose/bin.sun3/sun3access:*::
+#
+#
+############################
+# Q: [DISCOURAGED]. These lines "quarantine" specified servers. Because
+# of the way they operates, the same Q: lines MUST be installed by
+# everyone or the net will keep breaking. I CANNOT EMPHASIZE THIS ENOUGH.
+# Do NOT use Q: lines lightly!
+#
+# The fields are as follows:
+# Q:*:reason why quarantine is in place:servername
+#
+Q::this server is too slow and lags the net:cm5.eng.umd.edu::
diff --git a/doc/iauth-internals.txt b/doc/iauth-internals.txt
new file mode 100644
index 0000000..ccfa8e8
--- /dev/null
+++ b/doc/iauth-internals.txt
@@ -0,0 +1,350 @@
+ Internal IAUTH Workings
+ =======================
+
+ Andrew Snare
+
+Introduction
+------------
+
+The iauth daemon was written to offload some aspects of authenticating
+incoming ircd connections. Using a modular design, the original
+modules provides for identd lookup of incoming connections as well as
+checking for open socks proxies.
+
+When the ircd starts up, the iauth process is started as a slave
+process. The ircd communicates with the iauth daemon about new
+connections, and the iauth slave communicates information back as it
+becomes available.
+
+Communication Protocol
+----------------------
+
+IRCD Messages:-
+
+The communication protocol used to communicate from ircd to iauth is
+line-based and has the following form:
+
+ <id> <category> <information>
+
+ * <id> is used to identify the connection the information
+ concerns, and consists of the ircd's file-descriptor for the
+ connection.
+
+ * <category> is a single letter used to denote the type of
+ information being sent.
+
+ * <information> is the rest of the line ("\n"-terminated),
+ whose format depends on the category of information.
+
+Categories:
+
+ - "C"
+
+ Denotes a new connection to start on. The information has the
+ form of <remote-ip> <remote-port> <local-ip> <local-port>. Eg:
+
+ 2 C 192.168.2.10 13578 192.168.1.1 6667
+
+ This indicates a connection has been received on port 6667
+ with local IP-address of 192.167.1.1. The remote IP-address
+ was 192.168.2.10 (port 13578).
+
+ - "O"
+
+ Denotes an update to information about an existing
+ connection. The format of this is identical to a C-message (as
+ described above).
+
+ - "D"
+
+ Denotes a client has disconnected. No extra information is
+ provided. Eg:
+
+ 2 D
+
+ - "R"
+
+ This denotes a change of identifier for a client. The reason
+ for this currently is that sometimes ircd can re-map
+ file-descriptors (used as the identifier). The format of the
+ information is <new identifier>. Eg:
+
+ 2 R 1
+
+ This indicates the client that was on file-descriptor 2 is now
+ on file-descriptor 1 (unlikely, I'm sure!:).
+
+ - "N"
+
+ This denotes information has been received about the hostname
+ of a client. Format of the information is <hostname>. Eg:
+
+ 2 N host.example.com
+
+ This indicates the hostname of that client is
+ host.example.com.
+
+ - "d"
+
+ This denotes a DNS lookup for the client has timed out or
+ failed. This message has no other information. Eg:
+
+ 2 d
+
+ - "A" *
+
+ This denotes a host alias for the connection. Currently this
+ message is ignored by iauth and any information discarded.
+
+ - "U"
+
+ This denotes the username information provided by a
+ client. This information cannot be trusted, and is only used
+ by ircd when an identd lookup has failed. Format of the
+ information is <username>. Eg:
+
+ 2 U earthpig
+
+ This indicates the client supplied "earthpig" as the username
+ in the USER line during client handshaking with ircd.
+
+ - "P"
+
+ This denotes password information supplied by the client. Eg:
+
+ 2 P uhuh
+
+ This indicates the user supplied a password of "uhuh" during
+ client handshaking with ircd. A "U" message will always
+ immediately follow this message.
+
+ - "T"
+
+ This denotes the ircd is registering a client, which will
+ usually only occur if iauth has taken too long to get back
+ to ircd with a response. This message has no other
+ information. Eg:
+
+ 2 T
+
+ - "E" *
+
+ This denotes an error message from ircd. The information
+ provided has the form of <error message>. Eg:
+
+ 2 E I am a teapot.
+
+IAUTH Messages:
+
+The communication protocol used to communicate from iauth to ircd is
+line-based and has the following form:
+
+ <category> <information>
+
+ * <category> is a single letter used to denote the type of
+ information being sent.
+
+ * <information> is the rest of the line ("\n"-terminated),
+ whose format depends on the category of information.
+
+ - ">"
+
+ This is used to by iauth to send messages to &AUTH.
+
+ - "G"
+
+ This is used by iauth to set up debugging feedback from
+ ircd. Eg:
+
+ G 1
+
+ - "O"
+
+ This is used by iauth to tell ircd of some global iauth
+ policy decisions. Valid <information> includes the letters
+ "R", "T", "A" and "W" only. Eg:
+
+ O RTA
+
+ Valid policy types are:
+ R -- All clients _must_ be authenticated by iauth
+ to be allowed through;
+ T -- The IRC server should not accept new user
+ connections if iauth hasn't finished its work;
+ A -- The IRC server should send additional information
+ to iauth, such as a client-supplied password;
+ W -- Extra time should be allowed for requests
+ (usually to allow for hostname information to
+ become available).
+
+ - "a"
+
+ This indicates that iauth is reading a new configuration
+ file. Eg:
+
+ a
+
+ - "A" *
+
+ This is used to describe the iauth configuration as it is
+ read. The information consists of <hosts?> <module name>
+ <options>. Eg:
+
+ A * rfc931
+
+ This means that the rfc931 (identd) module is invoked for
+ every connection, and no options were given.
+
+ - "s" *
+
+ This is used to denote that any recorded statistics on iauth
+ should be reset. Eg:
+
+ s
+
+ - "S"
+
+ This is used to send iauth statistics. The information has the
+ form of <module name> <module-specific information>. Eg:
+
+ S rfc931 connected 0 unix 0 other 0 bad 0 out of 0
+
+ This indicates some statistics from the rfc931 module.
+
+ - "U" *
+
+ This is used to send username information (returned by identd)
+ to the ircd. This corresponds to information that has been
+ deemed usable to ircd by iauth. The information has the form
+ of <identifier> <remote IP> <remote port> <username>. Eg:
+
+ U 2 192.168.2.10 13578 earthpig
+
+ - "u" *
+
+ This is used to send username information (returned by identd)
+ to the ircd. This corresponds to information that has been not
+ deemed usable to ircd by iauth, usually due to the type of
+ reply received from identd. The information has the form of
+ <identifier> <remote IP> <remote port> <username>. Eg:
+
+ u 2 192.168.2.10 13578 earthpig
+
+ - "K"
+
+ This is used to indicate a client should be killed. The
+ information provided is of the form <identifier> <remote IP>
+ <remote port>. Eg:
+
+ K 2 203.36.167.162 13578
+
+ - "k"
+
+ This is used to indicate a client should be killed. The
+ information provided is the same as for the above "K" message
+ with the exception that this version is "quieter". ie, The
+ ircd won't be as verbose about the client being rejected.
+
+ - "D"
+
+ This is used to indicate that iauth's processing of a client
+ has finished. The information provided is of the form <id>
+ <remote IP> <remote port>. Eg:
+
+ D 2 203.36.167.162 13578
+
+ - "r" *
+
+ This is used by iauth to indicate it is shutting down. No
+ extra information is provided. Eg:
+
+ r
+
+Items marked with a * may be incorrect or contain uncertain
+information.
+
+Module Processing
+-----------------
+
+Module processing is done in a linear manner, one module at a
+time. When one module indicates it is finished with the client, iauth
+starts the next module on it. However, the matter is complicated
+slightly in that multiple passes can be made through the list of
+modules. By default each module is given 15 seconds to complete its
+work on a given client, before it gets timed-out.
+
+The first pass commences immediately when ircd notifies iauth of a
+client to check. A new pass commences:
+
+1) When DNS information about the client's hostname is finalised.
+
+2) When the USER information supplied by the client becomes available.
+
+Earlier versions of iauth did not commence a subsequent pass if DNS
+information was not available, but the current version starts one
+regardless.
+
+All modules are by default included in the first pass, with unused
+modules being included in the second pass if it commences prior to
+them being invoked. Modules are deferred to the second pass if they
+were configured using the "host = " directive (unless a "ip = " option
+was also specified and matched). There is a special case of "host = *"
+which forces a module to be delayed until hostname information is
+known, where it will always be invoked.
+
+Module Interface
+----------------
+
+The default modules are statically linked into the iauth
+daemon. However, there are now provisions for dynamically-loadable
+modules, as described by the iauth.conf man-page. Regardless of how
+they are linked/loaded, modules are currently expected to export the
+following functions (and array):
+
+char *name_init(AnInstance *self);
+void name_release(AnInstance *self);
+void name_stats(AnInstance *self);
+int name_start(u_int client);
+int name_work(u_int client);
+int name_timeout(u_int client);
+
+aModule Module_name =
+ { "name", name_init, name_release, name_stats,
+ name_start, name_work, name_timeout, name_clean };
+
+By convention the exported symbols use the form "name_symbol" where
+"name" is replaced by the module's name. For modules that are linked
+statically, a reference to Module_name must be added to the MList
+array near the start of conf_read() in a_conf.c
+
+For examples of what the exported functions are expected to do, please
+refer to the (internally documented) modules included in iauth.
+
+Limitations
+-----------
+
+Currently iauth suffers from several limitations. It is hoped that in
+the future these will be fixed. Patches are welcome. :) These
+limitations (in rough order of importance) are:
+
+1) After ircd has registered a client, iauth cannot reject or kill a
+connection. It is strongly desired that this be fixed.
+
+2) There is no way for a module to specify the "reason" a client
+connection was rejected (for display or other purposes).
+
+3) The current module design assumes a separate TCP/IP connection is
+required for each client check (or at least separate file-descriptors
+for each client can be watched for activity). While it's possible
+tricks could be used to work around this assumption, it has not been
+successfully done yet.
+
+Document Availability and Maintainence
+--------------------------------------
+
+This document was originally written by Andrew Snare and may contain
+errors and/or omissions. Please send any corrections to
+ajs@pigpond.com for inclusion in future versions. An up-to-date
+version of this document is available on the web at:
+
+ http://www.pigpond.com/~earthpig/iauth-internals.txt
diff --git a/doc/iauth.8 b/doc/iauth.8
new file mode 100644
index 0000000..14a415a
--- /dev/null
+++ b/doc/iauth.8
@@ -0,0 +1,54 @@
+.\" @(#)$Id: iauth.8,v 1.4 1998/11/09 20:07:12 kalt Exp $
+.TH IAUTH 8 "$Date: 1998/11/09 20:07:12 $"
+.SH NAME
+iauth \- The Internet Relay Chat Authentication Program
+.SH SYNOPSIS
+.hy 0
+.IP \fBiauth\fP
+[
+.B -v
+|
+.BI \-c " configfile"
+]
+.SH DESCRIPTION
+.LP
+\fIiauth\fP is a slave process used by the \fIircd\fP program to perform
+the authentication of incoming connections. The \fIircd\fP program starts
+\fIiauth\fP upon startup.
+
+\fIiauth\fP will close and reopen the log file whenever it receives a user
+signal 2, SIGUSR2. This is useful to rotate the log file.
+.SH OPTIONS
+.TP
+.BI \-c " filename"
+When this flag is given, the program will read the configuration file
+specify and validate it. This is useful to check for errors in the setup.
+.TP
+.B \-v
+This option dumps information about the version.
+.SH EXAMPLE
+.RS
+.nf
+millennium% \fBiauth -c iauth.conf\fP
+iauth 2.10
+
+Reading "iauth.conf"
+
+Module(s) loaded:
+ rfc931
+.fi
+.RE
+.SH COPYRIGHT
+(c) 1998 Christophe Kalt
+.LP
+For full COPYRIGHT see LICENSE file with IRC package.
+.LP
+.RE
+.SH FILES
+ "iauth.conf"
+.SH "SEE ALSO"
+iauth.conf(5) ircd(8)
+.SH BUGS
+None... ;-) if somebody finds one, please send mail to ircd-bugs@irc.org
+.SH AUTHOR
+Christophe Kalt.
diff --git a/doc/iauth.conf.5 b/doc/iauth.conf.5
new file mode 100644
index 0000000..832d9a8
--- /dev/null
+++ b/doc/iauth.conf.5
@@ -0,0 +1,159 @@
+.\" @(#)$Id: iauth.conf.5,v 1.16 1999/07/04 22:09:09 kalt Exp $
+.TH IAUTH.CONF 5 "$Date: 1999/07/04 22:09:09 $"
+.SH NAME
+iauth.conf \- The Internet Relay Chat Authentication Configuration File
+.SH DESCRIPTION
+.LP
+The \fIiauth.conf\fP file is read by the \fIiauth\fP program upon startup,
+it contains the list of modules that should be used to authenticate a
+particular connection. The list is ordered, which means that the first
+module to successfully authenticate a connection will be the last to be
+tried.
+
+The file is divided in sections, the first section is used for iauth
+options, each subsequent section specifies a module with eventual options
+using the following format:
+
+.RS
+.nf
+module\ \fImodule-name\fP
+[TAB]option = \fIstring\fP
+[TAB]host = \fIhost-name\fP
+[TAB]ip = \fIip-address\fP
+[TAB]timeout = \fIvalue\fP
+
+.fi
+.RE
+The section ends with an empty line. The \fImodule-name\fP defines which
+module the section applies to. A particular module may be used in several
+sections. A \fIstring\fP of undefined format may be specified, it will
+then be passed to the module upon initialization, see the MODULES section
+to find out if a module accepts any option.
+
+If \fIhost-name\fP and \fIip-address\fP fields are specified, then the
+module will only be used for connections matching one of the fields given
+in the configuration. An entry prefixed with the character ! indicates a
+negative match. IP addresses are checked first.
+
+If no host nor ip entry is specified, then the module will always be used.
+
+When writing a configuration file, one should \fBalways\fP verify the
+syntax using the \fIiauth\fP program to avoid later problems.
+.SH IAUTH OPTIONS
+.TP
+.B timeout = <seconds>
+This allows to specify how much time each module has to complete its work
+for each connection. This option can also be specified individually for
+each module. The default is 30 seconds.
+.TP
+.B required
+By specifying this keyword, the IRC server is told not to accept new user
+connections unless the authentication is handled by \fIiauth\fP. This does
+NOT mean that the server will wait forever to get the data from iauth, see
+the \fInotimeout\fP option.
+.TP
+.B notimeout
+By specifying this keyword, the IRC server is told not to accept new user
+connections if \fIiauth\fP hasn't finished its work in time.
+.TP
+.B extinfo
+This keyword allows extra information (user supplied username, and
+eventually password) to be received by \fIiauth\fP from the server. This
+is only useful is a module using this information is loaded.
+.TP
+.B shared <name> <mod_name.so>
+If iauth was compiled with Dynamically Shared Module support, it can be
+told to dynamically load a module using this option. The module can then
+be loaded.
+.SH MODULES
+.TP
+.B pipe
+This module is provided as a replacement to the (now obsolete) R
+configuration lines supported by the IRC daemon. It runs an external
+program with the client IP and port as arguments. The program should
+output either 'Y' (Yes, let the client in), or 'N' (No, don't let them
+in).
+
+Note that this module is quite expensive as it forks a separate process for
+each connection received by the IRC daemon.
+
+This module requires the following option:
+.B prog=/path/to/external/program
+.TP
+.B socks
+This module performs a basic check to verify that the host where the
+connection originated from doesn't run a SOCKS v4 or v5 proxy server on
+port 1080 that is open to the world. It is useful to reject abusive
+clients using a relay to evade kill lines and bans.
+
+This module understands seven options:
+.B reject
+to reject connections originating from a host where an open proxy
+was detected,
+.B log
+to log hostnames where an open proxy is detected.
+.B paranoid
+to consider proxies which deny the request because of a userid/ident
+mismatch to be OPEN proxies.
+.B cache[=value]
+to set the cache lifetime in minutes. By default, caching is enabled for
+30 minutes. A value of 0 disables caching.
+.B careful
+to make sure socks v5 is properly configured with IP rulesets. Without
+this parameter, module will not send additional query and assume first
+positive answer as valid.
+.B v4only
+to check only socks v4.
+.B v5only
+to check only socks v5.
+.TP
+.B rfc931
+This module is for authentication TCP connections using the protocol
+defined in RFC 1413 (which obsoletes RFC 931). It is always loaded, and
+does not recognize the \fIhost\fP nor \fIip\fP fields.
+.TP
+.B lhex
+This module acts as a proxy, communicating with a LHEx server to perform
+authentication of client connections. It takes a single (mandatory)
+option, which is the IP-address of the LHEx server to use.
+.SH EXAMPLE
+The following file will cause the IRC daemon to reject all connections
+originating from a system where an open proxy is running for hosts within
+*.fr and *.enserb.u-bordeaux.fr but not for other hosts matching
+*.u-bordeaux.fr. For all connections, an ident lookup (RFC 1413) will be
+performed. In addition, every connection is authenticated with the LHEx
+server at IP-address 127.0.0.1.
+
+.RS
+.nf
+module socks
+ option = reject,paranoid
+ host = *.enserb.u-bordeaux.fr
+ host = !*.u-bordeaux.fr
+ host = *.fr
+
+module rfc931
+
+module lhex
+ option = 127.0.0.1
+.fi
+.RE
+.SH CAVEATS
+When the option
+.B extinfo
+is set, connections registering as a server or a service with the IRC
+server are not guaranteed to receive the "user" authentication provided by
+modules (such as the rfc931 module).
+.RE
+.SH COPYRIGHT
+(c) 1998,1999 Christophe Kalt
+.LP
+For full COPYRIGHT see LICENSE file with IRC package.
+.LP
+.RE
+.SH FILES
+"iauth.conf"
+.SH "SEE ALSO"
+iauth(8)
+.SH AUTHOR
+Christophe Kalt.
diff --git a/doc/irc.1 b/doc/irc.1
new file mode 100644
index 0000000..d8dd677
--- /dev/null
+++ b/doc/irc.1
@@ -0,0 +1,85 @@
+.\" @(#)$Id: irc.1,v 1.5 1998/12/13 00:02:34 kalt Exp $
+.TH IRC 1 "$Date: 1998/12/13 00:02:34 $"
+=======
+.\" @(#)$Id: irc.1,v 1.5 1998/12/13 00:02:34 kalt Exp $
+.TH IRC 1 "$Date: 1998/12/13 00:02:34 $"
+.SH NAME
+irc \- User Interface to Internet Relay Chat Protocol
+.SH SYNOPSIS
+\fBirc\fP [\fB-p\fP \fIportnum\fP] [\fB-c\fP \fIchannel\fP] [ \fInickname\fP [ \fIserver\fP ]]
+.SH DESCRIPTION
+.LP
+\fBIrc\fP is a user interface to the Internet Relay Chat, a CB-like
+interactive discussion environment. It is structured into \fIchannels\fP,
+which are public discussion forums, and also allows for private intercommunication.
+Each participant has a \fInickname\fP, which is the one specified in the command
+line or else his login name.
+.LP
+Once invoked, \fBirc\fP connects as a client to the specified server,
+\fIserver\fP or to the default one (see below). The screen splits into a dialogue
+window (the major part
+of the screen) and a command line, from which messages can be sent and
+commands given to control irc.
+.SH COMMAND SYNTAX
+The syntax of irc commands is of the form \fB/COMMAND\fP. The most notable
+ones are listed below. For an uptodate list, use the \fBHELP\fP command
+of \fBirc\fP. Case is ignored.
+.IP "\fB/ADMIN\fR [\fIserver\fP]"
+Prints administrative information about an IRC \fIserver\fP.
+.IP "\fB/AWAY\fP [\fImessage\fP]"
+Mark yourself as being away (with an automatic reply \fImessage\fP
+if specified)
+.IP "\fB/BYE\fR, \fB/EXIT\fR, \fB/QUIT\fR"
+Terminate the session
+.IP "\fB/CHANNEL\fR [\fIchannel\fP]"
+Join another \fIchannel\fP
+.IP "\fB/CLEAR\fR"
+Clear the screen
+.IP "\fB/HELP\fR [\fIcommand\fP]"
+Display a brief description of the \fIcommand\fP (or list all commands, if none
+specified).
+.IP "\fB/SUMMON\fR \fIuser\fP"
+Allows to summon a \fIuser\fP specified as a full Internet address, i.e.,
+\fIlogin@host.domain\fP, to an IRC dialogue session (in much the same
+way as the talk(1) command). It is usable ONLY if the irc daemon runs on
+the target machine (host.domain).
+.IP "\fB/TOPIC\fR \fItopic\fP"
+Sets the \fItopic\fP for the current channel
+.IP "\fB/WHO\fR [\fIchannel\fP|*]"
+Lists all users of IRC if no argument, of the specified \fIchannel\fP or of the
+current channel (*).
+.SH ARGUMENTS
+.IP "\fB-p\fP \fIportnum\fP"
+TCP/IP "port number. Default is 6667 and this option should seldom if ever"
+be used.
+.IP "\fB-c\fP \fIchannel\fP"
+\fIChannel\fP number to join upon beginning of the session. Default is no channel.
+.IP "\fInickname\fP"
+\fINickname\fP used in the session (can be changed with the \fB/NICK\fP command).
+Default is user login name.
+.IP "\fIserver\fP"
+\fIServer\fP to connect to. Default is specified in the irc system configuration
+file, and can be superseded with the environment variable IRCSERVER.
+.SH EXAMPLE
+.RS
+.nf
+tolmoon% \fBirc -p6667 Wizard tolsun\fP
+.fi
+.RE
+.LP
+connects you to irc server in host tolsun (port 6667) with nickname Wizard
+.SH COPYRIGHT
+Copyright (c) 1988 University of Oulu, Computing Center, Finland.
+.nf
+Copyright (c) 1988,1989,1990 Jarkko Oikarinen
+.nf
+All rights reserved.
+For full COPYRIGHT see LICENSE file with IRC package.
+.SH "SEE ALSO"
+ircd(8)
+.SH BUGS
+What bugs ?
+.SH AUTHOR
+Jarkko Oikarinen <jto@tolsun.oulu.fi>
+.nf
+Manual page updated by Michel Fingerhut <Michel.Fingerhut@ircam.fr>
diff --git a/doc/ircd.8 b/doc/ircd.8
new file mode 100644
index 0000000..2727815
--- /dev/null
+++ b/doc/ircd.8
@@ -0,0 +1,202 @@
+.\" @(#)$Id ircd.8 2.0 (beta version) 29 Mar 1989 $
+.TH IRCD 8 "$Date: 1999/04/08 22:12:19 $"
+.SH NAME
+ircd \- The Internet Relay Chat Program Server
+.SH SYNOPSIS
+.hy 0
+.IP \fBircd\fP
+[
+.B \-abcioqst
+] [
+.BI \-f " configfile"
+] [
+.BI \-x " debuglevel"
+] [
+.BI \-h " hostname"
+] [
+.BI \-T " tunefile"
+] [
+.BI \-p " mode"
+]
+.IP \fBircd\fP
+.B \-v
+.SH DESCRIPTION
+.LP
+\fIircd\fP is the server (daemon) program for the Internet Relay Chat
+Program. The \fIircd\fP is a server in that its function is to "serve"
+the client program \fIirc(1)\fP with messages and commands. All commands
+and user messages are passed directly to the \fIircd\fP for processing
+and relaying to other ircd sites. The \fIirc(1)\fP program depends upon
+there being an \fIircd\fP server running somewhere (either on your local
+UNIX site or a remote ircd site) so that it will have somewhere to connect
+to and thus allow the user to begin talking to other users.
+
+\fIircd\fP will reread its configuration file whenever it received a hangup
+signal, SIGHUP.
+
+Sending an interrupt signal to \fIircd\fP process will cause it to restart.
+
+.SH OPTIONS
+.TP
+.B \-a
+Instructs the server to automatically die off if it loses all it's clients.
+.TP
+.B \-b
+If the ircd.tune file is corrupted, by default the server
+will not start. This option will make the server start
+anyways, with the default values (ignoring the corrupted
+file).
+.TP
+.B \-c
+This flag must be given if you are running ircd from \fI/dev/console\fP or
+any other situation where fd 0 isnt a tty and you want the server to fork
+off and run in the background. This needs to be given if you are starting
+\fIircd\fP from an \fIrc\fP (such as \fI/etc/rc.local\fP) file.
+.TP
+.B \-i
+The server was started by inetd and it should start accepting connections
+from standard input. The following inetd.conf-line could be used to start
+up ircd automatically when needed:
+.TP
+.B
+ircd stream tcp wait irc /etc/ircd ircd \-i
+
+allows inetd to start up ircd on request.
+.TP
+.B \-o
+Starts up a local ircdaemon. Standard input can be used to send IRC
+commands to the daemon. The user logging in from standard input will
+be given operator privileges on this local ircd. If ircd is a setuid program,
+it will call setuid(getuid()) before going to local mode. This option
+can be used in inetd.conf to allow users to open their own irc clients
+by simply connecting their clients to the correct ports. For example:
+.TP
+.B
+irc stream tcp nowait irc /etc/ircd ircd \\-f/etc/ircd.conf \\-o
+
+allows users connecting to irc port (specified in /etc/services) to start
+up their own ircdaemon. The configuration file should be used to check from
+which hosts these connections are allowed from. This option also turns
+on the autodie option -a.
+.TP
+.B \-q
+Using this option stops the server from doing DNS lookups on all the
+servers in your \fIircd.conf\fP file when it boots. This can take a lengthy
+amount of time if you have a large number of servers and they are not all
+close by.
+.TP
+.B \-s
+When this option is specified, \fIiauth\fP will not be
+started. This means that the IRC daemon will perform "ident
+lookups" (RFC 1413) internally to attempt to authenticate
+incoming connections. No other authentication mechanism
+will be used.
+.TP
+.B \-t
+Instructs the server to direct debugging output to standard output.
+.TP
+.BI \-f " filename"
+Specifies the ircd.conf file to be used for this ircdaemon. The option
+is used to override the default ircd.conf given at compile time.
+.TP
+.BI \-x " #"
+Defines the debuglevel for ircd. The higher the debuglevel, the more stuff
+gets directed to debugging file (or standard output if -t option was used
+as well).
+.TP
+.BI \-h " hostname"
+Allows the user to manually set the server name at startup. The default
+name is hostname.domainname.
+.TP
+.BI \-p " mode"
+Specify whether the server should enable built-in
+protections against various type of user abuse that is
+commonly found on big public networks. Possible modes are
+.BR strict " (default),"
+.BR on " and"
+.BR off .
+The
+.B strict
+option enables the protections, and refuses to establish a
+link to a server not running with this option. This is
+useful to force all servers on an IRC network to enable
+them.
+.TP
+.BI \-T " tunefile"
+Specifies the ircd.tune file to be used for this ircdaemon. The option
+is used to override the default ircd.tune given at compile
+time.
+.TP
+.B \-v
+This option prevents the server from starting, and dumps
+some information about the version instead.
+.TP
+.SH
+If you plan to connect your \fIircd\fP server to an existing Irc-Network,
+you will need to alter your local IRC CONFIGURATION FILE (typically named
+"ircd.conf") so that it will accept and make connections to other \fIircd\fP
+servers. This file contains the hostnames, Network Addresses, and sometimes
+passwords for connections to other ircds around the world. Because
+description of the actual file format of the "ircd.conf" file is beyond the
+scope of this document, please refer to the file INSTALL in the IRC source
+files documentation directory.
+.LP
+BOOTING THE SERVER: The \fIircd\fP server can be started as part of the
+UNIX boot procedure or just by placing the server into Unix Background.
+Keep in mind that if it is *not* part of your UNIXES Boot-up procedure
+then you will have to manually start the \fIircd\fP server each time your
+UNIX is rebooted. This means if your UNIX is prone to crashing
+or going for for repairs a lot it would make sense to start the \fIircd\fP
+server as part of your UNIX bootup procedure. In some cases the \fIirc(1)\fP
+will automatically attempt to boot the \fIircd\fP server if the user is
+on the SAME UNIX that the \fIircd\fP is supposed to be running on. If the
+\fIirc(1)\fP cannot connect to the \fIircd\fP server it will try to start
+the server on it's own and will then try to reconnect to the newly booted
+\fIircd\fP server.
+.SH EXAMPLE
+.RS
+.nf
+tolsun% \fBircd\fP
+.fi
+.RE
+.LP
+Places \fIircd\fP into UNIX Background and starts up the server for use.
+Note: You do not have to add the "&" to this command, the program will
+automatically detach itself from tty.
+.LP
+.RS
+.nf
+tolsun% \fBircd \-v\fP
+ircd 2.9.3 AaCDEfFHiIkMsu_V1
+ zlib not used
+ Tue Apr 1 1997 at 20:17:50 EDT #1
+.fi
+.RE
+.LP
+This indicates that this binary is the version 2.9.3 of the
+software. AaCDEfFHiIkMsu_V1 are the compile time options
+which were used. This binary does not support compression
+of server\-server links (does not use zlib) and was compiled
+on April the 1st.
+.SH COPYRIGHT
+(c) 1988,1989 University of Oulu, Computing Center, Finland,
+.LP
+(c) 1988,1989 Department of Information Processing Science,
+University of Oulu, Finland
+.LP
+(c) 1988,1989,1990,1991 Jarkko Oikarinen
+.LP
+For full COPYRIGHT see LICENSE file with IRC package.
+.LP
+.RE
+.SH FILES
+ /etc/utmp
+ "ircd.conf"
+.SH "SEE ALSO"
+iauth(8) irc(1) ircdwatch(8)
+.SH BUGS
+None... ;-) if somebody finds one, please send mail to ircd-bugs@irc.org
+.SH AUTHOR
+Jarkko Oikarinen, currently jto@tolsun.oulu.fi,
+manual page written by Jeff Trim, jtrim@orion.cair.du.edu,
+later modified by jto@tolsun.oulu.fi.
diff --git a/doc/m4macros b/doc/m4macros
new file mode 100644
index 0000000..2cc17d3
--- /dev/null
+++ b/doc/m4macros
@@ -0,0 +1,48 @@
+# @(#)$Id: m4macros,v 1.2 1997/04/21 13:50:04 kalt Exp $
+
+The following macros are included in "ircd.m4" for use with the m4 text
+preprocessor. "ircd.m4" is parsed before the IRC server conf file so they
+are all available for use with that.
+
+NOTE: The "ircd.m4" file is *ONLY* created by a "make install".
+
+VERSION - current version string as in patchlevel.h
+DEBUGMODE - if DEBUGMODE is define in config.h, is also defined for m4.
+HOSTNAME - taken from hostname(1)
+USER - username of person doing the "make install"
+PORT - default port number as in config.h
+PFREQ - default ping frequency as in config.h
+CFREQ - default connect frequency as in config.h
+MAXSENDQ - default max sendq as in config.h
+CL - use this to wrap a class number
+HOST - use this to wrap a hostname
+HOSTM - use this to wrap the hostmask number in N-lines
+ID - when wrapping the host field in an I-line, causes ident string return
+ to be used instead of user supplised username.
+PASS - use this to wrap passwords in C/N/I/O lines
+PING - use this to wrap the ping value in Y-lines
+APORT - use this to wrap the port number in I-lines
+CPORT - use this to wrap the port number in C-lines
+SERV - use this to wrap server names
+
+You might use some of these as
+C:foo.bar.edu:PASS(boo):foo.bar.edu:APORT(6667)
+I:ID(128.250.*)::ID(*.mu.oz.au):CPORT(6667)
+
+In addition to these (rather weak macros), some more complete ones are
+defined which already perform the above.
+
+ADMIN - provide fields to it as you would an A-line
+ALLOW - provide fields to it as you would an N-line
+BAN - provide fields to it as you would an K-line
+CLASS - provide fields to it as you would an Y-line
+CLIENT - provide fields to it as you would an I-line
+CONNECT - provide fields to it as you would an C-line
+ME - provide fields to it as you would an M-line
+HUB - first parameter is server you want to hub, second is optional and is
+ a mask against which other servers introduced must match against.
+LEAF - works like HUB, except that the mask is matched against server names
+ to check if the link should be dropped.
+SERVER - uses 6 fields, the first 4 as are found in an N-line, the last two
+ should be as you would use in a C-line. It expands out to provide
+ both a C and N line.
diff --git a/iauth/a_conf.c b/iauth/a_conf.c
new file mode 100644
index 0000000..602ab53
--- /dev/null
+++ b/iauth/a_conf.c
@@ -0,0 +1,548 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, iauth/a_conf.c
+ * Copyright (C) 1998 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: a_conf.c,v 1.21 1999/07/11 22:11:33 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "a_defines.h"
+#define A_CONF_C
+#include "a_externs.h"
+#undef A_CONF_C
+
+static aModule *Mlist[16];
+
+#define DEFAULT_TIMEOUT 30
+
+u_int debuglevel = 0;
+
+AnInstance *instances = NULL;
+
+static void
+conf_err(nb, msg, chk)
+u_int nb;
+char *msg, *chk;
+{
+ if (chk)
+ printf("line %d: %s\n", nb, msg);
+ else
+ sendto_log(ALOG_IRCD|ALOG_DCONF, LOG_ERR,
+ "Configuration error line %d: %s", nb, msg);
+}
+
+/*
+ * Match address by #IP bitmask (10.11.12.128/27)
+ */
+static int
+match_ipmask(mask, ipaddr)
+aTarget *mask;
+char *ipaddr;
+{
+#ifdef INET6
+ return 1;
+#else
+ int i1, i2, i3, i4;
+ u_long iptested;
+
+ if (sscanf(ipaddr, "%d.%d.%d.%d", &i1, &i2, &i3, &i4) != 4)
+ return -1;
+ iptested = htonl(i1 * 0x1000000 + i2 * 0x10000 + i3 * 0x100 + i4);
+ return ((iptested & mask->lmask) == mask->baseip) ? 0 : 1;
+#endif
+}
+
+/* conf_read: read the configuration file, instanciate modules */
+char *
+conf_read(cfile)
+char *cfile;
+{
+ AnInstance *ident = NULL; /* make sure this module is used */
+ u_char needh = 0; /* do we need hostname information for any host? */
+ u_char o_req = 0, o_dto = 0, o_wup = 0;
+ static char o_all[5];
+ u_int timeout = DEFAULT_TIMEOUT, totto = 0;
+ u_int lnnb = 0, i;
+ u_char icount = 0, Mcnt = 0;
+ char buffer[160], *ch;
+ AnInstance **last = &instances, *itmp;
+ FILE *cfh;
+
+ Mlist[Mcnt++] = &Module_rfc931;
+ Mlist[Mcnt++] = &Module_socks;
+ Mlist[Mcnt++] = &Module_pipe;
+ Mlist[Mcnt++] = &Module_lhex;
+ Mlist[Mcnt] = NULL;
+
+ cfh = fopen((cfile) ? cfile : IAUTHCONF_PATH, "r");
+ if (cfh)
+ {
+ while (fgets(buffer, 160, cfh))
+ {
+ if (ch = index(buffer, '\n'))
+ lnnb += 1;
+ else
+ {
+ conf_err(lnnb, "line too long, ignoring.",
+ cfile);
+ /* now skip what's left */
+ while (fgets(buffer, 160, cfh))
+ if (index(buffer, '\n'))
+ break;
+ continue;
+ }
+ if (buffer[0] == '#' || buffer[0] == '\n')
+ continue;
+ *ch = '\0';
+ if (ch = index(buffer, '#'))
+ *ch = '\0';
+ if (!strncmp("required", buffer, 8))
+ {
+ o_req = 1;
+ continue;
+ }
+ if (!strncmp("notimeout", buffer, 9))
+ {
+ o_dto = 1;
+ continue;
+ }
+ if (!strncmp("extinfo", buffer, 7))
+ {
+ o_wup = 1;
+ continue;
+ }
+ if (!strncmp("timeout = ", buffer, 10))
+ {
+ if (sscanf(buffer, "timeout = %u",
+ &timeout) != 1)
+ conf_err(lnnb, "Invalid setting.",
+ cfile);
+ continue;
+ }
+ /* debugmode setting */
+ if (!strncmp("debuglvl = 0x", buffer, 13))
+ {
+ if (sscanf(buffer, "debuglvl = %x",
+ &debuglevel) != 1)
+ conf_err(lnnb, "Invalid setting.",
+ cfile);
+ else if (!cfile)
+ sendto_log(ALOG_DCONF, LOG_DEBUG,
+ "debuglevel = %X",
+ debuglevel);
+ continue;
+ }
+#if defined(USE_DSM)
+ if (!strncmp("shared ", buffer, 7))
+ {
+ char lfname[80];
+ void *mod_handle;
+ aModule *(*load_func)();
+
+ ch = index(buffer+7, ' ');
+ if (ch == NULL)
+ {
+ conf_err(lnnb, "Syntax error.", cfile);
+ continue;
+ }
+ *ch++ = '\0';
+ mod_handle = dlopen(ch, RTLD_NOW);
+ if (mod_handle == NULL)
+ {
+ conf_err(lnnb, dlerror(), cfile);
+ continue;
+ }
+# if defined(DLSYM_NEEDS_UNDERSCORE)
+ sprintf(lfname, "_%s_load", buffer+7);
+# else
+ sprintf(lfname, "%s_load", buffer+7);
+# endif
+ load_func = (aModule *(*)())dlsym(mod_handle,
+ lfname);
+ if (load_func == NULL)
+ {
+ conf_err(lnnb,"Invalid shared object.",
+ cfile);
+ dlclose(mod_handle);
+ continue;
+ }
+ Mlist[Mcnt] = load_func();
+ if (Mlist[Mcnt])
+ {
+ Mcnt += 1;
+ Mlist[Mcnt] = NULL;
+ }
+ else
+ {
+ conf_err(lnnb, "Failed.", cfile);
+ dlclose(mod_handle);
+ }
+ continue;
+ }
+#endif
+ if (buffer[0] == '\t')
+ {
+ conf_err(lnnb, "Ignoring unexpected property.",
+ cfile);
+ continue;
+ }
+ /* at this point, it has to be the following */
+ if (strncasecmp("module ", buffer, 7))
+ {
+ conf_err(lnnb,
+ "Unexpected line: not a module.",
+ cfile);
+ continue;
+ }
+ for (i = 0; Mlist[i] != NULL; i++)
+ if (!strcasecmp(buffer+7, Mlist[i]->name))
+ break;
+ if (Mlist[i] == NULL)
+ {
+ conf_err(lnnb, "Unknown module name.", cfile);
+ continue;
+ }
+ if (Mlist[i] == &Module_rfc931 && ident)
+ {
+ conf_err(lnnb,
+ "This module can only be loaded once.",
+ cfile);
+ continue;
+ }
+ *last = (AnInstance *) malloc(sizeof(AnInstance));
+ (*last)->nexti = NULL;
+ (*last)->in = icount++;
+ (*last)->mod = Mlist[i];
+ (*last)->opt = NULL;
+ (*last)->popt = NULL;
+ (*last)->data = NULL;
+ (*last)->hostname = NULL;
+ (*last)->address = NULL;
+ (*last)->timeout = timeout;
+ if (Mlist[i] == &Module_rfc931)
+ ident = *last;
+
+ while (fgets(buffer, 160, cfh))
+ {
+ aTarget **ttmp;
+ u_long baseip = 0, lmask = 0;
+
+ if (ch = index(buffer, '\n'))
+ lnnb += 1;
+ else
+ {
+ conf_err(lnnb,
+ "line too long, ignoring.",
+ cfile);
+ /* now skip what's left */
+ while (fgets(buffer, 160, cfh))
+ if (index(buffer,'\n'))
+ break;
+ continue;
+ }
+ if (buffer[0] == '#')
+ continue;
+ if (buffer[0] == '\n')
+ break;
+ if (buffer[0] != '\t')
+ {
+ conf_err(lnnb, "Invalid syntax.",
+ cfile);
+ continue;
+ }
+ *ch = '\0';
+ if (!strncasecmp(buffer+1, "option = ", 9))
+ {
+ if ((*last)->opt)
+ conf_err(lnnb,
+ "Duplicate option keyword: ignored.",
+ cfile);
+ else
+ (*last)->opt =
+ mystrdup(buffer + 10);
+ continue;
+ }
+ if (!strncasecmp(buffer+1, "host = ", 7))
+ {
+ needh = 1;
+ ttmp = &((*last)->hostname);
+ ch = buffer + 8;
+ }
+ else if (!strncasecmp(buffer+1, "ip = ", 5))
+ {
+ ttmp = &((*last)->address);
+ ch = buffer + 6;
+ if (strchr(ch, '/'))
+ {
+ int i1, i2, i3, i4, m;
+
+ if (sscanf(ch,"%d.%d.%d.%d/%d",
+ &i1, &i2, &i3, &i4,
+ &m) != 5 ||
+ m < 1 || m > 31)
+ {
+ conf_err(lnnb,
+ "Bad mask.",
+ cfile);
+ continue;
+ }
+ lmask = htonl((u_long)0xffffffffL << (32 - m));
+ baseip = htonl(i1 * 0x1000000 +
+ i2 * 0x10000 +
+ i3 * 0x100 +
+ i4);
+ }
+ else
+ {
+ lmask = 0;
+ baseip = 0;
+ }
+ }
+ else if (!strncmp(buffer+1, "timeout = ", 10))
+ {
+ u_int local_timeout;
+ if (sscanf(buffer+1, "timeout = %u",
+ &local_timeout) != 1)
+ conf_err(lnnb,
+ "Invalid setting.",
+ cfile);
+ (*last)->timeout = local_timeout;
+ continue;
+ }
+ else
+ {
+ conf_err(lnnb, "Invalid keyword.",
+ cfile);
+ continue;
+ }
+ if (Mlist[i] == &Module_rfc931)
+ continue;
+ while (*ttmp)
+ ttmp = &((*ttmp)->nextt);
+ *ttmp = (aTarget *) malloc(sizeof(aTarget));
+ if (*ch == '!')
+ {
+ (*ttmp)->yes = -1;
+ ch++;
+ }
+ else
+ (*ttmp)->yes = 0;
+ (*ttmp)->value = mystrdup(ch);
+ if ((*ttmp)->baseip)
+ {
+ (*ttmp)->lmask = lmask;
+ (*ttmp)->baseip = baseip;
+ }
+ (*ttmp)->nextt = NULL;
+ }
+
+ last = &((*last)->nexti);
+ }
+ }
+ else if (cfile)
+ {
+ perror("fopen");
+ exit(0);
+ }
+ if (ident == NULL)
+ {
+ ident = *last = (AnInstance *) malloc(sizeof(AnInstance));
+ (*last)->nexti = NULL;
+ (*last)->opt = NULL;
+ (*last)->mod = &Module_rfc931;
+ (*last)->hostname = NULL;
+ (*last)->address = NULL;
+ (*last)->timeout = DEFAULT_TIMEOUT;
+ }
+ ident->timeout = MAX(DEFAULT_TIMEOUT, ident->timeout);
+
+ itmp = instances;
+ while (itmp)
+ {
+ totto += itmp->timeout;
+ itmp = itmp->nexti;
+ }
+ if (totto > ACCEPTTIMEOUT)
+ {
+ if (cfile)
+ printf("Warning: sum of timeouts exceeds ACCEPTTIMEOUT!\n");
+ else
+ sendto_log(ALOG_IRCD|ALOG_DCONF, LOG_ERR,
+ "Warning: sum of timeouts exceeds ACCEPTTIMEOUT!");
+ if (o_dto)
+ if (cfile)
+ printf("Error: \"notimeout\" is set!\n");
+ else
+ sendto_log(ALOG_IRCD|ALOG_DCONF, LOG_ERR,
+ "Error: \"notimeout\" is set!");
+ }
+
+ itmp = instances;
+ if (cfile)
+ {
+ aTarget *ttmp;
+ char *err;
+
+ printf("\nModule(s) loaded:\n");
+ while (itmp)
+ {
+ printf("\t%s\t%s\n", itmp->mod->name,
+ (itmp->opt) ? itmp->opt : "");
+ if (ttmp = itmp->hostname)
+ {
+ printf("\t\tHost = %s%s",
+ (ttmp->yes == 0) ? "" : "!",
+ ttmp->value);
+ while (ttmp = ttmp->nextt)
+ printf(",%s%s",
+ (ttmp->yes == 0) ? "" : "!",
+ ttmp->value);
+ printf("\n");
+ }
+ if (ttmp = itmp->address)
+ {
+ printf("\t\tIP = %s",
+ (ttmp->yes == 0) ? "" : "!",
+ ttmp->value);
+ while (ttmp = ttmp->nextt)
+ printf(",%s%s",
+ (ttmp->yes == 0) ? "" : "!",
+ ttmp->value);
+ printf("\n");
+ }
+ if (itmp->timeout != DEFAULT_TIMEOUT)
+ printf("\t\ttimeout: %u seconds\n",
+ itmp->timeout);
+ if (itmp->mod->init)
+ {
+ err = itmp->mod->init(itmp);
+ printf("\t\tInitialization: %s\n",
+ (err) ? err : "Successful");
+ }
+ itmp = itmp->nexti;
+ }
+ }
+ else
+ while (itmp)
+ {
+ if (itmp->mod->init)
+ itmp->mod->init(itmp);
+ itmp = itmp->nexti;
+ }
+
+ ch = o_all;
+ if (o_req) *ch++ = 'R';
+ if (o_dto) *ch++ = 'T';
+ if (o_wup) *ch++ = 'A';
+ if (needh) *ch++ = 'W';
+ *ch++ = '\0';
+ return o_all;
+}
+
+/* conf_match: check if an instance is to be applied to a connection
+ Returns -1: no match, and never will
+ 0: got a match, doIt[tm]
+ 1: no match, but might be later so ask again */
+int
+conf_match(cl, inst)
+u_int cl;
+AnInstance *inst;
+{
+ aTarget *ttmp;
+
+ /* general case, always matches */
+ if (inst->address == NULL && inst->hostname == NULL)
+ return 0;
+ /* feature case, "host = *" to force to wait for DNS info */
+ if ((cldata[cl].state & A_NOH) && inst->hostname &&
+ !strcmp(inst->hostname->value, "*"))
+ return 0;
+ /* check matches on IP addresses */
+ if (ttmp = inst->address)
+ while (ttmp)
+ {
+ if (ttmp->baseip)
+ {
+ if (match_ipmask(ttmp, cldata[cl].itsip) == 0)
+ return ttmp->yes;
+ }
+ else
+ if (match(ttmp->value, cldata[cl].itsip) == 0)
+ return ttmp->yes;
+ ttmp = ttmp->nextt;
+ }
+ /* check matches on hostnames */
+ if (ttmp = inst->hostname)
+ {
+ if (cldata[cl].state & A_GOTH)
+ {
+ while (ttmp)
+ {
+ if (match(ttmp->value, cldata[cl].host) == 0)
+ return ttmp->yes;
+ ttmp = ttmp->nextt;
+ }
+ /* no match, will never match */
+ return -1;
+ }
+ else if (cldata[cl].state & A_NOH)
+ return -1;
+ else
+ /* may be later, once we have DNS information */
+ return 1;
+ }
+ /* fall through, no match, will never match */
+ return -1;
+}
+
+/* conf_ircd: send the configuration to the ircd daemon */
+void
+conf_ircd()
+{
+ AnInstance *itmp = instances;
+ aTarget *ttmp;
+
+ sendto_ircd("a");
+ while (itmp)
+ {
+ if (itmp->address == NULL && itmp->hostname == NULL)
+ sendto_ircd("A * %s %s", itmp->mod->name,
+ (itmp->popt) ? itmp->popt : "");
+ else
+ {
+ ttmp = itmp->address;
+ while (ttmp)
+ {
+ sendto_ircd("A %s %s %s", ttmp->value,
+ itmp->mod->name,
+ (itmp->popt) ? itmp->popt : "");
+ ttmp = ttmp->nextt;
+ }
+ ttmp = itmp->hostname;
+ while (ttmp)
+ {
+ sendto_ircd("A %s %s %s", ttmp->value,
+ itmp->mod->name,
+ (itmp->popt) ? itmp->popt : "");
+ ttmp = ttmp->nextt;
+ }
+ }
+ itmp = itmp->nexti;
+ }
+}
diff --git a/iauth/a_conf_def.h b/iauth/a_conf_def.h
new file mode 100644
index 0000000..078a9a0
--- /dev/null
+++ b/iauth/a_conf_def.h
@@ -0,0 +1,56 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, iauth/a_conf_def.h
+ * Copyright (C) 1998 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.
+ */
+
+typedef struct Module aModule;
+typedef struct Instance AnInstance;
+typedef struct Target aTarget;
+
+struct Module
+{
+ char *name; /* module name */
+ char *(*init)(AnInstance *); /* instance initialization */
+ void (*release)(AnInstance *);/* instance releasing >UNUSED< */
+ void (*stats)(AnInstance *); /* send instance stats to ircd */
+ int (*start)(u_int); /* start authentication */
+ int (*work)(u_int); /* called whenever something has to be
+ * done (incoming data, timeout..) */
+ int (*timeout)(u_int); /* called when timeout is reached */
+ void (*clean)(u_int); /* finish/abort: cleanup*/
+};
+
+struct Instance
+{
+ AnInstance *nexti;
+ u_char in; /* instance number */
+ aModule *mod; /* module */
+ char *opt; /* options read from file */
+ char *popt; /* options to send to ircd */
+ void *data; /* private data: stats, ... */
+ aTarget *address;
+ aTarget *hostname;
+ u_int timeout;
+};
+
+struct Target
+{
+ char *value;
+ u_long baseip, lmask; /* a.b.c.d/z */
+ char yes;
+ aTarget *nextt;
+};
diff --git a/iauth/a_conf_ext.h b/iauth/a_conf_ext.h
new file mode 100644
index 0000000..f0416be
--- /dev/null
+++ b/iauth/a_conf_ext.h
@@ -0,0 +1,43 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, iauth/a_conf_ext.h
+ * Copyright (C) 1998 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.
+ */
+
+/* This file contains external definitions for global variables and functions
+ defined in iauth/a_conf.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef A_CONF_C
+extern u_int debuglevel;
+extern AnInstance *instances;
+#endif /* A_CONF_C */
+
+/* External definitions for global functions.
+ */
+#ifndef A_CONF_C
+# define EXTERN extern
+#else /* A_CONF_C */
+# define EXTERN
+#endif /* A_CONF_C */
+
+EXTERN char *conf_read __P((char *));
+EXTERN int conf_match __P((u_int, AnInstance *));
+EXTERN void conf_ircd();
+
+#undef EXTERN
diff --git a/iauth/a_defines.h b/iauth/a_defines.h
new file mode 100644
index 0000000..aff3038
--- /dev/null
+++ b/iauth/a_defines.h
@@ -0,0 +1,39 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, iauth/a_defines.h
+ * Copyright (C) 1998 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.
+ */
+
+/* This file includes all files defining constants, macros and types
+ definitions used by the authentication process.
+ */
+
+#define IAUTH_DEBUG 1
+
+#include "config.h"
+#include "patchlevel.h"
+
+#include "dbuf_def.h" /* needed for struct_def.h, sigh */
+#include "class_def.h" /* needed for struct_def.h, sigh */
+#include "struct_def.h"
+#if INET6
+# include "../ircd/nameser_def.h"
+#endif
+#include "support_def.h"
+
+#include "a_conf_def.h"
+#include "a_struct_def.h"
+#include "a_log_def.h"
diff --git a/iauth/a_externs.h b/iauth/a_externs.h
new file mode 100644
index 0000000..5108b56
--- /dev/null
+++ b/iauth/a_externs.h
@@ -0,0 +1,34 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, iauth/a_externs.h
+ * Copyright (C) 1998 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.
+ */
+
+/* This file includes all *_ext.h files containing external declarations
+ * for the authentication process.
+ */
+
+#include "match_ext.h"
+#include "support_ext.h"
+
+#include "a_conf_ext.h"
+#include "a_io_ext.h"
+#include "a_log_ext.h"
+
+#include "mod_rfc931_ext.h"
+#include "mod_socks_ext.h"
+#include "mod_pipe_ext.h"
+#include "mod_lhex_ext.h"
diff --git a/iauth/a_io.c b/iauth/a_io.c
new file mode 100644
index 0000000..a4bd57e
--- /dev/null
+++ b/iauth/a_io.c
@@ -0,0 +1,831 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, iauth/a_io.c
+ * Copyright (C) 1998 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: a_io.c,v 1.22 1999/07/11 22:09:59 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "a_defines.h"
+#define A_IO_C
+#include "a_externs.h"
+#undef A_IO_C
+
+anAuthData cldata[MAXCONNECTIONS]; /* index == ircd fd */
+static int cl_highest = -1;
+#if defined(USE_POLL)
+static int fd2cl[MAXCONNECTIONS]; /* fd -> cl mapping */
+#endif
+
+#define IOBUFSIZE 4096
+static char iobuf[IOBUFSIZE+1];
+static char rbuf[IOBUFSIZE+1]; /* incoming ircd stream */
+static int iob_len = 0, rb_len = 0;
+
+void
+init_io()
+{
+ bzero((char *) cldata, sizeof(cldata));
+}
+
+/* sendto_ircd() functions */
+#if ! USE_STDARG
+void
+sendto_ircd(pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)
+char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10;
+#else
+void
+vsendto_ircd(char *pattern, va_list va)
+#endif
+{
+ char ibuf[4096];
+
+#if ! USE_STDARG
+ sprintf(ibuf, pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
+#else
+ vsprintf(ibuf, pattern, va);
+#endif
+ DebugLog((ALOG_DSPY, 0, "To ircd: [%s]", ibuf));
+ strcat(ibuf, "\n");
+ if (write(0, ibuf, strlen(ibuf)) != strlen(ibuf))
+ {
+ sendto_log(ALOG_DMISC, LOG_NOTICE, "Daemon exiting. [w %s]",
+ strerror(errno));
+ exit(0);
+ }
+}
+
+#if USE_STDARG
+void
+sendto_ircd(char *pattern, ...)
+{
+ va_list va;
+ va_start(va, pattern);
+ vsendto_ircd(pattern, va);
+ va_end(va);
+}
+#endif
+
+/*
+ * next_io
+ *
+ * given an entry, look for the next module instance to start
+ */
+static void
+next_io(cl, last)
+int cl;
+AnInstance *last;
+{
+ DebugLog((ALOG_DIO, 0, "next_io(#%d, %x): last=%s state=0x%X", cl, last,
+ (last) ? last->mod->name : "", cldata[cl].state));
+
+ /* first, bail out immediately if the entry is flagged A_DONE */
+ if (cldata[cl].state & A_DONE)
+ return;
+
+ /* second, make sure the last instance which ran cleaned up */
+ if (cldata[cl].rfd > 0 || cldata[cl].wfd > 0)
+ {
+ /* last is defined here */
+ sendto_log(ALOG_IRCD|ALOG_DMISC, LOG_ERR,
+ "module \"%s\" didn't clean up fd's! (%d %d)",
+ last->mod->name, cldata[cl].rfd, cldata[cl].wfd);
+ if (cldata[cl].rfd > 0)
+ close(cldata[cl].rfd);
+ if (cldata[cl].wfd > 0 && cldata[cl].rfd != cldata[cl].wfd)
+ close(cldata[cl].wfd);
+ cldata[cl].rfd = cldata[cl].wfd = 0;
+ }
+
+ cldata[cl].buflen = 0;
+ cldata[cl].mod_status = 0;
+ cldata[cl].instance = NULL;
+ cldata[cl].timeout = 0;
+
+ /* third, if A_START is set, a new pass has to be started */
+ if (cldata[cl].state & A_START)
+ {
+ cldata[cl].state ^= A_START;
+ DebugLog((ALOG_DIO, 0, "next_io(#%d, %x): Starting again",
+ cl, last));
+ last = NULL; /* start from beginning */
+ }
+
+ /* fourth, find next instance to be ran */
+ if (last == NULL)
+ {
+ cldata[cl].instance = instances;
+ cldata[cl].ileft = 0;
+ }
+ else
+ cldata[cl].instance = last->nexti;
+
+ while (cldata[cl].instance)
+ {
+ int cm;
+
+ if (CheckBit(cldata[cl].idone, cldata[cl].instance->in))
+ {
+ DebugLog((ALOG_DIO, 0,
+ "conf_match(#%d, %x, goth=%d, noh=%d) skipped %x (%s)",
+ cl, last, (cldata[cl].state & A_GOTH) == A_GOTH,
+ (cldata[cl].state & A_NOH) == A_NOH,
+ cldata[cl].instance,
+ cldata[cl].instance->mod->name));
+ cldata[cl].instance = cldata[cl].instance->nexti;
+ continue;
+ }
+ cm = conf_match(cl, cldata[cl].instance);
+ DebugLog((ALOG_DIO, 0,
+ "conf_match(#%d, %x, goth=%d, noh=%d) said \"%s\" for %x (%s)",
+ cl, last, (cldata[cl].state & A_GOTH) == A_GOTH,
+ (cldata[cl].state & A_NOH) == A_NOH,
+ (cm==-1) ? "no match" : (cm==0) ? "match" : "try again",
+ cldata[cl].instance, cldata[cl].instance->mod->name));
+ if (cm == 0)
+ break;
+ if (cm == -1)
+ SetBit(cldata[cl].idone, cldata[cl].instance->in);
+ else /* cm == 1 */
+ cldata[cl].ileft += 1;
+ cldata[cl].instance = cldata[cl].instance->nexti;
+ }
+
+ if (cldata[cl].instance == NULL)
+ /* fifth, when there's no instance to try.. */
+ {
+ DebugLog((ALOG_DIO, 0,
+ "next_io(#%d, %x): no more instances to try (%d)",
+ cl, last, cldata[cl].ileft));
+ if (cldata[cl].ileft == 0)
+ {
+ /* we are done */
+ sendto_ircd("D %d %s %u ", cl, cldata[cl].itsip,
+ cldata[cl].itsport);
+ cldata[cl].state |= A_DONE;
+ free(cldata[cl].inbuffer);
+ cldata[cl].inbuffer = NULL;
+ }
+ return;
+ }
+ else
+ /* sixth, we've got an instance to try */
+ {
+ int r;
+
+ cldata[cl].timeout = time(NULL) + cldata[cl].instance->timeout;
+ r = cldata[cl].instance->mod->start(cl);
+ DebugLog((ALOG_DIO, 0,
+ "next_io(#%d, %x): %s->start() returned %d",
+ cl, last, cldata[cl].instance->mod->name, r));
+ if (r != 1)
+ /* started, or nothing to do or failed: don't try again */
+ SetBit(cldata[cl].idone, cldata[cl].instance->in);
+ if (r == 1)
+ cldata[cl].ileft += 1;
+ if (r != 0)
+ /* start() didn't start something */
+ next_io(cl, cldata[cl].instance);
+ }
+}
+
+/*
+ * parse_ircd
+ *
+ * parses data coming from ircd (doh ;-)
+ */
+static void
+parse_ircd()
+{
+ char *ch, *chp, *buf = iobuf;
+ int cl = -1, ncl;
+
+ iobuf[iob_len] = '\0';
+ while (ch = index(buf, '\n'))
+ {
+ *ch = '\0';
+ DebugLog((ALOG_DSPY, 0, "parse_ircd(): got [%s]", buf));
+
+ cl = atoi(chp = buf);
+ while (*chp++ != ' ');
+ switch (chp[0])
+ {
+ case 'C': /* new connection */
+ case 'O': /* old connection: do nothing, just update data */
+ if (cldata[cl].state & A_ACTIVE)
+ {
+ /* this is not supposed to happen!!! */
+ sendto_log(ALOG_IRCD, LOG_CRIT,
+ "Entry %d [%c] is already active (fatal)!",
+ cl, chp[0]);
+ exit(1);
+ }
+ if (cldata[cl].instance || cldata[cl].rfd > 0 ||
+ cldata[cl].wfd > 0)
+ {
+ sendto_log(ALOG_IRCD, LOG_CRIT,
+ "Entry %d [%c] is already active! (fatal)",
+ cl, chp[0]);
+ exit(1);
+ }
+ if (cldata[cl].authuser)
+ {
+ /* shouldn't be here - hmmpf */
+ sendto_log(ALOG_IRCD|ALOG_DIO, LOG_WARNING,
+ "Unreleased data [%c %d]!", chp[0],
+ cl);
+ free(cldata[cl].authuser);
+ cldata[cl].authuser = NULL;
+ }
+ if (cldata[cl].inbuffer)
+ {
+ /* shouldn't be here - hmmpf */
+ sendto_log(ALOG_IRCD|ALOG_DIO, LOG_WARNING,
+ "Unreleased buffer [%c %d]!",
+ chp[0], cl);
+ free(cldata[cl].inbuffer);
+ cldata[cl].inbuffer = NULL;
+ }
+ cldata[cl].user[0] = '\0';
+ cldata[cl].passwd[0] = '\0';
+ cldata[cl].host[0] = '\0';
+ bzero(cldata[cl].idone, BDSIZE);
+ cldata[cl].buflen = 0;
+ if (chp[0] == 'C')
+ cldata[cl].state = A_ACTIVE;
+ else
+ {
+ cldata[cl].state = A_ACTIVE|A_IGNORE;
+ break;
+ }
+ if (sscanf(chp+2, "%[^ ] %hu %[^ ] %hu",
+ cldata[cl].itsip, &cldata[cl].itsport,
+ cldata[cl].ourip, &cldata[cl].ourport) != 4)
+ {
+ sendto_log(ALOG_IRCD, LOG_CRIT,
+ "Bad data from ircd [%s] (fatal)",
+ chp);
+ exit(1);
+ }
+ /* we should really be using a pool of buffer here */
+ cldata[cl].inbuffer = malloc(INBUFSIZE+1);
+ if (cl > cl_highest)
+ cl_highest = cl;
+ next_io(cl, NULL); /* get started */
+ break;
+ case 'D': /* client disconnect */
+ if (!(cldata[cl].state & A_ACTIVE))
+ /*
+ ** this is not fatal, it happens with servers
+ ** we connected to (and more?).
+ ** It's better/safer to ignore here rather
+ ** than try to filter in ircd. -kalt
+ */
+ sendto_log(ALOG_IRCD, LOG_WARNING,
+ "Warning: Entry %d [D] is not active.", cl);
+ cldata[cl].state = 0;
+ if (cldata[cl].rfd > 0 || cldata[cl].wfd > 0)
+ cldata[cl].instance->mod->clean(cl);
+ cldata[cl].instance = NULL;
+ /* log something here? hmmpf */
+ if (cldata[cl].authuser)
+ free(cldata[cl].authuser);
+ cldata[cl].authuser = NULL;
+ if (cldata[cl].inbuffer)
+ free(cldata[cl].inbuffer);
+ cldata[cl].inbuffer = NULL;
+ break;
+ case 'R': /* fd remap */
+ if (!(cldata[cl].state & A_ACTIVE))
+ {
+ /* this should really not happen */
+ sendto_log(ALOG_IRCD, LOG_CRIT,
+ "Entry %d [R] is not active!", cl);
+ break;
+ }
+ ncl = atoi(chp+2);
+ if (cldata[ncl].state & A_ACTIVE)
+ {
+ /* this is not supposed to happen!!! */
+ sendto_log(ALOG_IRCD, LOG_CRIT,
+ "Entry %d [R] is already active (fatal)!", ncl);
+ exit(1);
+ }
+ if (cldata[ncl].instance || cldata[ncl].rfd > 0 ||
+ cldata[ncl].wfd > 0)
+ {
+ sendto_log(ALOG_IRCD, LOG_CRIT,
+ "Entry %d is already active! (fatal)",
+ ncl);
+ exit(1);
+ }
+ if (cldata[ncl].authuser)
+ {
+ /* shouldn't be here - hmmpf */
+ sendto_log(ALOG_IRCD|ALOG_DIO, LOG_WARNING,
+ "Unreleased data [%d]!", ncl);
+ free(cldata[ncl].authuser);
+ cldata[ncl].authuser = NULL;
+ }
+ if (cldata[ncl].inbuffer)
+ {
+ /* shouldn't be here - hmmpf */
+ sendto_log(ALOG_IRCD|ALOG_DIO, LOG_WARNING,
+ "Unreleased buffer [%c %d]!",
+ chp[0], ncl);
+ free(cldata[ncl].inbuffer);
+ cldata[ncl].inbuffer = NULL;
+ }
+ bcopy(cldata+cl, cldata+ncl, sizeof(anAuthData));
+
+ cldata[cl].state = 0;
+ cldata[cl].rfd = cldata[cl].wfd = 0;
+ cldata[cl].instance = NULL;
+ cldata[cl].authuser = NULL;
+ cldata[cl].inbuffer = NULL;
+ /*
+ ** this is the ugly part of having a slave (considering
+ ** that ircd remaps fd's: there is lag between the
+ ** server and the slave.
+ ** I can't think of any better way to handle this at
+ ** the moment -kalt
+ */
+ if (cldata[ncl].state & A_IGNORE)
+ break;
+ if (cldata[ncl].state & A_LATE)
+ /* pointless 99.9% of the time */
+ break;
+ if (cldata[ncl].authuser)
+ sendto_ircd("%c %d %s %u %s",
+ (cldata[ncl].state&A_UNIX)?'U':'u',
+ ncl, cldata[ncl].itsip,
+ cldata[ncl].itsport,
+ cldata[ncl].authuser);
+ if (cldata[ncl].state & A_DENY)
+ sendto_ircd("K %d %s %u ", ncl,
+ cldata[ncl].itsip,
+ cldata[ncl].itsport,
+ cldata[ncl].authuser);
+ if (cldata[ncl].state & A_DONE)
+ sendto_ircd("D %d %s %u ", ncl,
+ cldata[ncl].itsip,
+ cldata[ncl].itsport,
+ cldata[ncl].authuser);
+ break;
+ case 'N': /* hostname */
+ if (!(cldata[cl].state & A_ACTIVE))
+ {
+ /* let's be conservative and just ignore */
+ sendto_log(ALOG_IRCD, LOG_WARNING,
+ "Warning: Entry %d [N] is not active.", cl);
+ break;
+ }
+ if (cldata[cl].state & A_IGNORE)
+ break;
+ strcpy(cldata[cl].host, chp+2);
+ cldata[cl].state |= A_GOTH|A_START;
+ if (cldata[cl].instance == NULL)
+ next_io(cl, NULL);
+ break;
+ case 'A': /* host alias */
+ if (!(cldata[cl].state & A_ACTIVE))
+ {
+ /* let's be conservative and just ignore */
+ sendto_log(ALOG_IRCD, LOG_WARNING,
+ "Warning: Entry %d [A] is not active.", cl);
+ break;
+ }
+ if (cldata[cl].state & A_IGNORE)
+ break;
+ /* hmmpf */
+ break;
+ case 'U': /* user provided username */
+ if (!(cldata[cl].state & A_ACTIVE))
+ {
+ /* let's be conservative and just ignore */
+ sendto_log(ALOG_IRCD, LOG_WARNING,
+ "Warning: Entry %d [U] is not active.", cl);
+ break;
+ }
+ if (cldata[cl].state & A_IGNORE)
+ break;
+ strcpy(cldata[cl].user, chp+2);
+ cldata[cl].state |= A_GOTU|A_START;
+ if (cldata[cl].instance == NULL)
+ next_io(cl, NULL);
+ break;
+ case 'P': /* user provided password */
+ if (!(cldata[cl].state & A_ACTIVE))
+ {
+ /* let's be conservative and just ignore */
+ sendto_log(ALOG_IRCD, LOG_WARNING,
+ "Warning: Entry %d [P] is not active.", cl);
+ break;
+ }
+ if (cldata[cl].state & A_IGNORE)
+ break;
+ strcpy(cldata[cl].passwd, chp+2);
+ cldata[cl].state |= A_GOTP;
+ /*
+ ** U message will follow immediately,
+ ** no need to do any thing else here
+ */
+ break;
+ case 'T': /* ircd is registering the client */
+ /* what to do with this? abort/continue? */
+ cldata[cl].state |= A_LATE;
+ break;
+ case 'd': /* DNS timeout */
+ case 'n': /* No hostname information, but no timeout either */
+ if (!(cldata[cl].state & A_ACTIVE))
+ {
+ /* let's be conservative and just ignore */
+ sendto_log(ALOG_IRCD, LOG_WARNING,
+ "Warning: Entry %d [%c] is not active.",
+ cl, chp[0]);
+ break;
+ }
+ cldata[cl].state |= A_NOH|A_START;
+ if (cldata[cl].instance == NULL)
+ next_io(cl, NULL);
+ break;
+ case 'E': /* error message from ircd */
+ sendto_log(ALOG_DIRCD, LOG_DEBUG,
+ "Error from ircd: %s", chp);
+ break;
+ default:
+ sendto_log(ALOG_IRCD, LOG_ERR, "Unexpected data [%s]",
+ chp);
+ break;
+ }
+
+ buf = ch+1;
+ }
+ rb_len = 0; iob_len = 0;
+ if (strlen(buf))
+ bcopy(buf, rbuf, rb_len = strlen(buf));
+}
+
+/*
+ * loop_io
+ *
+ * select()/poll() loop
+ */
+void
+loop_io()
+{
+ /* the following is from ircd/s_bsd.c */
+#if ! USE_POLL
+# define SET_READ_EVENT( thisfd ) FD_SET( thisfd, &read_set)
+# define SET_WRITE_EVENT( thisfd ) FD_SET( thisfd, &write_set)
+# define CLR_READ_EVENT( thisfd ) FD_CLR( thisfd, &read_set)
+# define CLR_WRITE_EVENT( thisfd ) FD_CLR( thisfd, &write_set)
+# define TST_READ_EVENT( thisfd ) FD_ISSET( thisfd, &read_set)
+# define TST_WRITE_EVENT( thisfd ) FD_ISSET( thisfd, &write_set)
+
+ fd_set read_set, write_set;
+ int highfd = -1;
+#else
+/* most of the following use pfd */
+# define POLLSETREADFLAGS (POLLIN|POLLRDNORM)
+# define POLLREADFLAGS (POLLSETREADFLAGS|POLLHUP|POLLERR)
+# define POLLSETWRITEFLAGS (POLLOUT|POLLWRNORM)
+# define POLLWRITEFLAGS (POLLOUT|POLLWRNORM|POLLHUP|POLLERR)
+
+# define SET_READ_EVENT( thisfd ){ CHECK_PFD( thisfd );\
+ pfd->events |= POLLSETREADFLAGS;}
+# define SET_WRITE_EVENT( thisfd ){ CHECK_PFD( thisfd );\
+ pfd->events |= POLLSETWRITEFLAGS;}
+
+# define CLR_READ_EVENT( thisfd ) pfd->revents &= ~POLLSETREADFLAGS
+# define CLR_WRITE_EVENT( thisfd ) pfd->revents &= ~POLLSETWRITEFLAGS
+# define TST_READ_EVENT( thisfd ) pfd->revents & POLLREADFLAGS
+# define TST_WRITE_EVENT( thisfd ) pfd->revents & POLLWRITEFLAGS
+
+# define CHECK_PFD( thisfd ) \
+ if ( pfd->fd != thisfd ) { \
+ pfd = &poll_fdarray[nbr_pfds++];\
+ pfd->fd = thisfd; \
+ pfd->events = 0; \
+ }
+
+ struct pollfd poll_fdarray[MAXCONNECTIONS];
+ struct pollfd * pfd = poll_fdarray;
+ int nbr_pfds = 0;
+#endif
+
+ int i, nfds = 0;
+ struct timeval wait;
+ time_t now = time(NULL);
+
+#if !defined(USE_POLL)
+ FD_ZERO(&read_set);
+ FD_ZERO(&write_set);
+ highfd = 0;
+#else
+ /* set up such that CHECK_FD works */
+ nbr_pfds = 0;
+ pfd = poll_fdarray;
+ pfd->fd = -1;
+#endif /* USE_POLL */
+
+ SET_READ_EVENT(0); nfds = 1; /* ircd stream */
+#if defined(USE_POLL) && defined(IAUTH_DEBUG)
+ for (i = 0; i < MAXCONNECTIONS; i++)
+ fd2cl[i] = -1; /* sanity */
+#endif
+ for (i = 0; i <= cl_highest; i++)
+ {
+ if (cldata[i].timeout && cldata[i].timeout < now &&
+ cldata[i].instance /* shouldn't be needed.. but it is */)
+ {
+ DebugLog((ALOG_DIO, 0,
+ "io_loop(): module %s timeout [%d]",
+ cldata[i].instance->mod->name, i));
+ if (cldata[i].instance->mod->timeout(i) != 0)
+ next_io(i, cldata[i].instance);
+ }
+ if (cldata[i].rfd > 0)
+ {
+ SET_READ_EVENT(cldata[i].rfd);
+#if !defined(USE_POLL)
+ if (cldata[i].rfd > highfd)
+ highfd = cldata[i].rfd;
+#else
+ fd2cl[cldata[i].rfd] = i;
+#endif
+ nfds++;
+ }
+ else if (cldata[i].wfd > 0)
+ {
+ SET_WRITE_EVENT(cldata[i].wfd);
+#if ! USE_POLL
+ if (cldata[i].wfd > highfd)
+ highfd = cldata[i].wfd;
+#else
+ fd2cl[cldata[i].wfd] = i;
+#endif
+ nfds++;
+ }
+ }
+
+ DebugLog((ALOG_DIO, 0, "io_loop(): checking for %d fd's", nfds));
+ wait.tv_sec = 5; wait.tv_usec = 0;
+#if ! USE_POLL
+ nfds = select(highfd + 1, (SELECT_FDSET_TYPE *)&read_set,
+ (SELECT_FDSET_TYPE *)&write_set, 0, &wait);
+ DebugLog((ALOG_DIO, 0, "io_loop(): select() returned %d, errno = %d",
+ nfds, errno));
+#else
+ nfds = poll(poll_fdarray, nbr_pfds,
+ wait.tv_sec * 1000 + wait.tv_usec/1000 );
+ DebugLog((ALOG_DIO, 0, "io_loop(): poll() returned %d, errno = %d",
+ nfds, errno));
+ pfd = poll_fdarray;
+#endif
+ if (nfds == -1)
+ if (errno == EINTR)
+ return;
+ else
+ {
+ sendto_log(ALOG_IRCD, LOG_CRIT,
+ "fatal select/poll error: %s",
+ strerror(errno));
+ exit(1);
+ }
+ if (nfds == 0) /* end of timeout */
+ return;
+
+ /* no matter select() or poll() this is also fd # 0 */
+ if (TST_READ_EVENT(0))
+ nfds--;
+
+#if !defined(USE_POLL)
+ for (i = 0; i <= cl_highest && nfds; i++)
+#else
+ for (pfd = poll_fdarray+1; pfd != poll_fdarray+nbr_pfds && nfds; pfd++)
+#endif
+ {
+#if defined(USE_POLL)
+ i = fd2cl[pfd->fd];
+# if defined(IAUTH_DEBUG)
+ if (i == -1)
+ {
+ sendto_log(ALOG_DALL, LOG_CRIT,"io_loop(): fatal bug");
+ exit(1);
+ }
+# endif
+#endif
+ if (cldata[i].rfd <= 0 && cldata[i].wfd <= 0)
+ {
+#if defined(USE_POLL)
+ sendto_log(ALOG_IRCD, LOG_CRIT,
+ "io_loop(): fatal data inconsistency #%d (%d, %d)",
+ i, cldata[i].rfd, cldata[i].wfd);
+ exit(1);
+#else
+ continue;
+#endif
+ }
+ if (cldata[i].rfd > 0 && TST_READ_EVENT(cldata[i].rfd))
+ {
+ int len;
+
+ len = recv(cldata[i].rfd,
+ cldata[i].inbuffer + cldata[i].buflen,
+ INBUFSIZE - cldata[i].buflen, 0);
+ DebugLog((ALOG_DIO, 0, "io_loop(): i = #%d: recv(%d) returned %d, errno = %d", i, cldata[i].rfd, len, errno));
+ if (len < 0)
+ {
+ cldata[i].instance->mod->clean(i);
+ next_io(i, cldata[i].instance);
+ }
+ else
+ {
+ cldata[i].buflen += len;
+ if (cldata[i].instance->mod->work(i) != 0)
+ next_io(i, cldata[i].instance);
+ else if (len == 0)
+ {
+ cldata[i].instance->mod->clean(i);
+ next_io(i, cldata[i].instance);
+ }
+ }
+ nfds--;
+ }
+ else if (cldata[i].wfd > 0 && TST_WRITE_EVENT(cldata[i].wfd))
+ {
+ if (cldata[i].instance->mod->work(i) != 0)
+ next_io(i, cldata[i].instance);
+
+ nfds--;
+ }
+ }
+
+ /*
+ ** no matter select() or poll() this is also fd # 0
+ ** this has to be done last (for the USE_POLL version) because
+ ** of R messages we may get from the server :/
+ */
+#if defined(USE_POLL)
+ pfd = poll_fdarray;
+#endif
+ if (TST_READ_EVENT(0))
+ {
+ /* data from the ircd.. */
+ while (1)
+ {
+ if (rb_len)
+ bcopy(rbuf, iobuf, iob_len = rb_len);
+ if ((i=recv(0,iobuf+iob_len,IOBUFSIZE-iob_len,0)) <= 0)
+ {
+ DebugLog((ALOG_DIO, 0, "io_loop(): recv(0) returned %d, errno = %d", i, errno));
+ break;
+ }
+ iob_len += i;
+ DebugLog((ALOG_DIO, 0,
+ "io_loop(): got %d bytes from ircd [%d]", i,
+ iob_len));
+ parse_ircd();
+ }
+ if (i == 0)
+ {
+ sendto_log(ALOG_DMISC, LOG_NOTICE,
+ "Daemon exiting. [r]");
+ exit(0);
+ }
+ }
+
+#if defined(IAUTH_DEBUG)
+ if (nfds > 0)
+ sendto_log(ALOG_DIO, 0, "io_loop(): nfds = %d !!!", nfds);
+# if !defined(USE_POLL)
+ /* the equivalent should be written for poll() */
+ if (nfds == 0)
+ while (i <= cl_highest)
+ {
+ if (cldata[i].rfd > 0 && TST_READ_EVENT(cldata[i].rfd))
+ {
+ /* this should not happen! */
+ /* hmmpf */
+ }
+ i++;
+ }
+# endif
+#endif
+}
+
+/*
+ * set_non_blocking (ripped from ircd/s_bsd.c)
+ */
+static void
+set_non_blocking(fd, ip, port)
+int fd;
+char *ip;
+u_short port;
+{
+ int res, nonb = 0;
+
+#if NBLOCK_POSIX
+ nonb |= O_NONBLOCK;
+#endif
+#if NBLOCK_BSD
+ nonb |= O_NDELAY;
+#endif
+#if NBLOCK_SYSV
+ /* This portion of code might also apply to NeXT. -LynX */
+ res = 1;
+
+ if (ioctl (fd, FIONBIO, &res) < 0)
+ sendto_log(ALOG_IRCD, 0, "ioctl(fd,FIONBIO) failed for %s:%u",
+ ip, port);
+#else
+ if ((res = fcntl(fd, F_GETFL, 0)) == -1)
+ sendto_log(ALOG_IRCD, 0, "fcntl(fd, F_GETFL) failed for %s:%u",
+ ip, port);
+ else if (fcntl(fd, F_SETFL, res | nonb) == -1)
+ sendto_log(ALOG_IRCD, 0,
+ "fcntl(fd, F_SETL, nonb) failed for %s:%u",
+ ip, port);
+#endif
+}
+
+/*
+ * tcp_connect
+ *
+ * utility function for use in modules, creates a socket and connects
+ * it to an IP/port
+ *
+ * Returns the fd
+ */
+int
+tcp_connect(ourIP, theirIP, port, error)
+char *ourIP, *theirIP, **error;
+u_short port;
+{
+ int fd;
+ static char errbuf[BUFSIZ];
+ struct SOCKADDR_IN sk;
+
+ fd = socket(AFINET, SOCK_STREAM, 0);
+ if (fd < 0)
+ {
+ sprintf(errbuf, "socket() failed: %s", strerror(errno));
+ *error = errbuf;
+ return -1;
+ }
+ /*
+ * this bzero() shouldn't be needed.. should it?
+ * AIX 4.1.5 doesn't like not having it tho.. I have no clue why -kalt
+ */
+ bzero((char *)&sk, sizeof(sk));
+ sk.SIN_FAMILY = AFINET;
+#if defined(INET6)
+ if(!inet_pton(AF_INET6, ourIP, sk.sin6_addr.s6_addr))
+ bcopy(minus_one, sk.sin6_addr.s6_addr, IN6ADDRSZ);
+#else
+ sk.sin_addr.s_addr = inetaddr(ourIP);
+#endif
+ sk.SIN_PORT = htons(0);
+ if (bind(fd, (SAP)&sk, sizeof(sk)) < 0)
+ {
+ sprintf(errbuf, "bind() failed: %s", strerror(errno));
+ *error = errbuf;
+ close(fd);
+ return -1;
+ }
+ set_non_blocking(fd, theirIP, port);
+#if defined(INET6)
+ if(!inet_pton(AF_INET6, theirIP, sk.sin6_addr.s6_addr))
+ bcopy(minus_one, sk.sin6_addr.s6_addr, IN6ADDRSZ);
+#else
+ sk.sin_addr.s_addr = inetaddr(theirIP);
+#endif
+ sk.SIN_PORT = htons(port);
+ if (connect(fd, (SAP)&sk, sizeof(sk)) < 0 && errno != EINPROGRESS)
+ {
+ sprintf(errbuf, "connect() to %s %u failed: %s", theirIP, port,
+ strerror(errno));
+ *error = errbuf;
+ close(fd);
+ return -1;
+ }
+ *error = NULL;
+ return fd;
+}
diff --git a/iauth/a_io_ext.h b/iauth/a_io_ext.h
new file mode 100644
index 0000000..12ec257
--- /dev/null
+++ b/iauth/a_io_ext.h
@@ -0,0 +1,50 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, iauth/a_io_ext.h
+ * Copyright (C) 1998 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.
+ */
+
+/* This file contains external definitions for global variables and functions
+ defined in iauth/a_io.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef A_IO_C
+extern anAuthData cldata[MAXCONNECTIONS];
+#endif /* A_IO_C */
+
+/* External definitions for global functions.
+ */
+#ifndef A_IO_C
+#define EXTERN extern
+#else /* A_IO_C */
+#define EXTERN
+#endif /* A_IO_C */
+
+EXTERN void io_init();
+#if ! USE_STDARG
+EXTERN void sendto_ircd();
+#else /* USE_STDARG */
+EXTERN void vsendto_ircd (char *, va_list);
+EXTERN void sendto_ircd (char *, ...);
+#endif
+EXTERN void init_io __P(());
+EXTERN void loop_io __P(());
+EXTERN int tcp_connect __P((char *, char *, u_short, char **));
+
+/* __P(()) */
+#undef EXTERN
diff --git a/iauth/a_log.c b/iauth/a_log.c
new file mode 100644
index 0000000..5307cfe
--- /dev/null
+++ b/iauth/a_log.c
@@ -0,0 +1,123 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, iauth/a_log.c
+ * Copyright (C) 1998 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: a_log.c,v 1.6 1999/02/21 00:33:45 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "a_defines.h"
+#define A_LOG_C
+#include "a_externs.h"
+#undef A_LOG_C
+
+static FILE *debug = NULL, *authlog = NULL;
+
+void
+init_filelogs()
+{
+#if defined(IAUTH_DEBUG)
+ if (debug)
+ fclose(debug);
+ debug = fopen(IAUTHDBG_PATH, "w");
+# if defined(USE_SYSLOG)
+ if (!debug)
+ syslog(LOG_ERR, "Failed to open \"%s\" for writing",
+ IAUTHDBG_PATH);
+# endif
+#endif /* IAUTH_DEBUG */
+ if (authlog)
+ fclose(authlog);
+ authlog = fopen(FNAME_AUTHLOG, "a");
+#if defined(USE_SYSLOG)
+ if (!authlog)
+ syslog(LOG_NOTICE, "Failed to open \"%s\" for writing",
+ FNAME_AUTHLOG);
+#endif
+}
+
+void
+init_syslog()
+{
+#if defined(USE_SYSLOG)
+ openlog("iauth", LOG_PID|LOG_NDELAY, LOG_FACILITY);
+#endif
+}
+
+#if ! USE_STDARG
+void
+sendto_log(flags, slflag, pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)
+int flags, slflag;
+char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10;
+#else
+void
+vsendto_log(int flags, int slflag, char *pattern, va_list va)
+#endif
+{
+ char logbuf[4096];
+
+ logbuf[0] = '>';
+#if ! USE_STDARG
+ sprintf(logbuf+1, pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
+#else
+ vsprintf(logbuf+1, pattern, va);
+#endif
+
+#if defined(USE_SYSLOG)
+ if (slflag)
+ syslog(slflag, logbuf+1);
+#endif
+
+ strcat(logbuf, "\n");
+
+#if defined(IAUTH_DEBUG)
+ if ((flags & ALOG_DALL) && (flags & debuglevel) && debug)
+ {
+ fprintf(debug, logbuf+1);
+ fflush(debug);
+ }
+#endif
+ if (authlog && (flags & ALOG_FLOG))
+ {
+ fprintf(authlog, "%s: %s", myctime(time(NULL)), logbuf+1);
+ fflush(authlog);
+ }
+ if (flags & ALOG_IRCD)
+ {
+ write(0, logbuf, strlen(logbuf));
+#if defined(IAUTH_DEBUG)
+ if ((ALOG_DSPY & debuglevel) && debug)
+ {
+ fprintf(debug, "To ircd: %s", logbuf+1);
+ fflush(debug);
+ }
+#endif
+ }
+}
+
+#if USE_STDARG
+void
+sendto_log(int flags, int slflag, char *pattern, ...)
+{
+ va_list va;
+ va_start(va, pattern);
+ vsendto_log(flags, slflag, pattern, va);
+ va_end(va);
+}
+#endif
diff --git a/iauth/a_log_def.h b/iauth/a_log_def.h
new file mode 100644
index 0000000..e50df0b
--- /dev/null
+++ b/iauth/a_log_def.h
@@ -0,0 +1,41 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, iauth/a_log_def.h
+ * Copyright (C) 1998 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.
+ */
+
+#if defined(IAUTH_DEBUG)
+# define DebugLog(x) sendto_log x
+#else
+# define DebugLog(x) ;
+#endif
+
+#define ALOG_FLOG 0x01 /* file log */
+#define ALOG_IRCD 0x02 /* notice sent to ircd (then sent to &AUTH) */
+
+#define ALOG_DCONF 0x000100 /* debug: configuration file */
+#define ALOG_DMISC 0x000200 /* debug: misc stuff */
+#define ALOG_DIO 0x000400 /* debug: IO stuff */
+#define ALOG_DSPY 0x001000 /* debug: show ircd stream */
+#define ALOG_DIRCD 0x002000 /* debug: errors reported by ircd */
+
+#define ALOG_D931 0x010000 /* debug: module rfc931 */
+#define ALOG_DSOCKS 0x020000 /* debug: module socks */
+#define ALOG_DSOCKSC 0x040000 /* debug: module socks cache */
+#define ALOG_DPIPE 0x080000 /* debug: module pipe */
+#define ALOG_DLHEX 0x100000 /* debug: module pipe */
+
+#define ALOG_DALL 0x1F3700 /* any debug flag */
diff --git a/iauth/a_log_ext.h b/iauth/a_log_ext.h
new file mode 100644
index 0000000..d5887a0
--- /dev/null
+++ b/iauth/a_log_ext.h
@@ -0,0 +1,46 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, iauth/a_log_ext.h
+ * Copyright (C) 1998 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.
+ */
+
+/* This file contains external definitions for global variables and functions
+ defined in iauth/a_log.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef A_LOG_C
+#endif /* A_LOG_C */
+
+/* External definitions for global functions.
+ */
+#ifndef A_LOG_C
+# define EXTERN extern
+#else /* A_LOG_C */
+# define EXTERN
+#endif /* A_LOG_C */
+
+EXTERN void init_filelogs();
+EXTERN void init_syslog();
+#if ! USE_STDARG
+EXTERN void sendto_log();
+#else /* USE_STDARG */
+EXTERN void vsendto_log (int, int, char *, va_list);
+EXTERN void sendto_log (int, int, char *, ...);
+#endif /* USE_STDARG */
+
+#undef EXTERN
diff --git a/iauth/a_struct_def.h b/iauth/a_struct_def.h
new file mode 100644
index 0000000..d71b166
--- /dev/null
+++ b/iauth/a_struct_def.h
@@ -0,0 +1,72 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, iauth/a_struct_def.h
+ * Copyright (C) 1998 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.
+ */
+
+
+typedef struct AuthData anAuthData;
+
+#define INBUFSIZE 4096 /* I/O buffer size */
+#define MAXI 16 /* maximum number of instances */
+#define BDSIZE ((MAXI + 7) / 8) /* bit data size */
+
+struct AuthData
+{
+ /* the following are set by a_io.c and may be read by modules */
+ char user[USERLEN+1]; /* username */
+ char passwd[PASSWDLEN+1]; /* password */
+ char host[HOSTLEN+1]; /* hostname */
+ char itsip[HOSTLEN+1]; /* client ip */
+ u_short itsport; /* client port */
+ char ourip[HOSTLEN+1]; /* our ip */
+ u_short ourport; /* our port */
+ u_int state; /* state (general) */
+
+ /* the following are set by modules */
+ char *authuser; /* authenticated username */
+ u_char authfrom; /* where we got authuser from */
+
+ /* the following are for use by a_io.c only */
+ char idone[BDSIZE]; /* keeping track of instances' work */
+ u_char ileft; /* time saver, anything left? */
+
+ /* the following are shared by a_io.c & modules */
+ char *inbuffer; /* input buffer */
+ u_int buflen; /* length of data in buffer */
+ int rfd, wfd; /* fd's */
+ AnInstance *instance; /* the module instanciation working */
+ u_int mod_status; /* used by the module only! */
+ time_t timeout; /* timeout */
+};
+
+#define A_ACTIVE 0x0001 /* entry is active */
+#define A_START 0x0002 /* go through modules from beginning */
+#define A_DONE 0x0004 /* nothing left to be done */
+#define A_IGNORE 0x0010 /* ignore subsequent messages from ircd */
+#define A_LATE 0x0080 /* ircd is no longer waiting for a reply */
+
+#define A_GOTU 0x0100 /* got username (from ircd) */
+#define A_GOTP 0x0200 /* got password (from ircd) */
+#define A_GOTH 0x0400 /* got hostname (from ircd) */
+#define A_NOH 0x0800 /* no hostname available */
+
+#define A_UNIX 0x1000 /* authuser is suitable for use by ircd */
+#define A_DENY 0x8000 /* connection should be denied access */
+
+#define SetBit(v,n) v[n/8] |= (1 << (n % 8))
+#define UnsetBit(v,n) v[n/8] &= ~(1 << (n % 8))
+#define CheckBit(v,n) (v[n/8] & (1 << (n % 8)))
diff --git a/iauth/iauth.c b/iauth/iauth.c
new file mode 100644
index 0000000..395be72
--- /dev/null
+++ b/iauth/iauth.c
@@ -0,0 +1,226 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, iauth/iauthd.c
+ * Copyright (C) 1998 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: iauth.c,v 1.11 1999/06/17 01:22:20 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "a_defines.h"
+#define IAUTH_C
+#include "a_externs.h"
+#undef IAUTH_C
+
+static int do_log = 0;
+
+RETSIGTYPE dummy(s)
+int s;
+{
+ /* from common/bsd.c */
+#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
+# if 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
+}
+
+RETSIGTYPE s_log(s)
+int s;
+{
+# if POSIX_SIGNALS
+ struct sigaction act;
+
+ act.sa_handler = s_log;
+ act.sa_flags = 0;
+ (void)sigemptyset(&act.sa_mask);
+ (void)sigaddset(&act.sa_mask, SIGUSR2);
+ (void)sigaction(SIGUSR2, &act, NULL);
+# else
+ (void)signal(SIGUSR2, s_log);
+# endif
+ do_log = 1;
+}
+
+void
+init_signals()
+{
+ /* from ircd/ircd.c setup_signals() */
+#if POSIX_SIGNALS
+ struct sigaction act;
+
+ act.sa_handler = SIG_IGN;
+ act.sa_flags = 0;
+ (void)sigemptyset(&act.sa_mask);
+ (void)sigaddset(&act.sa_mask, SIGPIPE);
+ (void)sigaddset(&act.sa_mask, SIGALRM);
+# ifdef SIGWINCH
+ (void)sigaddset(&act.sa_mask, SIGWINCH);
+ (void)sigaction(SIGWINCH, &act, NULL);
+# endif
+ (void)sigaction(SIGPIPE, &act, NULL);
+ act.sa_handler = dummy;
+ (void)sigaction(SIGALRM, &act, NULL);
+/*
+ act.sa_handler = s_rehash;
+ (void)sigemptyset(&act.sa_mask);
+ (void)sigaddset(&act.sa_mask, SIGHUP);
+ (void)sigaction(SIGHUP, &act, NULL);
+ act.sa_handler = s_restart;
+ (void)sigaddset(&act.sa_mask, SIGINT);
+ (void)sigaction(SIGINT, &act, NULL);
+ act.sa_handler = s_die;
+ (void)sigaddset(&act.sa_mask, SIGTERM);
+ (void)sigaction(SIGTERM, &act, NULL);
+*/
+ act.sa_handler = s_log;
+ (void)sigaddset(&act.sa_mask, SIGUSR2);
+ (void)sigaction(SIGUSR2, &act, NULL);
+#else
+# ifndef HAVE_RELIABLE_SIGNALS
+ (void)signal(SIGPIPE, dummy);
+# ifdef SIGWINCH
+ (void)signal(SIGWINCH, dummy);
+# endif
+# else
+# ifdef SIGWINCH
+ (void)signal(SIGWINCH, SIG_IGN);
+# endif
+ (void)signal(SIGPIPE, SIG_IGN);
+# endif
+ (void)signal(SIGALRM, dummy);
+/*
+ (void)signal(SIGHUP, s_rehash);
+ (void)signal(SIGTERM, s_die);
+ (void)signal(SIGINT, s_restart);
+*/
+ (void)signal(SIGUSR2, s_log);
+#endif
+}
+
+int main(argc, argv)
+int argc;
+char *argv[];
+{
+ time_t nextst = time(NULL) + 90;
+ char *xopt;
+
+ if (argc == 2 && !strcmp(argv[1], "-X"))
+ exit(0);
+
+ if (isatty(0))
+ {
+ (void)printf("iauth %s", make_version());
+#if defined(USE_DSM)
+ (void)printf(" (with DSM support)\n");
+#else
+ (void)printf("\n");
+#endif
+ if (argc == 3 && !strcmp(argv[1], "-c"))
+ {
+ (void)printf("\nReading \"%s\"\n\n", argv[2]);
+ conf_read(argv[2]);
+ }
+ else
+ {
+#if defined(INET6)
+ (void)printf("\t+INET6\n");
+#endif
+#if defined(IAUTH_DEBUG)
+ (void)printf("\t+IAUTH_DEBUG\n");
+#endif
+#if defined(USE_POLL)
+ (void)printf("\t+USE_POLL\n");
+#endif
+ }
+ exit(0);
+ }
+
+ init_signals();
+ init_syslog();
+ init_filelogs();
+ sendto_log(ALOG_DMISC, LOG_NOTICE, "Daemon starting (%s%s).",
+ make_version(),
+#if defined(IAUTH_DEBUG)
+ "+debug"
+#else
+ ""
+#endif
+ );
+ init_io();
+ xopt = conf_read(NULL);
+ sendto_ircd("V %s", make_version());
+ sendto_ircd("O %s", xopt);
+ conf_ircd();
+
+#if defined(IAUTH_DEBUG)
+ if (debuglevel & ALOG_DIRCD)
+ sendto_ircd("G 1");
+ else
+#endif
+ sendto_ircd("G 0");
+
+ while (1)
+ {
+ loop_io();
+
+ if (do_log)
+ {
+ sendto_log(ALOG_IRCD|ALOG_DMISC, LOG_INFO,
+ "Got SIGUSR2, reinitializing log file(s).");
+ init_filelogs();
+ do_log = 0;
+ }
+
+ if (time(NULL) > nextst)
+ {
+ AnInstance *itmp = instances;
+
+ sendto_ircd("s");
+ while (itmp)
+ {
+ if (itmp->mod->stats)
+ itmp->mod->stats(itmp);
+ itmp = itmp->nexti;
+ }
+ nextst = time(NULL) + 60;
+ }
+ }
+}
diff --git a/iauth/mod_lhex.c b/iauth/mod_lhex.c
new file mode 100644
index 0000000..07e7e88
--- /dev/null
+++ b/iauth/mod_lhex.c
@@ -0,0 +1,318 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, iauth/mod_lhex.c
+ * Copyright (C) 1998-1999 Christophe Kalt and Andrew Snare
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id mod_lhex.c,v 1.12 1999/02/06 21:43:52 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "a_defines.h"
+#define MOD_LHEX_C
+#include "a_externs.h"
+#undef MOD_LHEX_C
+
+/****************************** PRIVATE *************************************/
+#define LHEXPORT 9674
+
+struct lhex_private
+{
+ /* stats */
+ u_int ok, banned;
+ u_int tried, clean, timeout;
+};
+
+/******************************** PUBLIC ************************************/
+
+/*
+ * lhex_init
+ *
+ * This procedure is called when a particular module is loaded.
+ * Returns NULL if everything went fine,
+ * an error message otherwise.
+ */
+char *
+lhex_init(self)
+AnInstance *self;
+{
+ struct lhex_private *mydata;
+
+#if defined(INET6)
+ return "IPv6 unsupported.";
+#endif
+ if(self->opt == NULL)
+ return "Aie! no option(s): no LHEx server to connect to!";
+ if(!inetaton(self->opt,NULL))
+ return "Aie! Option wasn't a valid IP address!";
+
+ /* Allocate the module data */
+ mydata = (struct lhex_private *) malloc(sizeof(struct lhex_private));
+ bzero((char *) mydata, sizeof(struct lhex_private));
+
+ self->popt = mystrdup(self->opt);
+ self->data = mydata;
+ return NULL;
+}
+
+/*
+ * lhex_release
+ *
+ * This procedure is called when a particular module is unloaded.
+ */
+void
+lhex_release(self)
+AnInstance *self;
+{
+ struct lhex_private *mydata = self->data;
+ free(mydata);
+ free(self->popt);
+}
+
+/*
+ * lhex_stats
+ *
+ * This procedure is called regularly to update statistics sent to ircd.
+ */
+void
+lhex_stats(self)
+AnInstance *self;
+{
+ struct lhex_private *mydata = self->data;
+
+ sendto_ircd("S lhex ok %u banned %u", mydata->ok, mydata->banned);
+ sendto_ircd("S lhex tried %u aborted %u / %u",
+ mydata->tried, mydata->clean, mydata->timeout);
+}
+
+/*
+ * lhex_start
+ *
+ * This procedure is called to start the LHEx check procedure.
+ * Returns 0 if everything went fine,
+ * anything else otherwise (nothing to be done, or failure)
+ *
+ * It is responsible for sending error messages where appropriate.
+ * In case of failure, it's responsible for cleaning up (e.g. lhex_clean
+ * will NOT be called)
+ */
+int
+lhex_start(cl)
+u_int cl;
+{
+ char *error;
+ int fd;
+ struct lhex_private *mydata = cldata[cl].instance->data;
+
+ if (cldata[cl].state & A_DENY)
+ {
+ /* no point of doing anything */
+ DebugLog((ALOG_DLHEX, 0,
+ "lhex_start(%d): A_DENY already set ", cl));
+ return -1;
+ }
+
+ DebugLog((ALOG_DLHEX, 0, "lhex_start(%d): Connecting to %s", cl,
+ cldata[cl].instance->opt));
+ mydata->tried += 1;
+ fd= tcp_connect(cldata[cl].ourip, cldata[cl].instance->opt,
+ LHEXPORT, &error);
+ if (fd < 0)
+ {
+ DebugLog((ALOG_DLHEX, 0,
+ "lhex_start(%d): tcp_connect() reported %s",
+ cl, error));
+ return -1;
+ }
+
+ cldata[cl].wfd = fd; /*so that lhex_work() is called when connected*/
+ return 0;
+}
+
+/*
+ * lhex_work
+ *
+ * This procedure is called whenever there's new data in the buffer.
+ * Returns 0 if everything went fine, and there is more work to be done,
+ * Returns -1 if the module has finished its work (and cleaned up).
+ *
+ * It is responsible for sending error messages where appropriate.
+ */
+int
+lhex_work(cl)
+u_int cl;
+{
+ DebugLog((ALOG_DLHEX, 0, "lhex_work(%d): %d %d buflen=%d", cl,
+ cldata[cl].rfd, cldata[cl].wfd, cldata[cl].buflen));
+ if (cldata[cl].wfd > 0)
+ {
+ /*
+ ** We haven't sent the query yet, the connection was just
+ ** established.
+ */
+ char query[3+7+6+4+USERLEN+2*HOSTLEN+8+3];/*strlen(atoi(cl))<=8*/
+ char *ident = cldata[cl].authuser;
+
+ /* This is part of every request */
+ sprintf(query, "id:%u ip:%s", cl, cldata[cl].itsip);
+
+ /* These bits are optional, depending on what's known */
+ if (ident)
+ {
+ strcat(query, " ident:");
+ strcat(query, ident);
+ }
+ if (cldata[cl].state & A_GOTH)
+ {
+ strcat(query, " host:");
+ strcat(query, cldata[cl].host);
+ }
+ /* Terminate the request */
+ strcat(query, "\r\n");
+
+ DebugLog((ALOG_DLHEX, 0, "lhex_work(%u): Sending query [%s]",
+ cl, query));
+ if (write(cldata[cl].wfd, query, strlen(query)) < 0)
+ {
+ /* most likely the connection failed */
+ DebugLog((ALOG_DLHEX, 0,
+ "lhex_work(%u): write() failed: %s",
+ cl, strerror(errno)));
+ close(cldata[cl].wfd);
+ cldata[cl].rfd = cldata[cl].wfd = 0;
+ return 1;
+ }
+ cldata[cl].rfd = cldata[cl].wfd;
+ cldata[cl].wfd = 0;
+ }
+ else
+ {
+ /* data's in from the other end */
+ char *ch, *nch;
+ u_int id;
+ int retval = 0;
+
+ cldata[cl].inbuffer[cldata[cl].buflen] = '\0';
+ nch = cldata[cl].inbuffer;
+ while((nch < (cldata[cl].inbuffer + cldata[cl].buflen)) &&
+ (ch = index(nch, '\r')) && !retval)
+ {
+ char *och = nch;
+ nch = ch+2; /* Skip the \r\n */
+ *ch = '\0';
+ DebugLog((ALOG_DLHEX, 0, "lhex_work(%u): Got [%s]",
+ cl, och));
+
+ /* Have a go at parsing the return info */
+ if(sscanf(och, "%u", &id) != 1)
+ DebugLog((ALOG_DLHEX, 0, "lhex_work(%u): "
+ "Malformed data!", cl));
+ else
+ {
+ struct lhex_private *d=cldata[cl].instance->data;
+ ch = index(och, ':');
+ while(isspace(*(++ch)));
+ if(!strcmp(ch,"OK"))
+ {
+ d->ok++;
+ DebugLog((ALOG_DLHEX, 0,
+ "lhex_work(%u): OK", id));
+ close(cldata[cl].rfd);
+ cldata[cl].rfd = 0;
+ retval = -1;
+ }
+ else if(!strcmp(ch,"Not OK"))
+ {
+ d->banned++;
+ DebugLog((ALOG_DLHEX, 0,
+ "lhex_work(%u): Not OK", id));
+ cldata[cl].state |= A_DENY;
+ /* I really wish we could send the
+ client a "reason" here :P */
+ sendto_ircd("K %d %s %u ", cl,
+ cldata[cl].itsip,
+ cldata[cl].itsport);
+ close(cldata[cl].rfd);
+ cldata[cl].rfd = 0;
+ retval = -1;
+ }
+ else
+ {
+#if 0
+ /* Call this info for the client */
+ sendto_ircd("I %d %s %u NOTICE AUTH :%s",
+ cl, cldata[cl].itsip,
+ cldata[cl].itsport, ch);
+#endif
+ retval = 0;
+ }
+ }
+ }
+ return retval;
+ }
+ return 0;
+}
+
+/*
+ * lhex_clean
+ *
+ * This procedure is called whenever the module should interrupt its work.
+ * It is responsible for cleaning up any allocated data, and in particular
+ * closing file descriptors.
+ */
+void
+lhex_clean(cl)
+u_int cl;
+{
+ struct lhex_private *mydata = cldata[cl].instance->data;
+
+ mydata->clean += 1;
+ DebugLog((ALOG_DLHEX, 0, "lhex_clean(%d): cleaning up", cl));
+ /*
+ ** only one of rfd and wfd may be set at the same time,
+ ** in any case, they would be the same fd, so only close() once
+ */
+ if (cldata[cl].rfd)
+ close(cldata[cl].rfd);
+ else if (cldata[cl].wfd)
+ close(cldata[cl].wfd);
+ cldata[cl].rfd = cldata[cl].wfd = 0;
+}
+
+/*
+ * lhex_timeout
+ *
+ * This procedure is called whenever the timeout set by the module is
+ * reached.
+ *
+ * Returns 0 if things are okay, -1 if check was aborted.
+ */
+int
+lhex_timeout(cl)
+u_int cl;
+{
+ struct lhex_private *mydata = cldata[cl].instance->data;
+
+ mydata->timeout += 1;
+ DebugLog((ALOG_DLHEX, 0, "lhex_timeout(%d): calling lhex_clean ", cl));
+ lhex_clean(cl);
+ return -1;
+}
+
+aModule Module_lhex =
+ { "lhex", lhex_init, lhex_release, lhex_stats,
+ lhex_start, lhex_work, lhex_timeout, lhex_clean };
diff --git a/iauth/mod_lhex_ext.h b/iauth/mod_lhex_ext.h
new file mode 100644
index 0000000..7777ca1
--- /dev/null
+++ b/iauth/mod_lhex_ext.h
@@ -0,0 +1,28 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, iauth/mod_lhex_ext.h
+ * Copyright (C) 1998-1999 Christophe Kalt and Andrew Snare
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in iauth/mod_lhex.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef MOD_LHEX_C
+extern aModule Module_lhex;
+#endif /* MOD_LHEX_C */
diff --git a/iauth/mod_pipe.c b/iauth/mod_pipe.c
new file mode 100644
index 0000000..df41157
--- /dev/null
+++ b/iauth/mod_pipe.c
@@ -0,0 +1,217 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, iauth/mod_pipe.c
+ * Copyright (C) 1999 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: mod_pipe.c,v 1.3 1999/03/11 19:53:20 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "a_defines.h"
+#define MOD_PIPE_C
+#include "a_externs.h"
+#undef MOD_PIPE_C
+
+/*
+ * pipe_init
+ *
+ * This procedure is called when a particular module is loaded.
+ * Returns NULL if everything went fine,
+ * an error message otherwise.
+ */
+char *
+pipe_init(self)
+AnInstance *self;
+{
+ if (self->opt == NULL)
+ return "Aie! no option(s): nothing to be done!";
+ if (strncasecmp(self->opt, "prog=", 5))
+ return "Aie! unknown option(s): nothing to be done!";
+ self->popt = self->opt + 5;
+ return self->popt;
+}
+
+/*
+ * pipe_release
+ *
+ * This procedure is called when a particular module is unloaded.
+void
+pipe_release(self)
+AnInstance *self;
+{
+}
+ */
+
+/*
+ * pipe_stats
+ *
+ * This procedure is called regularly to update statistics sent to ircd.
+void
+pipe_stats(self)
+AnInstance *self;
+{
+}
+ */
+
+/*
+ * pipe_start
+ *
+ * This procedure is called to start an authentication.
+ * Returns 0 if everything went fine,
+ * -1 otherwise (nothing to be done, or failure)
+ *
+ * It is responsible for sending error messages where appropriate.
+ * In case of failure, it's responsible for cleaning up (e.g. pipe_clean
+ * will NOT be called)
+ */
+int
+pipe_start(cl)
+u_int cl;
+{
+ int pp[2], rc;
+
+ DebugLog((ALOG_DPIPE, 0, "pipe_start(%d): Forking for %s %u", cl,
+ cldata[cl].itsip, cldata[cl].itsport));
+ if (pipe(pp) == -1)
+ {
+ DebugLog((ALOG_DPIPE, 0,
+ "pipe_start(%d): Error creating pipe: %s",
+ cl, strerror(errno)));
+ return -1;
+ }
+ switch (rc = vfork())
+ {
+ case -1 :
+ DebugLog((ALOG_DPIPE, 0,
+ "pipe_start(%d): Error forking: %s",
+ cl, strerror(errno)));
+ return -1;
+ case 0 :
+ {
+ (void)close(pp[0]);
+ for (rc = 2; rc < MAXCONNECTIONS; rc++)
+ if (rc != pp[1])
+ (void)close(rc);
+ if (pp[1] != 2)
+ (void)dup2(pp[1], 2);
+ (void)dup2(2, 1);
+ if (pp[1] != 2 && pp[1] != 1)
+ (void)close(pp[1]);
+ (void)execlp(cldata[cl].instance->popt,
+ cldata[cl].instance->popt,
+ cldata[cl].itsip, cldata[cl].itsport);
+ _exit(-1);
+ }
+ default :
+ (void)close(pp[1]);
+ break;
+ }
+
+ cldata[cl].rfd = pp[0];
+ return 0;
+}
+
+/*
+ * pipe_work
+ *
+ * This procedure is called whenever there's new data in the buffer.
+ * Returns 0 if everything went fine, and there is more work to be done,
+ * Returns -1 if the module has finished its work (and cleaned up).
+ *
+ * It is responsible for sending error messages where appropriate.
+ */
+int
+pipe_work(cl)
+u_int cl;
+{
+ DebugLog((ALOG_DPIPE, 0, "pipe_work(%d): %d %d buflen=%d %c", cl,
+ cldata[cl].rfd, cldata[cl].wfd, cldata[cl].buflen,
+ cldata[cl].inbuffer[0]));
+
+ switch (cldata[cl].inbuffer[0])
+ {
+ case 'Y':
+ break;
+ case 'N':
+ cldata[cl].state |= A_DENY;
+ sendto_ircd("K %d %s %u ", cl, cldata[cl].itsip,
+ cldata[cl].itsport);
+ break;
+#if 0
+ /* hm.. need deeper mods to ircd */
+ case 'y':
+ /* restricted connection only */
+ cldata[cl].state |= A_RESTRICT;
+ sendto_ircd("k %d %s %u ", cl, cldata[cl].itsip,
+ cldata[cl].itsport);
+ break;
+#endif
+ default :
+ /* error */
+ sendto_log(ALOG_FLOG|ALOG_IRCD, LOG_WARNING,
+ "pipe: unexpected %c for %s[%s]",
+ cldata[cl].inbuffer[0],
+ cldata[cl].host,
+ cldata[cl].itsip);
+ break;
+ }
+
+ /* We're done */
+ close(cldata[cl].rfd);
+ cldata[cl].rfd = 0;
+ return -1;
+}
+
+/*
+ * pipe_clean
+ *
+ * This procedure is called whenever the module should interrupt its work.
+ * It is responsible for cleaning up any allocated data, and in particular
+ * closing file descriptors.
+ */
+void
+pipe_clean(cl)
+u_int cl;
+{
+ DebugLog((ALOG_DPIPE, 0, "pipe_clean(%d): cleaning up", cl));
+ if (cldata[cl].rfd)
+ close(cldata[cl].rfd);
+ cldata[cl].rfd = 0;
+}
+
+/*
+ * pipe_timeout
+ *
+ * This procedure is called whenever the timeout set by the module is
+ * reached.
+ *
+ * Returns 0 if things are okay, -1 if authentication was aborted.
+ */
+int
+pipe_timeout(cl)
+u_int cl;
+{
+ DebugLog((ALOG_DPIPE, 0, "pipe_timeout(%d): calling pipe_clean ",
+ cl));
+ pipe_clean(cl);
+ return -1;
+}
+
+aModule Module_pipe =
+ { "pipe", pipe_init, NULL, NULL,
+ pipe_start, pipe_work, pipe_timeout, pipe_clean };
diff --git a/iauth/mod_pipe_ext.h b/iauth/mod_pipe_ext.h
new file mode 100644
index 0000000..9012250
--- /dev/null
+++ b/iauth/mod_pipe_ext.h
@@ -0,0 +1,28 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, iauth/mod_pipe_ext.h
+ * Copyright (C) 1999 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.
+ */
+
+/* This file contains external definitions for global variables and functions
+ defined in iauth/mod_pipe.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef MOD_PIPE_C
+extern aModule Module_pipe;
+#endif /* MOD_PIPE_C */
diff --git a/iauth/mod_rfc931.c b/iauth/mod_rfc931.c
new file mode 100644
index 0000000..80e5292
--- /dev/null
+++ b/iauth/mod_rfc931.c
@@ -0,0 +1,368 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, iauth/mod_rfc931.c
+ * Copyright (C) 1998 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: mod_rfc931.c,v 1.16 1999/07/11 20:56:25 chopin Exp $";
+#endif
+
+#include "os.h"
+#include "a_defines.h"
+#define MOD_RFC931_C
+#include "a_externs.h"
+#undef MOD_RFC931_C
+
+#define OPT_PROTOCOL 0x1
+#define OPT_LAZY 0x2
+
+struct _data
+{
+ u_char options;
+ u_int tried;
+ u_int connected;
+ u_int unx;
+ u_int other;
+ u_int bad;
+ u_int skipped;
+ u_int clean, timeout;
+};
+
+/*
+ * rfc931_init
+ *
+ * This procedure is called when a particular module is loaded.
+ * Returns NULL if everything went fine,
+ * an error message otherwise.
+ */
+char *
+rfc931_init(self)
+AnInstance *self;
+{
+ struct _data *dt;
+
+ dt = (struct _data *) malloc(sizeof(struct _data));
+ bzero((char *) dt, sizeof(struct _data));
+ self->data = (void *) dt;
+
+ /* undocumented option */
+ if (self->opt && strstr(self->opt, "protocol"))
+ dt->options |= OPT_PROTOCOL;
+ if (self->opt && strstr(self->opt, "lazy"))
+ dt->options |= OPT_LAZY;
+
+ if (dt->options & (OPT_LAZY|OPT_PROTOCOL))
+ self->popt = "protocol,lazy";
+ else if (dt->options & OPT_LAZY)
+ self->popt = "lazy";
+ else if (dt->options & OPT_PROTOCOL)
+ self->popt = "protocol";
+ else
+ return NULL;
+ return self->popt;
+}
+
+/*
+ * rfc931_release
+ *
+ * This procedure is called when a particular module is unloaded.
+ */
+void
+rfc931_release(self)
+AnInstance *self;
+{
+ struct _data *st = self->data;
+ free(st);
+}
+
+/*
+ * rfc931_stats
+ *
+ * This procedure is called regularly to update statistics sent to ircd.
+ */
+void
+rfc931_stats(self)
+AnInstance *self;
+{
+ struct _data *st = self->data;
+
+ sendto_ircd("S rfc931 connected %u unix %u other %u bad %u out of %u",
+ st->connected, st->unx, st->other, st->bad, st->tried);
+ sendto_ircd("S rfc931 skipped %u aborted %u / %u",
+ st->skipped, st->clean, st->timeout);
+}
+
+/*
+ * rfc931_start
+ *
+ * This procedure is called to start an authentication.
+ * Returns 0 if everything went fine,
+ * -1 else otherwise (nothing to be done, or failure)
+ *
+ * It is responsible for sending error messages where appropriate.
+ * In case of failure, it's responsible for cleaning up (e.g. rfc931_clean
+ * will NOT be called)
+ */
+int
+rfc931_start(cl)
+u_int cl;
+{
+ char *error;
+ int fd;
+ struct _data *st = cldata[cl].instance->data;
+
+ if (st->options & OPT_LAZY && cldata[cl].state & A_DENY)
+ {
+ DebugLog((ALOG_D931, 0, "rfc931_start(%d): Lazy.", cl));
+ return -1;
+ }
+ if (cldata[cl].authuser &&
+ cldata[cl].authfrom < cldata[cl].instance->in)
+ {
+ DebugLog((ALOG_D931, 0,
+ "rfc931_start(%d): Instance %d already got the info",
+ cl, cldata[cl].authfrom));
+ return -1;
+ }
+ DebugLog((ALOG_D931, 0, "rfc931_start(%d): Connecting to %s %u", cl,
+ cldata[cl].itsip, 113));
+ st->tried += 1;
+ fd = tcp_connect(cldata[cl].ourip, cldata[cl].itsip, 113, &error);
+ if (fd < 0)
+ {
+ DebugLog((ALOG_D931, 0,
+ "rfc931_start(%d): tcp_connect() reported %s",
+ cl, error));
+ return -1;
+ }
+
+ cldata[cl].wfd = fd; /*so that rfc931_work() is called when connected*/
+ return 0;
+}
+
+/*
+ * rfc931_work
+ *
+ * This procedure is called whenever there's new data in the buffer.
+ * Returns 0 if everything went fine, and there is more work to be done,
+ * Returns -1 if the module has finished its work (and cleaned up).
+ *
+ * It is responsible for sending error messages where appropriate.
+ */
+int
+rfc931_work(cl)
+u_int cl;
+{
+ struct _data *st = cldata[cl].instance->data;
+
+ DebugLog((ALOG_D931, 0, "rfc931_work(%d): %d %d buflen=%d", cl,
+ cldata[cl].rfd, cldata[cl].wfd, cldata[cl].buflen));
+ if (cldata[cl].wfd > 0)
+ {
+ /*
+ ** We haven't sent the query yet, the connection was just
+ ** established.
+ */
+ char query[32];
+
+ sprintf(query, "%u , %u\r\n", cldata[cl].itsport,
+ cldata[cl].ourport);
+ if (write(cldata[cl].wfd, query, strlen(query)) < 0)
+ {
+ /* most likely the connection failed */
+ DebugLog((ALOG_D931, 0,
+ "rfc931_work(%d): write() failed: %s", cl,
+ strerror(errno)));
+ close(cldata[cl].wfd);
+ cldata[cl].rfd = cldata[cl].wfd = 0;
+ return 1;
+ }
+ else
+ st->connected += 1;
+ cldata[cl].rfd = cldata[cl].wfd;
+ cldata[cl].wfd = 0;
+ }
+ else
+ {
+ /* data's in from the ident server */
+ char *ch;
+ u_char bad = 0;
+
+ cldata[cl].inbuffer[cldata[cl].buflen] = '\0';
+ ch = index(cldata[cl].inbuffer, '\r');
+ if (ch)
+ {
+ /* got all of it! */
+ *ch = '\0';
+ DebugLog((ALOG_D931, 0, "rfc931_work(%d): Got [%s]",
+ cl, cldata[cl].inbuffer));
+ if (cldata[cl].buflen > 1024)
+ cldata[cl].inbuffer[1024] = '\0';
+ if (ch = index(cldata[cl].inbuffer, '\n'))
+ /* delimiter for ircd<->iauth messages. */
+ *ch = '\0';
+ ch = cldata[cl].inbuffer;
+ while (*ch && !isdigit(*ch)) ch++;
+ if (!*ch || atoi(ch) != cldata[cl].itsport)
+ {
+ DebugLog((ALOG_D931, 0,
+ "remote port mismatch."));
+ ch = NULL;
+ }
+ while (ch && *ch && *ch != ',') ch++;
+ while (ch && *ch && !isdigit(*ch)) ch++;
+ if (ch && (!*ch || atoi(ch) != cldata[cl].ourport))
+ {
+ DebugLog((ALOG_D931, 0,
+ "local port mismatch."));
+ ch = NULL;
+ }
+ if (ch) ch = index(ch, ':');
+ if (ch) ch += 1;
+ while (ch && *ch && *ch == ' ') ch++;
+ if (ch && strncmp(ch, "USERID", 6))
+ {
+ DebugLog((ALOG_D931, 0, "No USERID."));
+ ch = NULL;
+ }
+ if (ch) ch = index(ch, ':');
+ if (ch) ch += 1;
+ while (ch && *ch && *ch == ' ') ch++;
+ if (ch)
+ {
+ int other = 0;
+
+ if (!strncmp(ch, "OTHER", 5))
+ other = 1;
+ ch = rindex(ch, ':');
+ if (ch) ch += 1;
+ while (ch && *ch && *ch == ' ') ch++;
+ if (ch && *ch)
+ {
+ if (cldata[cl].authuser)
+ free(cldata[cl].authuser);
+ cldata[cl].authuser = mystrdup(ch);
+ cldata[cl].authfrom =
+ cldata[cl].instance->in;
+ if (other)
+ st->other += 1;
+ else
+ {
+ st->unx += 1;
+ cldata[cl].state |= A_UNIX;
+ }
+ sendto_ircd("%c %d %s %u %s",
+ (other) ? 'u' : 'U', cl,
+ cldata[cl].itsip,
+ cldata[cl].itsport,
+ cldata[cl].authuser);
+ }
+ else
+ bad = 1;
+ }
+ else
+ bad = 1;
+ if (bad)
+ {
+ st->bad += 1;
+
+ if (st->options & OPT_PROTOCOL)
+ {
+ ch = cldata[cl].inbuffer;
+ while (*ch)
+ {
+ if (!(isalnum(*ch) ||
+ ispunct(*ch) ||
+ isspace(*ch)))
+ break;
+ ch += 1;
+ }
+ *ch = '\0';
+ sendto_log(ALOG_IRCD|ALOG_FLOG,
+ LOG_WARNING,
+ "rfc931: bad reply from %s[%s] to \"%u, %u\": %u, \"%s\"",
+ cldata[cl].host,
+ cldata[cl].itsip,
+ cldata[cl].itsport,
+ cldata[cl].ourport,
+ cldata[cl].buflen,
+ cldata[cl].inbuffer);
+ }
+ }
+ /*
+ ** In any case, our job is done, let's cleanup.
+ */
+ close(cldata[cl].rfd);
+ cldata[cl].rfd = 0;
+ return -1;
+ }
+ else
+ return 0;
+ }
+ return 0;
+}
+
+/*
+ * rfc931_clean
+ *
+ * This procedure is called whenever the module should interrupt its work.
+ * It is responsible for cleaning up any allocated data, and in particular
+ * closing file descriptors.
+ */
+void
+rfc931_clean(cl)
+u_int cl;
+{
+ struct _data *st = cldata[cl].instance->data;
+
+ st->clean += 1;
+ DebugLog((ALOG_D931, 0, "rfc931_clean(%d): cleaning up", cl));
+ /*
+ ** only one of rfd and wfd may be set at the same time,
+ ** in any case, they would be the same fd, so only close() once
+ */
+ if (cldata[cl].rfd)
+ close(cldata[cl].rfd);
+ else if (cldata[cl].wfd)
+ close(cldata[cl].wfd);
+ cldata[cl].rfd = cldata[cl].wfd = 0;
+}
+
+/*
+ * rfc931_timeout
+ *
+ * This procedure is called whenever the timeout set by the module is
+ * reached.
+ *
+ * Returns 0 if things are okay, -1 if authentication was aborted.
+ */
+int
+rfc931_timeout(cl)
+u_int cl;
+{
+ struct _data *st = cldata[cl].instance->data;
+
+ st->timeout += 1;
+ DebugLog((ALOG_D931, 0, "rfc931_timeout(%d): calling rfc931_clean ",
+ cl));
+ rfc931_clean(cl);
+ return -1;
+}
+
+aModule Module_rfc931 =
+ { "rfc931", rfc931_init, rfc931_release, rfc931_stats,
+ rfc931_start, rfc931_work, rfc931_timeout, rfc931_clean };
diff --git a/iauth/mod_rfc931_ext.h b/iauth/mod_rfc931_ext.h
new file mode 100644
index 0000000..b37892e
--- /dev/null
+++ b/iauth/mod_rfc931_ext.h
@@ -0,0 +1,45 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, iauth/mod_rfc931_ext.h
+ * Copyright (C) 1998 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.
+ */
+
+/* This file contains external definitions for global variables and functions
+ defined in iauth/mod_rfc931.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef MOD_RFC931_C
+extern aModule Module_rfc931;
+#endif /* MOD_RFC931_C */
+
+/* External definitions for global functions.
+ */
+#ifndef MOD_RFC931_C
+# define EXTERN extern
+#else /* MOD_RFC931_C */
+# define EXTERN
+#endif /* MOD_RFC931_C */
+
+/*
+EXTERN int rfc931_start __P((u_int));
+EXTERN int rfc931_work __P((u_int));
+EXTERN int rfc931_timeout __P((u_int));
+EXTERN void rfc931_clean __P((u_int));
+*/
+
+#undef EXTERN
diff --git a/iauth/mod_socks.c b/iauth/mod_socks.c
new file mode 100644
index 0000000..94742c4
--- /dev/null
+++ b/iauth/mod_socks.c
@@ -0,0 +1,632 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, iauth/mod_socks.c
+ * Copyright (C) 1998 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: mod_socks.c,v 1.25 1999/08/13 21:06:30 chopin Exp $";
+#endif
+
+#include "os.h"
+#include "a_defines.h"
+#define MOD_SOCKS_C
+#include "a_externs.h"
+#undef MOD_SOCKS_C
+
+/****************************** PRIVATE *************************************/
+
+#define CACHETIME 30
+
+#define SOCKSPORT 1080
+
+struct proxylog
+{
+ struct proxylog *next;
+ char ip[HOSTLEN+1];
+ u_char state; /* 0 = no proxy, 1 = open proxy, 2 = closed proxy */
+ time_t expire;
+};
+
+#define OPT_LOG 0x001
+#define OPT_DENY 0x002
+#define OPT_PARANOID 0x004
+#define OPT_CAREFUL 0x008
+#define OPT_V4ONLY 0x010
+#define OPT_V5ONLY 0x020
+#define OPT_PROTOCOL 0x100
+
+#define PROXY_NONE 0
+#define PROXY_OPEN 1
+#define PROXY_CLOSE 2
+#define PROXY_UNEXPECTED 3
+#define PROXY_BADPROTO 4
+
+#define ST_V4 0x01
+#define ST_V5 0x02
+#define ST_V5b 0x04
+
+struct socks_private
+{
+ struct proxylog *cache;
+ u_int lifetime;
+ u_char options;
+ /* stats */
+ u_int chitc, chito, chitn, cmiss, cnow, cmax;
+ u_int closed4, closed5, open4, open5, noprox;
+ u_int closed5b, open5b;
+};
+
+/*
+ * socks_open_proxy
+ *
+ * Found an open proxy for cl: deal with it!
+ */
+static void
+socks_open_proxy(cl, strver)
+int cl;
+char *strver;
+{
+ struct socks_private *mydata = cldata[cl].instance->data;
+
+ /* open proxy */
+ if (mydata->options & OPT_DENY)
+ {
+ cldata[cl].state |= A_DENY;
+ sendto_ircd("k %d %s %u ", cl, cldata[cl].itsip,
+ cldata[cl].itsport);
+ }
+ if (mydata->options & OPT_LOG)
+ sendto_log(ALOG_FLOG, LOG_INFO, "socks%s: open proxy: %s[%s]",
+ strver, cldata[cl].host, cldata[cl].itsip);
+}
+
+/*
+ * socks_add_cache
+ *
+ * Add an entry to the cache.
+ */
+static void
+socks_add_cache(cl, state)
+int cl, state;
+{
+ struct socks_private *mydata = cldata[cl].instance->data;
+ struct proxylog *next;
+
+ if (state == PROXY_OPEN)
+ if (cldata[cl].mod_status == ST_V4)
+ mydata->open4 += 1;
+ else if (cldata[cl].mod_status == ST_V5)
+ mydata->open5 += 1;
+ else
+ mydata->open5b += 1;
+ else if (state == PROXY_NONE)
+ mydata->noprox += 1;
+ else /* state == PROXY_CLOSE|PROXY_UNEXPECTED|PROXY_BADPROTO */
+ if (cldata[cl].mod_status == ST_V4)
+ mydata->closed4 += 1;
+ else if (cldata[cl].mod_status == ST_V5)
+ mydata->closed5 += 1;
+ else
+ mydata->closed5b += 1;
+
+ if (mydata->lifetime == 0)
+ return;
+
+ mydata->cnow += 1;
+ if (mydata->cnow > mydata->cmax)
+ mydata->cmax = mydata->cnow;
+
+ next = mydata->cache;
+ mydata->cache = (struct proxylog *)malloc(sizeof(struct proxylog));
+ mydata->cache->expire = time(NULL) + mydata->lifetime;
+ strcpy(mydata->cache->ip, cldata[cl].itsip);
+ mydata->cache->state = state;
+ mydata->cache->next = next;
+ DebugLog((ALOG_DSOCKSC, 0, "socks_add_cache(%d): new cache %s, open=%d",
+ cl, mydata->cache->ip, state));
+}
+
+/*
+ * socks_check_cache
+ *
+ * Check cache for an entry.
+ */
+static int
+socks_check_cache(cl)
+{
+ struct socks_private *mydata = cldata[cl].instance->data;
+ struct proxylog **last, *pl;
+ time_t now = time(NULL);
+
+ if (mydata->lifetime == 0)
+ return 0;
+
+ DebugLog((ALOG_DSOCKSC, 0, "socks_check_cache(%d): Checking cache for %s",
+ cl, cldata[cl].itsip));
+
+ last = &(mydata->cache);
+ while (pl = *last)
+ {
+ DebugLog((ALOG_DSOCKSC, 0, "socks_check_cache(%d): cache %s",
+ cl, pl->ip));
+ if (pl->expire < now)
+ {
+ DebugLog((ALOG_DSOCKSC, 0,
+ "socks_check_cache(%d): free %s (%d < %d)",
+ cl, pl->ip, pl->expire, now));
+ *last = pl->next;
+ free(pl);
+ mydata->cnow -= 1;
+ continue;
+ }
+ if (!strcasecmp(pl->ip, cldata[cl].itsip))
+ {
+ DebugLog((ALOG_DSOCKSC, 0,
+ "socks_check_cache(%d): match (%u)",
+ cl, pl->state));
+ pl->expire = now + mydata->lifetime; /* dubious */
+ if (pl->state == 1)
+ {
+ socks_open_proxy(cl, "C");
+ mydata->chito += 1;
+ }
+ else if (pl->state == 0)
+ mydata->chitn += 1;
+ else
+ mydata->chitc += 1;
+ return -1;
+ }
+ last = &(pl->next);
+ }
+ mydata->cmiss += 1;
+ return 0;
+}
+
+static int
+socks_write(cl, strver)
+u_int cl;
+char *strver;
+{
+ u_char query[13]; /* big enough to hold all queries */
+ int query_len = 13; /* lenght of socks4 query */
+ u_int a, b, c, d;
+
+ if (sscanf(cldata[cl].ourip, "%u.%u.%u.%u", &a,&b,&c,&d) != 4)
+ {
+ sendto_log(ALOG_DSOCKS|ALOG_IRCD, LOG_ERR,
+ "socks_write%s(%d): sscanf(\"%s\") failed",
+ strver, cl, cldata[cl].ourip);
+ close(cldata[cl].wfd);
+ cldata[cl].wfd = 0;
+ return -1;
+ }
+ if (cldata[cl].mod_status == ST_V4)
+ {
+ query[0] = 4; query[1] = 1;
+ query[2] = ((cldata[cl].ourport & 0xff00) >> 8);
+ query[3] = (cldata[cl].ourport & 0x00ff);
+ query[4] = a; query[5] = b; query[6] = c; query[7] = d;
+ query[8] = 'u'; query[9] = 's'; query[10] = 'e'; query[11] = 'r';
+ query[12] = 0;
+ }
+ else
+ {
+ query[0] = 5; query[1] = 1; query[2] = 0;
+ query_len = 3;
+ if (cldata[cl].mod_status == ST_V5b)
+ {
+ query_len = 10;
+ query[3] = 1;
+ query[4] = a; query[5] = b; query[6] = c; query[7] = d;
+ query[8] = ((cldata[cl].ourport & 0xff00) >>8);
+ query[9] = (cldata[cl].ourport & 0x00ff);
+ }
+ }
+
+ DebugLog((ALOG_DSOCKS, 0, "socks%s_write(%d): Checking %s %u",
+ strver, cl, cldata[cl].ourip, SOCKSPORT));
+ if (write(cldata[cl].wfd, query, query_len) != query_len)
+ {
+ /* most likely the connection failed */
+ DebugLog((ALOG_DSOCKS, 0, "socks%s_write(%d): write() failed: %s",
+ strver, cl, strerror(errno)));
+ socks_add_cache(cl, PROXY_NONE, 0);
+ close(cldata[cl].wfd);
+ cldata[cl].rfd = cldata[cl].wfd = 0;
+ return 1;
+ }
+ cldata[cl].rfd = cldata[cl].wfd;
+ cldata[cl].wfd = 0;
+ return 0;
+}
+
+static int
+socks_read(cl, strver)
+u_int cl;
+char *strver;
+{
+ struct socks_private *mydata = cldata[cl].instance->data;
+ int again = 0;
+ u_char state = PROXY_CLOSE;
+
+ /* data's in from the other end */
+ if (cldata[cl].buflen < 2)
+ return 0;
+
+ /* got all we need */
+ DebugLog((ALOG_DSOCKS, 0, "socks%s_read(%d): Got [%d %d]", strver, cl,
+ cldata[cl].inbuffer[0], cldata[cl].inbuffer[1]));
+
+ if (cldata[cl].mod_status == ST_V4)
+ {
+ if (cldata[cl].inbuffer[0] == 0)
+ {
+ if (cldata[cl].inbuffer[1] < 90 ||
+ cldata[cl].inbuffer[1] > 93)
+ state = PROXY_UNEXPECTED;
+ else
+ {
+ if (cldata[cl].inbuffer[1] == 90)
+ state = PROXY_OPEN;
+ else if ((mydata->options & OPT_PARANOID) &&
+ cldata[cl].inbuffer[1] != 91)
+ state = PROXY_OPEN;
+ }
+ }
+ else
+ state = PROXY_BADPROTO;
+ }
+ else /* ST_V5 or ST_V5b */
+ {
+ if (cldata[cl].inbuffer[0] == 5)
+ if (cldata[cl].inbuffer[1] == 0)
+ state = PROXY_OPEN;
+ else
+ {
+ if (cldata[cl].mod_status == ST_V5)
+ {
+ if ((u_char)cldata[cl].inbuffer[1] == 4 ||
+ ((u_char)cldata[cl].inbuffer[1] > 9 &&
+ (u_char)cldata[cl].inbuffer[1] != 255))
+ state = PROXY_UNEXPECTED;
+ }
+ else /* ST_V5b */
+ if ((u_char) cldata[cl].inbuffer[1] > 8)
+ state = PROXY_UNEXPECTED;
+ else if ((mydata->options&OPT_PARANOID) &&
+ cldata[cl].inbuffer[1] != 2)
+ state = PROXY_OPEN;
+ }
+ else
+ state = PROXY_BADPROTO;
+ }
+
+ if (cldata[cl].mod_status == ST_V4 && state != PROXY_OPEN &&
+ !(mydata->options & OPT_V4ONLY))
+ {
+ cldata[cl].mod_status = ST_V5;
+ cldata[cl].buflen=0;
+ close(cldata[cl].rfd);
+ cldata[cl].rfd = 0;
+ again = 1;
+ }
+
+ if (cldata[cl].mod_status == ST_V5 && state == PROXY_OPEN &&
+ (mydata->options & OPT_CAREFUL))
+ {
+ cldata[cl].mod_status = ST_V5b;
+ cldata[cl].buflen=0;
+ close(cldata[cl].rfd);
+ cldata[cl].rfd = 0;
+ again = 1;
+ }
+
+ if (state == PROXY_OPEN && again == 0)
+ socks_open_proxy(cl, strver);
+
+ if (state == PROXY_UNEXPECTED)
+ {
+ sendto_log(ALOG_FLOG, LOG_WARNING,
+ "socks%s: unexpected reply: %u,%u %s[%s]", strver,
+ cldata[cl].inbuffer[0], cldata[cl].inbuffer[1],
+ cldata[cl].host, cldata[cl].itsip);
+ sendto_log(ALOG_IRCD, 0, "socks%s: unexpected reply: %u,%u",
+ strver, cldata[cl].inbuffer[0],
+ cldata[cl].inbuffer[1]);
+ state = PROXY_CLOSE;
+ }
+
+ if (state == PROXY_BADPROTO && (mydata->options & OPT_PROTOCOL))
+ {
+ sendto_log(ALOG_FLOG, LOG_WARNING,
+ "socks%s: protocol error: %u,%u %s[%s]", strver,
+ cldata[cl].inbuffer[0], cldata[cl].inbuffer[1],
+ cldata[cl].host, cldata[cl].itsip);
+ sendto_log(ALOG_IRCD, 0, "socks%s: protocol error: %u,%u",
+ strver, cldata[cl].inbuffer[0],
+ cldata[cl].inbuffer[1]);
+ state = PROXY_CLOSE;
+ }
+
+ if (again == 1)
+ return socks_start(cl);
+ else
+ {
+ socks_add_cache(cl, state);
+ close(cldata[cl].rfd);
+ cldata[cl].rfd = 0;
+ return -1;
+ }
+ return 0;
+}
+
+/******************************** PUBLIC ************************************/
+
+/*
+ * socks_init
+ *
+ * This procedure is called when a particular module is loaded.
+ * Returns NULL if everything went fine,
+ * an error message otherwise.
+ */
+char *
+socks_init(self)
+AnInstance *self;
+{
+ struct socks_private *mydata;
+ char tmpbuf[80], cbuf[32];
+ static char txtbuf[80];
+
+#if defined(INET6)
+ return "IPv6 unsupported.";
+#endif
+ if (self->opt == NULL)
+ return "Aie! no option(s): nothing to be done!";
+
+ mydata = (struct socks_private *) malloc(sizeof(struct socks_private));
+ bzero((char *) mydata, sizeof(struct socks_private));
+ mydata->cache = NULL;
+ mydata->lifetime = CACHETIME;
+
+ tmpbuf[0] = txtbuf[0] = '\0';
+ if (strstr(self->opt, "log"))
+ {
+ mydata->options |= OPT_LOG;
+ strcat(tmpbuf, ",log");
+ strcat(txtbuf, ", Log");
+ }
+ if (strstr(self->opt, "reject"))
+ {
+ mydata->options |= OPT_DENY;
+ strcat(tmpbuf, ",reject");
+ strcat(txtbuf, ", Reject");
+ }
+ if (strstr(self->opt, "paranoid"))
+ {
+ mydata->options |= OPT_PARANOID;
+ strcat(tmpbuf, ",paranoid");
+ strcat(txtbuf, ", Paranoid");
+ }
+ if (strstr(self->opt, "careful"))
+ {
+ mydata->options |= OPT_CAREFUL;
+ strcat(tmpbuf, ",careful");
+ strcat(txtbuf, ", Careful");
+ }
+ if (strstr(self->opt, "v4only"))
+ {
+ mydata->options |= OPT_V4ONLY;
+ strcat(tmpbuf, ",v4only");
+ strcat(txtbuf, ", V4only");
+ }
+ if (strstr(self->opt, "v5only"))
+ {
+ mydata->options |= OPT_V5ONLY;
+ strcat(tmpbuf, ",v5only");
+ strcat(txtbuf, ", V5only");
+ }
+ if (strstr(self->opt, "protocol"))
+ {
+ mydata->options |= OPT_PROTOCOL;
+ strcat(tmpbuf, ",protocol");
+ strcat(txtbuf, ", Protocol");
+ }
+
+ if (mydata->options == 0)
+ return "Aie! unknown option(s): nothing to be done!";
+
+ if (strstr(self->opt, "cache"))
+ {
+ char *ch = index(self->opt, '=');
+
+ if (ch)
+ mydata->lifetime = atoi(ch+1);
+ }
+ sprintf(cbuf, ",cache=%d", mydata->lifetime);
+ strcat(tmpbuf, cbuf);
+ sprintf(cbuf, ", Cache %d (min)", mydata->lifetime);
+ strcat(txtbuf, cbuf);
+ mydata->lifetime *= 60;
+
+ self->popt = mystrdup(tmpbuf+1);
+ self->data = mydata;
+ return txtbuf+2;
+}
+
+/*
+ * socks_release
+ *
+ * This procedure is called when a particular module is unloaded.
+ */
+void
+socks_release(self)
+AnInstance *self;
+{
+ struct sock_private *mydata = self->data;
+ free(mydata);
+ free(self->popt);
+}
+
+/*
+ * socks_stats
+ *
+ * This procedure is called regularly to update statistics sent to ircd.
+ */
+void
+socks_stats(self)
+AnInstance *self;
+{
+ struct socks_private *mydata = self->data;
+
+ sendto_ircd("S socks open %u/%u/%u closed %u/%u/%u noproxy %u",
+ mydata->open4, mydata->open5, mydata->open5b,
+ mydata->closed4, mydata->closed5, mydata->closed5b,
+ mydata->noprox);
+ sendto_ircd("S socks cache open %u closed %u noproxy %u miss %u (%u <= %u)",
+ mydata->chito, mydata->chitc, mydata->chitn,
+ mydata->cmiss, mydata->cnow, mydata->cmax);
+}
+
+/*
+ * socks_start
+ *
+ * This procedure is called to start the socks check procedure.
+ * Returns 0 if everything went fine,
+ * -1 otherwise (nothing to be done, or failure)
+ *
+ * It is responsible for sending error messages where appropriate.
+ * In case of failure, it's responsible for cleaning up (e.g. socks_clean
+ * will NOT be called)
+ */
+int
+socks_start(cl)
+u_int cl;
+{
+ struct socks_private *mydata = cldata[cl].instance->data;
+ char *error;
+ int fd;
+
+ if (cldata[cl].state & A_DENY)
+ {
+ /* no point of doing anything */
+ DebugLog((ALOG_DSOCKS, 0,
+ "socks_start(%d): A_DENY alredy set ", cl));
+ return -1;
+ }
+
+ if (socks_check_cache(cl))
+ return -1;
+
+ DebugLog((ALOG_DSOCKS, 0, "socks_start(%d): Connecting to %s", cl,
+ cldata[cl].itsip));
+ fd= tcp_connect(cldata[cl].ourip, cldata[cl].itsip, SOCKSPORT, &error);
+ if (fd < 0)
+ {
+ DebugLog((ALOG_DSOCKS, 0,
+ "socks_start(%d): tcp_connect() reported %s", cl,error));
+ socks_add_cache(cl, PROXY_NONE, 0);
+ return -1;
+ }
+
+ cldata[cl].wfd = fd; /*so that socks_work() is called when connected*/
+
+ return 0;
+}
+
+/*
+ * socks_work
+ *
+ * This procedure is called whenever there's new data in the buffer.
+ * Returns 0 if everything went fine, and there is more work to be done,
+ * Returns -1 if the module has finished its work (and cleaned up).
+ *
+ * It is responsible for sending error messages where appropriate.
+ */
+int
+socks_work(cl)
+u_int cl;
+{
+ char *strver = "4";
+ struct socks_private *mydata = cldata[cl].instance->data;
+
+ if (cldata[cl].mod_status == 0)
+ if (mydata->options & OPT_V5ONLY)
+ cldata[cl].mod_status = ST_V5;
+ else
+ cldata[cl].mod_status = ST_V4;
+
+ if (cldata[cl].mod_status & ST_V5)
+ strver = "5";
+ else if (cldata[cl].mod_status & ST_V5b)
+ strver = "5b";
+
+ DebugLog((ALOG_DSOCKS, 0, "socks%s_work(%d): %d %d buflen=%d", strver,
+ cl, cldata[cl].rfd, cldata[cl].wfd, cldata[cl].buflen));
+
+ if (cldata[cl].wfd > 0)
+ /*
+ ** We haven't sent the query yet, the connection was just
+ ** established.
+ */
+ return socks_write(cl, strver);
+ else
+ return socks_read(cl, strver);
+}
+
+/*
+ * socks_clean
+ *
+ * This procedure is called whenever the module should interrupt its work.
+ * It is responsible for cleaning up any allocated data, and in particular
+ * closing file descriptors.
+ */
+void
+socks_clean(cl)
+u_int cl;
+{
+ DebugLog((ALOG_DSOCKS, 0, "socks_clean(%d): cleaning up", cl));
+ /*
+ ** only one of rfd and wfd may be set at the same time,
+ ** in any case, they would be the same fd, so only close() once
+ */
+ if (cldata[cl].rfd)
+ close(cldata[cl].rfd);
+ else if (cldata[cl].wfd)
+ close(cldata[cl].wfd);
+ cldata[cl].rfd = cldata[cl].wfd = 0;
+}
+
+/*
+ * socks_timeout
+ *
+ * This procedure is called whenever the timeout set by the module is
+ * reached.
+ *
+ * Returns 0 if things are okay, -1 if check was aborted.
+ */
+int
+socks_timeout(cl)
+u_int cl;
+{
+ DebugLog((ALOG_DSOCKS, 0, "socks_timeout(%d): calling socks_clean ", cl));
+ socks_clean(cl);
+ return -1;
+}
+
+aModule Module_socks =
+ { "socks", socks_init, socks_release, socks_stats,
+ socks_start, socks_work, socks_timeout, socks_clean };
diff --git a/iauth/mod_socks_ext.h b/iauth/mod_socks_ext.h
new file mode 100644
index 0000000..9f4df51
--- /dev/null
+++ b/iauth/mod_socks_ext.h
@@ -0,0 +1,28 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, iauth/mod_socks_ext.h
+ * Copyright (C) 1998 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.
+ */
+
+/* This file contains external definitions for global variables and functions
+ defined in iauth/mod_socks.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef MOD_SOCKS_C
+extern aModule Module_socks;
+#endif /* MOD_SOCKS_C */
diff --git a/irc/c_bsd.c b/irc/c_bsd.c
new file mode 100644
index 0000000..25bbd83
--- /dev/null
+++ b/irc/c_bsd.c
@@ -0,0 +1,149 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/c_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.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: c_bsd.c,v 1.5 1998/12/13 00:02:35 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "c_defines.h"
+#define C_BSD_C
+#include "c_externs.h"
+#undef C_BSD_C
+
+#ifdef AUTOMATON
+#ifdef DOCURSES
+#undef DOCURSES
+#endif
+#ifdef DOTERMCAP
+#undef DOTERMCAP
+#endif
+#endif /* AUTOMATON */
+
+#define STDINBUFSIZE (0x80)
+
+int client_init(host, portnum, cptr)
+char *host;
+int portnum;
+aClient *cptr;
+{
+ int sock;
+ static struct hostent *hp;
+ static struct SOCKADDR_IN server;
+
+ sock = socket(AFINET, SOCK_STREAM, 0);
+ if (sock < 0) {
+ perror("opening stream socket");
+ exit(1);
+ }
+ server.SIN_FAMILY = AFINET;
+
+ if (isdigit(*host))
+#ifdef INET6
+ {
+ if(!inet_pton(AF_INET6, host, server.sin6_addr.s6_addr))
+ bcopy(minus_one, server.sin6_addr.s6_addr, IN6ADDRSZ);
+ }
+#else
+ server.sin_addr.s_addr = inetaddr(host);
+#endif
+ else {
+#ifdef INET6
+ res_init();
+ _res.options|=RES_USE_INET6;
+#endif
+ hp = gethostbyname(host);
+ if (hp == 0) {
+ fprintf(stderr, "%s: unknown host\n", host);
+ exit(2);
+ }
+ bcopy(hp->h_addr, (char *)&server.SIN_ADDR, hp->h_length);
+ }
+ server.SIN_PORT = htons(portnum);
+ if (connect(sock, (SAP)&server, sizeof(server)) == -1) {
+ perror("irc");
+ exit(1);
+ }
+
+ cptr->acpt = cptr;
+ cptr->port = server.SIN_PORT;
+#ifdef INET6
+ bcopy(server.sin6_addr.s6_addr, cptr->ip.s6_addr, IN6ADDRSZ);
+#else
+ cptr->ip.s_addr = server.sin_addr.s_addr;
+#endif
+ return(sock);
+}
+
+void client_loop(sock)
+int sock;
+{
+ int i = 0, size, pos;
+ char apubuf[STDINBUFSIZE+1];
+ fd_set ready;
+
+ do {
+ if (sock < 0 || QuitFlag)
+ return;
+ FD_ZERO(&ready);
+ FD_SET(sock, &ready);
+ FD_SET(0, &ready);
+#ifdef DOCURSES
+ if (termtype == CURSES_TERM)
+ move(LINES-1,i); refresh();
+#endif
+#ifdef DOTERMCAP
+ if (termtype == TERMCAP_TERM)
+ tcap_move (-1, i);
+#endif
+ if (select(32, (SELECT_FDSET_TYPE *)&ready, 0, 0, NULL) < 0) {
+/* perror("select"); */
+ continue;
+ }
+ if (FD_ISSET(sock, &ready)) {
+ if ((size = read(sock, apubuf, STDINBUFSIZE)) < 0)
+ perror("receiving stream packet");
+ if (size <= 0) {
+ close(sock);
+ return;
+ }
+ dopacket(&me, apubuf, size);
+ }
+#ifndef AUTOMATON
+ if (FD_ISSET(0, &ready)) {
+ if ((size = read(0, apubuf, STDINBUFSIZE)) < 0) {
+ putline("FATAL ERROR: End of stdin file !");
+ return;
+ }
+ for (pos = 0; pos < size; pos++) {
+ i=do_char(apubuf[pos]);
+#ifdef DOCURSES
+ if (termtype == CURSES_TERM)
+ move(LINES-1, i);
+#endif
+#ifdef DOTERMCAP
+ if (termtype == CURSES_TERM)
+ tcap_move(-1, i);
+#endif
+ }
+ }
+#endif /* AUTOMATON */
+ } while (1);
+}
diff --git a/irc/c_bsd_ext.h b/irc/c_bsd_ext.h
new file mode 100644
index 0000000..fdd3500
--- /dev/null
+++ b/irc/c_bsd_ext.h
@@ -0,0 +1,39 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/c_bsd_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in irc/c_bsd.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef C_BSD_C
+extern char c_bsd_id[];
+#endif /* C_BSD_C */
+
+/* External definitions for global functions.
+ */
+#ifndef C_BSD_C
+#define EXTERN extern
+#else /* C_BSD_C */
+#define EXTERN
+#endif /* C_BSD_C */
+EXTERN int client_init __P((char *host, int portnum, aClient *cptr));
+EXTERN void client_loop __P((int sock));
+#undef EXTERN
diff --git a/irc/c_conf.c b/irc/c_conf.c
new file mode 100644
index 0000000..ee980f2
--- /dev/null
+++ b/irc/c_conf.c
@@ -0,0 +1,95 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/c_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.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: c_conf.c,v 1.3 1999/02/21 00:33:45 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "c_defines.h"
+#define C_CONF_C
+#include "c_externs.h"
+#undef C_CONF_C
+
+initconf(host, passwd, myname, port)
+char *host, *passwd, *myname;
+int *port;
+{
+ FILE *fd;
+ char line[256], *tmp;
+
+ if ((fd = fopen(IRCDCONF_PATH, "r")) == NULL)
+ return /* (-1) */ ;
+ while (fgets(line,255,fd)) {
+ if (line[0] == '#' || line[0] == '\n' ||
+ line[0] == ' ' || line[0] == '\t')
+ continue;
+ switch (*getfield(line))
+ {
+ case 'C': /* Server where I should try to connect */
+ case 'c': /* in case of link failures */
+ case 'I': /* Just plain normal irc client trying */
+ case 'i': /* to connect me */
+ case 'N': /* Server where I should NOT try to */
+ case 'n': /* connect in case of link failures */
+ /* but which tries to connect ME */
+ case 'O': /* Operator. Line should contain at least */
+ case 'o': /* password and host where connection is */
+ /* allowed from */
+ case 'M': /* Me. Host field is name used for this host */
+ case 'm': /* and port number is the number of the port */
+ case 'a':
+ case 'A':
+ case 'k':
+ case 'K':
+ case 'q':
+ case 'Q':
+ case 'l':
+ case 'L':
+ case 'y':
+ case 'Y':
+ case 'h':
+ case 'H':
+ case 'p':
+ case 'P':
+ break;
+ case 'U': /* Uphost, ie. host where client reading */
+ case 'u': /* this should connect. */
+ if (!(tmp = getfield(NULL)))
+ break;
+ strncpyzt(host, tmp, HOSTLEN);
+ if (!(tmp = getfield(NULL)))
+ break;
+ strncpyzt(passwd, tmp, PASSWDLEN);
+ if (!(tmp = getfield(NULL)))
+ break;
+ strncpyzt(myname, tmp, HOSTLEN);
+ if (!(tmp = getfield(NULL)))
+ break;
+ if ((*port = atoi(tmp)) == 0)
+ debug(DEBUG_ERROR,
+ "Error in config file, bad port field");
+ break;
+ default:
+/* debug(DEBUG_ERROR, "Error in config file: %s", line); */
+ break;
+ }
+ }
+}
diff --git a/irc/c_conf_ext.h b/irc/c_conf_ext.h
new file mode 100644
index 0000000..a46e39b
--- /dev/null
+++ b/irc/c_conf_ext.h
@@ -0,0 +1,38 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/c_conf_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in irc/c_conf.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef C_CONF_C
+extern char conf_id[];
+#endif /* C_CONF_C */
+
+/* External definitions for global functions.
+ */
+#ifndef C_CONF_C
+#define EXTERN extern
+#else /* C_CONF_C */
+#define EXTERN
+#endif /* C_CONF_C */
+EXTERN initconf __P((char *host, char *passwd, char *myname, int *port));
+#undef EXTERN
diff --git a/irc/c_debug.c b/irc/c_debug.c
new file mode 100644
index 0000000..4cf9156
--- /dev/null
+++ b/irc/c_debug.c
@@ -0,0 +1,61 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/c_debug.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: c_debug.c,v 1.3 1998/05/12 16:55:49 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "c_defines.h"
+#define C_DEBUG_C
+#include "c_externs.h"
+#undef C_DEBUG_C
+
+struct stats ircst, *ircstp = &ircst;
+
+#ifdef DEBUGMODE
+#if ! USE_STDARG
+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;
+#else
+void debug(int level, char *form, ...)
+#endif
+{
+ if (debuglevel >= 0)
+ if (level <= debuglevel) {
+ char buf[512];
+#if ! USE_STDARG
+ (void)sprintf(buf, form,
+ p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
+#else
+ va_list va;
+ va_start(va, form);
+ (void)vsprintf(buf, form, va);
+ va_end(va);
+#endif
+ putline(buf);
+ }
+}
+#else /* do nothing */
+void debug()
+{
+}
+#endif
diff --git a/irc/c_debug_ext.h b/irc/c_debug_ext.h
new file mode 100644
index 0000000..bb7ef4a
--- /dev/null
+++ b/irc/c_debug_ext.h
@@ -0,0 +1,49 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/c_debug_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in irc/c_debug.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef C_DEBUG_C
+extern char debug_id[];
+extern struct stats ircst, *ircstp;
+#endif /* C_DEBUG_C */
+
+/* External definitions for global functions.
+ */
+#ifndef C_DEBUG_C
+#define EXTERN extern
+#else /* C_DEBUG_C */
+#define EXTERN
+#endif /* C_DEBUG_C */
+#ifdef DEBUGMODE
+#if ! USE_STDARG
+EXTERN void debug __P((int level, char *form, char *p1, char *p2, char *p3,
+ char *p4, char *p5, char *p6, char *p7, char *p8,
+ char *p9, char *p10));
+#else
+EXTERN void debug __P((int level, char *form, ...));
+#endif
+#else
+EXTERN void debug();
+#endif
+#undef EXTERN
diff --git a/irc/c_defines.h b/irc/c_defines.h
new file mode 100644
index 0000000..f0982a0
--- /dev/null
+++ b/irc/c_defines.h
@@ -0,0 +1,35 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/c_defines.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 includes all files defining constants, macros and types
+ definitions used by the IRC client.
+ */
+
+#include "config.h"
+#include "patchlevel.h"
+
+#include "common_def.h"
+#include "dbuf_def.h"
+#include "class_def.h"
+#include "struct_def.h"
+#include "msg_def.h"
+#include "numeric_def.h"
+#include "support_def.h"
+#include "irc_def.h"
+#include "help_def.h"
diff --git a/irc/c_externs.h b/irc/c_externs.h
new file mode 100644
index 0000000..269efc8
--- /dev/null
+++ b/irc/c_externs.h
@@ -0,0 +1,44 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/c_externs.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 includes all *_ext.h files containing external declarations
+ * for the IRC client.
+ */
+
+#include "bsd_ext.h"
+#include "c_bsd_ext.h"
+#include "c_conf_ext.h"
+#include "c_debug_ext.h"
+#include "c_msg_ext.h"
+#include "c_numeric_ext.h"
+#include "c_version_ext.h"
+#include "ctcp_ext.h"
+#include "dbuf_ext.h"
+#include "edit_ext.h"
+#include "help_ext.h"
+#include "ignore_ext.h"
+#include "irc_ext.h"
+#include "match_ext.h"
+#include "packet_ext.h"
+#include "parse_ext.h"
+#include "screen_ext.h"
+#include "send_ext.h"
+#include "str_ext.h"
+#include "support_ext.h"
+#include "swear_ext.h"
diff --git a/irc/c_msg.c b/irc/c_msg.c
new file mode 100644
index 0000000..b571b7d
--- /dev/null
+++ b/irc/c_msg.c
@@ -0,0 +1,407 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/c_msg.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: c_msg.c,v 1.3 1999/02/21 00:14:59 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "c_defines.h"
+#define C_MSG_C
+#include "c_externs.h"
+#undef C_MSG_C
+
+char mybuf[513];
+
+void m_die() {
+ exit(-1);
+}
+
+int m_mode(sptr, cptr, parc, parv)
+aClient *sptr, *cptr;
+int parc;
+char *parv[];
+{
+ strcpy(mybuf, "*** Mode change ");
+ while (parc--) {
+ strcat(mybuf, parv[0]);
+ strcat(mybuf, " ");
+ parv++;
+ }
+ putline(mybuf);
+ return 0;
+}
+
+int m_wall(sptr, cptr, parc, parv)
+aClient *sptr, *cptr;
+int parc;
+char *parv[];
+{
+ sprintf(mybuf, "*** #%s# %s", parv[0], parv[1]);
+ putline(mybuf);
+ return 0;
+}
+
+int m_wallops(sptr, cptr, parc, parv)
+aClient *sptr, *cptr;
+int parc;
+char *parv[];
+{
+ sprintf(mybuf, "*** =%s= %s %s", parv[0], parv[1],
+ BadPtr(parv[2]) ? "" : parv[2]);
+ putline(mybuf);
+ return 0;
+}
+
+int m_ping(sptr, cptr, parc, parv)
+aClient *sptr, *cptr;
+int parc;
+char *parv[];
+{
+ if (parv[2] && *parv[2])
+ sendto_one(client, "PONG %s@%s %s", client->user->username,
+ client->sockhost, parv[2]);
+ else
+ sendto_one(client, "PONG %s@%s", client->user->username, client->sockhost);
+ return 0;
+}
+
+int m_pong(sptr, cptr, parc, parv)
+aClient *sptr, *cptr;
+int parc;
+char *parv[];
+{
+ sprintf(mybuf, "*** Received PONG message: %s %s from %s",
+ parv[1], (parv[2]) ? parv[2] : "", parv[0]);
+ putline(mybuf);
+ return 0;
+}
+
+int m_nick(sptr, cptr, parc, parv)
+aClient *sptr, *cptr;
+int parc;
+char *parv[];
+{
+ sprintf(mybuf,"*** Change: %s is now known as %s", parv[0], parv[1]);
+ if (!mycmp(me.name, parv[0])) {
+ strcpy(me.name, parv[1]);
+ write_statusline();
+ }
+ putline(mybuf);
+#ifdef AUTOMATON
+ a_nick(parv[0], parv[1]);
+#endif
+ return 0;
+}
+
+void m_away(sptr, cptr, parc, parv)
+aClient *sptr, *cptr;
+int parc;
+char *parv[];
+{
+ sprintf(mybuf,"*** %s is away: \"%s\"",parv[0], parv[1]);
+ putline(mybuf);
+}
+
+int m_server(sptr, cptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+ sprintf(mybuf,"*** New server: %s", parv[1]);
+ putline(mybuf);
+ return 0;
+}
+
+int m_topic(sptr, cptr, parc, parv)
+aClient *sptr, *cptr;
+int parc;
+char *parv[];
+{
+ sprintf(mybuf, "*** %s changed the topic on %s to: %s",
+ parv[0], parv[1], parv[2]);
+ putline(mybuf);
+ return 0;
+}
+
+int m_join(sptr, cptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+ char *tmp = index(parv[1], '\007'); /* Find o/v mode in 2.9 */
+
+ if (tmp)
+ *tmp = ' ';
+ sprintf(mybuf,"*** %s <%s> joined channel %s",
+ parv[0], userhost, parv[1]);
+ putline(mybuf);
+ return 0;
+}
+
+int m_part(sptr, cptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+ sprintf(mybuf,"*** Change: %s has left channel %s (%s)",
+ parv[0], parv[1], BadPtr(parv[2]) ? parv[1] : parv[2]);
+ putline(mybuf);
+ return 0;
+}
+
+void m_version(sptr, cptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+ sprintf(mybuf,"*** Version: %s", parv[1]);
+ putline(mybuf);
+}
+
+void m_bye()
+{
+#if defined(DOCURSES) && !defined(AUTOMATON) && !defined(VMSP)
+ echo();
+ nocrmode();
+ clear();
+ refresh();
+#endif
+ exit(-1);
+}
+
+int m_quit(sptr, cptr, parc, parv)
+aClient *sptr, *cptr;
+int parc;
+char *parv[];
+{
+ sprintf(mybuf,"*** Signoff: %s (%s)", parv[0], parv[1]);
+ putline(mybuf);
+#ifdef AUTOMATON
+ a_quit(sender);
+#endif
+ return 0;
+}
+
+int m_kill(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+ sprintf(mybuf,"*** Kill: %s (%s)", parv[0], parv[2]);
+ putline(mybuf);
+ return 0;
+}
+
+void m_info(sptr, cptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+ sprintf(mybuf,"*** Info: %s", parv[1]);
+ putline(mybuf);
+}
+
+void m_squit(sptr, cptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+ sprintf(mybuf,"*** Server %s has died. Snif.", parv[1]);
+ putline(mybuf);
+}
+
+void m_newwhoreply(channel, username, host, nickname, away, realname)
+char *channel, *username, *host, *nickname, *away, *realname;
+{
+ /* ...dirty hack, just assume all parameters present.. --msa */
+
+ if (*away == 'S')
+ sprintf(mybuf, " %-13s %s %-42s %s",
+ "Nickname", "Chan", "Name", "<User@Host>");
+ else {
+ int i;
+ char uh[USERLEN + HOSTLEN + 1];
+ if (!realname)
+ realname = "";
+ if (!username)
+ username = "";
+ i = 50-strlen(realname)-strlen(username);
+
+ if (channel[0] == '*')
+ channel = "";
+
+ if (strlen(host) > (size_t) i) /* kludge --argv */
+ host += strlen(host) - (size_t) i;
+
+ sprintf(uh, "%s@%s", username, host);
+
+ sprintf(mybuf, "%c %s%s %*s %s %*s",
+ away[0], nickname, away+1,
+ (int)(21-strlen(nickname)-strlen(away)), channel,
+ realname,
+ (int)(53-strlen(realname)), uh);
+ }
+}
+
+void m_newnamreply(sptr, cptr, parc, parv)
+aClient *sptr, *cptr;
+int parc;
+char *parv[];
+{
+ if (parv[2]) {
+ switch (parv[2][0]) {
+ case '*':
+ sprintf(mybuf,"Prv: %-3s %s", parv[3], parv[4]);
+ break;
+ case '=':
+ sprintf(mybuf,"Pub: %-3s %s", parv[3], parv[4]);
+ break;
+ case '@':
+ sprintf(mybuf,"Sec: %-3s %s", parv[3], parv[4]);
+ break;
+ default:
+ sprintf(mybuf,"???: %s %s %s", parv[3], parv[4], parv[5]);
+ break;
+ }
+ } else
+ sprintf(mybuf, "*** Internal Error: namreply");
+}
+
+void m_linreply(sptr, cptr, parc, parv)
+aClient *sptr, *cptr;
+int parc;
+char *parv[];
+{
+ sprintf(mybuf,"*** Server: %s (%s) %s", parv[2], parv[3], parv[4]);
+}
+
+int m_private(sptr, cptr, parc, parv)
+aClient *sptr, *cptr;
+int parc;
+char *parv[];
+{
+ anIgnore *iptr;
+
+ iptr = find_ignore(parv[0], (anIgnore *)NULL, userhost);
+ if ((iptr != (anIgnore *)NULL) &&
+ ((iptr->flags == IGNORE_TOTAL) ||
+ (IsChannelName(parv[1]) && (iptr->flags & IGNORE_PUBLIC)) ||
+ (!IsChannelName(parv[1]) && (iptr->flags & IGNORE_PRIVATE))))
+ return 0;
+ check_ctcp(sptr, cptr, parc, parv);
+
+ if (parv[0] && *parv[0]) {
+#ifdef AUTOMATON
+ a_privmsg(sender, parv[2]);
+#else
+ if (((*parv[1] >= '0') && (*parv[1] <= '9')) ||
+ (*parv[1] == '-') || (*parv[1] == '+') ||
+ IsChannelName(parv[1]) || (*parv[1] == '$')) {
+ sprintf(mybuf,"<%s:%s> %s", parv[0], parv[1], parv[2]);
+ } else {
+ sprintf(mybuf,"*%s* %s", parv[0], parv[2]);
+ last_to_me(parv[0]);
+ }
+ putline(mybuf);
+#endif
+ } else
+ putline(parv[2]); /* parv[2] and no parv[0] ?! - avalon */
+ return 0;
+}
+
+
+int m_kick(sptr, cptr, parc, parv)
+aClient *sptr, *cptr;
+int parc;
+char *parv[];
+{
+ sprintf(mybuf,"*** %s kicked %s off channel %s (%s)",
+ (parv[0]) ? parv[0] : "*Unknown*",
+ (parv[2]) ? parv[2] : "*Unknown*",
+ (parv[1]) ? parv[1] : "*Unknown*",
+ parv[3]);
+ if (!mycmp(me.name, parv[2])) {
+ free(querychannel);
+ querychannel = (char *)malloc(strlen(me.name) + 1);
+ strcpy(querychannel, me.name); /* Kludge? */
+ }
+ putline(mybuf);
+ return 0;
+}
+
+int m_notice(sptr, cptr, parc, parv)
+aClient *sptr, *cptr;
+int parc;
+char *parv[];
+{
+ anIgnore *iptr;
+
+ iptr = find_ignore(parv[0], (anIgnore *)NULL, userhost);
+ if ((iptr != (anIgnore *)NULL) &&
+ ((iptr->flags == IGNORE_TOTAL) ||
+ (IsChannelName(parv[1]) && (iptr->flags & IGNORE_PUBLIC)) ||
+ (!IsChannelName(parv[1]) && (iptr->flags & IGNORE_PRIVATE))))
+ return 0;
+
+ if (parv[0] && parv[0][0] && parv[1]) {
+ if ((*parv[1] >= '0' && *parv[1] <= '9') ||
+ *parv[1] == '-' || IsChannelName(parv[1]) ||
+ *parv[1] == '$' || *parv[1] == '+')
+ sprintf(mybuf,"(%s:%s) %s",parv[0],parv[1],parv[2]);
+ else if (index(userhost, '@')) /* user */
+ sprintf(mybuf, "-%s- %s", parv[0], parv[2]);
+ else /* service */
+ sprintf(mybuf, "-%s@%s- %s",
+ parv[0], userhost, parv[2]);
+ putline(mybuf);
+ } else
+ putline(parv[2]);
+ return 0;
+}
+
+int m_invite(sptr, cptr, parc, parv)
+aClient *sptr, *cptr;
+int parc;
+char *parv[];
+{
+ anIgnore *iptr;
+ if ((iptr = find_ignore(parv[0], (anIgnore *)NULL, userhost)) &&
+ (iptr->flags & IGNORE_PRIVATE))
+ return 0;
+#ifdef AUTOMATON
+ a_invite(parv[0], parv[2]);
+#else
+ sprintf(mybuf,"*** %s Invites you to channel %s", parv[0], parv[2]);
+ putline(mybuf);
+#endif
+ return 0;
+}
+
+int m_error(sptr, cptr, parc, parv)
+aClient *sptr, *cptr;
+int parc;
+char *parv[];
+{
+ sprintf(mybuf,"*** Error: %s %s", parv[1], (parv[2]) ? parv[2] : "");
+ putline(mybuf);
+ return 0;
+}
+
diff --git a/irc/c_msg_ext.h b/irc/c_msg_ext.h
new file mode 100644
index 0000000..8c5949d
--- /dev/null
+++ b/irc/c_msg_ext.h
@@ -0,0 +1,76 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/c_msg_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in irc/c_msg.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef C_MSG_C
+#ifndef lint
+extern char c_msg_id[];
+#endif
+extern char mybuf[];
+#endif /* C_MSG_C */
+
+/* External definitions for global functions.
+ */
+#ifndef C_MSG_C
+#define EXTERN extern
+#else /* C_MSG_C */
+#define EXTERN
+#endif /* C_MSG_C */
+EXTERN void m_die();
+EXTERN int m_mode __P((aClient *sptr, aClient *cptr, int parc, char *parv[]));
+EXTERN int m_wall __P((aClient *sptr, aClient *cptr, int parc, char *parv[]));
+EXTERN int m_wallops __P((aClient *sptr, aClient *cptr, int parc,
+ char *parv[]));
+EXTERN int m_ping __P((aClient *sptr, aClient *cptr, int parc, char *parv[]));
+EXTERN int m_pong __P((aClient *sptr, aClient *cptr, int parc, char *parv[]));
+EXTERN int m_nick __P((aClient *sptr, aClient *cptr, int parc, char *parv[]));
+EXTERN void m_away __P((aClient *sptr, aClient *cptr, int parc, char *parv[]));
+EXTERN int m_server __P((aClient *sptr, aClient *cptr, int parc,
+ char *parv[]));
+EXTERN int m_topic __P((aClient *sptr, aClient *cptr, int parc, char *parv[]));
+EXTERN int m_join __P((aClient *sptr, aClient *cptr, int parc, char *parv[]));
+EXTERN int m_part __P((aClient *sptr, aClient *cptr, int parc, char *parv[]));
+EXTERN void m_version __P((aClient *sptr, aClient *cptr, int parc,
+ char *parv[]));
+EXTERN void m_bye();
+EXTERN int m_quit __P((aClient *sptr, aClient *cptr, int parc, char *parv[]));
+EXTERN int m_kill __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN void m_info __P((aClient *sptr, aClient *cptr, int parc, char *parv[]));
+EXTERN void m_squit __P((aClient *sptr, aClient *cptr, int parc,
+ char *parv[]));
+EXTERN void m_newwhoreply __P((char *channel, char *username, char *host,
+ char *nickname, char *away, char *realname));
+EXTERN void m_newnamreply __P((aClient *sptr, aClient *cptr, int parc,
+ char *parv[]));
+EXTERN void m_linreply __P((aClient *sptr, aClient *cptr, int parc,
+ char *parv[]));
+EXTERN int m_private __P((aClient *sptr, aClient *cptr, int parc,
+ char *parv[]));
+EXTERN int m_kick __P((aClient *sptr, aClient *cptr, int parc, char *parv[]));
+EXTERN int m_notice __P((aClient *sptr, aClient *cptr, int parc,
+ char *parv[]));
+EXTERN int m_invite __P((aClient *sptr, aClient *cptr, int parc,
+ char *parv[]));
+EXTERN int m_error __P((aClient *sptr, aClient *cptr, int parc, char *parv[]));
+#undef EXTERN
diff --git a/irc/c_numeric.c b/irc/c_numeric.c
new file mode 100644
index 0000000..f124a05
--- /dev/null
+++ b/irc/c_numeric.c
@@ -0,0 +1,413 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/c_numeric.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.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: c_numeric.c,v 1.3 1997/09/03 17:45:35 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "c_defines.h"
+#define C_NUMERIC_C
+#include "c_externs.h"
+#undef C_NUMERIC_C
+
+/*
+** 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).
+*/
+
+int do_numeric(numeric, cptr, sptr, parc, parv)
+int numeric;
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+ {
+ char *tmp;
+ int i;
+ time_t l; /* ctime(&l) on STATS L */
+
+ /* ...make sure undefined parameters point to empty string */
+ for (i = parc; i < MAXPARA; parv[i++] = "");
+
+ switch (numeric)
+ {
+ case ERR_NOSUCHNICK:
+ sprintf(mybuf, "*** Error: %s: %s (%s)",
+ parv[0], parv[3], parv[2]);
+ sendto_one(&me, "WHOWAS %s 1", parv[2]);
+ break;
+ case ERR_WASNOSUCHNICK:
+ mybuf[0] = '\0';
+ break;
+ case ERR_NOSUCHSERVER:
+ sprintf(mybuf, "*** Error: %s: No such server (%s)",
+ parv[0], parv[2]);
+ break;
+ case ERR_NOSUCHCHANNEL:
+ sprintf(mybuf, "*** Error: %s: No such channel (%s)",
+ parv[0], parv[2]);
+ break;
+ case ERR_NOSUCHSERVICE:
+ sprintf(mybuf, "*** Error: %s: No such service (%s)",
+ parv[0], parv[2]);
+ break;
+ case ERR_TOOMANYCHANNELS:
+ sprintf(mybuf, "*** Error: %s: You have join max. channels",
+ parv[0]);
+ break;
+ case ERR_TOOMANYTARGETS:
+ sprintf(mybuf, "*** Error: %s: Too many targets given",
+ parv[0]);
+ break;
+ case ERR_NORECIPIENT:
+ sprintf(mybuf, "*** Error: %s: Message had no recipient",
+ parv[0]);
+ break;
+ case ERR_NOTEXTTOSEND:
+ sprintf(mybuf, "*** Error: %s: Empty messages cannot be sent",
+ parv[0]);
+ break;
+ case ERR_NOTOPLEVEL:
+ sprintf(mybuf, "*** Error: %s: No toplevel domainname given",
+ parv[0]);
+ break;
+ case ERR_WILDTOPLEVEL:
+ sprintf(mybuf, "*** Error: %s: Wildcard in toplevel name",
+ parv[0]);
+ break;
+ case ERR_UNKNOWNCOMMAND:
+ sprintf(mybuf, "*** Error: %s: Unknown command (%s)",
+ parv[0],parv[2]);
+ break;
+ case ERR_NONICKNAMEGIVEN:
+ sprintf(mybuf, "*** Error: %s: No nickname given", parv[0]);
+ break;
+ case ERR_ERRONEUSNICKNAME:
+ sprintf(mybuf,
+ "*** Error: %s: Some special characters cannot %s",
+ parv[0], "be used in nicknames");
+ break;
+ case ERR_NICKNAMEINUSE:
+ sprintf(mybuf,
+ "*** Error: %s: Nickname %s is already in use. %s",
+ parv[0], parv[2], "Please choose another.");
+ break;
+ case ERR_SERVICENAMEINUSE:
+ sprintf(mybuf, "*** Error: %s: Service %s is already in use.",
+ parv[0], parv[2]);
+ break;
+ case ERR_SERVICECONFUSED:
+ sprintf(mybuf, "Error: %s: Your service name is confused",
+ parv[0]);
+ break;
+ case ERR_USERNOTINCHANNEL:
+ sprintf(mybuf, "*** Error: %s: %s", parv[0],
+ (parv[2][0]) ? parv[2] :
+ "You have not joined any channel");
+ break;
+ case ERR_NOTONCHANNEL:
+ sprintf(mybuf, "*** Error: %s: %s %s",
+ parv[0], parv[3], parv[2]);
+ break;
+ case ERR_INVITEONLYCHAN:
+ sprintf(mybuf, "*** Error: %s: %s", parv[0],
+ "Magic locks open only with an invitation key");
+ break;
+ case ERR_BANNEDFROMCHAN:
+ sprintf(mybuf,"*** Error: %s: %s %s",
+ parv[0], "You are banned from the channel", parv[2]);
+ break;
+ case ERR_NOTREGISTERED:
+ sprintf(mybuf, "*** Error: %s: %s", parv[0],
+ (parv[2][0]) ? parv[2] :
+ "You have not registered yourself yet");
+ break;
+ case ERR_NEEDMOREPARAMS:
+ sprintf(mybuf, "*** Error: %s: %s: %s", parv[0], parv[2],
+ (parv[3][0]) ? parv[3] : "Not enough parameters");
+ break;
+ case ERR_ALREADYREGISTRED:
+ sprintf(mybuf, "*** Error: %s: %s", parv[0],
+ (parv[2][0]) ? parv[2] : "Identity problems, eh ?");
+ break;
+ case ERR_NOPERMFORHOST:
+ sprintf(mybuf, "*** Error: %s: %s", parv[0],
+ (parv[2][0]) ? parv[2] :
+ "Your host isn't among the privileged");
+ break;
+ case ERR_PASSWDMISMATCH:
+ sprintf(mybuf, "*** Error: %s: %s", parv[0],
+ (parv[2][0]) ? parv[2] : "Incorrect password");
+ break;
+ case ERR_YOUREBANNEDCREEP:
+ sprintf(mybuf, "*** %s: %s", parv[0],
+ (parv[2][0]) ? parv[2] :
+ "You're banned from irc...");
+ break;
+ case ERR_YOUWILLBEBANNED:
+ sprintf(mybuf, "*** Warning: You will be banned in %d minutes",
+ atoi(parv[2]));
+ break;
+ case ERR_CHANNELISFULL:
+ sprintf(mybuf, "*** Error: %s: Channel %s is full",
+ parv[0], parv[2]);
+ break;
+ case ERR_CANNOTSENDTOCHAN:
+ sprintf(mybuf, "*** Error: Sending to channel is %s",
+ "forbidden from heathens");
+ break;
+ case ERR_NOPRIVILEGES:
+ sprintf(mybuf, "*** Error: %s: %s", parv[0],
+ (parv[2][0]) ? parv[2] :
+ "Only few and chosen are granted privileges. You're not one.");
+ break;
+ case ERR_NOOPERHOST:
+ sprintf(mybuf, "*** Error: %s: %s", parv[0],
+ (parv[2][0]) ? parv[2] :
+ "Only few of mere mortals may try to enter the twilight zone..");
+ break;
+ case ERR_UMODEUNKNOWNFLAG:
+ sprintf(mybuf, "*** Error: %s: Unknown User Mode Flag",
+ parv[0]);
+ break;
+ case ERR_USERSDONTMATCH:
+ sprintf(mybuf, "*** Error: %s: Can only change your own mode",
+ parv[0]);
+ break;
+ case RPL_AWAY:
+ sprintf(mybuf, "*** %s: %s is away: %s", parv[0],
+ (parv[2][0]) ? parv[2] : "*Unknown*",
+ (parv[3][0]) ? parv[3] : "*No message (strange)*");
+ break;
+ case RPL_USERHOST:
+ sprintf(mybuf, "*** USERHOST reply: %s", parv[2]);
+ break;
+ case RPL_ISON:
+ sprintf(mybuf, "*** ISON reply: %s", parv[2]);
+ break;
+ case RPL_WHOISUSER:
+ sprintf(mybuf, "*** %s is %s@%s (%s)",
+ parv[2], parv[3], parv[4], parv[6]);
+ break;
+ case RPL_WHOWASUSER:
+ sprintf(mybuf, "*** %s was %s@%s (%s)",
+ parv[2], parv[3], parv[4], parv[6]);
+ break;
+ case RPL_WHOISSERVER:
+ if (parc == 4)
+ sprintf(mybuf, "*** On irc via server %s (%s)",
+ parv[2], parv[3]);
+ else
+ sprintf(mybuf, "*** On irc via server %s (%s)",
+ parv[3], parv[4]);
+ break;
+ case RPL_WHOISOPERATOR:
+ sprintf(mybuf, "*** %s has a connection to the twilight zone",
+ parv[2]);
+ break;
+ case RPL_WHOISCHANOP:
+ sprintf(mybuf, "*** %s has been touched by magic forces",
+ parv[2]);
+ break;
+ case RPL_WHOISIDLE:
+ sprintf(mybuf, "*** %s %s %s",
+ parv[2], parv[3], parv[4]);
+ break;
+ case RPL_WHOISCHANNELS:
+ sprintf(mybuf, "*** On Channels: %s", parv[3]);
+ break;
+ case RPL_LISTSTART:
+ sprintf(mybuf, "*** Chn Users Name");
+ break;
+ case RPL_LIST:
+ sprintf(mybuf, "*** %3s %5s %s",
+ (parv[2][0] == '*') ? "Prv" : parv[2],
+ parv[3], parv[4]);
+ break;
+ case RPL_LISTEND:
+ mybuf[0] = '\0';
+ break;
+ case RPL_NOTOPIC:
+ sprintf(mybuf, "*** %s: No Topic is set", parv[0]);
+ break;
+ case RPL_TOPIC:
+ sprintf(mybuf, "*** %s: Topic on %s is: %s", parv[0], parv[2],
+ parv[3]);
+ break;
+ case RPL_INVITING:
+ sprintf(mybuf, "*** %s: Inviting user %s into channel %s",
+ parv[0], parv[2], parv[3]);
+ break;
+ case RPL_VERSION:
+ /* sprintf(mybuf, "*** %s: Server %s runs ircd %s (%s)", parv[0], */
+ sprintf(mybuf, "*** Server %s runs ircd %s (%s)",
+ parv[3], parv[2], parv[4]);
+ break;
+ case RPL_KILLDONE:
+ sprintf(mybuf, "*** %s: May %s rest in peace",
+ parv[0], parv[2]);
+ break;
+ case RPL_INFO:
+ sprintf(mybuf, "*** %s: Info: %s", parv[0], parv[2]);
+ break;
+#if 1
+ case RPL_MOTD:
+ sprintf(mybuf, "*** %s: Motd: %s", parv[0], parv[2]);
+ break;
+#endif /* 0 Looks better this way! -Vesa */
+ case RPL_YOUREOPER:
+ sprintf(mybuf, "*** %s: %s", parv[0], (parv[2][0] == '\0') ?
+ "You have operator privileges now. Be nice to mere mortal souls" :
+ parv[2]);
+ break;
+ case RPL_NOTOPERANYMORE:
+ sprintf(mybuf, "*** %s: You are No Longer Have Operator %s",
+ parv[0], "Privileges");
+ break;
+ case RPL_REHASHING:
+ sprintf(mybuf, "*** %s: %s", parv[0], (parv[2][0] == '\0') ?
+ "Rereading configuration file.." : parv[2]);
+ break;
+ case RPL_MYPORTIS:
+ sprintf(mybuf, "*** %s: %s %s", parv[0], parv[2], parv[1]);
+ break;
+ case RPL_TIME:
+ sprintf(mybuf, "*** Time on host %s is %s",
+ parv[2], parv[3]);
+ break;
+ case RPL_CHANNELMODEIS:
+ sprintf(mybuf, "*** Mode is %s %s %s",
+ parv[2], parv[3], parv[4]);
+ break;
+ case RPL_LINKS:
+ m_linreply(cptr, sptr, parc, parv);
+ break;
+ case RPL_WHOREPLY:
+ m_newwhoreply(parv[2],parv[3],parv[4],parv[6],parv[7],parv[8]);
+ break;
+ case RPL_NAMREPLY:
+ m_newnamreply(cptr, sptr, parc, parv);
+ break;
+ case RPL_BANLIST:
+ sprintf(mybuf, "*** %s is banned on %s",
+ parv[3], parv[2]);
+ break;
+ case RPL_TRACELINK:
+ sprintf(mybuf,"%s<%s> Link %s> %s (%s up %s) bQ:%s fQ:%s",
+ parv[0], parv[3], parv[6], parv[4], parv[5], parv[7],
+ parv[8], parv[9]);
+ break;
+ case RPL_TRACESERVER:
+ if (parc <= 5)
+ sprintf(mybuf,"*** %s Class: %s %s: %s",
+ parv[0], parv[3], parv[2], parv[4]);
+ else
+ sprintf(mybuf,"*** %s %s Cl:%s %s/%s %s %s %s",
+ parv[0], parv[2], parv[3], parv[4],
+ parv[5], parv[6], parv[7], parv[8]);
+ break;
+ case RPL_TRACECONNECTING:
+ case RPL_TRACEHANDSHAKE:
+ case RPL_TRACEUNKNOWN:
+ case RPL_TRACEOPERATOR:
+ case RPL_TRACEUSER:
+ case RPL_TRACESERVICE:
+ case RPL_TRACENEWTYPE:
+ sprintf(mybuf,"*** %s %s Class: %s %s",
+ parv[0], parv[2], parv[3], parv[4]);
+ break;
+ case RPL_TRACELOG:
+ sprintf(mybuf,"*** %s File: %s level:%s ",
+ parv[0], parv[3], parv[4]);
+ break;
+ case RPL_TRACECLASS:
+ sprintf(mybuf,"*** %s Class: %s Links: %s",
+ parv[0], parv[3], parv[4]);
+ break;
+ case RPL_STATSLINKINFO:
+ l = time(NULL) - atol(parv[8]); /* count startup time */
+ tmp = (char *) ctime(&l);
+ *((char *) index(tmp, '\n')) = (char) '\0'; /* remove '\n' */
+ sprintf(mybuf,"*** %s: %s Q:%s sM:%s sB:%s rM:%s rB:%s D:%s",
+ parv[0], parv[2], parv[3], parv[4], parv[5],
+ parv[6], parv[7], tmp);
+ break;
+ case RPL_STATSCOMMANDS:
+ sprintf(mybuf, "*** %s: %s has been used %s times (%s bytes)",
+ parv[0], parv[2], parv[3], parv[4]);
+ break;
+ case RPL_STATSYLINE:
+ sprintf(mybuf, "*** %s: Cl:%s Pf:%s Cf:%s Max:%s Sq:%s",
+ parv[0], parv[3], parv[4],
+ parv[5], parv[6], parv[7]);
+ break;
+ case RPL_UMODEIS:
+ sprintf(mybuf, "*** %s: Mode for user %s is %s",
+ parv[0], parv[1], parv[2]);
+ break;
+#ifdef HIDE_NUMERICS
+ case RPL_STATSCLINE:
+ case RPL_STATSNLINE:
+ case RPL_STATSILINE:
+ sprintf(mybuf, "*** %s: %s:%s:*:%s:%s:%s",
+ parv[0], parv[2], parv[3], parv[5], parv[6], parv[7]);
+ break;
+ case RPL_STATSKLINE:
+ case RPL_STATSQLINE:
+ sprintf(mybuf, "*** %s: %s:%s:%s:%s:%s:%s",
+ parv[0], parv[2], parv[3], parv[4],
+ parv[5], parv[6], parv[7]);
+ break;
+ case RPL_SERVICEINFO:
+ sprintf(mybuf, "*** %s: Info For Service %s: %s",
+ parv[0], parv[3], parv[4]);
+ break;
+ case RPL_ENDOFWHO:
+ case RPL_ENDOFWHOIS:
+ case RPL_ENDOFWHOWAS:
+ case RPL_ENDOFINFO:
+ case RPL_ENDOFMOTD:
+ case RPL_ENDOFUSERS:
+ case RPL_ENDOFLINKS:
+ case RPL_ENDOFNAMES:
+ case RPL_ENDOFSTATS:
+ case RPL_ENDOFBANLIST:
+ case RPL_ENDOFSERVICES:
+ mybuf[0] = '\0';
+ break;
+#endif /* !HIDE_NUMERICS */
+ case RPL_WELCOME:
+ strcpy(me.name, parv[1]);
+ write_statusline();
+ default:
+ sprintf(mybuf, "%03d %s %s %s %s %s %s %s %s %s",
+ numeric, parv[0], parv[2],
+ parv[3], parv[4], parv[5], parv[6], parv[7],
+ parv[8], parv[9]);
+ break;
+ }
+ if (mybuf[0])
+ putline(mybuf);
+ return 0;
+}
diff --git a/irc/c_numeric_ext.h b/irc/c_numeric_ext.h
new file mode 100644
index 0000000..087d058
--- /dev/null
+++ b/irc/c_numeric_ext.h
@@ -0,0 +1,39 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/c_numeric_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in irc/c_numeric.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef C_NUMERIC_C
+extern char c_numeric_id[];
+#endif /* C_NUMERIC_C */
+
+/* External definitions for global functions.
+ */
+#ifndef C_NUMERIC_C
+#define EXTERN extern
+#else /* C_NUMERIC_C */
+#define EXTERN
+#endif /* C_NUMERIC_C */
+EXTERN int do_numeric __P((int numeric, aClient *cptr, aClient *sptr, int parc,
+ char *parv[]));
+#undef EXTERN
diff --git a/irc/c_version.c b/irc/c_version.c
new file mode 100644
index 0000000..2060dce
--- /dev/null
+++ b/irc/c_version.c
@@ -0,0 +1,46 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/c_version.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.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: c_version.c,v 1.3 1998/12/13 00:02:35 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "c_defines.h"
+#define C_VERSION_C
+#include "c_externs.h"
+#undef C_VERSION_C
+
+char *intro = "Internet Relay Chat v%s";
+char *version;
+char *infotext[] =
+ {
+ "Original code written by Jarkko Oikarinen <jto@tolsun.oulu.fi>",
+ "Copyright 1988,1989,1990 University of Oulu, Computing Center",
+ " and Jarkko Oikarinen",
+ 0,
+ };
+
+char *HEADEROLD =
+"*Internet Relay Chat* Type /help to get help * Client v%s * ";
+
+char *IRCHEADER =
+" *IRC Client v%s* %10.10s on %10.10s */help for help* ";
+
diff --git a/irc/c_version_ext.h b/irc/c_version_ext.h
new file mode 100644
index 0000000..34b5d6d
--- /dev/null
+++ b/irc/c_version_ext.h
@@ -0,0 +1,32 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/c_version_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in irc/c_version.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef C_VERSION_C
+extern char *intro;
+extern char *version;
+extern char *infotext[];
+extern char *HEADEROLD;
+extern char *IRCHEADER;
+#endif /* C_VERSION_C */
diff --git a/irc/ctcp.c b/irc/ctcp.c
new file mode 100644
index 0000000..5c05a3d
--- /dev/null
+++ b/irc/ctcp.c
@@ -0,0 +1,50 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/c_bsd.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: ctcp.c,v 1.2 1997/09/03 17:45:36 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "c_defines.h"
+#define CTCP_C
+#include "c_externs.h"
+#undef CTCP_C
+
+#define CTCP_CHAR 0x1
+
+void check_ctcp(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+ char *front = NULL, *back = NULL;
+
+ if (parc < 3)
+ return;
+
+ if (!(front = index(parv[2], CTCP_CHAR)))
+ return;
+ if (!(back = index(++front, CTCP_CHAR)))
+ return;
+ *back = '\0';
+ if (!strcmp(front, "VERSION"))
+ sendto_one(sptr, "NOTICE %s :%cVERSION %s%c", parv[0],
+ CTCP_CHAR, version, CTCP_CHAR);
+ *back = CTCP_CHAR;
+}
diff --git a/irc/ctcp_ext.h b/irc/ctcp_ext.h
new file mode 100644
index 0000000..e5a8fc8
--- /dev/null
+++ b/irc/ctcp_ext.h
@@ -0,0 +1,33 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/ctcp_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in irc/ctcp.c.
+ */
+
+/* External definitions for global functions.
+ */
+#ifndef CTCP_C
+#define EXTERN extern
+#else /* CTCP_C */
+#define EXTERN
+#endif /* CTCP_C */
+EXTERN void check_ctcp __P((aClient *cptr, aClient *sptr, int parc,
+ char *parv[]));
+#undef EXTERN
diff --git a/irc/edit.c b/irc/edit.c
new file mode 100644
index 0000000..3abe487
--- /dev/null
+++ b/irc/edit.c
@@ -0,0 +1,411 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/edit.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: edit.c,v 1.2 1997/09/03 17:45:37 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "c_defines.h"
+#define EDIT_C
+#include "c_externs.h"
+#undef EDIT_C
+
+#define FROM_START 0
+#define FROM_END 1
+#define RELATIVE 2
+
+static int esc=0;
+static int literal=0;
+
+int do_char(ch)
+char ch;
+{
+ static int first_time=0;
+
+ if (!first_time) {
+ toggle_ins();
+ toggle_ins();
+ first_time=1;
+#ifdef DOCURSES
+ if (termtype == CURSES_TERM)
+ refresh();
+#endif
+ }
+ if (esc == 1) {
+ do_after_esc(ch);
+ return tulosta_viimeinen_rivi();
+ }
+ switch (ch)
+ {
+ case '\000': /* NULL */
+ break;
+ case '\001': /* ^A */
+ bol(); /* beginning of line */
+ break;
+ case '\002': /* ^B */
+ back_ch(); /* backward char */
+ break;
+ case '\003': /* ^C */
+ rev_line(); /* reverse line */
+ break;
+ case '\004': /* ^D */
+ del_ch_right(); /* delete char from right */
+ break;
+ case '\005': /* ^E */
+ eol(); /* end of line */
+ break;
+ case '\006': /* ^F */
+ forw_ch(); /* forward char */
+ break;
+ case '\007': /* ^G */
+ add_ch(ch); /* bell */
+ break;
+ case '\010': /* ^H */
+ del_ch_left(); /* delete char to left */
+ break;
+ case '\011': /* TAB */
+ toggle_ins(); /* toggle insert mode */
+ break;
+ case '\012': /* ^J */
+ send_this_line(); /* send this line */
+ break;
+ case '\013': /* ^K */
+ kill_eol(); /* kill to end of line */
+ break;
+ case '\014': /* ^L */
+ refresh_screen(); /* refresh screen */
+ write_statusline();
+ break;
+ case '\015': /* ^M */
+ send_this_line(); /* send this line */
+ break;
+ case '\016': /* ^N */
+ next_in_history(); /* next in history */
+ break;
+ case '\017': /* ^O */
+ break;
+ case '\020': /* ^P */
+ previous_in_history(); /* previous in history */
+ break;
+ case '\021': /* ^Q */
+ break;
+ case '\022': /* ^R */
+ case '\023': /* ^S */
+ case '\024': /* ^T */
+ break;
+ case '\025': /* ^U */
+ kill_whole_line(); /* kill whole line */
+ break;
+ case '\026': /* ^V */
+ literal_next(); /* literal next */
+ break;
+ case '\027': /* ^W */
+ del_word_left(); /* delete word left */
+ break;
+ case '\030': /* ^X */
+ break;
+ case '\031': /* ^Y */
+ yank(); /* yank */
+ break;
+ case '\032': /* ^Z */
+ suspend_irc(0); /* suspend irc */
+ break;
+ case '\033': /* ESC */
+ got_esc();
+ break;
+ case '\177': /* DEL */
+ del_ch_left(); /* delete char to left */
+ break;
+ default:
+ add_ch(ch);
+ break;
+ }
+ return tulosta_viimeinen_rivi();
+}
+
+void bol()
+{
+ set_position(0, FROM_START);
+}
+
+void eol()
+{
+ set_position(0, FROM_END);
+ set_position(1, RELATIVE);
+}
+
+void back_ch()
+{
+ set_position(-1, RELATIVE);
+}
+
+void forw_ch()
+{
+ set_position(1, RELATIVE);
+}
+
+void rev_line()
+{
+ int i1, i2, i3, i4;
+
+ i4 = get_position();
+ set_position(0, FROM_START);
+ i1 = get_position();
+ set_position(0, FROM_END);
+ i1 = get_position()-i1;
+ set_position(i4, FROM_START);
+
+ for (i2 = 0; i2 > i1/2; i2++) {
+ i3 = get_char(i2);
+ set_char(i2, get_char(i1-i2-1));
+ set_char(i1-i2-1, i3);
+ }
+}
+
+void del_ch_right()
+{
+ int i1, i2, i3;
+
+ i1 = get_position();
+
+ if (!get_char(i1))
+ return; /* last char in line */
+ set_position(0, FROM_END);
+ i2 = get_position();
+ for (i3 = i1; i3 < i2; i3++)
+ set_char(i3, get_char(i3+1));
+ set_char(i3, 0);
+ set_position(i1, FROM_START);
+}
+
+void del_ch_left()
+{
+ int i1, i2, i3;
+
+ i1 = get_position();
+
+ if (!i1)
+ return; /* first pos in line */
+ set_position(0, FROM_END);
+ i2 = get_position();
+ for (i3 = i1-1; i3 < i2; i3++)
+ set_char(i3, get_char(i3+1));
+ set_char(i3, 0);
+ set_position(i1, FROM_START);
+ set_position(-1, RELATIVE);
+}
+
+RETSIGTYPE suspend_irc(s)
+int s;
+{
+#ifdef SIGTSTP
+ signal(SIGTSTP, suspend_irc);
+# ifdef DOCURSES
+ if (termtype == CURSES_TERM) {
+ echo();
+ nocrmode();
+ }
+# endif /* DOCURSES */
+# ifdef DOTERMCAP
+ if (termtype == TERMCAP_TERM)
+ io_off();
+# endif /* DOTERMCAP */
+# ifdef SIGSTOP
+ kill(getpid(), SIGSTOP);
+# endif /* SIGSTOP */
+# ifdef DOCURSES
+ if (termtype == CURSES_TERM) {
+ /* initscr(); */
+ noecho();
+ crmode();
+ clear();
+ refresh();
+ }
+# endif /* DOCURSES */
+# ifdef DOTERMCAP
+ if (termtype == TERMCAP_TERM) {
+ io_on(1);
+ clearscreen();
+ }
+# endif /* DOTERMCAP */
+ write_statusline();
+#else /* || */
+# if !defined(SVR3)
+ tstp();
+# endif
+#endif /* || */
+}
+
+void got_esc()
+{
+ esc = 1;
+}
+
+void do_after_esc(ch)
+char ch;
+{
+ if (literal) {
+ literal = 0;
+ add_ch(ch);
+ return;
+ }
+ esc = 0;
+ switch (ch)
+ {
+ case 'b':
+ word_back();
+ break;
+ case 'd':
+ del_word_right();
+ break;
+ case 'f':
+ word_forw();
+ break;
+ case 'y':
+ yank();
+ break;
+ case '\177':
+ del_word_left();
+ break;
+ default:
+ break;
+ }
+}
+
+void refresh_screen()
+{
+#ifdef DOCURSES
+ if (termtype == CURSES_TERM) {
+ clearok(curscr, TRUE);
+ refresh();
+ }
+#endif
+}
+
+void add_ch(ch)
+int ch;
+{
+ int i1, i2, i3;
+
+ if (in_insert_mode()) {
+ i1 = get_position();
+ set_position(0, FROM_END);
+ i2 = get_position();
+ for (i3 = i2; i3 >= 0; i3--)
+ set_char(i1+i3+1, get_char(i3+i1));
+ set_char(i1, ch);
+ set_position(i1, FROM_START);
+ set_position(1, RELATIVE);
+ } else {
+ i1 = get_position();
+ set_char(i1, ch);
+ set_position(i1, FROM_START);
+ set_position(1, RELATIVE);
+ }
+}
+
+void literal_next()
+{
+ got_esc();
+ literal=1;
+}
+
+void word_forw()
+{
+ int i1,i2;
+
+ i1 = get_position();
+
+ while ((i2 = get_char(i1)))
+ if ((i2 == (int)' ') || (i2 == (int)'\t') ||
+ (i2 == (int)'_') || (i2 == (int)'-'))
+ i1++;
+ else
+ break;
+ while ((i2 = get_char(i1)))
+ if ((i2 == (int)' ') || (i2 == (int)'\t') ||
+ (i2 == (int)'_') || (i2 == (int)'-'))
+ break;
+ else
+ i1++;
+ set_position(i1, FROM_START);
+}
+
+void word_back()
+{
+ int i1,i2;
+
+ i1 = get_position();
+ if (i1 != 0)
+ i1--;
+
+ while ((i2 = get_char(i1)))
+ if ((i2 == (int)' ') || (i2 == (int)'\t') ||
+ (i2 == (int)'_') || (i2 == (int)'-'))
+ i1--;
+ else
+ break;
+ while ((i2 = get_char(i1)))
+ if ((i2 == (int)' ') || (i2 == (int)'\t') ||
+ (i2 == (int)'_') || (i2 == (int)'-'))
+ break;
+ else
+ i1--;
+ if (i1 <= 0)
+ i1 = 0;
+ else
+ i1++;
+ set_position(i1, FROM_START);
+}
+
+void del_word_left()
+{
+ int i1, i2, i3, i4;
+
+ i1 = get_position();
+ word_back();
+ i2 = get_position();
+ set_position(0, FROM_END);
+ i3 = get_position();
+ for(i4 = i2; i4 <= i3 - (i1 - i2); i4++)
+ set_char(i4, get_char(i4 + (i1 - i2)));
+ for(; i4 <= i3; i4++)
+ set_char(i4, (int)'\0');
+ set_position(i2, FROM_START);
+}
+
+void del_word_right()
+{
+ int i1, i2, i3, i4;
+
+ i2 = get_position();
+ word_forw();
+ i1 = get_position();
+ set_position(0, FROM_END);
+ i3 = get_position();
+ for(i4 = i2; i4 <= i3 - (i1 - i2); i4++)
+ set_char(i4, get_char(i4 + (i1 - i2)));
+ for(; i4 <= i3; i4++)
+ set_char(i4, (int)'\0');
+ set_position(i2, FROM_START);
+}
+
+
diff --git a/irc/edit_ext.h b/irc/edit_ext.h
new file mode 100644
index 0000000..54a0963
--- /dev/null
+++ b/irc/edit_ext.h
@@ -0,0 +1,55 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/edit_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in irc/edit.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef EDIT_C
+extern char edit_id[];
+#endif /* EDIT_C */
+
+/* External definitions for global functions.
+ */
+#ifndef EDIT_C
+#define EXTERN extern
+#else /* EDIT_C */
+#define EXTERN
+#endif /* EDIT_C */
+EXTERN int do_char __P((char ch));
+EXTERN void bol();
+EXTERN void eol();
+EXTERN void back_ch();
+EXTERN void forw_ch();
+EXTERN void rev_line();
+EXTERN void del_ch_right();
+EXTERN void del_ch_left();
+EXTERN RETSIGTYPE suspend_irc __P((int s));
+EXTERN void got_esc();
+EXTERN void do_after_esc __P((char ch));
+EXTERN void refresh_screen();
+EXTERN void add_ch __P((int ch));
+EXTERN void literal_next();
+EXTERN void word_forw();
+EXTERN void word_back();
+EXTERN void del_word_left();
+EXTERN void del_word_right();
+#undef EXTERN
diff --git a/irc/help.c b/irc/help.c
new file mode 100644
index 0000000..71d3dfe
--- /dev/null
+++ b/irc/help.c
@@ -0,0 +1,228 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/help.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: help.c,v 1.2 1997/09/03 17:45:38 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "c_defines.h"
+#define HELP_C
+#include "c_externs.h"
+#undef HELP_C
+
+struct Help helplist[] = {
+ { "ADMIN", "/ADMIN <server>",
+ { "Prints administrative information about an IRC server.",
+ "<server> defaults to your own IRC server.", "", "", "" } },
+ { "AWAY", "/AWAY <message>",
+ { "<Mark yourself as being away. <message> is a message that will be",
+ "automatically sent to anyone who tries sending you a private message.",
+ "If you are already marked as being away, /AWAY will change your status",
+ "back to \"here.\"", "" } },
+ { "BYE", "/BYE",
+ { "Exit from IRC. /BYE, /EXIT, /QUIT and /SIGNOFF are identical.",
+ "", "", "", "" } },
+ { "CHANNEL", "/CHANNEL <channel>",
+ { "Leave the current channel and join a new one. Channel is any number",
+ "or a string beginning with a plus (+) sign. Numbered channels above 999",
+ "are private channels, you cannot see them by /LIST. Negative channels",
+ "are secret; they do not appear in /WHO at all. String channels are open",
+ "first, but the channel operators can change the mode with /MODE" } },
+ { "CLEAR", "/CLEAR",
+ { "Clear your screen.", "", "", "", "" } },
+ { "CMDCH", "/CMDCH <x>",
+ { "Changes your command prefix character to <x>. This is useful if you",
+ "often start lines with slashes. For example, after typing \"/cmdch #\"",
+ "your commands would look like #who or #links.", "", "" } },
+ { "DATE", "/DATE <server>",
+ { "Prints the date and time local to a specific server. <server> defaults",
+ "to your own IRC server. /DATE and /TIME are identical.", "", "", "" } },
+ { "EXIT", "/EXIT",
+ { "Exit from IRC. /BYE, /EXIT, /QUIT and /SIGNOFF are identical.",
+ "", "", "", "" } },
+#ifdef VMSP
+ { "EXEC", "/EXEC <CP/CMS command>",
+ { "Executes a CP/CMS command. If the command spends some time, you may",
+ "be signed off by the server. See UNKILL.",
+ "Warning: Screen is cleared after execcuting a command.",
+ "", "" } },
+#endif
+ { "HELP", "/HELP <command>",
+ { "/HELP without parameters lists all IRC commands.",
+ "/HELP followed by a command name prints a description of that command.",
+ "", "", "" } },
+ { "IGNORE", "/IGNORE <+|-><nicknames>",
+ { "Allows you to automatically ignore messages from certain users. If",
+ "+ is specified before <nicknames>, only public messages are ignored.",
+ "Similarly, - ignores only private messages. If neither symbol is given",
+ "all messages are ignored. /IGNORE without parameters prints the current",
+ "list of ignored users." } },
+ { "INFO", "/INFO",
+ { "Prints some information about IRC.", "", "", "", "" } },
+ { "INVITE", "/INVITE <channel> <nickname>",
+ { "Invites a user to join your channel. The user must be currently using",
+ "IRC.", "", "", "" } },
+ { "JOIN", "/JOIN <channel>{,<channel>} [<key>{,<key>}]",
+ { "Leave the current channel and join a new one. Channels above 999",
+ "are private channels; their numbers are not listed by /WHO. Negative",
+ "numbered channels are secret; they do not appear in /WHO at all.",
+ "/JOIN and /CHANNEL are identical.", "" } },
+ { "KICK", "/KICK <channel> <user> [<comment>]",
+ { "Kicks specified user off given channel",
+ "Only channel operators are privileged to use this command",
+ "Channel operator privileges can be given to other users of channel",
+ "by command '/MODE <channel> +o <user>' and taken away by command",
+ "'/MODE <channel> -o <user>'" } },
+ { "LINKS", "/LINKS [<pattern> [<server>]]",
+ { "Lists all active IRC servers.",
+ "If <pattern> is given, list all active irc links matching <pattern>",
+ "For example, /links *.fi lists all links in Finland", "", "" } },
+ { "LIST", "/LIST",
+ { "Lists all active channels and, if set, their topics.", "", "", "", "" } },
+ { "LUSERS", "/LUSERS",
+ { "Show the number of people and servers connected to the IRC network.",
+ "", "", "", "" } },
+ { "LOG", "/LOG <filename>",
+ { "Sends a copy of your IRC session to a file.",
+ "/LOG followed by a filename begins logging in the given file.",
+ "/LOG with no parameters turns logging off.", "", "" } },
+ { "MSG", "/MSG <nicknames> <message>",
+ { "Send a private message. <nicknames> should be one or more nicknames or",
+ "channel numbers separated by commas (no spaces). If <nicknames> is \",\"",
+ "your message is sent to the last person who sent you a private message.",
+ "If <nicknames> is \".\" it's sent to the last personyou sent one to.",
+ "Messages sent to , or . can (currently) contain no other recipients." } },
+ { "MODE", "/MODE <channel> [+|-]<modechars> <parameters>",
+ { "Mode command is quite complicated and it allows channel operators to",
+ "change channel mode. <modechars> is one of m (moderated), s (secret),",
+ "p (private), l (limited), t (topiclimited), a (anonymous), o (oper)",
+ "i (inviteonly). + or - sign whether the specifies mode should be added",
+ "or deleted. Parameter for l is the maximum users allowed" } },
+ { "MOTD", "/MOTD <server>",
+ { "Query for message-of-today in given server. If <server> parameter is",
+ "left out, query local server", "", "", "" } },
+ { "NAMES", "/NAMES <channel>{,<channel>}",
+ { "/NAMES without a parameter lists the nicknames of users on all channels.",
+ "/NAMES followed by a channel number lists the names on that channel.",
+ "", "", "" } },
+ { "NICK", "/NICK <nickname>",
+ { "Change your nickname. You cannot choose a nickname that is already in",
+ "use. Additionally, some characters cannot be used in nicknames.",
+ "", "", "" } },
+ { "QUERY", "/QUERY <nicknames>",
+ { "Begin private chat with <nicknames>. All subsequent messages you type",
+ "will be automatically sent only to <nicknames>. /QUERY without",
+ "parameters ends any current chat. You can send a normal message to your",
+ "channel by prefixing it with a slash and a space, like \"/ hi\".", "" } },
+ { "QUIT", "/QUIT [<comment>]",
+ { "Exit from IRC. /BYE, /EXIT, /QUIT and /SIGNOFF are identical.",
+ "", "", "", "" } },
+ { "SERVER", "/SERVER <server>",
+ { "Disconnects from currect server and connects your client into a new",
+ "server specified in command line", "", "", "" } },
+ { "SIGNOFF", "/SIGNOFF",
+ { "Exit from IRC. /BYE, /EXIT, /QUIT and /SIGNOFF are identical.",
+ "", "", "", "" } },
+ { "STATS", "/STATS [<c|h|i|k|l|m|n|o|q|y>]",
+ { "Shows various IRC server statistics. This command is rather boring",
+ "", "", "", "" } },
+ { "SUMMON", "/SUMMON <user> [<server>]",
+ { "Ask a user to enter IRC. <user> is of the form guest@tolsun.oulu.fi.",
+ "You can only summon users on machines where an IRC server is running.",
+ "Some servers may have disabled the /SUMMON command.", "", "" } },
+ { "TIME", "/TIME <server>",
+ { "Prints the date and time local to a specific server. <server> defaults",
+ "to your own IRC server. /DATE and /TIME are identical.", "", "", "" } },
+ { "TOPIC", "/TOPIC <channel> [<topic>]",
+ { "Sets the topic for the channel you're on.", "", "", "", "" } },
+ { "UNKILL", "/UNKILL",
+ { "Orders to irc reconnect to server if you happen to become killed",
+ "accidentally or in purpose", "", "", "" } },
+ { "USERS", "/USERS <host>",
+ { "List all users logged in to a host. The host must be running an IRC",
+ "server. Finger(1) usually works better.", "", "", "" } },
+ { "VERSION", "/VERSION <server>",
+ { "Prints the version number of an IRC server. <server> defaults to your",
+ "own IRC server.", "", "", "" } },
+ { "WHO", "/WHO <channel> [<o>]",
+ { "/WHO without parameters lists users on all channels.",
+ "/WHO followed by a channel number lists users on that channel.",
+ "/WHO * lists users that are on the same channel as you.",
+ "You cannot see users that are on negative-numbered channels.", "" } },
+ { "WHOIS", "/WHOIS <nicknames>{,<nickname>}",
+ { "/WHOIS prints information about a particular user, including his or",
+ "her name, host name and IRC server. <nicknames> should be one of more",
+ "nicknames separated by commas.", "", "" } },
+ { "WHOWAS", "/WHOWAS <nickname>{,<nickname>} [<count> [<server>]]",
+ { "/WHOWAS returns nickname history information for each of the given",
+ "nicknames.", "", "", "" } },
+ { NULL, NULL,
+ { NULL, NULL, NULL, NULL, NULL } }
+};
+
+char helpbuf[80];
+
+void do_help(ptr, temp)
+char *ptr, *temp;
+{
+ struct Help *hptr;
+ int count;
+
+ if (BadPtr(ptr)) {
+ sprintf(helpbuf, "*** Help: Internet Relay Chat v%s Commands:", version);
+ putline(helpbuf);
+ count = 0;
+ for (hptr = helplist; hptr->command; hptr++) {
+ sprintf(&helpbuf[count*10], "%10s", hptr->command);
+ if (++count >= 6) {
+ count = 0;
+ putline(helpbuf);
+ }
+ }
+ if (count)
+ putline(helpbuf);
+ putline("Type /HELP <command> to get help about a particular command.");
+ putline("For example \"/HELP signoff\" gives you help about the");
+ putline("/SIGNOFF command. To use a command you must prefix it with a");
+ putline("slash or whatever your current command character is (see");
+ putline("\"/HELP cmdch\"");
+ putline("*** End Help");
+ } else {
+ for (hptr = helplist; hptr->command; hptr++)
+ if (mycncmp(ptr, hptr->command))
+ break;
+
+ if (hptr->command == (char *) 0) {
+ putline("*** There is no help information for that command.");
+ putline("*** Type \"/HELP\" to get a list of commands.");
+ return;
+ }
+ sprintf(helpbuf, "*** Help: %s", hptr->syntax);
+ putline(helpbuf);
+ for (count = 0; count < 5; count++)
+ if (hptr->explanation[count] && *(hptr->explanation[count])) {
+ sprintf(helpbuf, " %s", hptr->explanation[count]);
+ putline(helpbuf);
+ }
+ putline("*** End Help");
+ }
+}
+
diff --git a/irc/help_def.h b/irc/help_def.h
new file mode 100644
index 0000000..82a6769
--- /dev/null
+++ b/irc/help_def.h
@@ -0,0 +1,23 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/help_def.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.
+ */
+
+struct Help {
+ char *command, *syntax, *explanation[5];
+};
diff --git a/irc/help_ext.h b/irc/help_ext.h
new file mode 100644
index 0000000..6a85893
--- /dev/null
+++ b/irc/help_ext.h
@@ -0,0 +1,40 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/help_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in irc/help.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef HELP_C
+extern struct Help helplist[];
+extern char help_id[];
+extern char helpbuf[];
+#endif /* HELP_C */
+
+/* External definitions for global functions.
+ */
+#ifndef HELP_C
+#define EXTERN extern
+#else /* HELP_C */
+#define EXTERN
+#endif /* HELP_C */
+EXTERN void do_help __P((char *ptr, char *temp));
+#undef EXTERN
diff --git a/irc/ignore.c b/irc/ignore.c
new file mode 100644
index 0000000..23bc5db
--- /dev/null
+++ b/irc/ignore.c
@@ -0,0 +1,141 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/ignore.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.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: ignore.c,v 1.2 1997/09/03 17:45:39 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "c_defines.h"
+#define IGNORE_C
+#include "c_externs.h"
+#undef IGNORE_C
+
+anIgnore *ignore = (anIgnore *) 0;
+char ibuf[80];
+
+void do_ignore(user, temp)
+char *user, *temp;
+{
+ char *ch, *wild = "*";
+ anIgnore *iptr;
+ char *apu = user, *uh;
+ int status;
+ if ((user == (char *) 0) || (*user == '\0')) {
+
+ putline("*** Current ignore list entries:");
+ for (iptr = ignore; iptr; iptr = iptr->next) {
+ sprintf(ibuf," Ignoring %s messages from user %s!%s",
+ (iptr->flags == IGNORE_TOTAL) ? "all" :
+ (iptr->flags == IGNORE_PRIVATE) ? "private" : "public",
+ iptr->user, iptr->from);
+ putline(ibuf);
+ }
+ putline("*** End of ignore list entries");
+ return;
+ }
+ while (apu && *apu) {
+ ch = apu;
+ if (*ch == '+') {
+ ch++;
+ status = IGNORE_PUBLIC;
+ }
+ else if (*ch == '-') {
+ ch++;
+ status = IGNORE_PRIVATE;
+ }
+ else
+ status = IGNORE_TOTAL;
+ if ((apu = index(ch, ',')))
+ *(apu++) = '\0';
+ if ((uh = index(ch, '!')))
+ *uh++ = '\0';
+ else if ((uh = index(ch, '@')))
+ *uh++ = '\0';
+ else
+ uh = wild;
+ if (!*ch)
+ ch = wild;
+ if ((iptr = find_ignore(ch, (anIgnore *)NULL, uh))) {
+ sprintf(ibuf,"*** Ignore removed: user %s!%s",
+ iptr->user, iptr->from);
+ putline(ibuf);
+ kill_ignore(iptr);
+ } else {
+ if (strlen(ch) > (size_t) NICKLEN)
+ ch[NICKLEN] = '\0';
+ if (add_ignore(ch, status, uh) >= 0) {
+ sprintf(ibuf,"*** Ignore %s messages from user %s!%s",
+ (status == IGNORE_TOTAL) ? "all" :
+ (status == IGNORE_PRIVATE) ? "private" : "public", ch, uh);
+ putline(ibuf);
+ } else
+ putline("Fatal Error: Cannot allocate memory for ignore buffer");
+ }
+ }
+}
+
+anIgnore *find_ignore(user, para, fromhost)
+char *user, *fromhost;
+anIgnore *para;
+{
+ anIgnore *iptr;
+ for (iptr = ignore; iptr; iptr=iptr->next)
+ if ((match(iptr->user, user) == 0) &&
+ (match(iptr->from, fromhost)==0))
+ break;
+
+ return iptr ? iptr : para;
+}
+
+int kill_ignore(iptr)
+anIgnore *iptr;
+{
+ anIgnore *i2ptr, *i3ptr = (anIgnore *) 0;
+ for (i2ptr = ignore; i2ptr; i2ptr = i2ptr->next) {
+ if (i2ptr == iptr)
+ break;
+ i3ptr = i2ptr;
+ }
+ if (i2ptr) {
+ if (i3ptr)
+ i3ptr->next = i2ptr->next;
+ else
+ ignore = i2ptr->next;
+ free(i2ptr);
+ return (1);
+ }
+ return (-1);
+}
+
+int add_ignore(ch, status, fromhost)
+char *ch, *fromhost;
+int status;
+{
+ anIgnore *iptr;
+ iptr = (anIgnore *) malloc(sizeof (anIgnore));
+ if (iptr == (anIgnore *) 0)
+ return(-1);
+ strncpyzt(iptr->user, ch, sizeof(iptr->user));
+ strncpyzt(iptr->from, fromhost, sizeof(iptr->from));
+ iptr->next = ignore;
+ ignore = iptr;
+ iptr->flags = status;
+ return(1);
+}
diff --git a/irc/ignore_ext.h b/irc/ignore_ext.h
new file mode 100644
index 0000000..f2e3d16
--- /dev/null
+++ b/irc/ignore_ext.h
@@ -0,0 +1,43 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/ignore_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in irc/ignore.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef IGNORE_C
+extern char ignore_id[];
+extern anIgnore *ignore;
+extern char ibuf[];
+#endif /* IGNORE_C */
+
+/* External definitions for global functions.
+ */
+#ifndef IGNORE_C
+#define EXTERN extern
+#else /* IGNORE_C */
+#define EXTERN
+#endif /* IGNORE_C */
+EXTERN void do_ignore __P((char *user, char *temp));
+EXTERN anIgnore *find_ignore __P((char *user, anIgnore *para, char *fromhost));
+EXTERN int kill_ignore __P((anIgnore *iptr));
+EXTERN int add_ignore __P((char *ch, int status, char *fromhost));
+#undef EXTERN
diff --git a/irc/irc.c b/irc/irc.c
new file mode 100644
index 0000000..7246f21
--- /dev/null
+++ b/irc/irc.c
@@ -0,0 +1,908 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/irc.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: irc.c,v 1.6 1998/12/13 00:02:35 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "c_defines.h"
+#define IRC_C
+#include "c_externs.h"
+#undef IRC_C
+
+#define DEPTH 10
+#define KILLMAX 2 /* Number of kills to accept to really die */
+ /* this is to prevent looping with /unkill */
+
+#ifdef AUTOMATON
+#ifdef DOCURSES
+#undef DOCURSES
+#endif
+#ifdef DOTERMCAP
+#undef DOTERMCAP
+#endif
+#endif /* AUTOMATON */
+
+struct Command commands[] = {
+ { (void (*)()) 0, "SIGNOFF", SERVER_CMD, "\0\0", MSG_QUIT },
+ { do_bye, "QUIT", LOCAL_FUNC, "\0\0", MSG_QUIT },
+ { do_bye, "EXIT", LOCAL_FUNC, "\0\0", MSG_QUIT },
+ { do_bye, "BYE", LOCAL_FUNC, "\0\0", MSG_QUIT },
+ { do_kill, "KILL", LOCAL_FUNC, "\0\0", MSG_KILL },
+ { (void (*)()) 0, "SUMMON", SERVER_CMD, "\0\0", MSG_SUMMON },
+ { (void (*)()) 0, "STATS", SERVER_CMD, "\0\0", MSG_STATS },
+ { (void (*)()) 0, "USERS", SERVER_CMD, "\0\0", MSG_USERS },
+ { (void (*)()) 0, "TIME", SERVER_CMD, "\0\0", MSG_TIME },
+ { (void (*)()) 0, "DATE", SERVER_CMD, "\0\0", MSG_TIME },
+ { (void (*)()) 0, "NAMES", SERVER_CMD, "\0\0", MSG_NAMES },
+ { (void (*)()) 0, "NICK", SERVER_CMD, "\0\0", MSG_NICK },
+ { (void (*)()) 0, "WHO", SERVER_CMD, "\0\0", MSG_WHO },
+ { (void (*)()) 0, "WHOIS", SERVER_CMD, "\0\0", MSG_WHOIS },
+ { (void (*)()) 0, "WHOWAS", SERVER_CMD, "\0\0", MSG_WHOWAS },
+ { do_kill, "LEAVE", LOCAL_FUNC, "\0\0", MSG_PART },
+ { do_kill, "PART", LOCAL_FUNC, "\0\0", MSG_PART },
+ { (void (*)()) 0, "WOPS", SERVER_CMD, "\0\0", MSG_WALLOPS },
+ { do_channel, "JOIN", LOCAL_FUNC, "\0\0", MSG_JOIN },
+ { do_channel, "CHANNEL", LOCAL_FUNC, "\0\0", MSG_JOIN },
+#ifdef VMSP
+ { do_exec, "EXEC", LOCAL_FUNC, "\0\0", "EXEC" },
+ { do_oper, "OPER", LOCAL_FUNC, "\0\0", "OPER" },
+#endif
+#ifdef GETPASS
+ { do_oper, "OPER", LOCAL_FUNC, "\0\0", "OPER" },
+#else
+ { (void (*)()) 0, "OPER", SERVER_CMD, "\0\0", MSG_OPER },
+#endif
+ { do_away, "AWAY", LOCAL_FUNC, "\0\0", MSG_AWAY },
+ { do_mypriv, "MSG", LOCAL_FUNC, "\0\0", MSG_PRIVATE },
+ { do_kill, "TOPIC", LOCAL_FUNC, "\0\0", MSG_TOPIC },
+ { do_cmdch, "CMDCH", LOCAL_FUNC, "\0\0", "CMDCH" },
+ { (void (*)()) 0, "INVITE", SERVER_CMD, "\0\0", MSG_INVITE },
+ { (void (*)()) 0, "INFO", SERVER_CMD, "\0\0", MSG_INFO },
+ { (void (*)()) 0, "LIST", SERVER_CMD, "\0\0", MSG_LIST },
+ { (void (*)()) 0, "KILL", SERVER_CMD, "\0\0", MSG_KILL },
+ { do_quote, "QUOTE", LOCAL_FUNC, "\0\0", "QUOTE" },
+ { (void (*)()) 0, "LINKS", SERVER_CMD, "\0\0", MSG_LINKS },
+ { (void (*)()) 0, "ADMIN", SERVER_CMD, "\0\0", MSG_ADMIN },
+ { do_ignore, "IGNORE", LOCAL_FUNC, "\0\0", "IGNORE" },
+ { (void (*)()) 0, "TRACE", SERVER_CMD, "\0\0", MSG_TRACE },
+ { do_help, "HELP", LOCAL_FUNC, "\0\0", "HELP" },
+ { do_log, "LOG", LOCAL_FUNC, "\0\0", "LOG" },
+ { (void (*)()) 0, "VERSION", SERVER_CMD, "\0\0", MSG_VERSION },
+ { do_clear, "CLEAR", LOCAL_FUNC, "\0\0", "CLEAR" },
+ { (void (*)()) 0, "REHASH", SERVER_CMD, "\0\0", MSG_REHASH },
+ { do_query, "QUERY", LOCAL_FUNC, "\0\0", "QUERY" },
+ { (void (*)()) 0, "LUSERS", SERVER_CMD, "\0\0", MSG_LUSERS },
+ { (void (*)()) 0, "MOTD", SERVER_CMD, "\0\0", MSG_MOTD },
+ { do_unkill, "UNKILL", LOCAL_FUNC, "\0\0", "UNKILL" },
+ { do_server, "SERVER", LOCAL_FUNC, "\0\0", "SERVER" },
+ { (void (*)()) 0, "MODE", SERVER_CMD, "\0\0", MSG_MODE },
+#ifdef MSG_MAIL
+ { (void (*)()) 0, "MAIL", SERVER_CMD, "\0\0", MSG_MAIL },
+#endif
+ { do_kick, "KICK", LOCAL_FUNC, "\0\0", MSG_KICK },
+ { (void (*)()) 0, "USERHOST",SERVER_CMD, "\0\0", MSG_USERHOST },
+ { (void (*)()) 0, "ISON", SERVER_CMD, "\0\0", MSG_ISON },
+ { (void (*)()) 0, "CONNECT", SERVER_CMD, "\0\0", MSG_CONNECT },
+ { do_kill, "SQUIT", LOCAL_FUNC, "\0\0", MSG_SQUIT },
+ { (void (*)()) 0, "SERVLIST",SERVER_CMD, "\0\0", MSG_SERVLIST },
+ { do_kill, "SQUERY", LOCAL_FUNC, "\0\0", MSG_SQUERY },
+ { do_kill, "NOTICE", LOCAL_FUNC, "\0\0", MSG_NOTICE },
+ { (void (*)()) 0, (char *) 0, 0, "\0\0", (char *) 0 }
+};
+
+aChannel *channel = NULL;
+aClient me, *client = &me;
+anUser meUser; /* User block for 'me' --msa */
+FILE *logfile = NULL;
+char buf[BUFSIZE];
+char *querychannel;
+int portnum, termtype = CURSES_TERM;
+int debuglevel = DEBUG_ERROR;
+int unkill_flag = 0, cchannel = 0;
+int QuitFlag = 0;
+
+static int KillCount = 0;
+static int apu = 0; /* Line number we're currently on screen */
+static int sock; /* Server socket fd */
+static char currserver[HOSTLEN + 1];
+
+#if defined(HPUX) || defined(SVR3) || defined(SVR4)
+char logbuf[BUFSIZ];
+#endif
+
+#ifdef MAIL50
+int ucontext = 0, perslength;
+char persname[81];
+
+struct itmlst
+ null_list[] = {{0,0,0,0}},
+ gplist[] = {{80, MAIL$_USER_PERSONAL_NAME,
+ &persname, &perslength}};
+#endif
+
+int main(argc, argv)
+int argc;
+char *argv[];
+{
+ static char usage[] =
+ "Usage: %s [-c channel] [-k passwd] [-p port] [-i] [-w] [-s] [nickname [server]]\n";
+ char channel[BUFSIZE+1];
+ int length, mode = 0;
+ struct passwd *userdata;
+ char *cp, *argv0=argv[0], *nickptr, *servptr, *getenv(), ch;
+
+ if ((cp = rindex(argv0, '/')) != NULL)
+ argv0 = ++cp;
+ portnum = PORTNUM;
+ *buf = *currserver = '\0';
+ channel[0] = '\0';
+ me.user = &meUser;
+ me.from = &me;
+ me.info = (char *) malloc(REALLEN);
+ setuid(getuid());
+ version = make_version();
+
+ while (argc > 1 && argv[1][0] == '-') {
+ switch(ch = argv[1][1])
+ {
+ case 'h':
+ printf(usage, argv0);
+ exit(1);
+ break;
+ case 'p':
+ length = 0;
+ if (argv[1][2] != '\0')
+ length = atoi(&argv[1][2]);
+ else if (argc > 2) {
+ length = atoi(argv[2]);
+ argv++;
+ argc--;
+ }
+ if (length <= 0) {
+ printf(usage, argv0);
+ exit(1);
+ }
+ cchannel = length;
+ break;
+ case 'c':
+ if (argv[1][2] != '\0')
+ strncpy(channel, &argv[1][2], BUFSIZE);
+ else if (argc > 2) {
+ strncpy(channel, argv[2], BUFSIZE);
+ argv++;
+ argc--;
+ }
+ if (!channel[0]) {
+ printf(usage, argv0);
+ exit(1);
+ }
+ break;
+ case 'i':
+ mode |= FLAGS_INVISIBLE;
+ break;
+ case 'w':
+ mode |= FLAGS_WALLOP;
+ break;
+ case 'k':
+ if (argv[1][2] != '\0')
+ strncpy(me.passwd, &argv[1][2], PASSWDLEN);
+ else if (argc > 2) {
+ strncpy(me.passwd, argv[2], PASSWDLEN);
+ argv++;
+ argc--;
+ }
+ if (!me.passwd[0]) {
+ printf(usage, argv0);
+ exit(1);
+ }
+ break;
+#ifdef DOTERMCAP
+ case 's':
+ termtype = TERMCAP_TERM;
+ break;
+#endif
+ case 'v':
+ (void)printf("irc %s\n", version);
+ exit(0);
+ }
+ argv++;
+ argc--;
+ }
+
+ me.name[0] = me.buffer[0] = '\0';
+ me.next = NULL;
+ me.status = STAT_ME;
+ if ((servptr = getenv("IRCSERVER")))
+ strncpyzt(currserver, servptr, HOSTLEN);
+ if (argc > 2)
+ strncpyzt(currserver, argv[2], HOSTLEN);
+
+ do {
+ QuitFlag = 0;
+ if (unkill_flag < 0)
+ unkill_flag += 2;
+#ifdef UPHOST
+ if (!*currserver)
+ strncpyzt(currserver, UPHOST, HOSTLEN);
+#else
+ if (!*currserver)
+ strncpyzt(currserver, me.sockhost, HOSTLEN);
+#endif
+ if (cchannel > 0)
+ portnum = cchannel;
+
+ sock = client_init(currserver, portnum, &me);
+ if (sock < 0) {
+ printf("sock < 0\n");
+ exit(1);
+ }
+ userdata = getpwuid(getuid());
+ if (strlen(userdata->pw_name) >= (size_t) USERLEN) {
+ userdata->pw_name[USERLEN-1] = '\0';
+ }
+ if (strlen(userdata->pw_gecos) >= (size_t) REALLEN) {
+ userdata->pw_gecos[REALLEN-1] = '\0';
+ }
+ /* FIX: jtrim@orion.cair.du.edu -- 3/14/88
+ & jto@tolsun.oulu.fi */
+ if (!*me.name) {
+ if (argc >= 2) {
+ strncpy(me.name, argv[1], NICKLEN);
+ } else if ((nickptr = getenv("IRCNICK"))) {
+ strncpy(me.name, nickptr, NICKLEN);
+ } else
+#ifdef AUTOMATON
+ strncpy(me.name, a_myname(), NICKLEN);
+#else
+ strncpy(me.name, userdata->pw_name ,NICKLEN);
+#endif
+ }
+ me.name[NICKLEN] = '\0';
+ /* END FIX */
+
+ if (argv0[0] == ':') {
+ strcpy(me.sockhost, "OuluBox");
+ strncpy(me.info, &argv0[1], REALLEN);
+ strncpy(meUser.username, argv[1], USERLEN);
+ } else {
+ sprintf(me.sockhost, "%d", mode);
+ if ((cp = getenv("IRCNAME")))
+ strncpy(me.info, cp, REALLEN);
+ else if ((cp = getenv("NAME")))
+ strncpy(me.info, cp, REALLEN);
+ else {
+#ifdef AUTOMATON
+ strncpy(me.info, a_myreal(), REALLEN);
+#else
+ strncpy(me.info,real_name(userdata),REALLEN);
+#endif
+ if (me.info[0] == '\0')
+ strcpy(me.info, "*real name unknown*");
+ }
+#ifdef AUTOMATON
+ strncpy(meUser.username, a_myuser(), USERLEN);
+#else
+ strncpy(meUser.username,userdata->pw_name,USERLEN);
+#endif
+ }
+ meUser.server = mystrdup(me.sockhost);
+ meUser.username[USERLEN] = '\0';
+ me.info[REALLEN] = '\0';
+ me.fd = sock;
+#ifdef AUTOMATON
+ a_init();
+#endif
+#ifdef DOCURSES
+ if (termtype == CURSES_TERM) {
+ initscr();
+ signal(SIGINT, quit_intr);
+ signal(SIGTSTP, suspend_irc);
+ noecho();
+ crmode();
+ clear();
+ refresh();
+ }
+#endif
+#ifdef DOTERMCAP
+ if (termtype == TERMCAP_TERM) {
+ printf("Io on !\n");
+ io_on(1);
+ clearscreen();
+ }
+#endif
+ if (me.passwd[0])
+ sendto_one(&me, "PASS %s", me.passwd);
+ sendto_one(&me, "NICK %s", me.name);
+ sendto_one(&me, "USER %s %s %s :%s", meUser.username,
+ me.sockhost, meUser.server, me.info);
+ querychannel = (char *)malloc(strlen(me.name) + 1);
+ strcpy(querychannel, me.name); /* Kludge? */
+ if (channel[0])
+ do_channel(channel, "JOIN");
+ myloop(sock);
+ if (logfile)
+ do_log(NULL, NULL);
+ printf("Press any key.");
+ refresh();
+ getchar();
+ printf("\n");
+#ifdef DOCURSES
+ if (termtype == CURSES_TERM) {
+ echo();
+ nocrmode();
+ endwin();
+ }
+#endif
+#ifdef DOTERMCAP
+ if (termtype == TERMCAP_TERM)
+ io_off();
+#endif
+ apu = 0;
+ } while (unkill_flag && KillCount++ < KILLMAX);
+ exit(0);
+}
+
+void intr()
+{
+ if (logfile)
+ do_log(NULL, NULL);
+
+#ifdef DOCURSES
+ if (termtype == CURSES_TERM) {
+ echo();
+ nocrmode();
+ endwin();
+ }
+#endif
+#ifdef DOTERMCAP
+ if (termtype == TERMCAP_TERM)
+ io_off();
+#endif
+ exit(0);
+}
+
+void myloop(sock)
+int sock;
+{
+ write_statusline();
+#ifdef DOTERMCAP
+ if (termtype == TERMCAP_TERM)
+ put_statusline();
+#endif
+ client_loop(sock);
+}
+
+#define QUERYLEN 50
+
+static char cmdch = '/';
+static char queryuser[QUERYLEN+2] = "";
+
+void do_cmdch(ptr, temp)
+char *ptr, *temp;
+{
+ if (BadPtr(ptr)) {
+ putline("Error: Command character not changed");
+ return;
+ }
+ cmdch = *ptr;
+}
+
+void do_quote(ptr, temp)
+char *ptr, *temp;
+{
+ if (BadPtr(ptr)) {
+ putline("*** Error: Empty command");
+ return;
+ }
+ sendto_one(&me,"%s", ptr);
+}
+
+void do_query(ptr, temp)
+char *ptr, *temp;
+{
+ if (BadPtr(ptr)) {
+ sprintf(buf, "*** Ending a private chat with %s", queryuser);
+ putline(buf);
+ queryuser[0] = '\0';
+ } else {
+ strncpyzt(queryuser, ptr, QUERYLEN);
+ sprintf(buf, "*** Beginning a private chat with %s",
+ queryuser);
+ putline(buf);
+ }
+}
+
+void do_mypriv(buf1, buf2)
+char *buf1, *buf2;
+{
+ char *tmp = index(buf1, ' ');
+
+ if (tmp == NULL) {
+ putline("*** Error: Empty message not sent");
+ return;
+ }
+ if (buf1[0] == ',' && buf1[1] == ' ') {
+ sendto_one(&me, "PRIVMSG %s :%s", last_to_me(NULL), &buf1[2]);
+ last_from_me(last_to_me(NULL));
+ *(tmp++) = '\0';
+ sprintf(buf,"-> !!*%s* %s", last_to_me(NULL), tmp);
+ putline(buf);
+ } else if (buf1[0] == '.' && buf1[1] == ' ') {
+ sendto_one(&me, "PRIVMSG %s :%s", last_from_me(NULL), &buf1[2]);
+ *(tmp++) = '\0';
+ sprintf(buf,"-> ##*%s* %s", last_from_me(NULL), tmp);
+ putline(buf);
+ } else {
+ *(tmp++) = '\0';
+ sendto_one(&me, "PRIVMSG %s :%s", buf1, tmp);
+ last_from_me(buf1);
+ if (*buf1 == '#' || *buf1 == '&' || *buf1 == '+' || atoi(buf1))
+ sprintf(buf, "%s> %s", buf1, tmp);
+ else
+ sprintf(buf,"->%s> %s", buf1, tmp);
+ putline(buf);
+ }
+}
+
+void do_myqpriv(buf1, buf2)
+char *buf1, *buf2;
+{
+ if (BadPtr(buf1)) {
+ putline("*** Error: Empty message not sent");
+ return;
+ }
+ sendto_one(&me, "PRIVMSG %s :%s", queryuser, buf1);
+
+ sprintf(buf,"-> *%s* %s", queryuser, buf1);
+ putline(buf);
+}
+
+void do_mytext(buf1, temp)
+char *buf1, *temp;
+{
+ sendto_one(&me, "PRIVMSG %s :%s", querychannel, buf1);
+ sprintf(buf,"%s> %s", querychannel, buf1);
+ putline(buf);
+}
+
+void do_unkill(buf, temp)
+char *buf, *temp;
+{
+ if (unkill_flag)
+ unkill_flag = 0;
+ else
+ unkill_flag = 1;
+
+ sprintf(buf, "*** Unkill feature turned %s",
+ (unkill_flag) ? "on" : "off");
+ putline(buf);
+}
+
+void do_bye(buf, tmp)
+char *buf, *tmp;
+{
+ unkill_flag = 0;
+ sendto_one(&me, "%s :%s", tmp, buf);
+}
+
+/* KILL, PART, SQUIT, TOPIC "CMD PARA1 [:PARA2]" */
+void do_kill(buf1, tmp)
+char *buf1, *tmp;
+{
+ char *b2;
+
+ b2 = index(buf1, SPACE); /* find end of servername */
+ if (b2) /* comment */
+ {
+ *b2 = 0;
+ sendto_one(&me, "%s %s :%s", tmp, buf1, b2 + 1);
+ }
+ else
+ sendto_one(&me, "%s %s", tmp, buf1);
+ if (*tmp == 'P') { /* PART */
+ free(querychannel);
+ querychannel = (char *)malloc(strlen(me.name) + 1);
+ strcpy(querychannel, me.name); /* Kludge? */
+ }
+}
+
+/* "CMD PARA1 PARA2 [:PARA3]" */
+void do_kick(buf1, tmp)
+char *buf1, *tmp;
+{
+ char *b2, *b3 = NULL;
+
+ b2 = index(buf1, SPACE); /* find end of channel name */
+ if (b2)
+ b3 = index(b2 + 1, SPACE); /* find end of victim name */
+ if (b3)
+ {
+ *b3 = 0;
+ sendto_one(&me, "%s %s :%s", tmp, buf1, b3 + 1);
+ }
+ else
+ sendto_one(&me, "%s %s :No comment", tmp, buf1);
+}
+
+/* "CMD :PARA1" */
+void do_away(buf1, tmp)
+char *buf1, *tmp;
+{
+ sendto_one(&me, "%s :%s", tmp, buf1);
+}
+
+void do_server(buf, tmp)
+char *buf, *tmp;
+{
+ strncpyzt(currserver, buf, HOSTLEN);
+ unkill_flag -= 2;
+ sendto_one(&me,"QUIT");
+ close(sock);
+ QuitFlag = 1;
+}
+
+void sendit(line)
+char *line;
+{
+ char *ptr = NULL;
+ struct Command *cmd = commands;
+
+ KillCount = 0;
+ if (line[0] != cmdch) {
+ if (*queryuser)
+ do_myqpriv(line, NULL);
+ else
+ do_mytext(line, NULL);
+ return /* 0 */ ;
+ }
+ if (line[1] == ' ')
+ do_mytext(&line[2], NULL);
+ else if (line[1]) {
+ for ( ; cmd->name; cmd++)
+ if ((ptr = mycncmp(&line[1], cmd->name)))
+ break;
+ if (!cmd->name)
+ putline("*** Error: Unknown command");
+ else {
+ switch (cmd->type)
+ {
+ case SERVER_CMD:
+ sendto_one(&me, "%s %s", cmd->extra, ptr);
+ break;
+ case LOCAL_FUNC:
+ (*cmd->func)(ptr, cmd->extra);
+ return;
+ break;
+ default:
+ putline("*** Error: Data error in irc.h");
+ break;
+ }
+ }
+ }
+}
+
+char *mycncmp(str1, str2)
+char *str1, *str2;
+{
+ int flag = 0;
+ char *s1;
+
+ for (s1 = str1; *s1 != ' ' && *s1 && *str2; s1++, str2++) {
+ /* if (!isascii(*s1)) */
+ if (*s1 & 0x80)
+ return 0;
+ *s1 = toupper(*s1);
+ if (*s1 != *str2)
+ flag = 1;
+ }
+ if (*s1 && *s1 != ' ' && *str2 == '\0')
+ return 0;
+ if (flag)
+ return 0;
+ if (*s1)
+ return s1 + 1;
+ else
+ return s1;
+}
+
+void do_clear(buf, temp)
+char *buf, *temp;
+{
+#ifdef DOCURSES
+ char header[HEADERLEN];
+
+ if (termtype == CURSES_TERM) {
+ apu = 0;
+ sprintf(header, IRCHEADER ,version, me.name, currserver);
+ clear();
+ standout();
+ mvaddstr(LINES - 2, 0, header);
+ standend();
+ refresh();
+ }
+#endif
+#ifdef DOTERMCAP
+ if (termtype == TERMCAP_TERM)
+ clearscreen();
+#endif
+}
+
+void putline(line)
+char *line;
+
+{
+ char *ptr, *ptr2;
+
+#ifdef DOCURSES
+ char ch='\0';
+ /* int pagelen = LINES - 3; not used -Armin */
+ int rmargin = COLS - 1;
+#endif
+
+ /*
+ ** This is a *safe* client--filter out all possibly dangerous
+ ** codes from the messages (this sets them as "_").
+ */
+ if (line)
+ for (ptr = line; *ptr; ptr++)
+ if ((*ptr < 32 && *ptr != 7 && *ptr != 9) ||
+ (*ptr > 126))
+ *ptr = '_';
+
+ ptr = line;
+
+#ifdef DOCURSES
+ if (termtype == CURSES_TERM) {
+ while (ptr) {
+
+/* first, see if we have to chop the string into pieces */
+
+ if (strlen(ptr) > (size_t) rmargin) {
+ ch = ptr[rmargin];
+ ptr[rmargin] = '\0';
+ ptr2 = &ptr[rmargin - 1];
+ }
+ else
+ ptr2 = NULL;
+
+/* move cursor to correct position and place line */
+
+ move(apu,0);
+ addstr(ptr);
+ if (logfile)
+ fprintf(logfile, "%s\n", ptr);
+
+/* now see if we are at the end of the page, and take action */
+
+#ifndef SCROLLINGCLIENT
+ /* clear one line. */
+ addstr("\n\n");
+ if (++apu > LINES - 4) {
+ apu = 0;
+ move(0,0);
+ clrtoeol();
+ }
+
+#else /* doesn't work, dumps core :-( */
+
+ if(++apu > LINES - 4) {
+ char header[HEADERLEN];
+ /* erase status line */
+ move(LINES - 2, 0 );
+ clrtobot();
+ refresh();
+ /* scroll screen */
+ scrollok(stdscr,TRUE);
+ move(LINES - 1, 0 );
+ addstr("\n\n\n\n");
+ refresh();
+ apu -= 4;
+ /* redraw status line */
+ sprintf(header, IRCHEADER, version,
+ me.name, currserver);
+ standout();
+ mvaddstr(LINES - 2, 0, header);
+ standend();
+ tulosta_viimeinen_rivi();
+ } else
+ addstr( "\n\n" );
+#endif
+
+/* finally, if this is a multiple-line line, munge things up so that
+ we print the next line. overwrites the end of the previous line. */
+
+ ptr = ptr2;
+ if (ptr2) {
+ *ptr2++ = '+';
+ *ptr2 = ch;
+ }
+ }
+ refresh();
+ }
+#endif
+#ifdef DOTERMCAP
+ if (termtype == TERMCAP_TERM)
+ tcap_putline(line);
+#endif
+#ifdef AUTOMATON
+ puts(line);
+#endif
+}
+
+int unixuser()
+{
+ return(!StrEq(me.sockhost,"OuluBox"));
+}
+
+void do_log(ptr, temp)
+char *ptr, *temp;
+{
+ time_t tloc;
+ char buf[150];
+ char *ptr2;
+
+ if (!unixuser())
+ return;
+ if (!logfile) { /* logging currently off */
+ if (BadPtr(ptr))
+ putline("*** You must specify a filename to log to.");
+ else {
+ if (!(logfile = fopen(ptr, "a"))) {
+ sprintf(buf,
+ "*** Error: Can't open log file %s.\n",
+ ptr);
+ putline(buf);
+ } else {
+#if defined(HPUX) || defined(SVR3) || defined(SVR4)
+ setvbuf(logfile,logbuf,_IOLBF,sizeof(logbuf));
+#else
+# if !defined(_SEQUENT_) && !defined(SVR4)
+ setlinebuf(logfile);
+# endif
+#endif
+ time(&tloc);
+ sprintf(buf,
+ "*** IRC session log started at %s",
+ ctime(&tloc));
+ ptr2 = rindex(buf, '\n');
+ *ptr2 = '.';
+ putline(buf);
+ }
+ }
+ } else { /* logging currently on */
+ if (BadPtr(ptr)) {
+
+ time(&tloc);
+ sprintf(buf, "*** IRC session log ended at %s",
+ ctime(&tloc));
+ ptr2 = rindex(buf, '\n');
+ *ptr2 = '.';
+ putline(buf);
+ fclose(logfile);
+ logfile = NULL;
+ } else
+ putline("*** Your session is already being logged.");
+ }
+}
+
+/* remember the commas */
+#define LASTKEEPLEN (MAXRECIPIENTS * (NICKLEN+1))
+
+char *last_to_me(sender)
+char *sender;
+{
+ static char name[LASTKEEPLEN+1] = ",";
+
+ if (sender)
+ strncpyzt(name, sender, sizeof(name));
+
+ return (name);
+}
+
+char *last_from_me(recipient)
+char *recipient;
+{
+ static char name[LASTKEEPLEN+1] = ".";
+
+ if (recipient)
+ strncpyzt(name, recipient, sizeof(name));
+
+ return (name);
+}
+
+/*
+ * Left out until it works with VMS as well..
+ */
+
+#ifdef GETPASS
+do_oper(ptr, xtra)
+char *ptr, *xtra;
+{
+ extern char *getmypass();
+
+ if (BadPtr(ptr))
+ ptr = getmypass("Enter nick & password: ");
+
+ sendto_one(&me, "%s %s", xtra, ptr);
+}
+#endif
+
+/* Fake routine (it's only in server...) */
+
+void do_channel(ptr, xtra)
+char *ptr, *xtra;
+{
+ char *p1;
+
+ if (BadPtr(ptr)) {
+ putline("*** Which channel do you want to join?");
+ return;
+ }
+
+ free((char *)querychannel);
+
+ if ((querychannel = (char *)malloc(strlen(ptr) + 1)))
+ {
+ /* Copy only channel name from *ptr -Vesa */
+ strcpy(buf, ptr);
+ if ((p1 = index(buf, ' ')))
+ *p1 = '\0';
+ if ((p1 = rindex(buf, ','))) /* The last channel */
+ strcpy(querychannel, p1 + 1);
+ else /* The only channel */
+ strcpy(querychannel, buf);
+ }
+ else
+ printf("Blah! Out of memory?\n");
+
+ sendto_one(&me, "%s %s", xtra, ptr);
+}
+
+void write_statusline()
+{
+#ifdef DOCURSES
+ char header[HEADERLEN];
+
+ if (termtype == CURSES_TERM) {
+ sprintf(header, IRCHEADER, version, me.name, currserver);
+ standout();
+ mvaddstr(LINES - 2, 0, header);
+ standend();
+ }
+#endif
+}
+
+RETSIGTYPE quit_intr(s)
+int s;
+{
+ signal(SIGINT, SIG_IGN);
+#ifdef DOCURSES
+ if (termtype == CURSES_TERM) {
+ clear();
+ refresh();
+ echo();
+ nocrmode();
+ endwin();
+ }
+#endif
+ exit(0);
+}
diff --git a/irc/irc_def.h b/irc/irc_def.h
new file mode 100644
index 0000000..26f7a6c
--- /dev/null
+++ b/irc/irc_def.h
@@ -0,0 +1,29 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/irc_def.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.
+ */
+
+struct Command {
+ void (*func)();
+ char *name;
+ int type;
+ char keybinding[3];
+ char *extra; /* Normally contains the command to send to irc daemon */
+};
+
+#define SERVER_CMD 0
+#define LOCAL_FUNC 1
diff --git a/irc/irc_ext.h b/irc/irc_ext.h
new file mode 100644
index 0000000..4ef47a8
--- /dev/null
+++ b/irc/irc_ext.h
@@ -0,0 +1,84 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/irc_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in irc/irc.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef IRC_C
+extern struct Command commands[];
+extern char irc_id[];
+extern aChannel *channel;
+extern aClient me, *client;
+extern anUser meUser;
+extern FILE *logfile;
+extern char buf[];
+extern char *querychannel;
+extern int portnum, termtype;
+extern int debuglevel;
+extern int unkill_flag, cchannel;
+extern int QuitFlag;
+#if defined(HPUX) || defined(SVR3) || defined(SVR4)
+extern char logbuf[];
+#endif
+#ifdef MAIL50
+extern int ucontext, perslength;
+extern char persname[];
+extern struct itmlst null_list[];
+#endif
+#endif /* IRC_C */
+
+/* External definitions for global functions.
+ */
+#ifndef IRC_C
+#define EXTERN extern
+#else /* IRC_C */
+#define EXTERN
+#endif /* IRC_C */
+EXTERN void intr();
+EXTERN void myloop __P((int sock));
+EXTERN void do_cmdch __P((char *ptr, char *temp));
+EXTERN void do_quote __P((char *ptr, char *temp));
+EXTERN void do_query __P((char *ptr, char *temp));
+EXTERN void do_mypriv __P((char *buf1, char *buf2));
+EXTERN void do_myqpriv __P((char *buf1, char *buf2));
+EXTERN void do_mytext __P((char *buf1, char *temp));
+EXTERN void do_unkill __P((char *buf, char *temp));
+EXTERN void do_bye __P((char *buf, char *tmp));
+EXTERN void do_kill __P((char *buf1, char *tmp));
+EXTERN void do_kick __P((char *buf1, char *tmp));
+EXTERN void do_away __P((char *buf1, char *tmp));
+EXTERN void do_server __P((char *buf, char *tmp));
+EXTERN void sendit __P((char *line));
+EXTERN char *mycncmp __P((char *str1, char *str2));
+EXTERN void do_clear __P((char *buf, char *temp));
+EXTERN void putline __P((char *line));
+EXTERN int unixuser();
+EXTERN void do_log __P((char *ptr, char *temp));
+EXTERN char *last_to_me __P((char *sender));
+EXTERN char *last_from_me __P((char *recipient));
+#ifdef GETPASS
+EXTERN do_oper __P((char *ptr, char *xtra));
+#endif
+EXTERN void do_channel __P((char *ptr, char *xtra));
+EXTERN void write_statusline();
+EXTERN RETSIGTYPE quit_intr __P((int s));
+#undef EXTERN
diff --git a/irc/screen.c b/irc/screen.c
new file mode 100644
index 0000000..01afa11
--- /dev/null
+++ b/irc/screen.c
@@ -0,0 +1,287 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/screen.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: screen.c,v 1.2 1997/09/03 17:45:42 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "c_defines.h"
+#define SCREEN_C
+#include "c_externs.h"
+#undef SCREEN_C
+
+#define SBUFSIZ 240
+
+#define FROM_START 0
+#define FROM_END 1
+#define RELATIVE 2
+
+#define HIST_SIZ 1000
+
+static char last_line[SBUFSIZ+1];
+static char yank_buffer[SBUFSIZ+1];
+static char history[HIST_SIZ][SBUFSIZ+1];
+static int position = 0;
+static int pos_in_history = 0;
+
+int insert = 1; /* default to insert mode */
+ /* I want insert mode, thazwhat emacs does ! //jkp */
+
+int get_char(pos)
+int pos;
+{
+ if (pos>=SBUFSIZ || pos<0)
+ return 0;
+ return (int)last_line[pos];
+}
+
+void set_char(pos, ch)
+int pos, ch;
+{
+ if (pos<0 || pos>=SBUFSIZ)
+ return;
+ if (ch<0)
+ ch=0;
+ last_line[pos]=(char)ch;
+}
+
+int get_yank_char(pos)
+int pos;
+{
+ if (pos>=SBUFSIZ || pos<0)
+ return 0;
+ return (int)yank_buffer[pos];
+}
+
+void set_yank_char(pos, ch)
+int pos, ch;
+{
+ if (pos<0 || pos>=SBUFSIZ)
+ return;
+ if (ch<0)
+ ch=0;
+ yank_buffer[pos]=(char)ch;
+}
+
+void set_position(disp, from)
+int disp, from;
+{
+ int i1;
+
+ switch (from) {
+ case FROM_START:
+ position=disp;
+ break;
+ case RELATIVE:
+ position+=disp;
+ break;
+ case FROM_END:
+ for (i1=0; get_char(i1); i1++);
+ position=i1-1;
+ break;
+ default:
+ position=0;
+ break;
+ }
+}
+
+int get_position()
+{
+ return position;
+}
+
+void toggle_ins()
+{
+ insert = !insert;
+#ifdef DOCURSES
+ if (termtype == CURSES_TERM) {
+ standout();
+ if (insert)
+ mvaddstr(LINES-2, 75, "INS");
+ else
+ mvaddstr(LINES-2, 75, "OWR");
+ standend();
+ }
+#endif
+#ifdef DOTERMCAP
+ if (termtype == TERMCAP_TERM)
+ put_insflag(insert);
+#endif
+}
+
+int in_insert_mode()
+{
+ return insert;
+}
+
+void send_this_line()
+{
+ record_line();
+ sendit(last_line);
+ clear_last_line();
+ bol();
+ tulosta_viimeinen_rivi();
+#ifdef DOCURSES
+ if (termtype == CURSES_TERM)
+ refresh();
+#endif
+}
+
+void record_line()
+{
+ static int place=0;
+ int i1;
+
+ for(i1=0; i1<SBUFSIZ; i1++)
+ history[place][i1]=get_char(i1);
+ place++;
+ if (place==HIST_SIZ)
+ place=0;
+ pos_in_history=place;
+}
+
+void clear_last_line()
+{
+ int i1;
+
+ for(i1=0; i1<SBUFSIZ; i1++)
+ set_char(i1,(int)'\0');
+}
+
+void kill_eol()
+{
+ int i1, i2, i3;
+
+ i1=get_position();
+ set_position(0, FROM_END);
+ i2=get_position();
+ for(i3=0; i3<SBUFSIZ; i3++)
+ set_yank_char(i3,(int)'\0');
+ for(i3=0; i3<=(i2-i1); i3++) {
+ set_yank_char(i3,get_char(i1+i3));
+ set_char(i1+i3, 0);
+ }
+ set_position(i1, FROM_START);
+}
+
+void next_in_history()
+{
+ int i1;
+
+ pos_in_history++;
+ if (pos_in_history==HIST_SIZ)
+ pos_in_history=0;
+ clear_last_line();
+
+ for (i1 = 0; history[pos_in_history][i1]; i1++)
+ set_char(i1, history[pos_in_history][i1]);
+
+ set_position(0, FROM_START);
+}
+
+void previous_in_history()
+{
+ int i1;
+
+ pos_in_history--;
+ if (pos_in_history<0)
+ pos_in_history=HIST_SIZ-1;
+ clear_last_line();
+ for (i1=0; history[pos_in_history][i1]; i1++)
+ set_char(i1, history[pos_in_history][i1]);
+
+ set_position(0, FROM_START);
+}
+
+void kill_whole_line()
+{
+ clear_last_line();
+ set_position(0, FROM_START);
+}
+
+void yank()
+{
+ int i1, i2, i3;
+
+ i1=get_position();
+ i2=0;
+ while (get_yank_char(i2))
+ i2++;
+
+ for(i3=SBUFSIZ-1; i3>=i1+i2; i3--)
+ set_char(i3, get_char(i3-i2));
+ for(i3=0; i3<i2; i3++)
+ set_char(i1+i3, get_yank_char(i3));
+}
+
+int tulosta_viimeinen_rivi()
+{
+ static int paikka=0;
+ int i1, i2, i3;
+
+ i1=get_position();
+ /* taytyyko siirtaa puskuria */
+ if (i1<(get_disp(paikka)+10) && paikka) {
+ paikka--;
+ i2=get_disp(paikka);
+ } else if (i1>(get_disp(paikka)+70)) {
+ paikka++;
+ i2=get_disp(paikka);
+ } else {
+ i2=get_disp(paikka);
+ }
+
+#ifdef DOCURSES
+ if (termtype == CURSES_TERM) {
+ move(LINES-1,0);
+ for(i3=0; i3<78; i3++)
+ if (get_char(i2+i3))
+ mvaddch(LINES-1, i3, get_char(i2+i3));
+ clrtoeol();
+ move(LINES-1, i1-get_disp(paikka));
+ refresh();
+ }
+#endif
+#ifdef DOTERMCAP
+ if (termtype == TERMCAP_TERM) {
+ tcap_move(-1, 0);
+ for(i3=0; i3<78; i3++)
+ if (get_char(i2+i3))
+/* tcap_putch(LINES-1, i3, get_char(i2+i3)); */
+ tcap_putch(-1, i3, get_char(i2+i3));
+/* clear_to_eol(); */
+ clear_to_eol(-1, 78);
+ tcap_move(-1, i1-get_disp(paikka));
+/* refresh(); */
+ }
+#endif
+ return (i1-get_disp(paikka));
+}
+
+int get_disp(paikka)
+int paikka;
+{
+ static int place[]={0,55,110,165,220};
+
+ if (paikka>4 || paikka<0)
+ return 0;
+ return place[paikka];
+}
diff --git a/irc/screen_ext.h b/irc/screen_ext.h
new file mode 100644
index 0000000..5dfd792
--- /dev/null
+++ b/irc/screen_ext.h
@@ -0,0 +1,56 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/screen_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in irc/screen.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef SCREEN_C
+extern char screen_id[];
+extern int insert;
+#endif /* SCREEN_C */
+
+/* External definitions for global functions.
+ */
+#ifndef SCREEN_C
+#define EXTERN extern
+#else /* SCREEN_C */
+#define EXTERN
+#endif /* SCREEN_C */
+EXTERN int get_char __P((int pos));
+EXTERN void set_char __P((int pos, int ch));
+EXTERN int get_yank_char __P((int pos));
+EXTERN void set_yank_char __P((int pos, int ch));
+EXTERN void set_position __P((int disp, int from));
+EXTERN int get_position();
+EXTERN void toggle_ins();
+EXTERN int in_insert_mode();
+EXTERN void send_this_line();
+EXTERN void record_line();
+EXTERN void clear_last_line();
+EXTERN void kill_eol();
+EXTERN void next_in_history();
+EXTERN void previous_in_history();
+EXTERN void kill_whole_line();
+EXTERN void yank();
+EXTERN int tulosta_viimeinen_rivi();
+EXTERN int get_disp __P((int paikka));
+#undef EXTERN
diff --git a/irc/str.c b/irc/str.c
new file mode 100644
index 0000000..aaff546
--- /dev/null
+++ b/irc/str.c
@@ -0,0 +1,84 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/str.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: str.c,v 1.2 1997/09/03 17:45:43 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "c_defines.h"
+#define STR_C
+#include "c_externs.h"
+#undef STR_C
+
+char * center(buf,str,len)
+char *buf, *str;
+int len;
+{
+ char i,j,k;
+ if ((i = strlen(str)) > len) {
+ buf[len-1] = '\0';
+ for(len--; len > 0; len--) buf[len-1] = str[len-1];
+ return(buf);
+ }
+ j = (len-i)/2;
+ for (k=0; k<j; k++) buf[k] = ' ';
+ buf[k] = '\0';
+ strcat(buf,str);
+ for (k=j+i; k<len; k++) buf[k] = ' ';
+ buf[len] = '\0';
+ return (buf);
+}
+
+/* William Wisner <wisner@b.cc.umich.edu>, 16 March 1989 */
+char *
+real_name(user)
+ struct passwd *user;
+{
+ char *bp, *cp;
+ static char name[REALLEN+1];
+
+ bp = user->pw_gecos;
+ cp = name;
+
+ name[REALLEN] = '\0';
+ do {
+ switch(*bp) {
+ case '&':
+ *cp = '\0';
+ strncat(name, user->pw_name, REALLEN-strlen(name));
+ name[REALLEN] = '\0';
+ *cp = toupper(*cp);
+ cp = index(name, '\0');
+ bp++;
+ break;
+ case ',':
+ *bp = *cp = '\0';
+ break;
+ case '\0':
+ *cp = *bp;
+ break;
+ default:
+ *cp++ = *bp++;
+ }
+ } while (*bp != '\0' && strlen(name) < (size_t) REALLEN);
+ return(name);
+}
+
diff --git a/irc/str_ext.h b/irc/str_ext.h
new file mode 100644
index 0000000..6198141
--- /dev/null
+++ b/irc/str_ext.h
@@ -0,0 +1,39 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/str_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in irc/str.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef STR_C
+extern char str_id[];
+#endif /* STR_C */
+
+/* External definitions for global functions.
+ */
+#ifndef STR_C
+#define EXTERN extern
+#else /* STR_C */
+#define EXTERN
+#endif /* STR_C */
+EXTERN char *center __P((char *buf, char *str, int len));
+EXTERN char *real_name __P((struct passwd *user));
+#undef EXTERN
diff --git a/irc/swear.c b/irc/swear.c
new file mode 100644
index 0000000..9c8b2a6
--- /dev/null
+++ b/irc/swear.c
@@ -0,0 +1,216 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/swear.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.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: swear.c,v 1.4 1998/12/13 00:02:35 kalt Exp $";
+#endif
+
+/* Curses replacement routines. Uses termcap */
+
+#include "os.h"
+#include "c_defines.h"
+#define SWEAR_C
+#include "c_externs.h"
+#undef SWEAR_C
+
+#define LLEN 60
+
+#ifdef DOTERMCAP
+
+static struct sgttyb oldtty, newtty;
+static char termcapentry[1024];
+static char codes[1024], *cls;
+
+static char *irc_termname;
+
+static int currow = 0;
+int irc_lines, irc_columns, scroll_ok = 0, scroll_status = 0;
+
+void tcap_putch(row, col, ch)
+int row, col;
+char ch;
+{
+ tcap_move(row, col);
+ putchar(ch);
+ fflush(stdout);
+}
+
+void tcap_move(row, col)
+int row, col;
+{
+ cls = codes;
+ tgetstr("cm",&cls);
+ if (row < 0)
+ row = irc_lines - row;
+ cls = tgoto(codes, col, row);
+ printf("%s",cls);
+ fflush(stdout);
+}
+
+void clear_to_eol(row, col)
+int row, col;
+{
+ tcap_move(row, col);
+ cls = codes;
+ tgetstr("ce", &cls);
+ printf("%s",codes);
+ fflush(stdout);
+}
+
+void clearscreen()
+{
+ cls = codes;
+ tgetstr("cl",&cls);
+ printf("%s",codes);
+ fflush(stdout);
+ currow = 0;
+}
+
+int
+io_on(flag)
+int flag;
+{
+/* if (ioctl(0, TIOCGETP, &oldtty) == -1) {
+ perror("ioctl");
+ return(-1);
+ }
+ newtty = oldtty;
+ newtty.sg_flags &= ~ECHO;
+ newtty.sg_flags |= CBREAK;
+ ioctl(0, TIOCSETP, &newtty); */
+ system("stty -echo cbreak");
+ if (tgetent(termcapentry,irc_termname=getenv("TERM")) != 1) {
+ printf("Cannot find termcap entry !\n");
+ fflush(stdout);
+ }
+ printf("TERMCAP=%s\n",termcapentry);
+ irc_lines = tgetnum("li");
+ irc_columns = tgetnum("co");
+ return(0);
+}
+
+int
+io_off()
+{
+ if (scroll_ok)
+ scroll_ok_off();
+ if (ioctl(0, TIOCSETP, &oldtty) < 0)
+ return(-1);
+ return(0);
+}
+
+void scroll_ok_off()
+{
+ cls = codes;
+ tgetstr("cs",&cls);
+ cls = tgoto(codes, irc_lines-1, 0);
+ printf("%s",cls);
+ scroll_ok = 0;
+}
+
+void scroll_ok_on()
+{
+ cls = codes;
+ tgetstr("cm",&cls);
+ cls = tgoto(codes, 0, 0);
+ printf("%s",cls);
+ cls = codes;
+ tgetstr("cs",&cls);
+ cls = tgoto(codes, irc_lines-3, 0);
+ printf("%s",cls);
+ fflush(stdout);
+ scroll_ok = scroll_status = 1;
+}
+
+void put_insflag(flag)
+int flag;
+{
+ flag = insert;
+ tcap_move(-2, irc_columns - 5);
+ cls = codes;
+ tgetstr("mr",&cls);
+ printf("%s",codes);
+ printf((flag) ? "INS" : "OWR");
+ cls = codes;
+ tgetstr("me",&cls);
+ printf("%s",codes);
+ fflush(stdout);
+}
+
+void put_statusline()
+{
+ tcap_move (-2, 0);
+ cls = codes;
+ tgetstr("mr",&cls);
+ printf("%s",codes);
+ printf(IRCHEADER, version);
+ cls = codes;
+ tgetstr("me",&cls);
+ printf("%s",codes);
+ fflush(stdout);
+}
+
+void tcap_putline(line)
+char *line;
+{
+ char *ptr = line, *ptr2, *newl;
+ char ch='\0';
+ while (ptr) {
+ if (strlen(ptr) > irc_columns-1) {
+ ch = ptr[irc_columns-1];
+ ptr[irc_columns-1] = '\0';
+ ptr2 = &ptr[irc_columns-2];
+ }
+ else
+ ptr2 = NULL;
+ if (scroll_ok) {
+ tcap_move(irc_lines-3, 0);
+ } else {
+ tcap_move(currow++,0);
+ if (currow > irc_lines - 4) currow = 0;
+ }
+ while (newl = index(ptr,'\n'))
+ *newl = '\0';
+ printf("%s",ptr);
+ if (scroll_ok)
+ printf("\n",ptr);
+ else {
+ if (currow == 0) {
+ clear_to_eol(1,0);
+ clear_to_eol(2,0);
+ }
+ else if (currow == irc_lines - 4) {
+ clear_to_eol(irc_lines-4,0);
+ clear_to_eol(0,0);
+ }
+ else {
+ clear_to_eol(currow+1,0);
+ clear_to_eol(currow+2,0);
+ }
+ }
+ ptr = ptr2;
+ if (ptr2) {
+ *ptr2++ = '+';
+ *ptr2 = ch;
+ }
+ }
+ fflush(stdout);
+}
+
+#endif /* DO_TERMCAP */
diff --git a/irc/swear_ext.h b/irc/swear_ext.h
new file mode 100644
index 0000000..ce1c85e
--- /dev/null
+++ b/irc/swear_ext.h
@@ -0,0 +1,53 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, irc/swear_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in irc/swear.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef SWEAR_C
+#ifdef DOTERMCAP
+extern char swear_id[];
+extern int irc_lines, irc_columns, scroll_ok, scroll_status;
+#endif
+#endif /* SWEAR_C */
+
+/* External definitions for global functions.
+ */
+#ifndef SWEAR_C
+#define EXTERN extern
+#else /* SWEAR_C */
+#define EXTERN
+#endif /* SWEAR_C */
+#ifdef DOTERMCAP
+EXTERN void tcap_putch __P((int row, int col, char ch));
+EXTERN void tcap_move __P((int row, int col));
+EXTERN void clear_to_eol __P((int row, int col));
+EXTERN void clearscreen();
+EXTERN int io_on __P((int flag));
+EXTERN int io_off();
+EXTERN void scroll_ok_off();
+EXTERN void scroll_ok_on();
+EXTERN void put_insflag __P((int flag));
+EXTERN void put_statusline();
+EXTERN void tcap_putline __P((char *line));
+#endif
+#undef EXTERN
diff --git a/ircd/buildm4 b/ircd/buildm4
new file mode 100755
index 0000000..bba769c
--- /dev/null
+++ b/ircd/buildm4
@@ -0,0 +1,98 @@
+#! /bin/sh
+# IRC - Internet Relay Chat, ircd/buildm4
+# Copyright (C) 1993, 1994 Darren Reed
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 1, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+# $Id: buildm4,v 1.11 1999/02/21 00:33:45 kalt Exp $
+#
+
+#
+# If only this was a perl script...*sigh*
+#
+INCLUDE=`../support/config.guess`
+# Installation with absolute path now (Kratz)
+M4=$1
+/bin/rm -f $M4
+egrep "^#def[^P]*PATCHLEVEL" ../common/patchlevel.h | \
+sed -e 's/[^\"]*\"\([^\"]*\)\"/define(VERSION,\1)/' >>$M4
+DEBUG=`egrep "^#define[ ]*DEBUGMODE" config.h`
+if [ -n "$DEBUG" ] ; then
+ echo "define(DEBUGMODE,1)" >>$M4
+else
+ echo "undefine(DEBUGMODE)" >>$M4
+fi
+HOST="`hostname | sed -e 's/\([a-zA-Z0-9\-]*\).*/\1/'`"
+echo "define(HOSTNAME,$HOST)" >> $M4
+
+echo "define(USER,$USER)" >>$M4
+
+PORT=`egrep '^#define[ ]*PORT[ ]*[0-9]*' ../$INCLUDE/config.h | \
+ sed -e 's/[^0-9]*\([0-9]*\).*/\1/'`
+echo "define(PORT,$PORT)" >> $M4
+
+PING=`egrep '^#define[ ]*PINGFREQUENCY[ ]*[0-9]*' ../$INCLUDE/config.h\
+ | sed -e 's/[^0-9]*\([0-9]*\).*/\1/'`
+echo "define(PFREQ,$PING)" >> $M4
+
+CONT=`egrep '^#define[ ]*CONNECTFREQUENCY[ ]*[0-9]*' ../$INCLUDE/config.h\
+ | sed -e 's/[^0-9]*\([0-9]*\).*/\1/'`
+echo "define(CFREQ,$CONT)" >> $M4
+
+MAXL=`egrep '^#define[ ]*MAXIMUM_LINKS[ ]*[0-9]* | head -1' \
+ ../$INCLUDE/config.h | sed -e 's/[^0-9]*\([0-9]*\).*/\1/'`
+echo "define(MAXLINKS,$MAXL)" >> $M4
+
+DOM=`egrep '^domain' /etc/resolv.conf | \
+ sed -e 's/^domain[ ]*\([^ ]*\).*/\1/'`
+echo "define(DOMAIN,$DOM)" >> $M4
+
+cat >>$M4 <<_EOF_
+define(CL,\`ifelse(len(\$1),0,0,\$1)')
+define(MAXSENDQ,0)
+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(UID,\`ifelse(len(\$1),0,unknown,\$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:\$4:)
+define(BANIDENT,k:\$1:\$2:\`UID(\$3)':\$4:)
+define(CLASS,Y:\$1:\`PING(\$2)':\$3:\`MAX(\$4)':\`SENDQ(\$5)':\$6:\$7)
+define(CLIENT,I:\`HOST(\$1)':\`PASS(\$2)':\`ifelse(len(HOST(\$3)),0,\$1,\$3)':\
+\`APORT(\$4)':\`CL(\$5)')
+define(RESTRICTED,I:\`HOST(\$1)':\`PASS(\$2)':\
+\`ifelse(len(HOST(\$3)),0,\$1,\$3)':\`APORT(\$4)':\`CL(\$5)')
+define(BOUNCE,B:\$1::\$2:\$3:)
+define(CONNECT,C:\`HOST(\$1)':\`PASS(\$2)':\`SERV(\$3)':\
+\`CPORT(\$4)':\`CL(\$5)')
+define(EXCLUDEVERSION,V:\$1:\$2:\`ifelse(len(\$3),0,*,\$3)'::)
+define(ME,M:\$1:\$2:\$3:\$4:\$5
+P:*:*:*:\$4)
+define(HUB,H:\`ifelse(len(\$2),0,*,\$2)':*:\$1)
+define(LEAF,L:\`ifelse(len(\$2),0,*,\$2)':*:\$1:1)
+define(SERVER,\`
+CONNECT(\$1,\$2,\$3,\$5,\$6)
+ALLOW(\$1,\$2,\$3,\$4,\$6)
+')
+_EOF_
diff --git a/ircd/channel.c b/ircd/channel.c
new file mode 100644
index 0000000..752f9ee
--- /dev/null
+++ b/ircd/channel.c
@@ -0,0 +1,3396 @@
+/************************************************************************
+ * 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.
+ */
+
+/* -- Jto -- 09 Jul 1990
+ * Bug fix
+ */
+
+/* -- Jto -- 03 Jun 1990
+ * Moved m_channel() and related functions from s_msg.c to here
+ * Many changes to start changing into string channels...
+ */
+
+/* -- Jto -- 24 May 1990
+ * Moved is_full() from list.c
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: channel.c,v 1.109 1999/08/13 17:30:16 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "s_defines.h"
+#define CHANNEL_C
+#include "s_externs.h"
+#undef CHANNEL_C
+
+aChannel *channel = NullChn;
+
+static void add_invite __P((aClient *, aChannel *));
+static int can_join __P((aClient *, aChannel *, char *));
+void channel_modes __P((aClient *, char *, char *, aChannel *));
+static int check_channelmask __P((aClient *, aClient *, char *));
+static aChannel *get_channel __P((aClient *, char *, int));
+static int set_mode __P((aClient *, aClient *, aChannel *, int *, int,\
+ char **, char *,char *));
+static void free_channel __P((aChannel *));
+
+static int add_modeid __P((int, aClient *, aChannel *, char *));
+static int del_modeid __P((int, aChannel *, char *));
+static Link *match_modeid __P((int, aClient *, aChannel *));
+
+static char *PartFmt = ":%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)
+Reg Link *lp;
+{
+ Reg 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;
+Reg int *chasing;
+{
+ Reg 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, sptr->name), user);
+ return NULL;
+ }
+ if (chasing)
+ *chasing = 1;
+ return who;
+}
+
+/*
+ * 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.
+ */
+static char *check_string(s)
+Reg 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 "*".
+ */
+static char *make_nick_user_host(nick, name, host)
+Reg char *nick, *name, *host;
+{
+ static char namebuf[NICKLEN+USERLEN+HOSTLEN+6];
+ Reg 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);
+}
+
+/*
+ * Ban functions to work with mode +b/+e/+I
+ */
+/* add_modeid - add an id to the list of modes "type" for chptr
+ * (belongs to cptr)
+ */
+
+static int add_modeid(type, cptr, chptr, modeid)
+int type;
+aClient *cptr;
+aChannel *chptr;
+char *modeid;
+{
+ Reg Link *mode;
+ Reg int cnt = 0, len = 0;
+
+ if (MyClient(cptr))
+ (void) collapse(modeid);
+ for (mode = chptr->mlist; mode; mode = mode->next)
+ {
+ len += strlen(mode->value.cp);
+ if (MyClient(cptr))
+ {
+ if ((len > MAXBANLENGTH) || (++cnt >= MAXBANS))
+ {
+ sendto_one(cptr, err_str(ERR_BANLISTFULL,
+ cptr->name),
+ chptr->chname, modeid);
+ return -1;
+ }
+ if (type == mode->flags &&
+ (!match(mode->value.cp, modeid) ||
+ !match(modeid, mode->value.cp)))
+ {
+ int rpl;
+
+ if (type == CHFL_BAN)
+ rpl = RPL_BANLIST;
+ else if (type == CHFL_EXCEPTION)
+ rpl = RPL_EXCEPTLIST;
+ else
+ rpl = RPL_INVITELIST;
+
+ sendto_one(cptr, rpl_str(rpl, cptr->name),
+ chptr->chname, mode->value.cp);
+ return -1;
+ }
+ }
+ else if (type == mode->flags && !mycmp(mode->value.cp, modeid))
+ return -1;
+
+ }
+ mode = make_link();
+ istat.is_bans++;
+ bzero((char *)mode, sizeof(Link));
+ mode->flags = type;
+ mode->next = chptr->mlist;
+ mode->value.cp = (char *)MyMalloc(len = strlen(modeid)+1);
+ istat.is_banmem += len;
+ (void)strcpy(mode->value.cp, modeid);
+ chptr->mlist = mode;
+ return 0;
+}
+
+/*
+ * del_modeid - delete an id belonging to chptr
+ * if modeid is null, delete all ids belonging to chptr.
+ */
+static int del_modeid(type, chptr, modeid)
+int type;
+aChannel *chptr;
+char *modeid;
+{
+ Reg Link **mode;
+ Reg Link *tmp;
+
+ if (modeid == NULL)
+ {
+ for (mode = &(chptr->mlist); *mode; mode = &((*mode)->next))
+ if (type == (*mode)->flags)
+ {
+ tmp = *mode;
+ *mode = tmp->next;
+ istat.is_banmem -= (strlen(tmp->value.cp) + 1);
+ istat.is_bans--;
+ MyFree(tmp->value.cp);
+ free_link(tmp);
+ break;
+ }
+ }
+ else for (mode = &(chptr->mlist); *mode; mode = &((*mode)->next))
+ if (type == (*mode)->flags &&
+ mycmp(modeid, (*mode)->value.cp)==0)
+ {
+ tmp = *mode;
+ *mode = tmp->next;
+ istat.is_banmem -= (strlen(modeid) + 1);
+ istat.is_bans--;
+ MyFree(tmp->value.cp);
+ free_link(tmp);
+ break;
+ }
+ return 0;
+}
+
+/*
+ * match_modeid - returns a pointer to the mode structure if matching else NULL
+ */
+static Link *match_modeid(type, cptr, chptr)
+int type;
+aClient *cptr;
+aChannel *chptr;
+{
+ Reg Link *tmp;
+ char *s;
+
+ if (!IsPerson(cptr))
+ return NULL;
+
+ s = make_nick_user_host(cptr->name, cptr->user->username,
+ cptr->user->host);
+
+ for (tmp = chptr->mlist; tmp; tmp = tmp->next)
+ if (tmp->flags == type && match(tmp->value.cp, s) == 0)
+ break;
+
+ if (!tmp && MyConnect(cptr))
+ {
+ char *ip = NULL;
+
+#ifdef INET6
+ ip = (char *) inetntop(AF_INET6, (char *)&cptr->ip,
+ mydummy, MYDUMMY_SIZE);
+#else
+ ip = (char *) inetntoa((char *)&cptr->ip);
+#endif
+
+ if (strcmp(ip, cptr->user->host))
+ {
+ s = make_nick_user_host(cptr->name,
+ cptr->user->username, ip);
+
+ for (tmp = chptr->mlist; tmp; tmp = tmp->next)
+ if (tmp->flags == type &&
+ match(tmp->value.cp, s) == 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;
+{
+ Reg Link *ptr;
+ Reg int sz = sizeof(aChannel) + strlen(chptr->chname);
+
+ if (who->user)
+ {
+ ptr = make_link();
+ ptr->flags = flags;
+ ptr->value.cptr = who;
+ ptr->next = chptr->members;
+ chptr->members = ptr;
+ istat.is_chanusers++;
+ if (chptr->users++ == 0)
+ {
+ istat.is_chan++;
+ istat.is_chanmem += sz;
+ }
+ if (chptr->users == 1 && chptr->history)
+ {
+ /* Locked channel */
+ istat.is_hchan--;
+ istat.is_hchanmem -= sz;
+ /*
+ ** The modes had been kept, but now someone is joining,
+ ** they should be reset to avoid desynchs
+ ** (you wouldn't want to join a +i channel, either)
+ **
+ ** This can be wrong in some cases such as a netjoin
+ ** which will not complete, or on a mixed net (with
+ ** servers that don't do channel delay) - kalt
+ */
+ if (*chptr->chname != '!')
+ bzero((char *)&chptr->mode, sizeof(Mode));
+ }
+
+#ifdef USE_SERVICES
+ if (chptr->users == 1)
+ check_services_butone(SERVICE_WANT_CHANNEL|
+ SERVICE_WANT_VCHANNEL,
+ NULL, &me, "CHANNEL %s %d",
+ chptr->chname, chptr->users);
+ else
+ check_services_butone(SERVICE_WANT_VCHANNEL,
+ NULL, &me, "CHANNEL %s %d",
+ chptr->chname, chptr->users);
+#endif
+ ptr = make_link();
+ ptr->flags = flags;
+ ptr->value.chptr = chptr;
+ ptr->next = who->user->channel;
+ who->user->channel = ptr;
+ if (!IsQuiet(chptr))
+ {
+ who->user->joined++;
+ istat.is_userc++;
+ }
+
+ if (!(ptr = find_user_link(chptr->clist, who->from)))
+ {
+ ptr = make_link();
+ ptr->value.cptr = who->from;
+ ptr->next = chptr->clist;
+ chptr->clist = ptr;
+ }
+ ptr->flags++;
+ }
+}
+
+void remove_user_from_channel(sptr, chptr)
+aClient *sptr;
+aChannel *chptr;
+{
+ Reg Link **curr;
+ Reg Link *tmp, *tmp2;
+
+ for (curr = &chptr->members; (tmp = *curr); curr = &tmp->next)
+ if (tmp->value.cptr == sptr)
+ {
+ /*
+ * if a chanop leaves (no matter how), record
+ * the time to be able to later massreop if
+ * necessary.
+ */
+ if (*chptr->chname == '!' &&
+ (tmp->flags & CHFL_CHANOP))
+ chptr->reop = timeofday + LDELAYCHASETIMELIMIT;
+
+ *curr = tmp->next;
+ free_link(tmp);
+ break;
+ }
+ for (curr = &sptr->user->channel; (tmp = *curr); curr = &tmp->next)
+ if (tmp->value.chptr == chptr)
+ {
+ *curr = tmp->next;
+ free_link(tmp);
+ break;
+ }
+ if (sptr->from)
+ tmp2 = find_user_link(chptr->clist, sptr->from);
+ else
+ tmp2 = find_user_link(chptr->clist, sptr);
+ if (tmp2 && !--tmp2->flags)
+ for (curr = &chptr->clist; (tmp = *curr); curr = &tmp->next)
+ if (tmp2 == tmp)
+ {
+ *curr = tmp->next;
+ free_link(tmp);
+ break;
+ }
+ if (!IsQuiet(chptr))
+ {
+ sptr->user->joined--;
+ istat.is_userc--;
+ }
+#ifdef USE_SERVICES
+ if (chptr->users == 1)
+ check_services_butone(SERVICE_WANT_CHANNEL|
+ SERVICE_WANT_VCHANNEL, NULL, &me,
+ "CHANNEL %s %d", chptr->chname,
+ chptr->users-1);
+ else
+ check_services_butone(SERVICE_WANT_VCHANNEL, NULL, &me,
+ "CHANNEL %s %d", chptr->chname,
+ chptr->users-1);
+#endif
+ if (--chptr->users <= 0)
+ {
+ u_int sz = sizeof(aChannel) + strlen(chptr->chname);
+
+ istat.is_chan--;
+ istat.is_chanmem -= sz;
+ istat.is_hchan++;
+ istat.is_hchanmem += sz;
+ free_channel(chptr);
+ }
+ istat.is_chanusers--;
+}
+
+static void change_chan_flag(lp, chptr)
+Link *lp;
+aChannel *chptr;
+{
+ Reg Link *tmp;
+ aClient *cptr = lp->value.cptr;
+
+ /*
+ * Set the channel members flags...
+ */
+ tmp = find_user_link(chptr->members, cptr);
+ if (lp->flags & MODE_ADD)
+ tmp->flags |= lp->flags & MODE_FLAGS;
+ else
+ {
+ tmp->flags &= ~lp->flags & MODE_FLAGS;
+ if (lp->flags & CHFL_CHANOP)
+ tmp->flags &= ~CHFL_UNIQOP;
+ }
+ /*
+ * and make sure client membership mirrors channel
+ */
+ tmp = find_user_link(cptr->user->channel, (aClient *)chptr);
+ if (lp->flags & MODE_ADD)
+ tmp->flags |= lp->flags & MODE_FLAGS;
+ else
+ {
+ tmp->flags &= ~lp->flags & MODE_FLAGS;
+ if (lp->flags & CHFL_CHANOP)
+ tmp->flags &= ~CHFL_UNIQOP;
+ }
+}
+
+int is_chan_op(cptr, chptr)
+aClient *cptr;
+aChannel *chptr;
+{
+ Reg Link *lp;
+ int chanop = 0;
+
+ if (MyConnect(cptr) && IsPerson(cptr) && IsRestricted(cptr) &&
+ *chptr->chname != '&')
+ return 0;
+ if (chptr)
+ if ((lp = find_user_link(chptr->members, cptr)))
+ chanop = (lp->flags & (CHFL_CHANOP|CHFL_UNIQOP));
+ if (chanop)
+ chptr->reop = 0;
+ return chanop;
+}
+
+int has_voice(cptr, chptr)
+aClient *cptr;
+aChannel *chptr;
+{
+ Reg Link *lp;
+
+ if (chptr)
+ if ((lp = find_user_link(chptr->members, cptr)))
+ return (lp->flags & CHFL_VOICE);
+
+ return 0;
+}
+
+int can_send(cptr, chptr)
+aClient *cptr;
+aChannel *chptr;
+{
+ Reg Link *lp;
+ Reg int member;
+
+ member = IsMember(cptr, chptr);
+ lp = find_user_link(chptr->members, cptr);
+
+ if ((!lp || !(lp->flags & (CHFL_CHANOP | CHFL_VOICE))) &&
+ !match_modeid(CHFL_EXCEPTION, cptr, chptr) &&
+ match_modeid(CHFL_BAN, cptr, chptr))
+ return (MODE_BAN);
+
+ if (chptr->mode.mode & MODE_MODERATED &&
+ (!lp || !(lp->flags & (CHFL_CHANOP|CHFL_VOICE))))
+ return (MODE_MODERATED);
+
+ if (chptr->mode.mode & MODE_NOPRIVMSGS && !member)
+ return (MODE_NOPRIVMSGS);
+
+ return 0;
+}
+
+aChannel *find_channel(chname, chptr)
+Reg char *chname;
+Reg aChannel *chptr;
+{
+ aChannel *achptr = chptr;
+
+ if (chname && *chname)
+ achptr = hash_find_channel(chname, chptr);
+ return achptr;
+}
+
+void setup_server_channels(mp)
+aClient *mp;
+{
+ aChannel *chptr;
+ int smode;
+
+ smode = MODE_MODERATED|MODE_TOPICLIMIT|MODE_NOPRIVMSGS|MODE_ANONYMOUS|
+ MODE_QUIET;
+
+ chptr = get_channel(mp, "&ERRORS", CREATE);
+ strcpy(chptr->topic, "SERVER MESSAGES: server errors");
+ add_user_to_channel(chptr, mp, CHFL_CHANOP);
+ chptr->mode.mode = smode;
+ chptr = get_channel(mp, "&NOTICES", CREATE);
+ strcpy(chptr->topic, "SERVER MESSAGES: warnings and notices");
+ add_user_to_channel(chptr, mp, CHFL_CHANOP);
+ chptr->mode.mode = smode;
+ chptr = get_channel(mp, "&KILLS", CREATE);
+ strcpy(chptr->topic, "SERVER MESSAGES: operator and server kills");
+ add_user_to_channel(chptr, mp, CHFL_CHANOP);
+ chptr->mode.mode = smode;
+ chptr = get_channel(mp, "&CHANNEL", CREATE);
+ strcpy(chptr->topic, "SERVER MESSAGES: fake modes");
+ add_user_to_channel(chptr, mp, CHFL_CHANOP);
+ chptr->mode.mode = smode;
+ chptr = get_channel(mp, "&NUMERICS", CREATE);
+ strcpy(chptr->topic, "SERVER MESSAGES: numerics received");
+ add_user_to_channel(chptr, mp, CHFL_CHANOP);
+ chptr->mode.mode = smode;
+ chptr = get_channel(mp, "&SERVERS", CREATE);
+ strcpy(chptr->topic, "SERVER MESSAGES: servers joining and leaving");
+ add_user_to_channel(chptr, mp, CHFL_CHANOP);
+ chptr->mode.mode = smode;
+ chptr = get_channel(mp, "&HASH", CREATE);
+ strcpy(chptr->topic, "SERVER MESSAGES: hash tables growth");
+ add_user_to_channel(chptr, mp, CHFL_CHANOP);
+ chptr->mode.mode = smode;
+ chptr = get_channel(mp, "&LOCAL", CREATE);
+ strcpy(chptr->topic, "SERVER MESSAGES: notices about local connections");
+ add_user_to_channel(chptr, mp, CHFL_CHANOP);
+ chptr->mode.mode = smode;
+ chptr = get_channel(mp, "&SERVICES", CREATE);
+ strcpy(chptr->topic, "SERVER MESSAGES: services joining and leaving");
+ add_user_to_channel(chptr, mp, CHFL_CHANOP);
+ chptr->mode.mode = smode;
+#if defined(USE_IAUTH)
+ chptr = get_channel(mp, "&AUTH", CREATE);
+ strcpy(chptr->topic,
+ "SERVER MESSAGES: messages from the authentication slave");
+ add_user_to_channel(chptr, mp, CHFL_CHANOP);
+ chptr->mode.mode = smode;
+#endif
+ chptr = get_channel(mp, "&DEBUG", CREATE);
+ strcpy(chptr->topic, "SERVER MESSAGES: debug messages [you shouldn't be here! ;)]");
+ add_user_to_channel(chptr, mp, CHFL_CHANOP);
+ chptr->mode.mode = smode|MODE_SECRET;
+
+ setup_svchans();
+}
+
+/*
+ * write the "simple" list of channel modes for channel chptr onto buffer mbuf
+ * with the parameters in pbuf.
+ */
+void channel_modes(cptr, mbuf, pbuf, chptr)
+aClient *cptr;
+Reg char *mbuf, *pbuf;
+aChannel *chptr;
+{
+ *mbuf++ = '+';
+ if (chptr->mode.mode & MODE_SECRET)
+ *mbuf++ = 's';
+ else if (chptr->mode.mode & MODE_PRIVATE)
+ *mbuf++ = 'p';
+ if (chptr->mode.mode & MODE_MODERATED)
+ *mbuf++ = 'm';
+ if (chptr->mode.mode & MODE_TOPICLIMIT)
+ *mbuf++ = 't';
+ if (chptr->mode.mode & MODE_INVITEONLY)
+ *mbuf++ = 'i';
+ if (chptr->mode.mode & MODE_NOPRIVMSGS)
+ *mbuf++ = 'n';
+ if (chptr->mode.mode & MODE_ANONYMOUS)
+ *mbuf++ = 'a';
+ if (chptr->mode.mode & MODE_QUIET)
+ *mbuf++ = 'q';
+ if (chptr->mode.mode & MODE_REOP)
+ *mbuf++ = 'r';
+ if (chptr->mode.limit)
+ {
+ *mbuf++ = 'l';
+ if (IsMember(cptr, chptr) || IsServer(cptr))
+ SPRINTF(pbuf, "%d ", chptr->mode.limit);
+ }
+ if (*chptr->mode.key)
+ {
+ *mbuf++ = 'k';
+ if (IsMember(cptr, chptr) || IsServer(cptr))
+ (void)strcat(pbuf, chptr->mode.key);
+ }
+ *mbuf++ = '\0';
+ return;
+}
+
+static void send_mode_list(cptr, chname, top, mask, flag)
+aClient *cptr;
+Link *top;
+int mask;
+char flag, *chname;
+{
+ Reg Link *lp;
+ Reg char *cp, *name;
+ int count = 0, send = 0;
+
+ cp = modebuf + strlen(modebuf);
+ if (*parabuf) /* mode +l or +k xx */
+ count = strlen(modebuf)-1;
+ for (lp = top; lp; lp = lp->next)
+ {
+ if (!(lp->flags & mask))
+ continue;
+ if (mask == CHFL_BAN || mask == CHFL_EXCEPTION ||
+ mask == CHFL_INVITE)
+ name = lp->value.cp;
+ else
+ name = lp->value.cptr->name;
+ if (strlen(parabuf) + strlen(name) + 10 < (size_t) MODEBUFLEN)
+ {
+ (void)strcat(parabuf, " ");
+ (void)strcat(parabuf, name);
+ count++;
+ *cp++ = flag;
+ *cp = '\0';
+ }
+ else if (*parabuf)
+ send = 1;
+ if (count == 3)
+ send = 1;
+ if (send)
+ {
+ sendto_one(cptr, ":%s MODE %s %s %s",
+ ME, chname, modebuf, parabuf);
+ send = 0;
+ *parabuf = '\0';
+ cp = modebuf;
+ *cp++ = '+';
+ if (count != 3)
+ {
+ (void)strcpy(parabuf, name);
+ *cp++ = flag;
+ }
+ count = 0;
+ *cp = '\0';
+ }
+ }
+}
+
+/*
+ * send "cptr" a full list of the modes for channel chptr.
+ */
+void send_channel_modes(cptr, chptr)
+aClient *cptr;
+aChannel *chptr;
+{
+#if 0
+this is probably going to be very annoying, but leaving the following code
+uncommented may just lead to desynchs..
+ if ((*chptr->chname != '#' && *chptr->chname != '!')
+ || chptr->users == 0) /* channel is empty (locked), thus no mode */
+ return;
+#endif
+
+ if (check_channelmask(&me, cptr, chptr->chname))
+ return;
+
+ *modebuf = *parabuf = '\0';
+ channel_modes(cptr, modebuf, parabuf, chptr);
+
+ if (modebuf[1] || *parabuf)
+ sendto_one(cptr, ":%s MODE %s %s %s",
+ ME, chptr->chname, modebuf, parabuf);
+
+ *parabuf = '\0';
+ *modebuf = '+';
+ modebuf[1] = '\0';
+ send_mode_list(cptr, chptr->chname, chptr->mlist, CHFL_BAN, 'b');
+ if (cptr->serv->version & SV_NMODE)
+ {
+ if (modebuf[1] || *parabuf)
+ {
+ /* only needed to help compatibility */
+ sendto_one(cptr, ":%s MODE %s %s %s",
+ ME, chptr->chname, modebuf, parabuf);
+ *parabuf = '\0';
+ *modebuf = '+';
+ modebuf[1] = '\0';
+ }
+ send_mode_list(cptr, chptr->chname, chptr->mlist,
+ CHFL_EXCEPTION, 'e');
+ send_mode_list(cptr, chptr->chname, chptr->mlist,
+ CHFL_INVITE, 'I');
+ }
+ if (modebuf[1] || *parabuf)
+ sendto_one(cptr, ":%s MODE %s %s %s",
+ ME, chptr->chname, modebuf, parabuf);
+}
+
+/*
+ * send "cptr" a full list of the channel "chptr" members and their
+ * +ov status, using NJOIN
+ */
+void send_channel_members(cptr, chptr)
+aClient *cptr;
+aChannel *chptr;
+{
+ Reg Link *lp;
+ Reg aClient *c2ptr;
+ Reg int cnt = 0, len = 0, nlen;
+
+ if (check_channelmask(&me, cptr, chptr->chname) == -1)
+ return;
+ if (*chptr->chname == '!' && !(cptr->serv->version & SV_NCHAN))
+ return;
+
+ sprintf(buf, ":%s NJOIN %s :", ME, chptr->chname);
+ len = strlen(buf);
+
+ for (lp = chptr->members; lp; lp = lp->next)
+ {
+ c2ptr = lp->value.cptr;
+ nlen = strlen(c2ptr->name);
+ if ((len + nlen) > (size_t) (BUFSIZE - 9)) /* ,@+ \r\n\0 */
+ {
+ sendto_one(cptr, "%s", buf);
+ sprintf(buf, ":%s NJOIN %s :", ME, chptr->chname);
+ len = strlen(buf);
+ cnt = 0;
+ }
+ if (cnt)
+ {
+ buf[len++] = ',';
+ buf[len] = '\0';
+ }
+ if (lp->flags & (CHFL_UNIQOP|CHFL_CHANOP|CHFL_VOICE))
+ {
+ if (lp->flags & CHFL_UNIQOP)
+ {
+ buf[len++] = '@';
+ buf[len++] = '@';
+ }
+ else
+ {
+ if (lp->flags & CHFL_CHANOP)
+ buf[len++] = '@';
+ }
+ if (lp->flags & CHFL_VOICE)
+ buf[len++] = '+';
+ buf[len] = '\0';
+ }
+ (void)strcpy(buf + len, c2ptr->name);
+ len += nlen;
+ cnt++;
+ }
+ if (*buf && cnt)
+ sendto_one(cptr, "%s", buf);
+
+ return;
+}
+
+/*
+ * m_mode
+ * parv[0] - sender
+ * parv[1] - target; channels and/or user
+ * parv[2] - optional modes
+ * parv[n] - optional parameters
+ */
+
+int m_mode(cptr, sptr, parc, parv)
+aClient *cptr;
+aClient *sptr;
+int parc;
+char *parv[];
+{
+ int mcount = 0, chanop;
+ int penalty = 0;
+ aChannel *chptr;
+ char *name, *p = NULL;
+
+ if (parc < 1)
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]), "MODE");
+ return 1;
+ }
+
+ parv[1] = canonize(parv[1]);
+
+ for (name = strtoken(&p, parv[1], ","); name;
+ name = strtoken(&p, NULL, ","))
+ {
+ clean_channelname(name);
+ chptr = find_channel(name, NullChn);
+ if (chptr == NullChn)
+ {
+ parv[1] = name;
+ penalty += m_umode(cptr, sptr, parc, parv);
+ continue;
+ }
+ if (check_channelmask(sptr, cptr, name))
+ {
+ penalty += 1;
+ continue;
+ }
+ if (!UseModes(name))
+ {
+ sendto_one(sptr, err_str(ERR_NOCHANMODES, parv[0]),
+ name);
+ penalty += 1;
+ continue;
+ }
+ chanop = is_chan_op(sptr, chptr) || IsServer(sptr);
+
+ if (parc < 3) /* Only a query */
+ {
+ *modebuf = *parabuf = '\0';
+ modebuf[1] = '\0';
+ channel_modes(sptr, modebuf, parabuf, chptr);
+ sendto_one(sptr, rpl_str(RPL_CHANNELMODEIS, parv[0]),
+ name, modebuf, parabuf);
+ penalty += 1;
+ }
+ else /* Check parameters for the channel */
+ {
+ if(!(mcount = set_mode(cptr, sptr, chptr, &penalty,
+ parc - 2, parv + 2,
+ modebuf, parabuf)))
+ continue; /* no valid mode change */
+ if ((mcount < 0) && MyConnect(sptr) && !IsServer(sptr))
+ { /* rejected mode change */
+ int num = ERR_CHANOPRIVSNEEDED;
+
+ if (IsClient(sptr) && IsRestricted(sptr))
+ num = ERR_RESTRICTED;
+ sendto_one(sptr, err_str(num, parv[0]), name);
+ continue;
+ }
+ if (strlen(modebuf) > (size_t)1)
+ { /* got new mode to pass on */
+ if (modebuf[1] == 'e' || modebuf[1] == 'I')
+ /* 2.9.x compatibility */
+ sendto_match_servs_v(chptr, cptr,
+ SV_NMODE,
+ ":%s MODE %s %s %s",
+ parv[0], name,
+ modebuf, parabuf);
+ else
+ sendto_match_servs(chptr, cptr,
+ ":%s MODE %s %s %s",
+ parv[0], name,
+ modebuf, parabuf);
+ if ((IsServer(cptr) && !IsServer(sptr) &&
+ !chanop) || mcount < 0)
+ {
+ sendto_flag(SCH_CHAN,
+ "Fake: %s MODE %s %s %s",
+ parv[0], name, modebuf,
+ parabuf);
+ ircstp->is_fake++;
+ }
+ else
+ {
+ sendto_channel_butserv(chptr, sptr,
+ ":%s MODE %s %s %s",
+ parv[0], name,
+ modebuf, parabuf);
+#ifdef USE_SERVICES
+ *modebuf = *parabuf = '\0';
+ modebuf[1] = '\0';
+ channel_modes(&me, modebuf, parabuf,
+ chptr);
+ check_services_butone(SERVICE_WANT_MODE,
+ NULL, sptr,
+ "MODE %s %s",
+ name, modebuf);
+#endif
+ }
+ } /* if(modebuf) */
+ } /* else(parc>2) */
+ } /* for (parv1) */
+ return penalty;
+}
+
+/*
+ * Check and try to apply the channel modes passed in the parv array for
+ * the client cptr 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, penalty, parc, parv, mbuf, pbuf)
+Reg aClient *cptr, *sptr;
+aChannel *chptr;
+int parc, *penalty;
+char *parv[], *mbuf, *pbuf;
+{
+ static Link chops[MAXMODEPARAMS+3];
+ static int flags[] = {
+ MODE_PRIVATE, 'p', MODE_SECRET, 's',
+ MODE_MODERATED, 'm', MODE_NOPRIVMSGS, 'n',
+ MODE_TOPICLIMIT, 't', MODE_INVITEONLY, 'i',
+ MODE_ANONYMOUS, 'a', MODE_REOP, 'r',
+ 0x0, 0x0 };
+
+ Reg Link *lp = NULL;
+ Reg char *curr = parv[0], *cp = NULL;
+ Reg int *ip;
+ u_int whatt = MODE_ADD;
+ int limitset = 0, count = 0, chasing = 0;
+ int nusers = 0, ischop, new, len, keychange = 0, opcnt = 0;
+ aClient *who;
+ Mode *mode, oldm;
+ Link *plp = NULL;
+ int compat = -1; /* to prevent mixing old/new modes */
+
+ *mbuf = *pbuf = '\0';
+ if (parc < 1)
+ return 0;
+
+ mode = &(chptr->mode);
+ bcopy((char *)mode, (char *)&oldm, sizeof(Mode));
+ ischop = IsServer(sptr) || is_chan_op(sptr, chptr);
+ new = mode->mode;
+
+ while (curr && *curr && count >= 0)
+ {
+ if (compat == -1 && *curr != '-' && *curr != '+')
+ if (*curr == 'e' || *curr == 'I')
+ compat = 1;
+ else
+ compat = 0;
+ switch (*curr)
+ {
+ case '+':
+ whatt = MODE_ADD;
+ break;
+ case '-':
+ whatt = MODE_DEL;
+ break;
+ case 'O':
+ if (parc > 0)
+ {
+ if (*chptr->chname == '!')
+ {
+ if (IsMember(sptr, chptr))
+ {
+ *penalty += 1;
+ parc--;
+ /* Feature: no other modes after this query */
+ *(curr+1) = '\0';
+ for (lp = chptr->members; lp; lp = lp->next)
+ if (lp->flags & CHFL_UNIQOP)
+ {
+ sendto_one(sptr,
+ rpl_str(RPL_UNIQOPIS,
+ sptr->name),
+ chptr->chname,
+ lp->value.cptr->name);
+ break;
+ }
+ if (!lp)
+ sendto_one(sptr,
+ err_str(ERR_NOSUCHNICK,
+ sptr->name),
+ chptr->chname);
+ break;
+ }
+ else /* not IsMember() */
+ {
+ if (!IsServer(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOTONCHANNEL, sptr->name),
+ chptr->chname);
+ *(curr+1) = '\0';
+ break;
+ }
+ }
+ }
+ else /* *chptr->chname != '!' */
+ sendto_one(cptr, err_str(ERR_UNKNOWNMODE,
+ sptr->name), *curr, chptr->chname);
+ *(curr+1) = '\0';
+ break;
+ }
+ /*
+ * is this really ever used ?
+ * or do ^G & NJOIN do the trick?
+ */
+ if (*chptr->chname != '!' || whatt == MODE_DEL ||
+ !IsServer(sptr))
+ {
+ *penalty += 1;
+ --parc;
+ parv++;
+ break;
+ }
+ case 'o' :
+ case 'v' :
+ *penalty += 1;
+ if (--parc <= 0)
+ break;
+ parv++;
+ *parv = check_string(*parv);
+ if (opcnt >= MAXMODEPARAMS)
+#ifndef V29PlusOnly
+ if (MyClient(sptr) || opcnt >= MAXMODEPARAMS + 1)
+#endif
+ break;
+ if (!IsServer(sptr) && !IsMember(sptr, chptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOTONCHANNEL,
+ sptr->name),
+ chptr->chname);
+ 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 (!IsMember(who, chptr))
+ {
+ sendto_one(sptr, err_str(ERR_USERNOTINCHANNEL,
+ sptr->name),
+ parv[0], chptr->chname);
+ break;
+ }
+ if (who == cptr && whatt == MODE_ADD && *curr == 'o')
+ break;
+
+ if (whatt == MODE_ADD)
+ {
+ lp = &chops[opcnt++];
+ lp->value.cptr = who;
+ lp->flags = (*curr == 'O') ? MODE_UNIQOP:
+ (*curr == 'o') ? MODE_CHANOP:
+ MODE_VOICE;
+ lp->flags |= MODE_ADD;
+ }
+ else if (whatt == MODE_DEL)
+ {
+ lp = &chops[opcnt++];
+ lp->value.cptr = who;
+ lp->flags = (*curr == 'o') ? MODE_CHANOP:
+ MODE_VOICE;
+ lp->flags |= MODE_DEL;
+ }
+ if (plp && plp->flags == lp->flags &&
+ plp->value.cptr == lp->value.cptr)
+ {
+ opcnt--;
+ break;
+ }
+ plp = lp;
+ /*
+ ** If this server noticed the nick change, the
+ ** information must be propagated back upstream.
+ ** This is a bit early, but at most this will generate
+ ** just some extra messages if nick appeared more than
+ ** once in the MODE message... --msa
+ */
+/* nobody can figure this part of the code anymore.. -kalt
+ if (chasing && ischop)
+ sendto_one(cptr, ":%s MODE %s %c%c %s",
+ ME, chptr->chname,
+ whatt == MODE_ADD ? '+' : '-',
+ *curr, who->name);
+*/
+ count++;
+ *penalty += 2;
+ break;
+ case 'k':
+ *penalty += 1;
+ if (--parc <= 0)
+ break;
+ parv++;
+ /* check now so we eat the parameter if present */
+ if (keychange)
+ break;
+ {
+ Reg u_char *s;
+
+ for (s = (u_char *)*parv; *s; )
+ if (*s > 0x7f)
+ if (*s > 0xa0)
+ *s++ &= 0x7f;
+ else
+ *s = '\0';
+ else
+ s++;
+ }
+
+ if (!**parv)
+ break;
+ *parv = check_string(*parv);
+ if (opcnt >= MAXMODEPARAMS)
+#ifndef V29PlusOnly
+ if (MyClient(sptr) || opcnt >= MAXMODEPARAMS + 1)
+#endif
+ break;
+ if (whatt == MODE_ADD)
+ {
+ if (*mode->key && !IsServer(cptr))
+ sendto_one(cptr, err_str(ERR_KEYSET,
+ cptr->name), chptr->chname);
+ else if (ischop &&
+ (!*mode->key || IsServer(cptr)))
+ {
+ if (**parv == ':')
+ /* this won't propagate right*/
+ break;
+ 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 (ischop && (mycmp(mode->key, *parv) == 0 ||
+ IsServer(cptr)))
+ {
+ lp = &chops[opcnt++];
+ lp->value.cp = mode->key;
+ lp->flags = MODE_KEY|MODE_DEL;
+ keychange = 1;
+ }
+ }
+ count++;
+ *penalty += 2;
+ break;
+ case 'b':
+ *penalty += 1;
+ if (--parc <= 0) /* ban list query */
+ {
+ /* Feature: no other modes after ban query */
+ *(curr+1) = '\0'; /* Stop MODE # bb.. */
+ for (lp = chptr->mlist; lp; lp = lp->next)
+ if (lp->flags == CHFL_BAN)
+ sendto_one(cptr,
+ rpl_str(RPL_BANLIST,
+ cptr->name),
+ chptr->chname,
+ lp->value.cp);
+ sendto_one(cptr, rpl_str(RPL_ENDOFBANLIST,
+ cptr->name), chptr->chname);
+ break;
+ }
+ parv++;
+ if (BadPtr(*parv))
+ break;
+ if (opcnt >= MAXMODEPARAMS)
+#ifndef V29PlusOnly
+ if (MyClient(sptr) || opcnt >= MAXMODEPARAMS + 1)
+#endif
+ break;
+ if (whatt == MODE_ADD)
+ {
+ if (**parv == ':')
+ /* this won't propagate right */
+ break;
+ 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;
+ }
+ count++;
+ *penalty += 2;
+ break;
+ case 'e':
+ *penalty += 1;
+ if (--parc <= 0) /* exception list query */
+ {
+ /* Feature: no other modes after query */
+ *(curr+1) = '\0'; /* Stop MODE # bb.. */
+ for (lp = chptr->mlist; lp; lp = lp->next)
+ if (lp->flags == CHFL_EXCEPTION)
+ sendto_one(cptr,
+ rpl_str(RPL_EXCEPTLIST,
+ cptr->name),
+ chptr->chname,
+ lp->value.cp);
+ sendto_one(cptr, rpl_str(RPL_ENDOFEXCEPTLIST,
+ cptr->name), chptr->chname);
+ break;
+ }
+ parv++;
+ if (BadPtr(*parv))
+ break;
+ if (opcnt >= MAXMODEPARAMS)
+#ifndef V29PlusOnly
+ if (MyClient(sptr) || opcnt >= MAXMODEPARAMS + 1)
+#endif
+ break;
+ if (whatt == MODE_ADD)
+ {
+ if (**parv == ':')
+ /* this won't propagate right */
+ break;
+ lp = &chops[opcnt++];
+ lp->value.cp = *parv;
+ lp->flags = MODE_ADD|MODE_EXCEPTION;
+ }
+ else if (whatt == MODE_DEL)
+ {
+ lp = &chops[opcnt++];
+ lp->value.cp = *parv;
+ lp->flags = MODE_DEL|MODE_EXCEPTION;
+ }
+ count++;
+ *penalty += 2;
+ break;
+ case 'I':
+ *penalty += 1;
+ if (--parc <= 0) /* invite list query */
+ {
+ /* Feature: no other modes after query */
+ *(curr+1) = '\0'; /* Stop MODE # bb.. */
+ for (lp = chptr->mlist; lp; lp = lp->next)
+ if (lp->flags == CHFL_INVITE)
+ sendto_one(cptr,
+ rpl_str(RPL_INVITELIST,
+ cptr->name),
+ chptr->chname,
+ lp->value.cp);
+ sendto_one(cptr, rpl_str(RPL_ENDOFINVITELIST,
+ cptr->name), chptr->chname);
+ break;
+ }
+ parv++;
+ if (BadPtr(*parv))
+ break;
+ if (opcnt >= MAXMODEPARAMS)
+#ifndef V29PlusOnly
+ if (MyClient(sptr) || opcnt >= MAXMODEPARAMS + 1)
+#endif
+ break;
+ if (whatt == MODE_ADD)
+ {
+ if (**parv == ':')
+ /* this won't propagate right */
+ break;
+ lp = &chops[opcnt++];
+ lp->value.cp = *parv;
+ lp->flags = MODE_ADD|MODE_INVITE;
+ }
+ else if (whatt == MODE_DEL)
+ {
+ lp = &chops[opcnt++];
+ lp->value.cp = *parv;
+ lp->flags = MODE_DEL|MODE_INVITE;
+ }
+ count++;
+ *penalty += 2;
+ break;
+ case 'l':
+ *penalty += 1;
+ /*
+ * limit 'l' to only *1* change per mode command but
+ * eat up others.
+ */
+ if (limitset || !ischop)
+ {
+ if (whatt == MODE_ADD && --parc > 0)
+ parv++;
+ break;
+ }
+ if (whatt == MODE_DEL)
+ {
+ limitset = 1;
+ nusers = 0;
+ count++;
+ break;
+ }
+ if (--parc > 0)
+ {
+ if (BadPtr(*parv))
+ break;
+ if (opcnt >= MAXMODEPARAMS)
+#ifndef V29PlusOnly
+ if (MyClient(sptr) ||
+ opcnt >= MAXMODEPARAMS + 1)
+#endif
+ break;
+ if (!(nusers = atoi(*++parv)))
+ break;
+ lp = &chops[opcnt++];
+ lp->flags = MODE_ADD|MODE_LIMIT;
+ limitset = 1;
+ count++;
+ *penalty += 2;
+ break;
+ }
+ sendto_one(cptr, err_str(ERR_NEEDMOREPARAMS,
+ cptr->name), "MODE +l");
+ break;
+ case 'i' : /* falls through for default case */
+ if (whatt == MODE_DEL)
+ while ((lp = chptr->invites))
+ del_invite(lp->value.cptr, chptr);
+ default:
+ *penalty += 1;
+ for (ip = flags; *ip; ip += 2)
+ if (*(ip+1) == *curr)
+ break;
+
+ if (*ip)
+ {
+ if (*ip == MODE_ANONYMOUS &&
+ whatt == MODE_DEL && *chptr->chname == '!')
+ sendto_one(sptr,
+ err_str(ERR_UNIQOPRIVSNEEDED,
+ sptr->name), chptr->chname);
+ else if (((*ip == MODE_ANONYMOUS &&
+ whatt == MODE_ADD &&
+ *chptr->chname == '#') ||
+ (*ip == MODE_REOP &&
+ *chptr->chname != '!')) &&
+ !IsServer(sptr))
+ sendto_one(cptr,
+ err_str(ERR_UNKNOWNMODE,
+ sptr->name), *curr,
+ chptr->chname);
+ else if ((*ip == MODE_REOP ||
+ *ip == MODE_ANONYMOUS) &&
+ !IsServer(sptr) &&
+ !(is_chan_op(sptr,chptr) &CHFL_UNIQOP)
+ && *chptr->chname == '!')
+ /* 2 modes restricted to UNIQOP */
+ sendto_one(sptr,
+ err_str(ERR_UNIQOPRIVSNEEDED,
+ sptr->name), chptr->chname);
+ else
+ {
+ /*
+ ** If the channel is +s, ignore +p
+ ** modes coming from a server.
+ ** (Otherwise, it's desynch'ed) -kalt
+ */
+ if (whatt == MODE_ADD &&
+ *ip == MODE_PRIVATE &&
+ IsServer(sptr) &&
+ (new & MODE_SECRET))
+ break;
+ if (whatt == MODE_ADD)
+ {
+ if (*ip == MODE_PRIVATE)
+ new &= ~MODE_SECRET;
+ else if (*ip == MODE_SECRET)
+ new &= ~MODE_PRIVATE;
+ new |= *ip;
+ }
+ else
+ new &= ~*ip;
+ count++;
+ *penalty += 2;
+ }
+ }
+ else if (!IsServer(cptr))
+ sendto_one(cptr, err_str(ERR_UNKNOWNMODE,
+ cptr->name), *curr, chptr->chname);
+ break;
+ }
+ curr++;
+ /*
+ * Make sure modes strings such as "+m +t +p +i" are parsed
+ * fully.
+ */
+ if (!*curr && parc > 0)
+ {
+ curr = *++parv;
+ parc--;
+ }
+ /*
+ * Make sure old and new (+e/+I) modes won't get mixed
+ * together on the same line
+ */
+ if (MyClient(sptr) && curr && *curr != '-' && *curr != '+')
+ if (*curr == 'e' || *curr == 'I')
+ {
+ if (compat == 0)
+ *curr = '\0';
+ }
+ else if (compat == 1)
+ *curr = '\0';
+ } /* end of while loop for MODE processing */
+
+ whatt = 0;
+
+ for (ip = flags; *ip; ip += 2)
+ if ((*ip & new) && !(*ip & oldm.mode))
+ {
+ if (whatt == 0)
+ {
+ *mbuf++ = '+';
+ whatt = 1;
+ }
+ if (ischop)
+ {
+ mode->mode |= *ip;
+ if (*ip == MODE_ANONYMOUS && MyPerson(sptr))
+ {
+ sendto_channel_butone(NULL, &me, chptr, ":%s NOTICE %s :The anonymous flag is being set on channel %s.", ME, chptr->chname, chptr->chname);
+ sendto_channel_butone(NULL, &me, chptr, ":%s NOTICE %s :Be aware that anonymity on IRC is NOT securely enforced!", ME, chptr->chname);
+ }
+ }
+ *mbuf++ = *(ip+1);
+ }
+
+ for (ip = flags; *ip; ip += 2)
+ if ((*ip & oldm.mode) && !(*ip & new))
+ {
+ if (whatt != -1)
+ {
+ *mbuf++ = '-';
+ whatt = -1;
+ }
+ if (ischop)
+ mode->mode &= ~*ip;
+ *mbuf++ = *(ip+1);
+ }
+
+ if (limitset && !nusers && mode->limit)
+ {
+ if (whatt != -1)
+ {
+ *mbuf++ = '-';
+ whatt = -1;
+ }
+ mode->mode &= ~MODE_LIMIT;
+ mode->limit = 0;
+ *mbuf++ = 'l';
+ }
+
+ /*
+ * Reconstruct "+beIkOov" chain.
+ */
+ if (opcnt)
+ {
+ Reg int i = 0;
+ Reg char c = '\0';
+ char *user, *host, numeric[16];
+
+/* if (opcnt > MAXMODEPARAMS)
+ opcnt = MAXMODEPARAMS;
+*/
+ 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++ = '+';
+ whatt = MODE_ADD;
+ }
+ else
+ {
+ *mbuf++ = '-';
+ whatt = MODE_DEL;
+ }
+ len = strlen(pbuf);
+ /*
+ * get c as the mode char and tmp as a pointer to
+ * the paramter for this mode change.
+ */
+ switch(lp->flags & MODE_WPARAS)
+ {
+ case MODE_CHANOP :
+ c = 'o';
+ cp = lp->value.cptr->name;
+ break;
+ case MODE_UNIQOP :
+ c = 'O';
+ cp = lp->value.cptr->name;
+ break;
+ case MODE_VOICE :
+ c = 'v';
+ cp = lp->value.cptr->name;
+ break;
+ case MODE_BAN :
+ c = 'b';
+ cp = lp->value.cp;
+ if ((user = index(cp, '!')))
+ *user++ = '\0';
+ if ((host = rindex(user ? user : cp, '@')))
+ *host++ = '\0';
+ cp = make_nick_user_host(cp, user, host);
+ if (user)
+ *(--user) = '!';
+ if (host)
+ *(--host) = '@';
+ break;
+ case MODE_EXCEPTION :
+ c = 'e';
+ cp = lp->value.cp;
+ if ((user = index(cp, '!')))
+ *user++ = '\0';
+ if ((host = rindex(user ? user : cp, '@')))
+ *host++ = '\0';
+ cp = make_nick_user_host(cp, user, host);
+ if (user)
+ *(--user) = '!';
+ if (host)
+ *(--host) = '@';
+ break;
+ case MODE_INVITE :
+ c = 'I';
+ cp = lp->value.cp;
+ if ((user = index(cp, '!')))
+ *user++ = '\0';
+ if ((host = rindex(user ? user : cp, '@')))
+ *host++ = '\0';
+ cp = make_nick_user_host(cp, user, host);
+ if (user)
+ *(--user) = '!';
+ if (host)
+ *(--host) = '@';
+ 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) + 2 > (size_t) MODEBUFLEN)
+ break;
+ /*
+ * pass on +/-o/v regardless of whether they are
+ * redundant or effective but check +b's to see if
+ * it existed before we created it.
+ */
+ switch(lp->flags & MODE_WPARAS)
+ {
+ case MODE_KEY :
+ *mbuf++ = c;
+ (void)strcat(pbuf, cp);
+ len += strlen(cp);
+ (void)strcat(pbuf, " ");
+ len++;
+ if (!ischop)
+ break;
+ if (strlen(cp) > (size_t) KEYLEN)
+ *(cp+KEYLEN) = '\0';
+ if (whatt == MODE_ADD)
+ strncpyzt(mode->key, cp,
+ sizeof(mode->key));
+ else
+ *mode->key = '\0';
+ break;
+ case MODE_LIMIT :
+ *mbuf++ = c;
+ (void)strcat(pbuf, cp);
+ len += strlen(cp);
+ (void)strcat(pbuf, " ");
+ len++;
+ if (!ischop)
+ break;
+ mode->limit = nusers;
+ break;
+ case MODE_CHANOP : /* fall through case */
+ if (ischop && lp->value.cptr == sptr &&
+ lp->flags == MODE_CHANOP|MODE_DEL)
+ chptr->reop = timeofday +
+ LDELAYCHASETIMELIMIT;
+ case MODE_UNIQOP :
+ case MODE_VOICE :
+ *mbuf++ = c;
+ (void)strcat(pbuf, cp);
+ len += strlen(cp);
+ (void)strcat(pbuf, " ");
+ len++;
+ if (ischop)
+ change_chan_flag(lp, chptr);
+ break;
+ case MODE_BAN :
+ if (ischop &&
+ (((whatt & MODE_ADD) &&
+ !add_modeid(CHFL_BAN, sptr, chptr, cp))||
+ ((whatt & MODE_DEL) &&
+ !del_modeid(CHFL_BAN, chptr, cp))))
+ {
+ *mbuf++ = c;
+ (void)strcat(pbuf, cp);
+ len += strlen(cp);
+ (void)strcat(pbuf, " ");
+ len++;
+ }
+ break;
+ case MODE_EXCEPTION :
+ if (ischop &&
+ (((whatt & MODE_ADD) &&
+ !add_modeid(CHFL_EXCEPTION, sptr, chptr, cp))||
+ ((whatt & MODE_DEL) &&
+ !del_modeid(CHFL_EXCEPTION, chptr, cp))))
+ {
+ *mbuf++ = c;
+ (void)strcat(pbuf, cp);
+ len += strlen(cp);
+ (void)strcat(pbuf, " ");
+ len++;
+ }
+ break;
+ case MODE_INVITE :
+ if (ischop &&
+ (((whatt & MODE_ADD) &&
+ !add_modeid(CHFL_INVITE, sptr, chptr, cp))||
+ ((whatt & MODE_DEL) &&
+ !del_modeid(CHFL_INVITE, chptr, cp))))
+ {
+ *mbuf++ = c;
+ (void)strcat(pbuf, cp);
+ len += strlen(cp);
+ (void)strcat(pbuf, " ");
+ len++;
+ }
+ break;
+ }
+ } /* for (; i < opcnt; i++) */
+ } /* if (opcnt) */
+
+ *mbuf++ = '\0';
+
+ return ischop ? count : -count;
+}
+
+static int can_join(sptr, chptr, key)
+aClient *sptr;
+Reg aChannel *chptr;
+char *key;
+{
+ Link *lp = NULL, *banned;
+
+ if (chptr->users == 0 && (bootopt & BOOT_PROT) &&
+ chptr->history != 0 && *chptr->chname != '!')
+ return (timeofday > chptr->history) ? 0 : ERR_UNAVAILRESOURCE;
+
+ for (lp = sptr->user->invited; lp; lp = lp->next)
+ if (lp->value.chptr == chptr)
+ break;
+
+ if (banned = match_modeid(CHFL_BAN, sptr, chptr))
+ if (match_modeid(CHFL_EXCEPTION, sptr, chptr))
+ banned = NULL;
+ else if (lp == NULL)
+ return (ERR_BANNEDFROMCHAN);
+
+ if ((chptr->mode.mode & MODE_INVITEONLY)
+ && !match_modeid(CHFL_INVITE, sptr, chptr)
+ && (lp == NULL))
+ return (ERR_INVITEONLYCHAN);
+
+ if (*chptr->mode.key && (BadPtr(key) || mycmp(chptr->mode.key, key)))
+ return (ERR_BADCHANNELKEY);
+
+ if (chptr->mode.limit && (chptr->users >= chptr->mode.limit) &&
+ (lp == NULL))
+ return (ERR_CHANNELISFULL);
+
+ if (banned)
+ sendto_channel_butone(&me, &me, chptr,
+ ":%s NOTICE %s :%s carries an invitation (overriding ban on %s).",
+ ME, chptr->chname, sptr->name,
+ banned->value.cp);
+ return 0;
+}
+
+/*
+** Remove bells and commas from channel name
+*/
+
+void clean_channelname(cn)
+Reg char *cn;
+{
+ for (; *cn; cn++)
+ if (*cn == '\007' || *cn == ' ' || *cn == ',')
+ {
+ *cn = '\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;
+{
+ Reg char *s, *t;
+
+ if (*chname == '&' && IsServer(cptr))
+ return -1;
+ s = rindex(chname, ':');
+ if (!s)
+ return 0;
+ if ((t = index(s, '\007')))
+ *t = '\0';
+
+ s++;
+ if (match(s, ME) || (IsServer(cptr) && match(s, cptr->name)))
+ {
+ if (MyClient(sptr))
+ sendto_one(sptr, err_str(ERR_BADCHANMASK, sptr->name),
+ chname);
+ if (t)
+ *t = '\007';
+ return -1;
+ }
+ if (t)
+ *t = '\007';
+ 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;
+ {
+ Reg 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->history = 0;
+ channel = chptr;
+ (void)add_to_channel_hash_table(chname, chptr);
+ }
+ return chptr;
+ }
+
+static void add_invite(cptr, chptr)
+aClient *cptr;
+aChannel *chptr;
+{
+ Reg Link *inv, **tmp;
+
+ del_invite(cptr, chptr);
+ /*
+ * delete last link in chain if the list is max length
+ */
+ if (list_length(cptr->user->invited) >= MAXCHANNELSPERUSER)
+ {
+/* This forgets the channel side of invitation -Vesa
+ inv = cptr->user->invited;
+ cptr->user->invited = inv->next;
+ free_link(inv);
+*/
+ del_invite(cptr, cptr->user->invited->value.chptr);
+ }
+ /*
+ * add client to channel invite list
+ */
+ inv = make_link();
+ inv->value.cptr = cptr;
+ inv->next = chptr->invites;
+ chptr->invites = inv;
+ istat.is_useri++;
+ /*
+ * add channel to the end of the client invite list
+ */
+ for (tmp = &(cptr->user->invited); *tmp; tmp = &((*tmp)->next))
+ ;
+ inv = make_link();
+ inv->value.chptr = chptr;
+ inv->next = NULL;
+ (*tmp) = inv;
+ istat.is_invite++;
+}
+
+/*
+ * Delete Invite block from channel invite list and client invite list
+ */
+void del_invite(cptr, chptr)
+aClient *cptr;
+aChannel *chptr;
+{
+ Reg Link **inv, *tmp;
+
+ for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
+ if (tmp->value.cptr == cptr)
+ {
+ *inv = tmp->next;
+ free_link(tmp);
+ istat.is_invite--;
+ break;
+ }
+
+ for (inv = &(cptr->user->invited); (tmp = *inv); inv = &tmp->next)
+ if (tmp->value.chptr == chptr)
+ {
+ *inv = tmp->next;
+ free_link(tmp);
+ istat.is_useri--;
+ break;
+ }
+}
+
+/*
+** The last user has left the channel, free data in the channel block,
+** and eventually the channel block itself.
+*/
+static void free_channel(chptr)
+aChannel *chptr;
+{
+ Reg Link *tmp;
+ Link *obtmp;
+ int len = sizeof(aChannel) + strlen(chptr->chname), now = 0;
+
+ if (chptr->history == 0 || timeofday >= chptr->history)
+ /* no lock, nor expired lock, channel is no more, free it */
+ now = 1;
+
+ if (*chptr->chname != '!' || now)
+ {
+ while ((tmp = chptr->invites))
+ del_invite(tmp->value.cptr, chptr);
+
+ tmp = chptr->mlist;
+ while (tmp)
+ {
+ obtmp = tmp;
+ tmp = tmp->next;
+ istat.is_banmem -= (strlen(obtmp->value.cp) + 1);
+ istat.is_bans--;
+ MyFree(obtmp->value.cp);
+ free_link(obtmp);
+ }
+ chptr->mlist = NULL;
+ }
+
+ if (now)
+ {
+ istat.is_hchan--;
+ istat.is_hchanmem -= len;
+ if (chptr->prevch)
+ chptr->prevch->nextch = chptr->nextch;
+ else
+ channel = chptr->nextch;
+ if (chptr->nextch)
+ chptr->nextch->prevch = chptr->prevch;
+ del_from_channel_hash_table(chptr->chname, chptr);
+
+ if (*chptr->chname == '!' && close_chid(chptr->chname+1))
+ cache_chid(chptr);
+ else
+ MyFree((char *)chptr);
+ }
+}
+
+/*
+** m_join
+** parv[0] = sender prefix
+** parv[1] = channel
+** parv[2] = channel password (key)
+*/
+int m_join(cptr, sptr, parc, parv)
+Reg aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+ static char jbuf[BUFSIZE], cbuf[BUFSIZE];
+ Reg Link *lp;
+ Reg aChannel *chptr;
+ Reg char *name, *key = NULL;
+ int i, flags = 0;
+ char *p = NULL, *p2 = NULL, *s, chop[5];
+
+ if (parc < 2 || *parv[1] == '\0')
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]), "JOIN");
+ return 1;
+ }
+
+ *jbuf = '\0';
+ *cbuf = '\0';
+ /*
+ ** Rebuild list of channels joined to be the actual result of the
+ ** JOIN. Note that "JOIN 0" is the destructive problem.
+ ** Also note that this can easily trash the correspondance between
+ ** parv[1] and parv[2] lists.
+ */
+ for (i = 0, name = strtoken(&p, parv[1], ","); name;
+ name = strtoken(&p, NULL, ","))
+ {
+ if (check_channelmask(sptr, cptr, name)==-1)
+ continue;
+ if (*name == '&' && !MyConnect(sptr))
+ continue;
+ if (*name == '0' && !atoi(name))
+ {
+ (void)strcpy(jbuf, "0");
+ continue;
+ }
+ if (*name == '!')
+ {
+ chptr = NULL;
+ /*
+ ** !channels are special:
+ ** !!channel is supposed to be a new channel,
+ ** and requires a unique name to be built.
+ ** ( !#channel is obsolete )
+ ** !channel cannot be created, and must already
+ ** exist.
+ */
+ if (*(name+1) == '\0' ||
+ (*(name+1) == '#' && *(name+2) == '\0') ||
+ (*(name+1) == '!' && *(name+2) == '\0'))
+ {
+ if (MyClient(sptr))
+ sendto_one(sptr,
+ err_str(ERR_NOSUCHCHANNEL,
+ parv[0]), name);
+ continue;
+ }
+ if (*name == '!' && (*(name+1) == '#' ||
+ *(name+1) == '!'))
+ {
+ if (!MyClient(sptr))
+ {
+ sendto_flag(SCH_NOTICE,
+ "Invalid !%c channel from %s for %s",
+ *(name+1),
+ get_client_name(cptr,TRUE),
+ sptr->name);
+ continue;
+ }
+#if 0
+ /*
+ ** Note: creating !!!foo, e.g. !<ID>!foo is
+ ** a stupid thing to do because /join !!foo
+ ** will not join !<ID>!foo but create !<ID>foo
+ ** Some logic here could be reversed, but only
+ ** to find that !<ID>foo would be impossible to
+ ** create if !<ID>!foo exists.
+ ** which is better? it's hard to say -kalt
+ */
+ if (*(name+3) == '!')
+ {
+ sendto_one(sptr,
+ err_str(ERR_NOSUCHCHANNEL,
+ parv[0]), name);
+ continue;
+ }
+#endif
+ chptr = hash_find_channels(name+2, NULL);
+ if (chptr)
+ {
+ sendto_one(sptr,
+ err_str(ERR_TOOMANYTARGETS,
+ parv[0]),
+ "Duplicate", name,
+ "Join aborted.");
+ continue;
+ }
+ if (check_chid(name+2))
+ {
+ /*
+ * This is a bit wrong: if a channel
+ * rightfully ceases to exist, it
+ * can still be *locked* for up to
+ * 2*CHIDNB^3 seconds (~24h)
+ * Is it a reasonnable price to pay to
+ * ensure shortname uniqueness? -kalt
+ */
+ sendto_one(sptr,
+ err_str(ERR_UNAVAILRESOURCE,
+ parv[0]), name);
+ continue;
+ }
+ sprintf(buf, "!%.*s%s", CHIDLEN, get_chid(),
+ name+2);
+ name = buf;
+ }
+ else if (!find_channel(name, NullChn) &&
+ !(*name == '!' && *name != 0 &&
+ (chptr = hash_find_channels(name+1, NULL))))
+ {
+ if (MyClient(sptr))
+ sendto_one(sptr,
+ err_str(ERR_NOSUCHCHANNEL,
+ parv[0]), name);
+ if (!IsServer(cptr))
+ continue;
+ /* from a server, it is legitimate */
+ }
+ else if (chptr)
+ {
+ /* joining a !channel using the short name */
+ if (MyConnect(sptr) &&
+ hash_find_channels(name+1, chptr))
+ {
+ sendto_one(sptr,
+ err_str(ERR_TOOMANYTARGETS,
+ parv[0]),
+ "Duplicate", name,
+ "Join aborted.");
+ continue;
+ }
+ name = chptr->chname;
+ }
+ }
+ if (!IsChannelName(name) ||
+ (*name == '!' && IsChannelName(name+1)))
+ {
+ if (MyClient(sptr))
+ sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL,
+ parv[0]), name);
+ continue;
+ }
+ if (*jbuf)
+ (void)strcat(jbuf, ",");
+ (void)strncat(jbuf, name, sizeof(jbuf) - i - 1);
+ i += strlen(name)+1;
+ }
+
+ 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))
+ {
+ if (sptr->user->channel == NULL)
+ continue;
+ while ((lp = sptr->user->channel))
+ {
+ chptr = lp->value.chptr;
+ sendto_channel_butserv(chptr, sptr,
+ PartFmt,
+ parv[0], chptr->chname,
+ IsAnonymous(chptr) ? "None" :
+ (key ? key : parv[0]));
+ remove_user_from_channel(sptr, chptr);
+ }
+ sendto_match_servs(NULL, cptr, ":%s JOIN 0 :%s",
+ parv[0], key ? key : parv[0]);
+ continue;
+ }
+
+ if (cptr->serv && (s = index(name, '\007')))
+ *s++ = '\0';
+ else
+ clean_channelname(name), s = NULL;
+
+ if (MyConnect(sptr) &&
+ sptr->user->joined >= MAXCHANNELSPERUSER) {
+ /* Feature: Cannot join &flagchannels either
+ if already joined MAXCHANNELSPERUSER times. */
+ sendto_one(sptr, err_str(ERR_TOOMANYCHANNELS,
+ parv[0]), name);
+ /* can't return, need to send the info everywhere */
+ continue;
+ }
+
+ chptr = get_channel(sptr, name, CREATE);
+
+ if (IsMember(sptr, chptr))
+ continue;
+ if (!chptr ||
+ (MyConnect(sptr) && (i = can_join(sptr, chptr, key))))
+ {
+ sendto_one(sptr, err_str(i, parv[0]), name);
+ continue;
+ }
+
+ /*
+ ** local client is first to enter previously nonexistant
+ ** channel so make them (rightfully) the Channel
+ ** Operator.
+ */
+ flags = 0;
+ chop[0] = '\0';
+ if (MyConnect(sptr) && UseModes(name) &&
+ (!IsRestricted(sptr) || (*name == '&')) && !chptr->users &&
+ !(chptr->history && *chptr->chname == '!'))
+ {
+ if (*name == '!')
+ strcpy(chop, "\007O");
+ else
+ strcpy(chop, "\007o");
+ s = chop+1; /* tricky */
+ }
+ /*
+ ** Complete user entry to the new channel (if any)
+ */
+ if (s && UseModes(name))
+ {
+ if (*s == 'O')
+ /*
+ * there can never be another mode here,
+ * because we use NJOIN for netjoins.
+ * here, it *must* be a channel creation. -kalt
+ */
+ flags |= CHFL_UNIQOP|CHFL_CHANOP;
+ else if (*s == 'o')
+ {
+ flags |= CHFL_CHANOP;
+ if (*(s+1) == 'v')
+ flags |= CHFL_VOICE;
+ }
+ else if (*s == 'v')
+ flags |= CHFL_VOICE;
+ }
+ add_user_to_channel(chptr, sptr, flags);
+ /*
+ ** notify all users on the channel
+ */
+ sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s",
+ parv[0], name);
+ if (s && UseModes(name))
+ {
+ /* no need if user is creating the channel */
+ if (chptr->users != 1)
+ sendto_channel_butserv(chptr, sptr,
+ ":%s MODE %s +%s %s %s",
+ cptr->name, name, s,
+ parv[0],
+ *(s+1)=='v'?parv[0]:"");
+ *--s = '\007';
+ }
+ /*
+ ** If s wasn't set to chop+1 above, name is now #chname^Gov
+ ** again (if coming from a server, and user is +o and/or +v
+ ** of course ;-)
+ ** This explains the weird use of name and chop..
+ ** Is this insane or subtle? -krys
+ */
+ if (MyClient(sptr))
+ {
+ del_invite(sptr, chptr);
+ if (chptr->topic[0] != '\0')
+ sendto_one(sptr, rpl_str(RPL_TOPIC, parv[0]),
+ name, chptr->topic);
+ parv[1] = name;
+ (void)m_names(cptr, sptr, 2, parv);
+ if (IsAnonymous(chptr) && !IsQuiet(chptr))
+ {
+ sendto_one(sptr, ":%s NOTICE %s :Channel %s has the anonymous flag set.", ME, chptr->chname, chptr->chname);
+ sendto_one(sptr, ":%s NOTICE %s :Be aware that anonymity on IRC is NOT securely enforced!", ME, chptr->chname);
+ }
+ }
+ /*
+ ** notify other servers
+ */
+ if (index(name, ':') || *chptr->chname == '!') /* compat */
+ sendto_match_servs(chptr, cptr, ":%s JOIN :%s%s",
+ parv[0], name, chop);
+ else if (*chptr->chname != '&')
+ {
+ if (*cbuf)
+ strcat(cbuf, ",");
+ strcat(cbuf, name);
+ if (chop)
+ strcat(cbuf, chop);
+ }
+ }
+ if (*cbuf)
+ sendto_serv_butone(cptr, ":%s JOIN :%s", parv[0], cbuf);
+ return 2;
+}
+
+/*
+** m_njoin
+** parv[0] = sender prefix
+** parv[1] = channel
+** parv[2] = channel members and modes
+*/
+int m_njoin(cptr, sptr, parc, parv)
+Reg aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+ char nbuf[BUFSIZE], *q, *name, *target, *p, mbuf[4];
+ int chop, cnt = 0, nj = 0;
+ aChannel *chptr = NULL;
+ aClient *acptr;
+
+ if (parc < 3 || *parv[2] == '\0')
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]),"NJOIN");
+ return 1;
+ }
+ *nbuf = '\0'; q = nbuf;
+ for (target = strtoken(&p, parv[2], ","); target;
+ target = strtoken(&p, NULL, ","))
+ {
+ /* check for modes */
+ chop = 0;
+ mbuf[0] = '\0';
+ if (*target == '@')
+ {
+ if (*(target+1) == '@')
+ {
+ /* actually never sends in a JOIN ^G */
+ if (*(target+2) == '+')
+ {
+ strcpy(mbuf, "\007Ov");
+ chop = CHFL_UNIQOP|CHFL_CHANOP| \
+ CHFL_VOICE;
+ name = target + 3;
+ }
+ else
+ {
+ strcpy(mbuf, "\007O");
+ chop = CHFL_UNIQOP|CHFL_CHANOP;
+ name = target + 2;
+ }
+ }
+ else
+ {
+ if (*(target+1) == '+')
+ {
+ strcpy(mbuf, "\007ov");
+ chop = CHFL_CHANOP|CHFL_VOICE;
+ name = target+2;
+ }
+ else
+ {
+ strcpy(mbuf, "\007o");
+ chop = CHFL_CHANOP;
+ name = target+1;
+ }
+ }
+ }
+ else if (*target == '+')
+ {
+ strcpy(mbuf, "\007v");
+ chop = CHFL_VOICE;
+ name = target+1;
+ }
+ else
+ name = target;
+ /* find user */
+ if (!(acptr = find_person(name, (aClient *)NULL)))
+ continue;
+ /* is user who we think? */
+ if (acptr->from != cptr)
+ continue;
+ /* get channel pointer */
+ if (!chptr)
+ {
+ if (check_channelmask(sptr, cptr, parv[1]) == -1)
+ {
+ sendto_flag(SCH_DEBUG,
+ "received NJOIN for %s from %s",
+ parv[1],
+ get_client_name(cptr, TRUE));
+ return 0;
+ }
+ chptr = get_channel(acptr, parv[1], CREATE);
+ if (!IsChannelName(parv[1]) || chptr == NULL)
+ {
+ sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL,
+ parv[0]), parv[1]);
+ return 0;
+ }
+ }
+ /* make sure user isn't already on channel */
+ if (IsMember(acptr, chptr))
+ {
+ sendto_flag(SCH_ERROR, "NJOIN protocol error from %s",
+ get_client_name(cptr, TRUE));
+ sendto_one(cptr, "ERROR :NJOIN protocol error");
+ continue;
+ }
+ /* add user to channel */
+ add_user_to_channel(chptr, acptr, UseModes(parv[1]) ? chop :0);
+ /* build buffer for NJOIN capable servers */
+ if (q != nbuf)
+ *q++ = ',';
+ while (*target)
+ *q++ = *target++;
+ /* send 2.9 style join to other servers */
+ if (*chptr->chname != '!')
+ nj = sendto_match_servs_notv(chptr, cptr, SV_NJOIN,
+ ":%s JOIN %s%s", name,
+ parv[1],
+ UseModes(parv[1]) ? mbuf :
+ "");
+ /* send join to local users on channel */
+ sendto_channel_butserv(chptr, acptr, ":%s JOIN %s", name,
+ parv[1]);
+ /* build MODE for local users on channel, eventually send it */
+ if (*mbuf)
+ {
+ if (!UseModes(parv[1]))
+ {
+ sendto_one(cptr, err_str(ERR_NOCHANMODES,
+ parv[0]), parv[1]);
+ continue;
+ }
+ switch (cnt)
+ {
+ case 0:
+ *parabuf = '\0'; *modebuf = '\0';
+ /* fall through */
+ case 1:
+ strcat(modebuf, mbuf+1);
+ cnt += strlen(mbuf+1);
+ if (*parabuf)
+ {
+ strcat(parabuf, " ");
+ }
+ strcat(parabuf, name);
+ if (mbuf[2])
+ {
+ strcat(parabuf, " ");
+ strcat(parabuf, name);
+ }
+ break;
+ case 2:
+ sendto_channel_butserv(chptr, &me,
+ ":%s MODE %s +%s%c %s %s",
+ sptr->name, parv[1],
+ modebuf, mbuf[1],
+ parabuf, name);
+ if (mbuf[2])
+ {
+ strcpy(modebuf, mbuf+2);
+ strcpy(parabuf, name);
+ cnt = 1;
+ }
+ else
+ cnt = 0;
+ break;
+ }
+ if (cnt == 3)
+ {
+ sendto_channel_butserv(chptr, &me,
+ ":%s MODE %s +%s %s",
+ sptr->name, parv[1],
+ modebuf, parabuf);
+ cnt = 0;
+ }
+ }
+ }
+ /* send eventual MODE leftover */
+ if (cnt)
+ sendto_channel_butserv(chptr, &me, ":%s MODE %s +%s %s",
+ sptr->name, parv[1], modebuf, parabuf);
+
+ /* send NJOIN to capable servers */
+ *q = '\0';
+ if (nbuf[0])
+ sendto_match_servs_v(chptr, cptr, SV_NJOIN, ":%s NJOIN %s :%s",
+ parv[0], parv[1], nbuf);
+ return 0;
+}
+
+/*
+** m_part
+** parv[0] = sender prefix
+** parv[1] = channel
+*/
+int m_part(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+ {
+ Reg aChannel *chptr;
+ char *p = NULL, *name, *comment = "";
+
+ if (parc < 2 || parv[1][0] == '\0')
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]), "PART");
+ return 1;
+ }
+
+ *buf = '\0';
+
+ for (; (name = strtoken(&p, parv[1], ",")); parv[1] = NULL)
+ {
+ chptr = get_channel(sptr, name, 0);
+ if (!chptr)
+ {
+ if (MyPerson(sptr))
+ sendto_one(sptr,
+ err_str(ERR_NOSUCHCHANNEL, parv[0]),
+ name);
+ continue;
+ }
+ if (check_channelmask(sptr, cptr, name))
+ continue;
+ if (!IsMember(sptr, chptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOTONCHANNEL, parv[0]),
+ name);
+ continue;
+ }
+ comment = (BadPtr(parv[2])) ? parv[0] : parv[2];
+ if (IsAnonymous(chptr) && (comment == parv[0]))
+ comment = "None";
+ if (strlen(comment) > (size_t) TOPICLEN)
+ comment[TOPICLEN] = '\0';
+
+ /*
+ ** Remove user from the old channel (if any)
+ */
+ if (!index(name, ':') && (*chptr->chname != '!'))
+ { /* channel:*.mask */
+ if (*name != '&')
+ {
+ if (*buf)
+ (void)strcat(buf, ",");
+ (void)strcat(buf, name);
+ }
+ }
+ else
+ sendto_match_servs(chptr, cptr, PartFmt,
+ parv[0], name, comment);
+ sendto_channel_butserv(chptr, sptr, PartFmt,
+ parv[0], name, comment);
+ remove_user_from_channel(sptr, chptr);
+ }
+ if (*buf)
+ sendto_serv_butone(cptr, PartFmt, parv[0], buf, comment);
+ return 4;
+ }
+
+/*
+** 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, penalty = 0;
+ char *comment, *name, *p = NULL, *user, *p2 = NULL;
+ int mlen, len = 0, nlen;
+
+ if (parc < 3 || *parv[1] == '\0')
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]), "KICK");
+ return 1;
+ }
+ if (IsServer(sptr))
+ sendto_flag(SCH_NOTICE, "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';
+ mlen = 7 + strlen(parv[0]);
+
+ for (; (name = strtoken(&p, parv[1], ",")); parv[1] = NULL)
+ {
+ if (penalty++ >= MAXPENALTY && MyPerson(sptr))
+ break;
+ chptr = get_channel(sptr, name, !CREATE);
+ if (!chptr)
+ {
+ if (MyPerson(sptr))
+ sendto_one(sptr,
+ err_str(ERR_NOSUCHCHANNEL, parv[0]),
+ name);
+ continue;
+ }
+ if (check_channelmask(sptr, cptr, name))
+ continue;
+ if (!UseModes(name))
+ {
+ sendto_one(sptr, err_str(ERR_NOCHANMODES, parv[0]),
+ name);
+ continue;
+ }
+ if (!IsServer(sptr) && !is_chan_op(sptr, chptr))
+ {
+ if (!IsMember(sptr, chptr))
+ sendto_one(sptr, err_str(ERR_NOTONCHANNEL,
+ parv[0]), chptr->chname);
+ else
+ sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED,
+ parv[0]), chptr->chname);
+ continue;
+ }
+ if (len + mlen + strlen(name) < (size_t) BUFSIZE / 2)
+ {
+ if (*buf)
+ (void)strcat(buf, ",");
+ (void)strcat(buf, name);
+ len += strlen(name) + 1;
+ }
+ else
+ continue;
+ nlen = 0;
+
+ for (; (user = strtoken(&p2, parv[2], ",")); parv[2] = NULL)
+ {
+ penalty++;
+ if (!(who = find_chasing(sptr, user, &chasing)))
+ continue; /* No such user left! */
+ if (nlen + mlen + strlen(who->name) >
+ (size_t) BUFSIZE - NICKLEN)
+ continue;
+ if (IsMember(who, chptr))
+ {
+ sendto_channel_butserv(chptr, sptr,
+ ":%s KICK %s %s :%s", parv[0],
+ name, who->name, comment);
+ /* Don't send &local &kicks out */
+ if (*chptr->chname != '&' &&
+ *chptr->chname != '!' &&
+ index(chptr->chname, ':') == NULL) {
+ if (*nickbuf)
+ (void)strcat(nickbuf, ",");
+ (void)strcat(nickbuf, who->name);
+ nlen += strlen(who->name);
+ }
+ else
+ sendto_match_servs(chptr, cptr,
+ ":%s KICK %s %s :%s",
+ parv[0], name,
+ who->name, comment);
+ remove_user_from_channel(who,chptr);
+ penalty += 2;
+ if (penalty > MAXPENALTY && MyPerson(sptr))
+ break;
+ }
+ else
+ sendto_one(sptr,
+ err_str(ERR_USERNOTINCHANNEL,
+ parv[0]), user, name);
+ } /* loop on parv[2] */
+ } /* loop on parv[1] */
+
+ if (*buf && *nickbuf)
+ sendto_serv_butone(cptr, ":%s KICK %s %s :%s",
+ parv[0], buf, nickbuf, comment);
+ return penalty;
+}
+
+int count_channels(sptr)
+aClient *sptr;
+{
+Reg aChannel *chptr;
+ Reg int count = 0;
+
+ for (chptr = channel; chptr; chptr = chptr->nextch)
+ {
+ if (chptr->users) /* don't count channels in history */
+#ifdef SHOW_INVISIBLE_LUSERS
+ if (SecretChannel(chptr))
+ {
+ if (IsAnOper(sptr))
+ count++;
+ }
+ else
+#endif
+ count++;
+ }
+ return (count);
+}
+
+/*
+** m_topic
+** parv[0] = sender prefix
+** parv[1] = topic text
+*/
+int m_topic(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+ {
+ aChannel *chptr = NullChn;
+ char *topic = NULL, *name, *p = NULL;
+ int penalty = 1;
+
+ if (parc < 2)
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]),
+ "TOPIC");
+ return 1;
+ }
+
+ parv[1] = canonize(parv[1]);
+
+ for (; (name = strtoken(&p, parv[1], ",")); parv[1] = NULL)
+ {
+ if (!UseModes(name))
+ {
+ sendto_one(sptr, err_str(ERR_NOCHANMODES, parv[0]),
+ name);
+ continue;
+ }
+ if (parc > 1 && IsChannelName(name))
+ {
+ chptr = find_channel(name, NullChn);
+ if (!chptr || !IsMember(sptr, chptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOTONCHANNEL,
+ parv[0]), name);
+ continue;
+ }
+ if (parc > 2)
+ topic = parv[2];
+ }
+
+ if (!chptr)
+ {
+ sendto_one(sptr, rpl_str(RPL_NOTOPIC, parv[0]), name);
+ return penalty;
+ }
+
+ if (check_channelmask(sptr, cptr, name))
+ continue;
+
+ if (!topic) /* only asking for topic */
+ {
+ if (chptr->topic[0] == '\0')
+ sendto_one(sptr, rpl_str(RPL_NOTOPIC, parv[0]),
+ chptr->chname);
+ else
+ sendto_one(sptr, rpl_str(RPL_TOPIC, parv[0]),
+ chptr->chname, chptr->topic);
+ }
+ else if ((chptr->mode.mode & MODE_TOPICLIMIT) == 0 ||
+ is_chan_op(sptr, chptr))
+ { /* setting a topic */
+ strncpyzt(chptr->topic, topic, sizeof(chptr->topic));
+ sendto_match_servs(chptr, cptr,":%s TOPIC %s :%s",
+ parv[0], chptr->chname,
+ chptr->topic);
+ sendto_channel_butserv(chptr, sptr, ":%s TOPIC %s :%s",
+ parv[0],
+ chptr->chname, chptr->topic);
+#ifdef USE_SERVICES
+ check_services_butone(SERVICE_WANT_TOPIC,
+ NULL, sptr, ":%s TOPIC %s :%s",
+ parv[0], chptr->chname,
+ chptr->topic);
+#endif
+ penalty += 2;
+ }
+ else
+ sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED, parv[0]),
+ chptr->chname);
+ }
+ return penalty;
+ }
+
+/*
+** 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, parv[0]),
+ "INVITE");
+ return 1;
+ }
+
+ if (!(acptr = find_person(parv[1], (aClient *)NULL)))
+ {
+ sendto_one(sptr, err_str(ERR_NOSUCHNICK, parv[0]), parv[1]);
+ return 1;
+ }
+ clean_channelname(parv[2]);
+ if (check_channelmask(sptr, acptr->user->servp->bcptr, parv[2]))
+ return 1;
+ if (*parv[2] == '&' && !MyClient(acptr))
+ return 1;
+ chptr = find_channel(parv[2], NullChn);
+
+ if (!chptr)
+ {
+ sendto_prefix_one(acptr, sptr, ":%s INVITE %s :%s",
+ parv[0], parv[1], parv[2]);
+ if (MyConnect(sptr))
+ {
+ sendto_one(sptr, rpl_str(RPL_INVITING, parv[0]),
+ acptr->name, parv[2]);
+ if (acptr->user->flags & FLAGS_AWAY)
+ sendto_one(sptr, rpl_str(RPL_AWAY, parv[0]),
+ acptr->name, (acptr->user->away) ?
+ acptr->user->away : "Gone");
+ }
+ return 3;
+ }
+
+ if (!IsMember(sptr, chptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOTONCHANNEL, parv[0]), parv[2]);
+ return 1;
+ }
+
+ if (IsMember(acptr, chptr))
+ {
+ sendto_one(sptr, err_str(ERR_USERONCHANNEL, parv[0]),
+ parv[1], parv[2]);
+ return 1;
+ }
+
+ if ((chptr->mode.mode & MODE_INVITEONLY) && !is_chan_op(sptr, chptr))
+ {
+ sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED,
+ parv[0]), chptr->chname);
+ return 1;
+ }
+
+ if (MyConnect(sptr))
+ {
+ sendto_one(sptr, rpl_str(RPL_INVITING, parv[0]),
+ acptr->name, ((chptr) ? (chptr->chname) : parv[2]));
+ if (acptr->user->flags & FLAGS_AWAY)
+ sendto_one(sptr, rpl_str(RPL_AWAY, parv[0]),
+ acptr->name,
+ (acptr->user->away) ? acptr->user->away :
+ "Gone");
+ }
+
+ if (MyConnect(acptr))
+ if (chptr && /* (chptr->mode.mode & MODE_INVITEONLY) && */
+ sptr->user && is_chan_op(sptr, chptr))
+ add_invite(acptr, chptr);
+
+ sendto_prefix_one(acptr, sptr, ":%s INVITE %s :%s",parv[0],
+ acptr->name, ((chptr) ? (chptr->chname) : parv[2]));
+ return 2;
+}
+
+
+/*
+** m_list
+** parv[0] = sender prefix
+** parv[1] = channel
+*/
+int m_list(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+ {
+ aChannel *chptr;
+ char *name, *p = NULL;
+ int rlen = 0;
+
+ if (parc > 1 &&
+ hunt_server(cptr, sptr, ":%s LIST %s %s", 2, parc, parv))
+ return 10;
+ if (BadPtr(parv[1]))
+ for (chptr = channel; chptr; chptr = chptr->nextch)
+ {
+ if (!sptr->user ||
+ !chptr->users || /* empty locked channel */
+ (SecretChannel(chptr) && !IsMember(sptr, chptr)))
+ continue;
+ name = ShowChannel(sptr, chptr) ? chptr->chname : NULL;
+ rlen += sendto_one(sptr, rpl_str(RPL_LIST, parv[0]),
+ name ? name : "*", chptr->users,
+ name ? chptr->topic : "");
+ if (!MyConnect(sptr) && rlen > CHREPLLEN)
+ break;
+ }
+ else {
+ parv[1] = canonize(parv[1]);
+ for (; (name = strtoken(&p, parv[1], ",")); parv[1] = NULL)
+ {
+ chptr = find_channel(name, NullChn);
+ if (chptr && ShowChannel(sptr, chptr) && sptr->user)
+ {
+ rlen += sendto_one(sptr, rpl_str(RPL_LIST,
+ parv[0]), name,
+ chptr->users, chptr->topic);
+ if (!MyConnect(sptr) && rlen > CHREPLLEN)
+ break;
+ }
+ if (*name == '!')
+ {
+ chptr = NULL;
+ while (chptr=hash_find_channels(name+1, chptr))
+ {
+ int scr = SecretChannel(chptr) &&
+ !IsMember(sptr, chptr);
+ rlen += sendto_one(sptr,
+ rpl_str(RPL_LIST,
+ parv[0]),
+ chptr->chname,
+ (scr) ? -1 :
+ chptr->users,
+ (scr) ? "" :
+ chptr->topic);
+ if (!MyConnect(sptr) &&
+ rlen > CHREPLLEN)
+ break;
+ }
+ }
+ }
+ }
+ if (!MyConnect(sptr) && rlen > CHREPLLEN)
+ sendto_one(sptr, err_str(ERR_TOOMANYMATCHES, parv[0]),
+ !BadPtr(parv[1]) ? parv[1] : "*");
+ sendto_one(sptr, rpl_str(RPL_LISTEND, parv[0]));
+ return 2;
+ }
+
+
+/************************************************************************
+ * 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[];
+{
+ Reg aChannel *chptr;
+ Reg aClient *c2ptr;
+ Reg Link *lp;
+ aChannel *ch2ptr = NULL;
+ int idx, flag, len, mlen, rlen = 0;
+ char *s, *para = parc > 1 ? parv[1] : NULL;
+
+ if (parc > 1 &&
+ hunt_server(cptr, sptr, ":%s NAMES %s %s", 2, parc, parv))
+ return 10;
+
+ mlen = strlen(ME) + 10; /* server names + : : + spaces + "353" */
+ mlen += strlen(parv[0]);
+ if (!BadPtr(para))
+ {
+ s = index(para, ',');
+ if (s && MyConnect(sptr) && s != para)
+ {
+ parv[1] = ++s;
+ (void)m_names(cptr, sptr, parc, parv);
+ }
+ 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->users || /* locked empty channel */
+ ((chptr != ch2ptr) && !BadPtr(para))) /* 'wrong' channel */
+ continue;
+ if (!MyConnect(sptr) && (BadPtr(para) || (rlen > CHREPLLEN)))
+ break;
+ if ((BadPtr(para) || !HiddenChannel(chptr)) &&
+ !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 = '@';
+
+ if (IsAnonymous(chptr))
+ {
+ if ((lp = find_user_link(chptr->members, sptr)))
+ {
+ if (lp->flags & CHFL_CHANOP)
+ (void)strcat(buf, "@");
+ else if (lp->flags & CHFL_VOICE)
+ (void)strcat(buf, "+");
+ (void)strcat(buf, parv[0]);
+ }
+ rlen += strlen(buf);
+ sendto_one(sptr, rpl_str(RPL_NAMREPLY, parv[0]), buf);
+ continue;
+ }
+ idx = len + 4; /* channel name + [@=] + 2?? */
+ flag = 1;
+ for (lp = chptr->members; lp; lp = lp->next)
+ {
+ c2ptr = lp->value.cptr;
+ if (IsInvisible(c2ptr) && !IsMember(sptr,chptr))
+ continue;
+ if (lp->flags & CHFL_CHANOP)
+ {
+ (void)strcat(buf, "@");
+ idx++;
+ }
+ else if (lp->flags & CHFL_VOICE)
+ {
+ (void)strcat(buf, "+");
+ idx++;
+ }
+ (void)strncat(buf, c2ptr->name, NICKLEN);
+ idx += strlen(c2ptr->name) + 1;
+ flag = 1;
+ (void)strcat(buf," ");
+ if (mlen + idx + NICKLEN + 1 > BUFSIZE - 2)
+ {
+ sendto_one(sptr, rpl_str(RPL_NAMREPLY,
+ 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)
+ {
+ rlen += strlen(buf);
+ sendto_one(sptr, rpl_str(RPL_NAMREPLY, parv[0]), buf);
+ }
+ } /* for(channels) */
+ if (!BadPtr(para))
+ {
+ if (!MyConnect(sptr) && (rlen > CHREPLLEN))
+ sendto_one(sptr, err_str(ERR_TOOMANYMATCHES, parv[0]),
+ para);
+ sendto_one(sptr, rpl_str(RPL_ENDOFNAMES, parv[0]), para);
+ 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) || IsInvisible(c2ptr))
+ continue;
+ if (!MyConnect(sptr) && (BadPtr(para) || (rlen > CHREPLLEN)))
+ break;
+ lp = c2ptr->user->channel;
+ /*
+ * don't 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))
+ 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)
+ {
+ rlen += strlen(buf);
+ sendto_one(sptr, rpl_str(RPL_NAMREPLY, parv[0]), buf);
+ (void)strncpy(buf, "* * :", 6);
+ idx = 5;
+ flag = 0;
+ }
+ }
+ if (flag)
+ {
+ rlen += strlen(buf);
+ sendto_one(sptr, rpl_str(RPL_NAMREPLY, parv[0]), buf);
+ }
+ if (!MyConnect(sptr) && rlen > CHREPLLEN)
+ sendto_one(sptr, err_str(ERR_TOOMANYMATCHES, parv[0]),
+ para ? para : "*");
+ /* This is broken.. remove the recursion? */
+ sendto_one(sptr, rpl_str(RPL_ENDOFNAMES, parv[0]), "*");
+ return 2;
+}
+
+void send_user_joins(cptr, user)
+aClient *cptr, *user;
+{
+ Reg Link *lp;
+ Reg aChannel *chptr;
+ Reg int cnt = 0, len = 0, clen;
+ char *mask;
+
+ *buf = ':';
+ (void)strcpy(buf+1, user->name);
+ (void)strcat(buf, " JOIN ");
+ len = strlen(user->name) + 7;
+
+ for (lp = user->user->channel; lp; lp = lp->next)
+ {
+ chptr = lp->value.chptr;
+ if (*chptr->chname == '&')
+ continue;
+ if (*chptr->chname == '!' && !(cptr->serv->version & SV_NCHAN))
+ /* in reality, testing SV_NCHAN here is pointless */
+ continue;
+ if ((mask = index(chptr->chname, ':')))
+ if (match(++mask, cptr->name))
+ continue;
+ clen = strlen(chptr->chname);
+ if ((clen + len) > (size_t) BUFSIZE - 7)
+ {
+ if (cnt)
+ sendto_one(cptr, "%s", buf);
+ *buf = ':';
+ (void)strcpy(buf+1, user->name);
+ (void)strcat(buf, " JOIN ");
+ len = strlen(user->name) + 7;
+ cnt = 0;
+ }
+ if (cnt)
+ {
+ len++;
+ (void)strcat(buf, ",");
+ }
+ (void)strcpy(buf + len, chptr->chname);
+ len += clen;
+ if (lp->flags & (CHFL_UNIQOP|CHFL_CHANOP|CHFL_VOICE))
+ {
+ buf[len++] = '\007';
+ if (lp->flags & CHFL_UNIQOP) /*this should be useless*/
+ buf[len++] = 'O';
+ if (lp->flags & CHFL_CHANOP)
+ buf[len++] = 'o';
+ if (lp->flags & CHFL_VOICE)
+ buf[len++] = 'v';
+ buf[len] = '\0';
+ }
+ cnt++;
+ }
+ if (*buf && cnt)
+ sendto_one(cptr, "%s", buf);
+
+ return;
+}
+
+#define CHECKFREQ 300
+/* consider reoping an opless !channel */
+static int
+reop_channel(now, chptr)
+time_t now;
+aChannel *chptr;
+{
+ Link *lp, op;
+
+ op.value.chptr = NULL;
+ if (chptr->users <= 5 && (now - chptr->history > DELAYCHASETIMELIMIT))
+ {
+ /* few users, no recent split: this is really a small channel */
+ char mbuf[4], nbuf[3*(NICKLEN+1)+1];
+ int cnt;
+
+ lp = chptr->members;
+ while (lp)
+ {
+ if (lp->flags & CHFL_CHANOP)
+ {
+ chptr->reop = 0;
+ return 0;
+ }
+ if (MyConnect(lp->value.cptr))
+ op.value.cptr = lp->value.cptr;
+ lp = lp->next;
+ }
+ if (op.value.cptr == NULL &&
+ ((now - chptr->reop) < LDELAYCHASETIMELIMIT))
+ /*
+ ** do nothing if no local users,
+ ** unless the reop is really overdue.
+ */
+ return 0;
+ sendto_channel_butone(&me, &me, chptr,
+ ":%s NOTICE %s :Enforcing channel mode +r (%d)",
+ ME, chptr->chname, now - chptr->reop);
+ op.flags = MODE_ADD|MODE_CHANOP;
+ lp = chptr->members;
+ cnt = 3;
+ while (lp)
+ {
+ if (cnt == 3)
+ {
+ mbuf[cnt] = '\0';
+ if (lp != chptr->members)
+ {
+ sendto_match_servs_v(chptr, NULL, SV_NCHAN,
+ ":%s MODE %s +%s %s",
+ ME, chptr->chname,
+ mbuf, nbuf);
+ sendto_channel_butserv(chptr, &me,
+ ":%s MODE %s +%s %s",
+ ME, chptr->chname,
+ mbuf, nbuf);
+ }
+ cnt = 0;
+ mbuf[0] = nbuf[0] = '\0';
+ }
+ op.value.cptr = lp->value.cptr;
+ change_chan_flag(&op, chptr);
+ mbuf[cnt++] = 'o';
+ strcat(nbuf, lp->value.cptr->name);
+ strcat(nbuf, " ");
+ lp = lp->next;
+ }
+ if (cnt)
+ {
+ mbuf[cnt] = '\0';
+ sendto_match_servs_v(chptr, NULL, SV_NCHAN,
+ ":%s MODE %s +%s %s",
+ ME, chptr->chname, mbuf, nbuf);
+ sendto_channel_butserv(chptr, &me, ":%s MODE %s +%s %s",
+ ME, chptr->chname, mbuf, nbuf);
+ }
+ }
+ else
+ {
+ time_t idlelimit = now -
+ MIN((LDELAYCHASETIMELIMIT/2), (2*CHECKFREQ));
+
+ lp = chptr->members;
+ while (lp)
+ {
+ if (lp->flags & CHFL_CHANOP)
+ {
+ chptr->reop = 0;
+ return 0;
+ }
+ if (MyConnect(lp->value.cptr) &&
+ lp->value.cptr->user->last > idlelimit &&
+ (op.value.cptr == NULL ||
+ lp->value.cptr->user->last>op.value.cptr->user->last))
+ op.value.cptr = lp->value.cptr;
+ lp = lp->next;
+ }
+ if (op.value.cptr == NULL)
+ return 0;
+ sendto_channel_butone(&me, &me, chptr,
+ ":%s NOTICE %s :Enforcing channel mode +r (%d)", ME,
+ chptr->chname, now - chptr->reop);
+ op.flags = MODE_ADD|MODE_CHANOP;
+ change_chan_flag(&op, chptr);
+ sendto_match_servs_v(chptr, NULL, SV_NCHAN, ":%s MODE %s +o %s",
+ ME, chptr->chname, op.value.cptr->name);
+ sendto_channel_butserv(chptr, &me, ":%s MODE %s +o %s",
+ ME, chptr->chname, op.value.cptr->name);
+ }
+ chptr->reop = 0;
+ return 1;
+}
+
+/*
+ * Cleanup locked channels, run frequently.
+ *
+ * A channel life is defined by its users and the history stamp.
+ * It is alive if one of the following is true:
+ * chptr->users > 0 (normal state)
+ * chptr->history >= time(NULL) (eventually locked)
+ * It is locked if empty but alive.
+ *
+ * The history stamp is set when a remote user with channel op exits.
+ */
+time_t collect_channel_garbage(now)
+time_t now;
+{
+ static u_int max_nb = 0; /* maximum of live channels */
+ static u_char split = 0;
+ Reg aChannel *chptr = channel;
+ Reg u_int cur_nb = 1, curh_nb = 0, r_cnt = 0;
+ aChannel *del_ch;
+#ifdef DEBUGMODE
+ u_int del = istat.is_hchan;
+#endif
+#define SPLITBONUS (CHECKFREQ - 50)
+
+ collect_chid();
+
+ while (chptr)
+ {
+ if (chptr->users == 0)
+ curh_nb++;
+ else
+ {
+ cur_nb++;
+ if (*chptr->chname == '!' &&
+ (chptr->mode.mode & MODE_REOP) &&
+ chptr->reop && chptr->reop <= now)
+ r_cnt += reop_channel(now, chptr);
+ }
+ chptr = chptr->nextch;
+ }
+ if (cur_nb > max_nb)
+ max_nb = cur_nb;
+
+ if (r_cnt)
+ sendto_flag(SCH_CHAN, "Re-opped %u channel(s).", r_cnt);
+
+ /*
+ ** check for huge netsplits, if so, garbage collection is not really
+ ** done but make sure there aren't too many channels kept for
+ ** history - krys
+ */
+ if ((2*curh_nb > cur_nb) && curh_nb < max_nb)
+ split = 1;
+ else
+ {
+ split = 0;
+ /* no empty channel? let's skip the while! */
+ if (curh_nb == 0)
+ {
+#ifdef DEBUGMODE
+ sendto_flag(SCH_LOCAL,
+ "Channel garbage: live %u (max %u), hist %u (extended)",
+ cur_nb - 1, max_nb - 1, curh_nb);
+#endif
+ /* Check again after CHECKFREQ seconds */
+ return (time_t) (now + CHECKFREQ);
+ }
+ }
+
+ chptr = channel;
+ while (chptr)
+ {
+ /*
+ ** In case we are likely to be split, extend channel locking.
+ ** most splits should be short, but reality seems to prove some
+ ** aren't.
+ */
+ if (!chptr->history)
+ {
+ chptr = chptr->nextch;
+ continue;
+ }
+ if (split) /* net splitted recently and we have a lock */
+ chptr->history += SPLITBONUS; /* extend lock */
+
+ if ((chptr->users == 0) && (chptr->history <= now))
+ {
+ del_ch = chptr;
+
+ chptr = del_ch->nextch;
+ free_channel(del_ch);
+ }
+ else
+ chptr = chptr->nextch;
+ }
+
+#ifdef DEBUGMODE
+ sendto_flag(SCH_LOCAL,
+ "Channel garbage: live %u (max %u), hist %u (removed %u)%s",
+ cur_nb - 1, max_nb - 1, curh_nb, del - istat.is_hchan,
+ (split) ? " split detected" : "");
+#endif
+ /* Check again after CHECKFREQ seconds */
+ return (time_t) (now + CHECKFREQ);
+}
diff --git a/ircd/channel_def.h b/ircd/channel_def.h
new file mode 100644
index 0000000..7413f16
--- /dev/null
+++ b/ircd/channel_def.h
@@ -0,0 +1,29 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/channel_def.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.
+ */
+
+#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 MAXMODEPARAMS 3
diff --git a/ircd/channel_ext.h b/ircd/channel_ext.h
new file mode 100644
index 0000000..361d387
--- /dev/null
+++ b/ircd/channel_ext.h
@@ -0,0 +1,64 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/channel_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in ircd/channel.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef CHANNEL_C
+extern aChannel *channel;
+#endif /* CHANNEL_C */
+
+/* External definitions for global functions.
+ */
+#ifndef CHANNEL_C
+#define EXTERN extern
+#else /* CHANNEL_C */
+#define EXTERN
+#endif /* CHANNEL_C */
+EXTERN void remove_user_from_channel __P((aClient *sptr, aChannel *chptr));
+EXTERN int is_chan_op __P((aClient *cptr, aChannel *chptr));
+EXTERN int has_voice __P((aClient *cptr, aChannel *chptr));
+EXTERN int can_send __P((aClient *cptr, aChannel *chptr));
+EXTERN aChannel *find_channel __P((Reg char *chname, Reg aChannel *chptr));
+EXTERN void setup_server_channels __P((aClient *mp));
+EXTERN void channel_modes __P((aClient *cptr, Reg char *mbuf, Reg char *pbuf,
+ aChannel *chptr));
+EXTERN void send_channel_modes __P((aClient *cptr, aChannel *chptr));
+EXTERN void send_channel_members __P((aClient *cptr, aChannel *chptr));
+EXTERN int m_mode __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN void clean_channelname __P((Reg char *cn));
+EXTERN void del_invite __P((aClient *cptr, aChannel *chptr));
+EXTERN int m_join __P((Reg aClient *cptr, Reg aClient *sptr, int parc,
+ char *parv[]));
+EXTERN int m_njoin __P((Reg aClient *cptr, Reg aClient *sptr, int parc,
+ char *parv[]));
+EXTERN int m_part __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN int m_kick __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN int count_channels __P((aClient *sptr));
+EXTERN int m_topic __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN int m_invite __P((aClient *cptr, aClient *sptr, int parc,
+ char *parv[]));
+EXTERN int m_list __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN int m_names __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN void send_user_joins __P((aClient *cptr, aClient *user));
+EXTERN time_t collect_channel_garbage __P((time_t now));
+#undef EXTERN
diff --git a/ircd/chkconf.c b/ircd/chkconf.c
new file mode 100644
index 0000000..7c0032d
--- /dev/null
+++ b/ircd/chkconf.c
@@ -0,0 +1,745 @@
+/************************************************************************
+ * 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: chkconf.c,v 1.13 1999/03/11 23:40:12 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "s_defines.h"
+#define CHKCONF_C
+#include "match_ext.h"
+#undef CHKCONF_C
+
+#define MyMalloc(x) malloc(x)
+/*#define MyFree(x) free(x)*/
+
+static void new_class();
+static char *getfield(), confchar ();
+static int openconf(), validate __P((aConfItem *));
+static int dgets __P((int, char *, int));
+static aClass *get_class();
+static aConfItem *initconf();
+
+static int numclasses = 0, *classarr = (int *)NULL, debugflag = 0;
+static char *configfile = IRCDCONF_PATH;
+static char nullfield[] = "";
+static char maxsendq[12];
+
+#define SHOWSTR(x) ((x) ? (x) : "*")
+
+int main(argc, argv)
+int argc;
+char *argv[];
+{
+ if (argc > 1 && !strncmp(argv[1], "-h", 2)) {
+ (void)fprintf(stderr, "Usage: %s [-h] [-d[#]] [%s]\n",
+ argv[0], IRCDCONF_PATH);
+ exit(0);
+ }
+ new_class(0);
+
+ if (argc > 1 && !strncmp(argv[1], "-d", 2))
+ {
+ debugflag = 1;
+ if (argv[1][2])
+ debugflag = atoi(argv[1]+2);
+ argc--, argv++;
+ }
+ if (argc > 1)
+ configfile = argv[1];
+ return validate(initconf());
+}
+
+/*
+ * openconf
+ *
+ * returns -1 on any error or else the fd opened from which to read the
+ * configuration file from. This may either be th4 file direct or one end
+ * of a pipe from m4.
+ */
+static int openconf()
+{
+#ifdef M4_PREPROC
+ int pi[2];
+
+ /* ircd.m4 with full path now! Kratz */
+ if (access(IRCDM4_PATH, R_OK) == -1)
+ {
+ (void)fprintf(stderr, "%s missing.\n", IRCDM4_PATH);
+ return -1;
+ }
+ 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", IRCDM4_PATH, configfile, 0);
+ perror("m4");
+ exit(-1);
+ default :
+ (void)close(pi[1]);
+ return pi[0];
+ }
+#else
+ return open(configfile, O_RDONLY);
+#endif
+}
+
+/*
+** 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;
+ aConfItem *aconf = NULL, *ctop = NULL;
+
+ (void)fprintf(stderr, "initconf(): ircd.conf = %s\n", configfile);
+ if ((fd = openconf()) == -1)
+ {
+#ifdef M4_PREPROC
+ (void)wait(0);
+#endif
+ return NULL;
+ }
+
+ (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
+ while ((dh = dgets(fd, line, sizeof(line) - 1)) > 0)
+ {
+ 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+1)); s++)
+ ;
+ tmp++;
+ }
+ else if (*tmp == '#')
+ *tmp = '\0';
+ }
+ if (!*line || *line == '#' || *line == '\n' ||
+ *line == ' ' || *line == '\t')
+ continue;
+
+ if (line[1] != IRCDCONF_DELIMITER)
+ {
+ (void)fprintf(stderr, "ERROR: Bad config line (%s)\n",
+ line);
+ if (IRCDCONF_DELIMITER != ':')
+ (void)fprintf(stderr,
+ "\tWrong delimiter? (should be %c)\n",
+ IRCDCONF_DELIMITER);
+ 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 */
+ case 'a': /* of this server. */
+ aconf->status = CONF_ADMIN;
+ break;
+ case 'B': /* bounce line */
+ case 'b':
+ aconf->status = CONF_BOUNCE;
+ 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 'D': /* auto connect restrictions */
+ case 'd':
+ aconf->status = CONF_DENY;
+ 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;
+ /* Operator. Line should contain at least */
+ /* password and host where connection is */
+ case 'L': /* guaranteed leaf server */
+ case 'l':
+ aconf->status = CONF_LEAF;
+ break;
+ /* Me. Host field is name used for this host */
+ /* and port number is the number of the port */
+ case 'M':
+ case 'm':
+ aconf->status = CONF_ME;
+ break;
+ case 'N': /* Server where I should NOT try to */
+ case 'n': /* connect in case of lp failures */
+ /* but which tries to connect ME */
+ ++ncount;
+ aconf->status = CONF_NOCONNECT_SERVER;
+ break;
+ case 'O':
+ aconf->status = CONF_OPERATOR;
+ break;
+ /* Local Operator, (limited privs --SRB) */
+ case 'o':
+ aconf->status = CONF_LOCOP;
+ break;
+ case 'P': /* listen port line */
+ case 'p':
+ aconf->status = CONF_LISTEN_PORT;
+ break;
+ case 'Q': /* a server that you don't want in your */
+ case 'q': /* network. USE WITH CAUTION! */
+ aconf->status = CONF_QUARANTINED_SERVER;
+ break;
+#ifdef R_LINES
+ case 'R': /* extended K line */
+ case 'r': /* Offers more options of how to restrict */
+ aconf->status = CONF_RESTRICT;
+ break;
+#endif
+ case 'S': /* Service. Same semantics as */
+ case 's': /* CONF_OPERATOR */
+ aconf->status = CONF_SERVICE;
+ break;
+ case 'U': /* Uphost, ie. host where client reading */
+ case 'u': /* this should connect. */
+ /* This is for client only, I must ignore this */
+ /* ...U-line should be removed... --msa */
+ break;
+ case 'V':
+ aconf->status = CONF_VER;
+ break;
+ case 'Y':
+ case 'y':
+ aconf->status = CONF_CLASS;
+ break;
+ default:
+ (void)fprintf(stderr,
+ "\tERROR: unknown conf line letter (%c)\n",
+ *tmp);
+ break;
+ }
+
+ if (IsIllegal(aconf))
+ continue;
+
+ for (;;) /* Fake loop, that I can use break here --msa */
+ {
+ if ((tmp = getfield(NULL)) == NULL)
+ break;
+ DupString(aconf->host, tmp);
+ if ((tmp = getfield(NULL)) == NULL)
+ break;
+ DupString(aconf->passwd, tmp);
+ if ((tmp = getfield(NULL)) == NULL)
+ break;
+ DupString(aconf->name, tmp);
+ if ((tmp = getfield(NULL)) == NULL)
+ break;
+ aconf->port = atoi(tmp);
+ if ((tmp = getfield(NULL)) == NULL)
+ break;
+ if (!(aconf->status & CONF_CLASS))
+ aconf->class = get_class(atoi(tmp));
+ break;
+ }
+ if (!aconf->class && (aconf->status & (CONF_CONNECT_SERVER|
+ CONF_NOCONNECT_SERVER|CONF_OPS|CONF_CLIENT)))
+ {
+ (void)fprintf(stderr,
+ "\tWARNING: No class. Default 0\n");
+ aconf->class = get_class(0);
+ }
+ /*
+ ** 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,
+ "\tWARNING: missing sendq field\n");
+ (void)fprintf(stderr, "\t\t default: %d\n",
+ QUEUELEN);
+ (void)sprintf(maxsendq, "%d", QUEUELEN);
+ }
+ 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)
+ {
+#ifdef UNIXPORT
+ struct stat sb;
+
+ if (!aconf->host)
+ (void)fprintf(stderr, "\tERROR: %s\n",
+ "null host field in P-line");
+ else if (index(aconf->host, '/'))
+ {
+ if (stat(aconf->host, &sb) == -1)
+ {
+ (void)fprintf(stderr, "\tERROR: (%s) ",
+ aconf->host);
+ perror("stat");
+ }
+ else if ((sb.st_mode & S_IFMT) != S_IFDIR)
+ (void)fprintf(stderr,
+ "\tERROR: %s not directory\n",
+ aconf->host);
+ }
+#else
+ if (!aconf->host)
+ (void)fprintf(stderr, "\tERROR: %s\n",
+ "null host field in P-line");
+ else if (index(aconf->host, '/'))
+ (void)fprintf(stderr, "\t%s %s\n",
+ "WARNING: / present in P-line",
+ "for non-UNIXPORT configuration");
+#endif
+ 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;
+ }
+
+ if (aconf->status & CONF_VER)
+ {
+ if (*aconf->host && !index(aconf->host, '/'))
+ (void)fprintf(stderr,
+ "\tWARNING: No / in V line.");
+ else if (*aconf->passwd && !index(aconf->passwd, '/'))
+ (void)fprintf(stderr,
+ "\tWARNING: No / in V line.");
+ }
+print_confline:
+ if (debugflag > 8)
+ (void)printf("(%d) (%s) (%s) (%s) (%d) (%s)\n",
+ aconf->status, aconf->host, aconf->passwd,
+ aconf->name, aconf->port, maxsendq);
+ (void)fflush(stdout);
+ if (aconf->status & (CONF_SERVER_MASK|CONF_HUB|CONF_LEAF))
+ {
+ aconf->next = ctop;
+ ctop = aconf;
+ aconf = NULL;
+ }
+ }
+ (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(irc_newline)
+char *irc_newline;
+{
+ static char *line = NULL;
+ char *end, *field;
+
+ if (irc_newline)
+ line = irc_newline;
+ if (line == NULL)
+ return(NULL);
+
+ field = line;
+ if ((end = (char *)index(line, IRCDCONF_DELIMITER)) == NULL)
+ {
+ line = NULL;
+ if ((end = (char *)index(field,'\n')) == NULL)
+ end = field + strlen(field);
+ }
+ else
+ line = end + 1;
+ *end = '\0';
+ return(field);
+}
+
+
+/*
+** read a string terminated by \r or \n in from a fd
+**
+** Created: Sat Dec 12 06:29:58 EST 1992 by avalon
+** Returns:
+** 0 - EOF
+** -1 - error on read
+** >0 - number of bytes returned (<=num)
+** After opening a fd, it is necessary to init dgets() by calling it as
+** dgets(x,y,0);
+** to mark the buffer as being empty.
+*/
+static int dgets(fd, buf, num)
+int fd, num;
+char *buf;
+{
+ static char dgbuf[8192];
+ static char *head = dgbuf, *tail = dgbuf;
+ register char *s, *t;
+ register int n, nr;
+
+ /*
+ ** Sanity checks.
+ */
+ if (head == tail)
+ *head = '\0';
+ if (!num)
+ {
+ head = tail = dgbuf;
+ *head = '\0';
+ return 0;
+ }
+ if (num > sizeof(dgbuf) - 1)
+ num = sizeof(dgbuf) - 1;
+dgetsagain:
+ if (head > dgbuf)
+ {
+ for (nr = tail - head, s = head, t = dgbuf; nr > 0; nr--)
+ *t++ = *s++;
+ tail = t;
+ head = dgbuf;
+ }
+ /*
+ ** check input buffer for EOL and if present return string.
+ */
+ if (head < tail &&
+ ((s = index(head, '\n')) || (s = index(head, '\r'))) && s < tail)
+ {
+ n = MIN(s - head + 1, num); /* at least 1 byte */
+dgetsreturnbuf:
+ bcopy(head, buf, n);
+ head += n;
+ if (head == tail)
+ head = tail = dgbuf;
+ return n;
+ }
+
+ if (tail - head >= num) /* dgets buf is big enough */
+ {
+ n = num;
+ goto dgetsreturnbuf;
+ }
+
+ n = sizeof(dgbuf) - (tail - dgbuf) - 1;
+ nr = read(fd, tail, n);
+ if (nr == -1)
+ {
+ head = tail = dgbuf;
+ return -1;
+ }
+ if (!nr)
+ {
+ if (head < tail)
+ {
+ n = MIN(head - tail, num);
+ goto dgetsreturnbuf;
+ }
+ head = tail = dgbuf;
+ return 0;
+ }
+ tail += nr;
+ *tail = '\0';
+ for (t = head; (s = index(t, '\n')); )
+ {
+ if ((s > head) && (s > dgbuf))
+ {
+ t = s-1;
+ for (nr = 0; *t == '\\'; nr++)
+ t--;
+ if (nr & 1)
+ {
+ t = s+1;
+ s--;
+ nr = tail - t;
+ while (nr--)
+ *s++ = *t++;
+ tail -= 2;
+ *tail = '\0';
+ }
+ else
+ s++;
+ }
+ else
+ s++;
+ t = s;
+ }
+ *tail = '\0';
+ goto dgetsagain;
+}
+
+
+static int validate(top)
+aConfItem *top;
+{
+ 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,
+ SHOWSTR(aconf->passwd), aconf->name);
+ return valid ? 0 : -1;
+}
+
+static char confchar(status)
+u_int status;
+{
+ static char letrs[] = "QIiCcNoOMKARYSLPHV";
+ char *s = letrs;
+
+ status &= ~(CONF_MATCH|CONF_ILLEGAL);
+
+ for (; *s; s++, status >>= 1)
+ if (status & 1)
+ return *s;
+ return '-';
+}
+
+void outofmemory()
+{
+ (void)write(2, "Out of memory\n", 14);
+ exit(-1);
+}
diff --git a/ircd/class.c b/ircd/class.c
new file mode 100644
index 0000000..e3457c8
--- /dev/null
+++ b/ircd/class.c
@@ -0,0 +1,256 @@
+/*
+ * 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: class.c,v 1.6 1997/12/19 13:35:57 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "s_defines.h"
+#define CLASS_C
+#include "s_externs.h"
+#undef CLASS_C
+
+#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;
+{
+ Reg Link *tmp;
+ Reg 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|
+ CONF_ZCONNECT_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 (MAX(60, 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, hlocal, uhlocal,
+ hglobal, uhglobal)
+int class, ping, confreq, maxli, hlocal, uhlocal, hglobal, uhglobal;
+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;
+ MaxSendq(p) = QUEUELEN;
+ istat.is_class++;
+ }
+ else
+ p = t;
+ Debug((DEBUG_DEBUG,
+"Add Class %d: p %x t %x - cf: %d pf: %d ml: %d sq: %l ml: %d.%d mg: %d.%d",
+ class, p, t, confreq, ping, maxli, QUEUELEN, hlocal, uhlocal,
+ hglobal, uhglobal));
+ Class(p) = class;
+ ConFreq(p) = confreq;
+ PingFreq(p) = ping;
+ MaxLinks(p) = maxli;
+ if (sendq)
+ MaxSendq(p) = sendq;
+ MaxHLocal(p) = hlocal;
+ MaxUHLocal(p) = uhlocal;
+ MaxHGlobal(p) = hglobal;
+ MaxUHGlobal(p) = uhglobal;
+ 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()
+{
+ Reg 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);
+ istat.is_class--;
+ }
+ }
+ else
+ cltmp2 = cltmp;
+ }
+}
+
+void initclass()
+{
+ classes = (aClass *)make_class();
+ istat.is_class++;
+
+ Class(FirstClass()) = 0;
+ ConFreq(FirstClass()) = CONNECTFREQUENCY;
+ PingFreq(FirstClass()) = PINGFREQUENCY;
+ MaxLinks(FirstClass()) = MAXIMUM_LINKS;
+ MaxSendq(FirstClass()) = QUEUELEN;
+ Links(FirstClass()) = 0;
+ NextClass(FirstClass()) = NULL;
+}
+
+void report_classes(sptr, to)
+aClient *sptr;
+char *to;
+{
+ Reg aClass *cltmp;
+
+ for (cltmp = FirstClass(); cltmp; cltmp = NextClass(cltmp))
+ sendto_one(sptr, rpl_str(RPL_STATSYLINE, to), 'Y',
+ Class(cltmp), PingFreq(cltmp), ConFreq(cltmp),
+ MaxLinks(cltmp), MaxSendq(cltmp),
+ MaxHLocal(cltmp), MaxUHLocal(cltmp),
+ MaxHGlobal(cltmp), MaxUHGlobal(cltmp));
+}
+
+long get_sendq(cptr)
+aClient *cptr;
+{
+ Reg int sendq = QUEUELEN, retc = BAD_CLIENT_CLASS;
+ Reg Link *tmp;
+ Reg aClass *cl;
+
+ if (cptr->serv)
+ sendq = MaxSendq(cptr->serv->nline->class);
+ else if (cptr && !IsMe(cptr) && (cptr->confs))
+ for (tmp = cptr->confs; tmp; tmp = tmp->next)
+ {
+ if (!tmp->value.aconf ||
+ !(cl = tmp->value.aconf->class))
+ continue;
+ if (Class(cl) > retc)
+ sendq = MaxSendq(cl);
+ }
+ return sendq;
+}
diff --git a/ircd/class_ext.h b/ircd/class_ext.h
new file mode 100644
index 0000000..6d9fadb
--- /dev/null
+++ b/ircd/class_ext.h
@@ -0,0 +1,49 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/class_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in ircd/class.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef CLASS_C
+extern aClass *classes;
+#endif /* CLASS_C */
+
+/* External definitions for global functions.
+ */
+#ifndef CLASS_C
+#define EXTERN extern
+#else /* CLASS_C */
+#define EXTERN
+#endif /* CLASS_C */
+EXTERN int get_conf_class __P((aConfItem *aconf));
+EXTERN int get_client_class __P((aClient *acptr));
+EXTERN int get_client_ping __P((aClient *acptr));
+EXTERN int get_con_freq __P((aClass *clptr));
+EXTERN void add_class __P((int class, int ping, int confreq, int maxli,
+ long sendq, int hlocal, int uhlocal,
+ int hglobal, int uhglobal));
+EXTERN aClass *find_class __P((int cclass));
+EXTERN void check_class();
+EXTERN void initclass();
+EXTERN void report_classes __P((aClient *sptr, char *to));
+EXTERN long get_sendq __P((aClient *cptr));
+#undef EXTERN
diff --git a/ircd/hash.c b/ircd/hash.c
new file mode 100644
index 0000000..9d31f47
--- /dev/null
+++ b/ircd/hash.c
@@ -0,0 +1,940 @@
+/************************************************************************
+ * 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.
+ */
+#ifndef lint
+static char rcsid[] = "@(#)$Id: hash.c,v 1.15 1999/06/25 21:50:01 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "s_defines.h"
+#define HASH_C
+#include "s_externs.h"
+#undef HASH_C
+
+static aHashEntry *clientTable = NULL;
+static aHashEntry *channelTable = NULL;
+static aHashEntry *serverTable = NULL;
+static unsigned int *hashtab = NULL;
+static int clhits = 0, clmiss = 0, clsize = 0;
+static int chhits = 0, chmiss = 0, chsize = 0;
+static int svsize = 0;
+int _HASHSIZE = 0;
+int _CHANNELHASHSIZE = 0;
+int _SERVERSIZE = 0;
+
+/*
+ * 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.
+ */
+
+/*
+ * hash_nick_name
+ *
+ * this function must be *quick*. Thus there should be no multiplication
+ * or division or modulus in the inner loop. subtraction and other bit
+ * operations allowed.
+ */
+static u_int hash_nick_name(nname, store)
+char *nname;
+int *store;
+{
+ Reg u_char *name = (u_char *)nname;
+ Reg u_char ch;
+ Reg u_int hash = 1;
+
+ for (; (ch = *name); name++)
+ {
+ hash <<= 1;
+ hash += hashtab[(int)ch];
+ }
+ /*
+ if (hash < 0)
+ hash = -hash;
+ */
+ *store = hash;
+ hash %= _HASHSIZE;
+ return (hash);
+}
+
+/*
+ * hash_channel_name
+ *
+ * calculate a hash value on at most the first 30 characters of the channel
+ * name. Most names are short than this or dissimilar in this range. There
+ * is little or no point hashing on a full channel name which maybe 255 chars
+ * long.
+ */
+static u_int hash_channel_name(hname, store, shortname)
+char *hname, shortname;
+int *store;
+{
+ Reg u_char *name = (u_char *)hname;
+ Reg u_char ch;
+ Reg int i = 30;
+ Reg u_int hash = 5;
+
+ if (*name == '!' && shortname == 0)
+ name += 1 + CHIDLEN;
+ for (; (ch = *name) && --i; name++)
+ {
+ hash <<= 1;
+ hash += hashtab[(u_int)ch] + (i << 1);
+ }
+ *store = hash;
+ hash %= _CHANNELHASHSIZE;
+ return (hash);
+}
+
+/* bigger prime
+ *
+ * given a positive integer, return a prime number that's larger
+ *
+ * 13feb94 gbl
+ */
+static int bigger_prime(size)
+int size;
+{
+ int trial, failure, sq;
+
+ if (size < 0)
+ return -1;
+
+ if (size < 4)
+ return size;
+
+ if (size % 2 == 0) /* Make sure it's odd because... */
+ size++;
+
+ for ( ; ; size += 2) /* ...no point checking even numbers - Core */
+ {
+ failure = 0;
+ sq = (int)sqrt((double)size);
+ for (trial = 2; trial <= sq ; trial++)
+ {
+ if ((size % trial) == 0)
+ {
+ failure = 1;
+ break;
+ }
+ }
+ if (!failure)
+ return size;
+ }
+ /* return -1; */ /* Never reached */
+}
+
+/*
+ * clear_*_hash_table
+ *
+ * Nullify the hashtable and its contents so it is completely empty.
+ */
+static void clear_client_hash_table(size)
+int size;
+{
+ _HASHSIZE = bigger_prime(size);
+ clhits = 0;
+ clmiss = 0;
+ if (!clientTable)
+ clientTable = (aHashEntry *)MyMalloc(_HASHSIZE *
+ sizeof(aHashEntry));
+ bzero((char *)clientTable, sizeof(aHashEntry) * _HASHSIZE);
+ Debug((DEBUG_DEBUG, "Client Hash Table Init: %d (%d)",
+ _HASHSIZE, size));
+}
+
+static void clear_channel_hash_table(size)
+int size;
+{
+ _CHANNELHASHSIZE = bigger_prime(size);
+ chmiss = 0;
+ chhits = 0;
+ if (!channelTable)
+ channelTable = (aHashEntry *)MyMalloc(_CHANNELHASHSIZE *
+ sizeof(aHashEntry));
+ bzero((char *)channelTable, sizeof(aHashEntry) * _CHANNELHASHSIZE);
+ Debug((DEBUG_DEBUG, "Channel Hash Table Init: %d (%d)",
+ _CHANNELHASHSIZE, size));
+}
+
+static void clear_server_hash_table(size)
+int size;
+{
+ _SERVERSIZE = bigger_prime(size);
+ if (!serverTable)
+ serverTable = (aHashEntry *)MyMalloc(_SERVERSIZE *
+ sizeof(aHashEntry));
+ bzero((char *)serverTable, sizeof(aHashEntry) * _SERVERSIZE);
+ Debug((DEBUG_DEBUG, "Server Hash Table Init: %d (%d)",
+ _SERVERSIZE, size));
+}
+
+void inithashtables()
+{
+ Reg int i;
+
+ clear_client_hash_table((_HASHSIZE) ? _HASHSIZE : HASHSIZE);
+ clear_channel_hash_table((_CHANNELHASHSIZE) ? _CHANNELHASHSIZE
+ : CHANNELHASHSIZE);
+ clear_server_hash_table((_SERVERSIZE) ? _SERVERSIZE : SERVERSIZE);
+
+ /*
+ * Moved multiplication out from the hashfunctions and into
+ * a pre-generated lookup table. Should save some CPU usage
+ * even on machines with a fast mathprocessor. -- Core
+ */
+ hashtab = (u_int *) MyMalloc(256 * sizeof(u_int));
+ for (i = 0; i < 256; i++)
+ hashtab[i] = tolower((char)i) * 109;
+}
+
+static void bigger_hash_table(size, table, new)
+int *size;
+aHashEntry *table;
+int new;
+{
+ Reg aClient *cptr;
+ Reg aChannel *chptr;
+ Reg aServer *sptr;
+ aHashEntry *otab = table;
+ int osize = *size;
+
+ while (!new || new <= osize)
+ if (!new)
+ {
+ new = osize;
+ new = bigger_prime(1 + (int)((float)new * 1.30));
+ }
+ else
+ new = bigger_prime(1 + new);
+
+ Debug((DEBUG_NOTICE, "bigger_h_table(*%#x = %d,%#x,%d)",
+ size, osize, table, new));
+
+ *size = new;
+ MyFree((char *)table);
+ table = (aHashEntry *)MyMalloc(sizeof(*table) * new);
+ bzero((char *)table, sizeof(*table) * new);
+
+ if (otab == channelTable)
+ {
+ Debug((DEBUG_ERROR, "Channel Hash Table from %d to %d (%d)",
+ osize, new, chsize));
+ chmiss = 0;
+ chhits = 0;
+ chsize = 0;
+ channelTable = table;
+ for (chptr = channel; chptr; chptr = chptr->nextch)
+ chptr->hnextch = NULL;
+ for (chptr = channel; chptr; chptr = chptr->nextch)
+ (void)add_to_channel_hash_table(chptr->chname, chptr);
+ sendto_flag(SCH_HASH, "Channel Hash Table from %d to %d (%d)",
+ osize, new, chsize);
+ }
+ else if (otab == clientTable)
+ {
+ Debug((DEBUG_ERROR, "Client Hash Table from %d to %d (%d)",
+ osize, new, clsize));
+ sendto_flag(SCH_HASH, "Client Hash Table from %d to %d (%d)",
+ osize, new, clsize);
+ clmiss = 0;
+ clhits = 0;
+ clsize = 0;
+ clientTable = table;
+ for (cptr = client; cptr; cptr = cptr->next)
+ cptr->hnext = NULL;
+ for (cptr = client; cptr; cptr = cptr->next)
+ (void)add_to_client_hash_table(cptr->name, cptr);
+ }
+ else if (otab == serverTable)
+ {
+ Debug((DEBUG_ERROR, "Server Hash Table from %d to %d (%d)",
+ osize, new, svsize));
+ sendto_flag(SCH_HASH, "Server Hash Table from %d to %d (%d)",
+ osize, new, svsize);
+ svsize = 0;
+ serverTable = table;
+ for (sptr = svrtop; sptr; sptr = sptr->nexts)
+ sptr->shnext = NULL;
+ for (sptr = svrtop; sptr; sptr = sptr->nexts)
+ (void)add_to_server_hash_table(sptr, sptr->bcptr);
+ }
+ ircd_writetune(tunefile);
+ return;
+}
+
+
+/*
+ * add_to_client_hash_table
+ */
+int add_to_client_hash_table(name, cptr)
+char *name;
+aClient *cptr;
+{
+ Reg u_int hashv;
+
+ hashv = hash_nick_name(name, &cptr->hashv);
+ cptr->hnext = (aClient *)clientTable[hashv].list;
+ clientTable[hashv].list = (void *)cptr;
+ clientTable[hashv].links++;
+ clientTable[hashv].hits++;
+ clsize++;
+ if (clsize > _HASHSIZE)
+ bigger_hash_table(&_HASHSIZE, clientTable, 0);
+ return 0;
+}
+
+/*
+ * add_to_channel_hash_table
+ */
+int add_to_channel_hash_table(name, chptr)
+char *name;
+aChannel *chptr;
+{
+ Reg u_int hashv;
+
+ hashv = hash_channel_name(name, &chptr->hashv, 0);
+ chptr->hnextch = (aChannel *)channelTable[hashv].list;
+ channelTable[hashv].list = (void *)chptr;
+ channelTable[hashv].links++;
+ channelTable[hashv].hits++;
+ chsize++;
+ if (chsize > _CHANNELHASHSIZE)
+ bigger_hash_table(&_CHANNELHASHSIZE, channelTable, 0);
+ return 0;
+}
+
+/*
+ * add_to_server_hash_table
+ */
+int add_to_server_hash_table(sptr, cptr)
+aServer *sptr;
+aClient *cptr;
+{
+ Reg u_int hashv;
+
+ Debug((DEBUG_DEBUG, "Add %s token %d/%d/%s cptr %#x to server table",
+ sptr->bcptr->name, sptr->stok, sptr->ltok, sptr->tok, cptr));
+ hashv = sptr->stok * 15053;
+ hashv %= _SERVERSIZE;
+ sptr->shnext = (aServer *)serverTable[hashv].list;
+ serverTable[hashv].list = (void *)sptr;
+ serverTable[hashv].links++;
+ serverTable[hashv].hits++;
+ svsize++;
+ if (svsize > _SERVERSIZE)
+ bigger_hash_table(&_SERVERSIZE, serverTable, 0);
+ return 0;
+}
+
+/*
+ * del_from_client_hash_table
+ */
+int del_from_client_hash_table(name, cptr)
+char *name;
+aClient *cptr;
+{
+ Reg aClient *tmp, *prev = NULL;
+ Reg u_int hashv;
+
+ hashv = cptr->hashv;
+ hashv %= _HASHSIZE;
+ 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--;
+ clsize--;
+ return 1;
+ }
+ else
+ {
+ sendto_flag(SCH_ERROR, "cl-hash table failure");
+ Debug((DEBUG_ERROR, "cl-hash table failure"));
+ /*
+ * Should never actually return from here and
+ * if we do it is an error/inconsistency in the
+ * hash table.
+ */
+ return -1;
+ }
+ }
+ prev = tmp;
+ }
+ return 0;
+}
+
+/*
+ * del_from_channel_hash_table
+ */
+int del_from_channel_hash_table(name, chptr)
+char *name;
+aChannel *chptr;
+{
+ Reg aChannel *tmp, *prev = NULL;
+ Reg u_int hashv;
+
+ hashv = chptr->hashv;
+ hashv %= _CHANNELHASHSIZE;
+ 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--;
+ chsize--;
+ return 1;
+ }
+ else
+ {
+ sendto_flag(SCH_ERROR, "ch-hash table failure");
+ return -1;
+ }
+ }
+ prev = tmp;
+ }
+ return 0;
+}
+
+
+/*
+ * del_from_server_hash_table
+ */
+int del_from_server_hash_table(sptr, cptr)
+aServer *sptr;
+aClient *cptr;
+{
+ Reg aServer *tmp, *prev = NULL;
+ Reg u_int hashv;
+
+ hashv = sptr->stok * 15053;
+ hashv %= _SERVERSIZE;
+ for (tmp = (aServer *)serverTable[hashv].list; tmp; tmp = tmp->shnext)
+ {
+ if (tmp == sptr)
+ {
+ if (prev)
+ prev->shnext = tmp->shnext;
+ else
+ serverTable[hashv].list = (void *)tmp->shnext;
+ tmp->shnext = NULL;
+ if (serverTable[hashv].links > 0)
+ {
+ serverTable[hashv].links--;
+ svsize--;
+ return 1;
+ }
+ else
+ {
+ sendto_flag(SCH_ERROR, "se-hash table failure");
+ return -1;
+ }
+ }
+ prev = tmp;
+ }
+ return 0;
+}
+
+
+/*
+ * hash_find_client
+ */
+aClient *hash_find_client(name, cptr)
+char *name;
+aClient *cptr;
+{
+ Reg aClient *tmp;
+ Reg aClient *prv = NULL;
+ Reg aHashEntry *tmp3;
+ u_int hashv, hv;
+
+ hashv = hash_nick_name(name, &hv);
+ tmp3 = &clientTable[hashv];
+
+ /*
+ * Got the bucket, now search the chain.
+ */
+ for (tmp = (aClient *)tmp3->list; tmp; prv = tmp, tmp = tmp->hnext)
+ if (hv == tmp->hashv && mycmp(name, tmp->name) == 0)
+ {
+ 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;
+ }
+ return (tmp);
+ }
+ clmiss++;
+ return (cptr);
+}
+
+/*
+ * hash_find_server
+ */
+aClient *hash_find_server(server, cptr)
+char *server;
+aClient *cptr;
+{
+ Reg aClient *tmp, *prv = NULL;
+ Reg char *t;
+ Reg char ch;
+ aHashEntry *tmp3;
+ u_int hashv, hv;
+
+ hashv = hash_nick_name(server, &hv);
+ tmp3 = &clientTable[hashv];
+
+ for (tmp = (aClient *)tmp3->list; tmp; prv = tmp, tmp = tmp->hnext)
+ {
+ if (!IsServer(tmp) && !IsMe(tmp))
+ continue;
+ if (hv == tmp->hashv && mycmp(server, tmp->name) == 0)
+ {
+ clhits++;
+ if (prv)
+ {
+ aClient *tmp2;
+
+ tmp2 = (aClient *)tmp3->list;
+ tmp3->list = (void *)tmp;
+ prv->hnext = tmp->hnext;
+ tmp->hnext = tmp2;
+ }
+ return (tmp);
+ }
+ }
+ 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 isn't 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 = '*';
+ /*
+ * Don't need to check IsServer() here since nicknames can't
+ * have *'s in them anyway.
+ */
+ if (((tmp = hash_find_client(t, cptr))) != cptr)
+ {
+ *t = ch;
+ return (tmp);
+ }
+ *t = ch;
+ }
+ clmiss++;
+ return (cptr);
+}
+
+/*
+ * hash_find_channel
+ */
+aChannel *hash_find_channel(name, chptr)
+char *name;
+aChannel *chptr;
+{
+ Reg aChannel *tmp, *prv = NULL;
+ Reg aHashEntry *tmp3;
+ u_int hashv, hv;
+
+ hashv = hash_channel_name(name, &hv, 0);
+ tmp3 = &channelTable[hashv];
+
+ for (tmp = (aChannel *)tmp3->list; tmp; prv = tmp, tmp = tmp->hnextch)
+ if (hv == tmp->hashv && mycmp(name, tmp->chname) == 0)
+ {
+ chhits++;
+ if (prv)
+ {
+ register aChannel *tmp2;
+
+ tmp2 = (aChannel *)tmp3->list;
+ tmp3->list = (void *)tmp;
+ prv->hnextch = tmp->hnextch;
+ tmp->hnextch = tmp2;
+ }
+ return (tmp);
+ }
+ chmiss++;
+ return chptr;
+}
+
+/*
+ * hash_find_channels
+ *
+ * look up matches for !?????name instead of a real match.
+ */
+aChannel *hash_find_channels(name, chptr)
+char *name;
+aChannel *chptr;
+{
+ aChannel *tmp;
+ u_int hashv, hv;
+
+ if (chptr == NULL)
+ {
+ aHashEntry *tmp3;
+
+ hashv = hash_channel_name(name, &hv, 1);
+ tmp3 = &channelTable[hashv];
+ chptr = (aChannel *) tmp3->list;
+ }
+ else
+ {
+ hv = chptr->hashv;
+ chptr = chptr->hnextch;
+ }
+
+ if (chptr == NULL)
+ return NULL;
+ for (tmp = chptr; tmp; tmp = tmp->hnextch)
+ if (hv == tmp->hashv && *tmp->chname == '!' &&
+ mycmp(name, tmp->chname + CHIDLEN + 1) == 0)
+ {
+ chhits++;
+ return (tmp);
+ }
+ chmiss++;
+ return NULL;
+}
+
+/*
+ * hash_find_stoken
+ */
+aServer *hash_find_stoken(tok, cptr, dummy)
+int tok;
+aClient *cptr;
+void *dummy;
+{
+ Reg aServer *tmp, *prv = NULL;
+ Reg aHashEntry *tmp3;
+ u_int hashv, hv;
+
+ hv = hashv = tok * 15053;
+ hashv %= _SERVERSIZE;
+ tmp3 = &serverTable[hashv];
+
+ for (tmp = (aServer *)tmp3->list; tmp; prv = tmp, tmp = tmp->shnext)
+ if (tmp->stok == tok && tmp->bcptr->from == cptr)
+ {
+ if (prv)
+ {
+ Reg aServer *tmp2;
+
+ tmp2 = (aServer *)tmp3->list;
+ tmp3->list = (void *)tmp;
+ prv->shnext = tmp->shnext;
+ tmp->shnext = tmp2;
+ }
+ return (tmp);
+ }
+ return (aServer *)dummy;
+}
+
+/*
+ * 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;
+
+ 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 (2);
+ case 'r' :
+ {
+ Reg aClient *acptr;
+
+ sendto_one(sptr,"NOTICE %s :Rehashing Client List.", parv[0]);
+ clear_client_hash_table(_HASHSIZE);
+ for (acptr = client; acptr; acptr = acptr->next)
+ (void)add_to_client_hash_table(acptr->name, acptr);
+ break;
+ }
+ case 'R' :
+ {
+ Reg aChannel *acptr;
+
+ sendto_one(sptr,"NOTICE %s :Rehashing Channel List.", parv[0]);
+ clear_channel_hash_table(_CHANNELHASHSIZE);
+ 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_channel_name(parv[2], NULL, 0));
+ return (2);
+ case 'h' :
+ if (parc > 2)
+ sendto_one(sptr,"NOTICE %s :%s hash to entry %d",
+ parv[0], parv[2],
+ hash_nick_name(parv[2], NULL));
+ return (2);
+ case 'n' :
+ {
+ aClient *tmp;
+ int max;
+
+ if (parc <= 2 || !IsAnOper(sptr))
+ return (1);
+ 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 (2);
+ }
+ case 'N' :
+ {
+ aChannel *tmp;
+ int max;
+
+ if (parc <= 2 || !IsAnOper(sptr))
+ return (1);
+ 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 (2);
+ }
+ case 'S' :
+#else
+ if (parc>1&&!strcmp(parv[1],"sums")){
+#endif
+ sendto_one(sptr, "NOTICE %s :[SBSDC] [SUSER]", parv[0]);
+ sendto_one(sptr, "NOTICE %s :[SSERV] [IRCDC]", parv[0]);
+ sendto_one(sptr, "NOTICE %s :[CHANC] [SMISC]", parv[0]);
+ sendto_one(sptr, "NOTICE %s :[HASHC] [VERSH]", parv[0]);
+ sendto_one(sptr, "NOTICE %s :[MAKEF] HOSTID", parv[0]);
+#ifndef DEBUGMODE
+ }
+#endif
+ return 2;
+#ifdef DEBUGMODE
+ case 'z' :
+ {
+ if (parc <= 2 || !IsAnOper(sptr))
+ return 1;
+ l = atoi(parv[2]);
+ if (l < 256)
+ return 1;
+ bigger_hash_table(&_HASHSIZE, clientTable, l);
+ sendto_one(sptr, "NOTICE %s :HASHSIZE now %d", parv[0], l);
+ break;
+ }
+ case 'Z' :
+ {
+ if (parc <= 2 || !IsAnOper(sptr))
+ return 1;
+ l = atoi(parv[2]);
+ if (l < 256)
+ return 1;
+ bigger_hash_table(&_CHANNELHASHSIZE, channelTable, l);
+ 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 * (float)tothits) / (1.0 * (float)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 2;
+#endif
+}
+
+
diff --git a/ircd/hash_def.h b/ircd/hash_def.h
new file mode 100644
index 0000000..e19c3ce
--- /dev/null
+++ b/ircd/hash_def.h
@@ -0,0 +1,32 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/hash_def.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.
+ */
+
+typedef struct hashentry {
+ int hits;
+ int links;
+ void *list;
+} aHashEntry;
+
+/*
+ * it is not important for these to be "big" as ircd will make them grow
+ * as required.
+ */
+#define HASHSIZE ((int)((float)MAXCONNECTIONS*1.75))
+#define CHANNELHASHSIZE ((int)(((float)MAXCONNECTIONS*1.75)/2.0))
+#define SERVERSIZE (MAXCONNECTIONS/10)
diff --git a/ircd/hash_ext.h b/ircd/hash_ext.h
new file mode 100644
index 0000000..8ee1d88
--- /dev/null
+++ b/ircd/hash_ext.h
@@ -0,0 +1,52 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/hash_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in ircd/hash.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef HASH_C
+extern int _HASHSIZE;
+extern int _CHANNELHASHSIZE;
+extern int _SERVERSIZE;
+#endif /* HASH_C */
+
+/* External definitions for global functions.
+ */
+#ifndef HASH_C
+#define EXTERN extern
+#else /* HASH_C */
+#define EXTERN
+#endif /* HASH_C */
+EXTERN void inithashtables();
+EXTERN int add_to_client_hash_table __P((char *name, aClient *cptr));
+EXTERN int add_to_channel_hash_table __P((char *name, aChannel *chptr));
+EXTERN int add_to_server_hash_table __P((aServer *sptr, aClient *cptr));
+EXTERN int del_from_client_hash_table __P((char *name, aClient *cptr));
+EXTERN int del_from_channel_hash_table __P((char *name, aChannel *chptr));
+EXTERN int del_from_server_hash_table __P((aServer *sptr, aClient *cptr));
+EXTERN aClient *hash_find_client __P((char *name, aClient *cptr));
+EXTERN aClient *hash_find_server __P((char *server, aClient *cptr));
+EXTERN aChannel *hash_find_channel __P((char *name, aChannel *chptr));
+EXTERN aChannel *hash_find_channels __P((char *name, aChannel *chptr));
+EXTERN aServer *hash_find_stoken __P((int tok, aClient *cptr, void *dummy));
+EXTERN int m_hash __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+#undef EXTERN
diff --git a/ircd/ircd.c b/ircd/ircd.c
new file mode 100644
index 0000000..72bbf95
--- /dev/null
+++ b/ircd/ircd.c
@@ -0,0 +1,1287 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/ircd.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: ircd.c,v 1.62 1999/08/13 17:17:42 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "s_defines.h"
+#define IRCD_C
+#include "s_externs.h"
+#undef IRCD_C
+
+aClient me; /* That's me */
+aClient *client = &me; /* Pointer to beginning of Client list */
+
+static void open_debugfile(), setup_signals(), io_loop();
+
+istat_t istat;
+char **myargv;
+int rehashed = 0;
+int portnum = -1; /* Server port number, listening this */
+char *configfile = IRCDCONF_PATH; /* Server configuration file */
+int debuglevel = -1; /* Server debug level */
+int bootopt = BOOT_PROT|BOOT_STRICTPROT; /* Server boot option flags */
+char *debugmode = ""; /* -"- -"- -"- -"- */
+char *sbrk0; /* initial sbrk(0) */
+char *tunefile = IRCDTUNE_PATH;
+static int dorehash = 0,
+ dorestart = 0,
+ restart_iauth = 0;
+
+time_t nextconnect = 1; /* time for next try_connections call */
+time_t nextgarbage = 1; /* time for next collect_channel_garbage 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 nextiarestart = 1; /* next time to check if iauth is alive */
+
+#ifdef PROFIL
+extern etext();
+
+RETSIGTYPE s_monitor(s)
+int s;
+{
+ static int mon = 0;
+#if POSIX_SIGNALS
+ struct sigaction act;
+#endif
+
+ (void)moncontrol(mon);
+ mon = 1 - mon;
+#if 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
+
+RETSIGTYPE s_die(s)
+int s;
+{
+#ifdef USE_SYSLOG
+ (void)syslog(LOG_CRIT, "Server Killed By SIGTERM");
+#endif
+ ircd_writetune(tunefile);
+ flush_connections(me.fd);
+ exit(-1);
+}
+
+#if defined(USE_IAUTH)
+RETSIGTYPE s_slave(s)
+int s;
+{
+# if POSIX_SIGNALS
+ struct sigaction act;
+
+ act.sa_handler = s_slave;
+ 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_slave);
+# endif
+ restart_iauth = 1;
+}
+#endif
+
+static RETSIGTYPE s_rehash(s)
+int s;
+{
+#if POSIX_SIGNALS
+ struct sigaction act;
+
+ 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
+ dorehash = 1;
+}
+
+void restart(mesg)
+char *mesg;
+{
+#ifdef USE_SYSLOG
+ (void)syslog(LOG_WARNING, "Restarting Server because: %s (%u)", mesg,
+ (u_int)((char *)sbrk((size_t)0)-sbrk0));
+#endif
+ sendto_flag(SCH_NOTICE, "Restarting server because: %s (%u)", mesg,
+ (u_int)((char *)sbrk((size_t)0)-sbrk0));
+ server_reboot();
+}
+
+RETSIGTYPE s_restart(s)
+int s;
+{
+#if POSIX_SIGNALS
+ struct sigaction act;
+
+ act.sa_handler = s_restart;
+ act.sa_flags = 0;
+ (void)sigemptyset(&act.sa_mask);
+ (void)sigaddset(&act.sa_mask, SIGINT);
+ (void)sigaction(SIGINT, &act, NULL);
+#else
+ (void)signal(SIGHUP, SIG_DFL); /* sysV -argv */
+#endif
+ dorestart = 1;
+}
+
+void server_reboot()
+{
+ Reg int i;
+
+ sendto_flag(SCH_NOTICE, "Aieeeee!!! Restarting server... (%u)",
+ (u_int)((char *)sbrk((size_t)0)-sbrk0));
+
+ Debug((DEBUG_NOTICE,"Restarting server..."));
+ 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);
+ ircd_writetune(tunefile);
+ if (!(bootopt & (BOOT_INETD|BOOT_OPER)))
+ {
+ (void)execv(IRCD_PATH, 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", IRCD_PATH,
+ 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;
+{
+ static time_t lastsort = 0;
+ Reg aConfItem *aconf;
+ Reg aClient *cptr;
+ aConfItem **pconf;
+ int confrq;
+ time_t next = 0;
+ aClass *cltmp;
+ aConfItem *con_conf = NULL;
+ double f, f2;
+ aCPing *cp;
+
+ 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_ZCONNECT_SERVER)))
+ continue;
+ /*
+ ** 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;
+ }
+ send_ping(aconf);
+ if (aconf->port <= 0)
+ continue;
+
+ cltmp = Class(aconf);
+ confrq = get_con_freq(cltmp);
+ aconf->hold = currenttime + confrq;
+ /*
+ ** Found a CONNECT config with port specified, scan clients
+ ** and see if this server is already connected?
+ */
+ cptr = find_name(aconf->name, (aClient *)NULL);
+ if (!cptr)
+ cptr = find_mask(aconf->name, (aClient *)NULL);
+ /*
+ ** It is not connected, scan clients and see if any matches
+ ** a D(eny) line.
+ */
+ if (find_denied(aconf->name, Class(cltmp)))
+ continue;
+ /* We have a candidate, let's see if it could be the best. */
+ if (!cptr && (Links(cltmp) < MaxLinks(cltmp)) &&
+ (!con_conf ||
+ (con_conf->pref > aconf->pref && aconf->pref >= 0) ||
+ (con_conf->pref == -1 &&
+ Class(cltmp) > ConfClass(con_conf))))
+ con_conf = aconf;
+ if ((next > aconf->hold) || (next == 0))
+ next = aconf->hold;
+ }
+ if (con_conf)
+ {
+ 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_flag(SCH_NOTICE,
+ "Connection to %s[%s] activated.",
+ con_conf->name, con_conf->host);
+ }
+ Debug((DEBUG_NOTICE,"Next connection check : %s", myctime(next)));
+ /*
+ * calculate preference value based on accumulated stats.
+ */
+ if (!lastsort || lastsort < currenttime)
+ {
+ for (aconf = conf; aconf; aconf = aconf->next)
+ if (!(cp = aconf->ping) || !cp->seq || !cp->recvd)
+ aconf->pref = -1;
+ else
+ {
+ f = (double)cp->recvd / (double)cp->seq;
+ f2 = pow(f, (double)20.0);
+ if (f2 < (double)0.001)
+ f = (double)0.001;
+ else
+ f = f2;
+ f2 = (double)cp->ping / (double)cp->recvd;
+ f = f2 / f;
+ if (f > 100000.0)
+ f = 100000.0;
+ aconf->pref = (u_int) (f * (double)100.0);
+ }
+ lastsort = currenttime + 60;
+ }
+ return (next);
+}
+
+
+static void close_held(cptr)
+aClient *cptr;
+{
+ Reg aClient *acptr;
+ int i;
+
+ for (i = highest_fd; i >= 0; i--)
+ if ((acptr = local[i]) && (cptr->port == acptr->port) &&
+ (acptr != cptr) && IsHeld(acptr) &&
+ !bcmp((char *)&cptr->ip, (char *)&acptr->ip,
+ sizeof(acptr->ip)))
+ {
+ (void) exit_client(acptr, acptr, &me,
+ "Reconnect Timeout");
+ return;
+ }
+}
+
+
+static time_t check_pings(currenttime)
+time_t currenttime;
+{
+ static time_t lkill = 0;
+ Reg aClient *cptr;
+ Reg int kflag = 0;
+ int ping = 0, i, rflag = 0;
+ time_t oldest = 0, timeout;
+ char *reason;
+
+ for (i = highest_fd; i >= 0; i--)
+ {
+ if (!(cptr = local[i]) || IsListening(cptr) || IsLog(cptr) ||
+ IsHeld(cptr))
+ continue;
+
+ /*
+ * K and R lines once per minute, max. This is the max.
+ * granularity in K-lines anyway (with time field).
+ */
+ if ((currenttime - lkill > 60) || rehashed)
+ {
+ if (IsPerson(cptr))
+ {
+ kflag = find_kill(cptr, rehashed, &reason);
+#ifdef R_LINES_OFTEN
+ rflag = find_restrict(cptr);
+#endif
+ }
+ else
+ {
+ kflag = rflag = 0;
+ reason = NULL;
+ }
+ }
+ ping = IsRegistered(cptr) ? get_client_ping(cptr) :
+ ACCEPTTIMEOUT;
+ Debug((DEBUG_DEBUG, "c(%s) %d p %d k %d r %d a %d",
+ cptr->name, cptr->status, ping, kflag, 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 (!kflag && !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 (kflag || rflag ||
+ ((currenttime - cptr->lasttime) >= (2 * ping) &&
+ (cptr->flags & FLAGS_PINGSENT)) ||
+ (!IsRegistered(cptr) &&
+ (currenttime - cptr->firsttime) >= ping))
+ {
+ if (IsReconnect(cptr))
+ {
+ sendto_flag(SCH_ERROR,
+ "Reconnect timeout to %s",
+ get_client_name(cptr, TRUE));
+ close_held(cptr);
+ (void)exit_client(cptr, cptr, &me,
+ "Ping timeout");
+ }
+ if (!IsRegistered(cptr) &&
+ (DoingDNS(cptr) || DoingAuth(cptr) ||
+ DoingXAuth(cptr)))
+ {
+ if (cptr->authfd >= 0)
+ {
+ (void)close(cptr->authfd);
+ cptr->authfd = -1;
+ cptr->count = 0;
+ *cptr->buffer = '\0';
+ }
+ Debug((DEBUG_NOTICE, "%s/%c%s timeout %s",
+ (DoingDNS(cptr)) ? "DNS" : "dns",
+ (DoingXAuth(cptr)) ? "X" : "x",
+ (DoingAuth(cptr)) ? "AUTH" : "auth",
+ get_client_name(cptr,TRUE)));
+ del_queries((char *)cptr);
+ ClearAuth(cptr);
+#if defined(USE_IAUTH)
+ if (DoingDNS(cptr) || DoingXAuth(cptr))
+ {
+ if (DoingDNS(cptr) &&
+ (iauth_options & XOPT_EXTWAIT))
+ {
+ /* iauth wants more time */
+ sendto_iauth("%d d", cptr->fd);
+ ClearDNS(cptr);
+ cptr->lasttime = currenttime;
+ continue;
+ }
+ if (DoingXAuth(cptr) &&
+ (iauth_options & XOPT_NOTIMEOUT))
+ {
+ cptr->exitc = EXITC_AUTHTOUT;
+ sendto_iauth("%d T", cptr->fd);
+ ereject_user(cptr, " Timeout ",
+ "Authentication Timeout");
+ continue;
+ }
+ sendto_iauth("%d T", cptr->fd);
+ SetDoneXAuth(cptr);
+ }
+#endif
+ ClearDNS(cptr);
+ ClearXAuth(cptr);
+ ClearWXAuth(cptr);
+ cptr->firsttime = currenttime;
+ cptr->lasttime = currenttime;
+ continue;
+ }
+ if (IsServer(cptr) || IsConnecting(cptr) ||
+ IsHandshake(cptr))
+ sendto_flag(SCH_NOTICE,
+ "No response from %s closing link",
+ 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 (kflag && IsPerson(cptr))
+ {
+ char buf[100];
+
+ sendto_flag(SCH_NOTICE,
+ "Kill line active for %s",
+ get_client_name(cptr, FALSE));
+ cptr->exitc = EXITC_KLINE;
+ if (!BadPtr(reason))
+ sprintf(buf, "Kill line active: %.80s",
+ reason);
+ (void)exit_client(cptr, cptr, &me, (reason) ?
+ buf : "Kill line active");
+ }
+
+#if defined(R_LINES) && defined(R_LINES_OFTEN)
+ else if (IsPerson(cptr) && rflag)
+ {
+ sendto_flag(SCH_NOTICE,
+ "Restricting %s, closing link.",
+ get_client_name(cptr,FALSE));
+ cptr->exitc = EXITC_RLINE;
+ (void)exit_client(cptr, cptr, &me,
+ "Restricting");
+ }
+#endif
+ else
+ {
+ cptr->exitc = EXITC_PING;
+ (void)exit_client(cptr, cptr, &me,
+ "Ping timeout");
+ }
+ continue;
+ }
+ else if (IsRegistered(cptr) &&
+ (cptr->flags & FLAGS_PINGSENT) == 0)
+ {
+ /*
+ * if we havent PINGed the connection and we havent
+ * heard from it in a while, PING it to make sure
+ * it is still alive.
+ */
+ cptr->flags |= FLAGS_PINGSENT;
+ /* not nice but does the job */
+ cptr->lasttime = currenttime - ping;
+ sendto_one(cptr, "PING :%s", me.name);
+ }
+ping_timeout:
+ timeout = cptr->lasttime + ping;
+ while (timeout <= currenttime)
+ timeout += ping;
+ if (timeout < oldest || !oldest)
+ oldest = timeout;
+ }
+ if (currenttime - lkill > 60)
+ lkill = currenttime;
+ if (!oldest || oldest < currenttime)
+ oldest = currenttime + PINGFREQUENCY;
+ if (oldest < currenttime + 2)
+ oldest += 2;
+ Debug((DEBUG_NOTICE,"Next check_ping() call at: %s, %d %d %d",
+ myctime(oldest), ping, oldest, currenttime));
+ return (oldest);
+}
+
+
+static void setup_me(mp)
+aClient *mp;
+{
+ struct passwd *p;
+
+ p = getpwuid(getuid());
+ strncpyzt(mp->username, (p) ? p->pw_name : "unknown",
+ sizeof(mp->username));
+ (void)get_my_name(mp, mp->sockhost, sizeof(mp->sockhost)-1);
+
+ /* Setup hostp - fake record to resolve localhost. -Toor */
+ mp->hostp = (struct hostent *)MyMalloc(sizeof(struct hostent));
+ mp->hostp->h_name = MyMalloc(strlen(me.sockhost)+1);
+ strcpy(mp->hostp->h_name, mp->sockhost);
+ mp->hostp->h_aliases = (char **)MyMalloc(sizeof(char *));
+ *mp->hostp->h_aliases = NULL;
+ mp->hostp->h_addrtype = AFINET;
+ mp->hostp->h_length =
+#ifdef INET6
+ IN6ADDRSZ;
+#else
+ sizeof(long);
+#endif
+ mp->hostp->h_addr_list = (char **)MyMalloc(2*sizeof(char *));
+#ifdef INET6
+ mp->hostp->h_addr_list[0] = (char *)&in6addr_loopback;
+#else
+ mp->hostp->h_addr_list[0] = (void *)MyMalloc(mp->hostp->h_length);
+ *(long *)(mp->hostp->h_addr_list[0]) = IN_LOOPBACKNET;
+#endif
+ mp->hostp->h_addr_list[1] = NULL ;
+
+ if (mp->name[0] == '\0')
+ strncpyzt(mp->name, mp->sockhost, sizeof(mp->name));
+ if (me.info == DefInfo)
+ me.info = mystrdup("IRCers United");
+ mp->lasttime = mp->since = mp->firsttime = time(NULL);
+ mp->hopcount = 0;
+ mp->authfd = -1;
+ mp->auth = mp->username;
+ mp->confs = NULL;
+ mp->flags = 0;
+ mp->acpt = mp->from = mp;
+ mp->next = NULL;
+ mp->user = NULL;
+ mp->fd = -1;
+ SetMe(mp);
+ (void) make_server(mp);
+ mp->serv->snum = find_server_num (ME);
+ (void) make_user(mp);
+ istat.is_users++; /* here, cptr->next is NULL, see make_user() */
+ mp->user->flags |= FLAGS_OPER;
+ mp->serv->up = mp->name;
+ mp->user->server = find_server_string(mp->serv->snum);
+ strncpyzt(mp->user->username, (p) ? p->pw_name : "unknown",
+ sizeof(mp->user->username));
+ (void) strcpy(mp->user->host, mp->name);
+
+ (void)add_to_client_hash_table(mp->name, mp);
+
+ setup_server_channels(mp);
+}
+
+/*
+** 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 [-a] [-b] [-c]%s [-h servername] [-q] [-o] [-i] [-T tunefile] [-p (strict|on|off)] [-s] [-v] %s\n",
+#ifdef CMDLINE_CONFIG
+ " [-f config]",
+#else
+ "",
+#endif
+#ifdef DEBUGMODE
+ " [-x loglevel] [-t]"
+#else
+ ""
+#endif
+ );
+ (void)printf("Server not started\n\n");
+ exit(-1);
+}
+
+int main(argc, argv)
+int argc;
+char *argv[];
+{
+ uid_t uid, euid;
+
+ (void) myctime(time(NULL)); /* Don't ask, just *don't* ask */
+ 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
+
+#ifdef CHROOTDIR
+ ircd_res_init();
+ if (chroot(ROOT_PATH))
+ {
+ perror("chroot");
+ (void)fprintf(stderr,"%s: Cannot chroot: %s.\n", IRCD_PATH,
+ ROOT_PATH);
+ exit(5);
+ }
+#endif /*CHROOTDIR*/
+
+#ifdef ZIP_LINKS
+ if (zlib_version[0] == '0')
+ {
+ fprintf(stderr, "zlib version 1.0 or higher required\n");
+ exit(1);
+ }
+ if (zlib_version[0] != ZLIB_VERSION[0])
+ {
+ fprintf(stderr, "incompatible zlib version\n");
+ exit(1);
+ }
+ if (strcmp(zlib_version, ZLIB_VERSION) != 0)
+ {
+ fprintf(stderr, "warning: different zlib version\n");
+ }
+#endif
+
+ myargv = argv;
+ (void)umask(077); /* better safe than sorry --SRB */
+ bzero((char *)&me, sizeof(me));
+
+ version = make_version(); /* Generate readable version string */
+
+ /*
+ ** 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 'b':
+ bootopt |= BOOT_BADTUNE;
+ break;
+ case 'c':
+ bootopt |= BOOT_CONSOLE;
+ break;
+ case 'q':
+ bootopt |= BOOT_QUICK;
+ 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
+ case 'h':
+ if (*p == '\0')
+ bad_command();
+ strncpyzt(me.name, p, sizeof(me.name));
+ break;
+ case 'i':
+ bootopt |= BOOT_INETD|BOOT_AUTODIE;
+ break;
+ case 'p':
+ if (!strcmp(p, "strict"))
+ bootopt |= BOOT_PROT|BOOT_STRICTPROT;
+ else if (!strcmp(p, "on"))
+ bootopt |= BOOT_PROT;
+ else if (!strcmp(p, "off"))
+ bootopt &= ~(BOOT_PROT|BOOT_STRICTPROT);
+ else
+ bad_command();
+ break;
+ case 's':
+ bootopt |= BOOT_NOIAUTH;
+ break;
+ case 't':
+ (void)setuid((uid_t)uid);
+ bootopt |= BOOT_TTY;
+ break;
+ case 'T':
+ if (*p == '\0')
+ bad_command();
+ tunefile = p;
+ break;
+ case 'v':
+ (void)printf("ircd %s %s\n\tzlib %s\n\t%s #%s\n",
+ version, serveropts,
+#ifndef ZIP_LINKS
+ "not used",
+#else
+ zlib_version,
+#endif
+ creation, generation);
+ 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();
+ }
+ }
+
+ if (argc > 0)
+ bad_command(); /* This exits out */
+
+#if defined(USE_IAUTH) && defined(__CYGWIN32__)
+ if ((bootopt & BOOT_NOIAUTH) == 0)
+ {
+ bootopt |= BOOT_NOIAUTH;
+ (void)fprintf(stderr, "WARNING: Assuming -s option.\n");
+ }
+#endif
+
+#ifndef 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)
+ (void)setuid((uid_t)euid);
+# if defined(IRC_UID) && defined(IRC_GID)
+ if ((int)getuid() == 0)
+ {
+ /* 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)setgid(IRC_GID);
+ (void)setuid(IRC_UID);
+ }
+# endif
+#endif /*CHROOTDIR/UID/GID*/
+
+#if defined(USE_IAUTH)
+ if ((bootopt & BOOT_NOIAUTH) == 0)
+ switch (vfork())
+ {
+ case -1:
+ fprintf(stderr, "%s: Unable to fork!", myargv[0]);
+ exit(-1);
+ case 0:
+ close(0); close(1); close(3);
+ if (execl(IAUTH_PATH, IAUTH, "-X", NULL) < 0)
+ _exit(-1);
+ default:
+ {
+ int rc;
+
+ (void)wait(&rc);
+ if (rc != 0)
+ {
+ fprintf(stderr,
+ "%s: error: unable to find \"%s\".\n",
+ myargv[0], IAUTH_PATH);
+ exit(-1);
+ }
+ }
+ }
+#endif
+
+ setup_signals();
+
+ /* 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);
+ }
+
+ initstats();
+ ircd_readtune(tunefile);
+ timeofday = time(NULL);
+#ifdef CACHED_MOTD
+ motd = NULL;
+ read_motd(IRCDMOTD_PATH);
+#endif
+ inithashtables();
+ initlists();
+ initclass();
+ initwhowas();
+ timeofday = time(NULL);
+ open_debugfile();
+ timeofday = time(NULL);
+ (void)init_sys();
+
+#ifdef USE_SYSLOG
+ openlog(myargv[0], LOG_PID|LOG_NDELAY, LOG_FACILITY);
+#endif
+ timeofday = time(NULL);
+ if (initconf(bootopt) == -1)
+ {
+ Debug((DEBUG_FATAL, "Failed in reading configuration file %s",
+ configfile));
+ /* no can do.
+ (void)printf("Couldn't open configuration file %s\n",
+ configfile);
+ */
+ exit(-1);
+ }
+ else
+ {
+ aClient *acptr = NULL;
+ int i;
+
+ for (i = 0; i <= highest_fd; i++)
+ {
+ if (!(acptr = local[i]))
+ continue;
+ if (IsListening(acptr))
+ break;
+ acptr = NULL;
+ }
+ /* exit if there is nothing to listen to */
+ if (acptr == NULL)
+ exit(-1);
+ }
+
+ dbuf_init();
+ setup_me(&me);
+ check_class();
+ ircd_writetune(tunefile);
+ if (bootopt & BOOT_INETD)
+ {
+ aClient *tmp;
+ aConfItem *aconf;
+
+ tmp = make_client(NULL);
+
+ tmp->fd = 0;
+ tmp->flags = FLAGS_LISTEN;
+ tmp->acpt = tmp;
+ tmp->from = tmp;
+ tmp->firsttime = time(NULL);
+
+ SetMe(tmp);
+
+ (void)strcpy(tmp->name, "*");
+
+ if (inetport(tmp, 0, "0.0.0.0", 0))
+ tmp->fd = -1;
+ if (tmp->fd == 0)
+ {
+ aconf = make_conf();
+ aconf->status = CONF_LISTEN_PORT;
+ aconf->clients++;
+ aconf->next = conf;
+ conf = aconf;
+
+ tmp->confs = make_link();
+ tmp->confs->next = NULL;
+ tmp->confs->value.aconf = aconf;
+ add_fd(tmp->fd, &fdas);
+ add_fd(tmp->fd, &fdall);
+ set_non_blocking(tmp->fd, tmp);
+ }
+ else
+ exit(5);
+ }
+ if (bootopt & BOOT_OPER)
+ {
+ aClient *tmp = add_connection(&me, 0);
+
+ if (!tmp)
+ exit(1);
+ SetMaster(tmp);
+ local[0] = tmp;
+ }
+ else
+ write_pidfile();
+
+ Debug((DEBUG_NOTICE,"Server ready..."));
+#ifdef USE_SYSLOG
+ syslog(LOG_NOTICE, "Server Ready: v%s (%s #%s)", version, creation,
+ generation);
+#endif
+ timeofday = time(NULL);
+ while (1)
+ io_loop();
+}
+
+
+void io_loop()
+{
+ static time_t delay = 0;
+ int maxs = 4;
+
+ /*
+ ** 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 && timeofday >= nextconnect)
+ nextconnect = try_connections(timeofday);
+ /*
+ ** Every once in a while, hunt channel structures that
+ ** can be freed.
+ */
+ if (timeofday >= nextgarbage)
+ nextgarbage = collect_channel_garbage(timeofday);
+ /*
+ ** DNS checks. One to timeout queries, one for cache expiries.
+ */
+ if (timeofday >= nextdnscheck)
+ nextdnscheck = timeout_query_list(timeofday);
+ if (timeofday >= nextexpire)
+ nextexpire = expire_cache(timeofday);
+ /*
+ ** 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 -= timeofday;
+ /*
+ ** 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);
+
+ /*
+ ** First, try to drain traffic from servers (this includes listening
+ ** ports). Give up, either if there's no traffic, or too many
+ ** iterations.
+ */
+ while (maxs--)
+ if (read_message(0, &fdas, 0))
+ flush_fdary(&fdas);
+ else
+ break;
+
+ Debug((DEBUG_DEBUG, "delay for %d", delay));
+ /*
+ ** Second, deal with _all_ clients but only try to empty sendQ's for
+ ** servers. Other clients are dealt with below..
+ */
+ if (read_message(1, &fdall, 1) == 0 && delay > 1)
+ {
+ /*
+ ** Timed out (e.g. *NO* traffic at all).
+ ** Try again but also check to empty sendQ's for all clients.
+ */
+ sendto_flag(SCH_DEBUG, "read_message(RO) -> 0 [%d]", delay);
+ (void)read_message(delay - 1, &fdall, 0);
+ }
+ timeofday = time(NULL);
+
+ Debug((DEBUG_DEBUG ,"Got message(s)"));
+ /*
+ ** ...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 (timeofday >= nextping)
+ {
+ nextping = check_pings(timeofday);
+ rehashed = 0;
+ }
+
+ if (dorestart)
+ restart("Caught SIGINT");
+ if (dorehash)
+ { /* Only on signal, not on oper /rehash */
+ ircd_writetune(tunefile);
+ (void)rehash(&me, &me, 1);
+ dorehash = 0;
+ }
+ if (restart_iauth || timeofday >= nextiarestart)
+ {
+ start_iauth(restart_iauth);
+ restart_iauth = 0;
+ nextiarestart = timeofday + 15;
+ }
+ /*
+ ** Flush output buffers on all connections now if they
+ ** have data in them (or at least try to flush)
+ ** -avalon
+ */
+ flush_connections(me.fd);
+
+#ifdef DEBUGMODE
+ checklists();
+#endif
+
+}
+
+/*
+ * open_debugfile
+ *
+ * If the -t option is not given on the command line when the server is
+ * started, all debugging output is sent to the file set by IRCDDBG_PATH.
+ * 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 don't waste the fd.
+ */
+static void open_debugfile()
+{
+#ifdef DEBUGMODE
+ int fd;
+ aClient *cptr;
+
+ if (debuglevel >= 0)
+ {
+ cptr = make_client(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(IRCDDBG_PATH, 0);
+ if ((fd = open(IRCDDBG_PATH,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, IRCDDBG_PATH,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()
+{
+#if POSIX_SIGNALS
+ struct sigaction act;
+
+ act.sa_handler = SIG_IGN;
+ act.sa_flags = 0;
+ (void)sigemptyset(&act.sa_mask);
+ (void)sigaddset(&act.sa_mask, SIGPIPE);
+ (void)sigaddset(&act.sa_mask, SIGALRM);
+# ifdef SIGWINCH
+ (void)sigaddset(&act.sa_mask, SIGWINCH);
+ (void)sigaction(SIGWINCH, &act, NULL);
+# endif
+ (void)sigaction(SIGPIPE, &act, NULL);
+ act.sa_handler = dummy;
+ (void)sigaction(SIGALRM, &act, NULL);
+ act.sa_handler = s_rehash;
+ (void)sigemptyset(&act.sa_mask);
+ (void)sigaddset(&act.sa_mask, SIGHUP);
+ (void)sigaction(SIGHUP, &act, NULL);
+ act.sa_handler = s_restart;
+ (void)sigaddset(&act.sa_mask, SIGINT);
+ (void)sigaction(SIGINT, &act, NULL);
+ act.sa_handler = s_die;
+ (void)sigaddset(&act.sa_mask, SIGTERM);
+ (void)sigaction(SIGTERM, &act, NULL);
+# if defined(USE_IAUTH)
+ act.sa_handler = s_slave;
+ (void)sigaddset(&act.sa_mask, SIGUSR1);
+ (void)sigaction(SIGUSR1, &act, NULL);
+ act.sa_handler = SIG_IGN;
+# ifdef SA_NOCLDWAIT
+ act.sa_flags = SA_NOCLDWAIT;
+# else
+ act.sa_flags = 0;
+# endif
+ (void)sigaddset(&act.sa_mask, SIGCHLD);
+ (void)sigaction(SIGCHLD, &act, NULL);
+# endif
+
+#else /* POSIX_SIGNALS */
+
+# ifndef HAVE_RELIABLE_SIGNALS
+ (void)signal(SIGPIPE, dummy);
+# ifdef SIGWINCH
+ (void)signal(SIGWINCH, dummy);
+# endif
+# else /* HAVE_RELIABLE_SIGNALS */
+# ifdef SIGWINCH
+ (void)signal(SIGWINCH, SIG_IGN);
+# endif
+ (void)signal(SIGPIPE, SIG_IGN);
+# endif /* HAVE_RELIABLE_SIGNALS */
+ (void)signal(SIGALRM, dummy);
+ (void)signal(SIGHUP, s_rehash);
+ (void)signal(SIGTERM, s_die);
+ (void)signal(SIGINT, s_restart);
+# if defined(USE_IAUTH)
+ (void)signal(SIGUSR1, s_slave);
+ (void)signal(SIGCHLD, SIG_IGN);
+# endif
+#endif /* POSIX_SIGNAL */
+
+#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
+}
+
+/*
+ * Called from bigger_hash_table(), s_die(), server_reboot(),
+ * main(after initializations), grow_history(), rehash(io_loop) signal.
+ */
+void ircd_writetune(filename)
+char *filename;
+{
+ int fd;
+ char buf[100];
+
+ (void)truncate(filename, 0);
+ if ((fd = open(filename, O_CREAT|O_WRONLY, 0600)) >= 0)
+ {
+ (void)sprintf(buf, "%d\n%d\n%d\n%d\n%d\n%d\n", ww_size,
+ lk_size, _HASHSIZE, _CHANNELHASHSIZE,
+ _SERVERSIZE, poolsize);
+ if (write(fd, buf, strlen(buf)) == -1)
+ sendto_flag(SCH_ERROR,
+ "Failed (%d) to write tune file: %s.",
+ errno, mybasename(filename));
+ else
+ sendto_flag(SCH_NOTICE, "Updated %s.",
+ mybasename(filename));
+ close(fd);
+ }
+ else
+ sendto_flag(SCH_ERROR, "Failed (%d) to open tune file: %s.",
+ errno, mybasename(filename));
+}
+
+/*
+ * Called only from main() at startup.
+ */
+void ircd_readtune(filename)
+char *filename;
+{
+ int fd, t_data[6];
+ char buf[100];
+
+ buf[0] = '\0';
+ if ((fd = open(filename, O_RDONLY)) != -1)
+ {
+ read(fd, buf, 100); /* no panic if this fails.. */
+ if (sscanf(buf, "%d\n%d\n%d\n%d\n%d\n%d\n", &t_data[0],
+ &t_data[1], &t_data[2], &t_data[3],
+ &t_data[4], &t_data[5]) != 6)
+ {
+ close(fd);
+ if (bootopt & BOOT_BADTUNE)
+ return;
+ else
+ {
+ fprintf(stderr,
+ "ircd tune file %s: bad format\n",
+ filename);
+ exit(1);
+ }
+ }
+
+ /*
+ ** Initiate the tune-values after successfully
+ ** reading the tune-file.
+ */
+ ww_size = t_data[0];
+ lk_size = t_data[1];
+ _HASHSIZE = t_data[2];
+ _CHANNELHASHSIZE = t_data[3];
+ _SERVERSIZE = t_data[4];
+ poolsize = t_data[5];
+
+ /*
+ ** the lock array only grows if the whowas array grows,
+ ** I don't think it should be initialized with a lower
+ ** size since it will never adjust unless whowas array does.
+ */
+ if (lk_size < ww_size)
+ lk_size = ww_size;
+ close(fd);
+ }
+}
diff --git a/ircd/ircd_ext.h b/ircd/ircd_ext.h
new file mode 100644
index 0000000..e47b148
--- /dev/null
+++ b/ircd/ircd_ext.h
@@ -0,0 +1,62 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/ircd_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in ircd/ircd.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef IRCD_C
+extern aClient me;
+extern aClient *client;
+extern istat_t istat;
+extern char **myargv;
+extern int rehashed;
+extern int portnum;
+extern char *configfile;
+extern int debuglevel;
+extern int bootopt;
+extern char *debugmode;
+extern char *sbrk0;
+extern char *tunefile;
+extern time_t nextconnect;
+extern time_t nextgarbage;
+extern time_t nextping;
+extern time_t nextdnscheck;
+extern time_t nextexpire;
+#endif /* IRCD_C */
+
+/* External definitions for global functions.
+ */
+#ifndef IRCD_C
+#define EXTERN extern
+#else /* IRCD_C */
+#define EXTERN
+#endif /* IRCD_C */
+#ifdef PROFIL
+EXTERN RETSIGTYPE s_monitor __P((int s));
+#endif /* PROFIL */
+EXTERN RETSIGTYPE s_die __P((int s));
+EXTERN void restart __P((char *mesg));
+EXTERN RETSIGTYPE s_restart __P((int s));
+EXTERN void server_reboot();
+EXTERN void ircd_writetune __P((char *filename));
+EXTERN void ircd_readtune __P((char *filename));
+#undef EXTERN
diff --git a/ircd/list.c b/ircd/list.c
new file mode 100644
index 0000000..52ba815
--- /dev/null
+++ b/ircd/list.c
@@ -0,0 +1,685 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/list.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Finland
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* -- Jto -- 20 Jun 1990
+ * extern void free() fixed as suggested by
+ * gruner@informatik.tu-muenchen.de
+ */
+
+/* -- Jto -- 03 Jun 1990
+ * Added chname initialization...
+ */
+
+/* -- Jto -- 24 May 1990
+ * Moved is_full() to channel.c
+ */
+
+/* -- Jto -- 10 May 1990
+ * Added #include <sys.h>
+ * Changed memset(xx,0,yy) into bzero(xx,yy)
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: list.c,v 1.9 1999/07/02 16:49:37 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "s_defines.h"
+#define LIST_C
+#include "s_externs.h"
+#undef LIST_C
+
+char *DefInfo = "*Not On This Net*"; /* constant */
+
+#ifdef DEBUGMODE
+static struct liststats {
+ int inuse;
+} cloc, crem, users, servs, links, classs, aconfs;
+
+#endif
+
+aServer *svrtop = 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..."));
+ sendto_flag(SCH_NOTICE, "Ouch!!! Out of memory...");
+ restart("Out of Memory");
+}
+
+#ifdef DEBUGMODE
+void checklists()
+{
+ aServer *sp;
+ anUser *up;
+
+ for (sp = svrtop; sp; sp = sp->nexts)
+ if (sp->bcptr->serv != sp)
+ Debug((DEBUG_ERROR, "svrtop: %#x->%#x->%#x != %#x",
+ sp, sp->bcptr, sp->bcptr->serv, sp));
+}
+#endif
+
+/*
+** 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;
+{
+ Reg aClient *cptr = NULL;
+ Reg 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->status = STAT_UNKNOWN;
+ cptr->fd = -1;
+ (void)strcpy(cptr->username, "unknown");
+ cptr->info = DefInfo;
+ if (size == CLIENT_LOCAL_SIZE)
+ {
+ cptr->since = cptr->lasttime = cptr->firsttime = timeofday;
+ cptr->confs = NULL;
+ cptr->sockhost[0] = '\0';
+ cptr->buffer[0] = '\0';
+ cptr->authfd = -1;
+ cptr->auth = cptr->username;
+ cptr->exitc = EXITC_UNDEF;
+#ifdef ZIP_LINKS
+ cptr->zip = NULL;
+#endif
+ }
+ return (cptr);
+}
+
+void free_client(cptr)
+aClient *cptr;
+{
+ if (cptr->info != DefInfo)
+ MyFree(cptr->info);
+ 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;
+{
+ Reg 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->flags = 0;
+ user->channel = NULL;
+ user->invited = NULL;
+ user->uwas = NULL;
+ cptr->user = user;
+ user->servp = NULL;
+ user->bcptr = cptr;
+ if (cptr->next) /* the only cptr->next == NULL is me */
+ istat.is_users++;
+ }
+ return user;
+}
+
+aServer *make_server(cptr)
+aClient *cptr;
+{
+ Reg aServer *serv = cptr->serv, *sp, *spp = NULL;
+
+ if (!serv)
+ {
+ serv = (aServer *)MyMalloc(sizeof(aServer));
+#ifdef DEBUGMODE
+ servs.inuse++;
+#endif
+ serv->user = NULL;
+ serv->snum = -1;
+ *serv->by = '\0';
+ *serv->tok = '\0';
+ serv->stok = 0;
+ serv->up = NULL;
+ serv->refcnt = 1;
+ serv->nexts = NULL;
+ cptr->serv = serv;
+
+ for (sp = svrtop; sp; spp = sp, sp = sp->nexts)
+ if (spp && ((spp->ltok) + 1 < sp->ltok))
+ break;
+ serv->prevs = spp;
+ if (spp)
+ {
+ serv->ltok = spp->ltok + 1;
+ spp->nexts = serv;
+ }
+ else
+ { /* Me, myself and I alone */
+ svrtop = serv;
+ serv->ltok = 1;
+ }
+
+ if (sp)
+ {
+ serv->nexts = sp;
+ sp->prevs = serv;
+ }
+ serv->bcptr = cptr;
+ SPRINTF(serv->tok, "%d", serv->ltok);
+ serv->lastload = 0;
+ }
+ return cptr->serv;
+}
+
+/*
+** free_user
+** Decrease user reference count by one and realease block,
+** if count reaches 0
+*/
+void free_user(user, cptr)
+Reg anUser *user;
+aClient *cptr;
+{
+ aServer *serv;
+
+ if (--user->refcnt <= 0)
+ {
+ if ((serv = user->servp))
+ {
+ user->servp = NULL; /* to avoid some impossible loop */
+ free_server(serv, cptr);
+ }
+ if (user->away)
+ {
+ istat.is_away--;
+ istat.is_awaymem -= (strlen(user->away) + 1);
+ MyFree((char *)user->away);
+ }
+ /*
+ * sanity check
+ */
+ if (user->joined || user->refcnt < 0 ||
+ user->invited || user->channel || user->uwas ||
+ user->bcptr)
+ {
+ char buf[512];
+ /*too many arguments for dumpcore() and sendto_flag()*/
+ SPRINTF(buf, "%#x %#x %#x %#x %d %d %#x (%s)",
+ user, user->invited, user->channel, user->uwas,
+ user->joined, user->refcnt,
+ user->bcptr,
+ (user->bcptr) ? user->bcptr->name :"none");
+#ifdef DEBUGMODE
+ dumpcore("%#x user (%s!%s@%s) %s",
+ cptr, cptr ? cptr->name : "<noname>",
+ user->username, user->host, buf);
+#else
+ sendto_flag(SCH_ERROR,
+ "* %#x user (%s!%s@%s) %s *",
+ cptr, cptr ? cptr->name : "<noname>",
+ user->username, user->host, buf);
+#endif
+ }
+ MyFree((char *)user);
+#ifdef DEBUGMODE
+ users.inuse--;
+#endif
+ }
+}
+
+void free_server(serv, cptr)
+aServer *serv;
+aClient *cptr;
+{
+ if (--serv->refcnt <= 0)
+ {
+ if (serv->refcnt < 0 || serv->prevs || serv->nexts ||
+ serv->bcptr || serv->user)
+ {
+ char buf[512];
+ SPRINTF(buf, "%d %#x %#x %#x %#x (%s)",
+ serv->refcnt, serv->prevs, serv->nexts,
+ serv->user, serv->bcptr,
+ (serv->bcptr) ? serv->bcptr->name : "none");
+#ifdef DEBUGMODE
+ dumpcore("%#x server %s %s",
+ cptr, cptr ? cptr->name : "<noname>", buf);
+ servs.inuse--;
+#else
+ sendto_flag(SCH_ERROR, "* %#x server %s %s *",
+ cptr, cptr ? cptr->name : "<noname>", buf);
+#endif
+ }
+ MyFree((char *)serv);
+ }
+}
+
+/*
+ * taken the code from ExitOneClient() for this and placed it here.
+ * - avalon
+ * remove client **AND** _related structures_ from lists,
+ * *free* them too. -krys
+ */
+void remove_client_from_list(cptr)
+Reg aClient *cptr;
+{
+ checklist();
+ if (cptr->hopcount == 0) /* is there another way, at this point? */
+ istat.is_localc--;
+ else
+ istat.is_remc--;
+ 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)
+ {
+ istat.is_users--;
+ /* decrement reference counter, and eventually free it */
+ cptr->user->bcptr = NULL;
+ (void)free_user(cptr->user, cptr);
+ }
+
+ if (cptr->serv)
+ {
+ /* has to be removed from the list of aServer structures */
+ if (cptr->serv->nexts)
+ cptr->serv->nexts->prevs = cptr->serv->prevs;
+ if (cptr->serv->prevs)
+ cptr->serv->prevs->nexts = cptr->serv->nexts;
+ if (svrtop == cptr->serv)
+ svrtop = cptr->serv->nexts;
+ cptr->serv->prevs = NULL;
+ cptr->serv->nexts = NULL;
+
+ if (cptr->serv->user)
+ {
+ free_user(cptr->serv->user, cptr);
+ cptr->serv->user = NULL;
+ }
+
+ /* decrement reference counter, and eventually free it */
+ cptr->serv->bcptr = NULL;
+ free_server(cptr->serv, cptr);
+ }
+
+ if (cptr->service)
+ /*
+ ** has to be removed from the list of aService structures,
+ ** no reference counter for services, thus this part of the
+ ** code can safely be included in free_service()
+ */
+ free_service(cptr);
+
+#ifdef DEBUGMODE
+ if (cptr->fd == -2)
+ cloc.inuse--;
+ else
+ crem.inuse--;
+#endif
+
+ (void)free_client(cptr);
+ numclients--;
+ return;
+}
+
+/*
+ * move the client aClient struct before its server's
+ */
+void reorder_client_in_list(cptr)
+aClient *cptr;
+{
+ if (cptr->user == NULL && cptr->service == NULL)
+ return;
+
+ /* update neighbours */
+ if (cptr->next)
+ cptr->next->prev = cptr->prev;
+ if (cptr->prev)
+ cptr->prev->next = cptr->next;
+ else
+ client = cptr->next;
+
+ /* re-insert */
+ if (cptr->user)
+ {
+ cptr->next = cptr->user->servp->bcptr;
+ cptr->prev = cptr->user->servp->bcptr->prev;
+#ifdef DEBUGMODE
+ sendto_flag(SCH_DEBUG, "%p [%s] moved before server: %p [%s]",
+ cptr, cptr->name, cptr->user->servp->bcptr,
+ cptr->user->servp->bcptr->name);
+#endif
+ }
+ else if (cptr->service)
+ {
+ cptr->next = cptr->service->servp->bcptr;
+ cptr->prev = cptr->service->servp->bcptr->prev;
+ }
+
+ /* update new neighbours */
+ if (cptr->prev)
+ cptr->prev->next = cptr;
+ else
+ client = cptr;
+ cptr->next->prev = cptr;
+}
+
+/*
+ * 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.
+ */
+ if (cptr->from == cptr)
+ istat.is_localc++;
+ else
+ istat.is_remc++;
+ if (cptr->user)
+ istat.is_users++;
+
+ cptr->next = client;
+ client = cptr;
+
+ if (cptr->next)
+ cptr->next->prev = cptr;
+
+ numclients++;
+ return;
+}
+
+/*
+ * Look for ptr in the linked listed pointed to by link.
+ */
+Link *find_user_link(lp, ptr)
+Reg Link *lp;
+Reg aClient *ptr;
+{
+ if (ptr)
+ for (; lp; lp = lp->next)
+ if (lp->value.cptr == ptr)
+ return (lp);
+ return NULL;
+}
+
+Link *find_channel_link(lp, ptr)
+Reg Link *lp;
+Reg aChannel *ptr;
+{
+ if (ptr)
+ for (; lp; lp = lp->next)
+ if (lp->value.chptr == ptr)
+ return (lp);
+ return NULL;
+}
+
+Link *make_link()
+{
+ Reg Link *lp;
+
+ lp = (Link *)MyMalloc(sizeof(Link));
+#ifdef DEBUGMODE
+ links.inuse++;
+#endif
+ lp->flags = 0;
+ return lp;
+}
+
+void free_link(lp)
+Reg Link *lp;
+{
+ MyFree((char *)lp);
+#ifdef DEBUGMODE
+ links.inuse--;
+#endif
+}
+
+
+aClass *make_class()
+{
+ Reg aClass *tmp;
+
+ tmp = (aClass *)MyMalloc(sizeof(aClass));
+#ifdef DEBUGMODE
+ classs.inuse++;
+#endif
+ return tmp;
+}
+
+void free_class(tmp)
+Reg aClass *tmp;
+{
+ MyFree((char *)tmp);
+#ifdef DEBUGMODE
+ classs.inuse--;
+#endif
+}
+
+aConfItem *make_conf()
+{
+ Reg aConfItem *aconf;
+
+ aconf = (struct ConfItem *)MyMalloc(sizeof(aConfItem));
+
+#ifdef DEBUGMODE
+ aconfs.inuse++;
+#endif
+ istat.is_conf++;
+ istat.is_confmem += sizeof(aConfItem);
+
+ bzero((char *)&aconf->ipnum, sizeof(struct in_addr));
+ aconf->clients = aconf->port = 0;
+ aconf->next = NULL;
+ aconf->host = aconf->passwd = aconf->name = NULL;
+ aconf->ping = NULL;
+ aconf->status = CONF_ILLEGAL;
+ aconf->pref = -1;
+ aconf->hold = time(NULL);
+ Class(aconf) = NULL;
+ 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_conf(aconf)
+aConfItem *aconf;
+{
+ del_queries((char *)aconf);
+
+ istat.is_conf--;
+ istat.is_confmem -= aconf->host ? strlen(aconf->host)+1 : 0;
+ istat.is_confmem -= aconf->passwd ? strlen(aconf->passwd)+1 : 0;
+ istat.is_confmem -= aconf->name ? strlen(aconf->name)+1 : 0;
+ istat.is_confmem -= aconf->ping ? sizeof(*aconf->ping) : 0;
+ istat.is_confmem -= sizeof(aConfItem);
+
+ MyFree(aconf->host);
+ if (aconf->passwd)
+ bzero(aconf->passwd, strlen(aconf->passwd));
+ if (aconf->ping)
+ MyFree((char *)aconf->ping);
+ 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
+
+
+void add_fd(fd, ary)
+int fd;
+FdAry *ary;
+{
+ Debug((DEBUG_DEBUG,"add_fd(%d,%#x)", fd, ary));
+ if (fd >= 0)
+ ary->fd[++(ary->highest)] = fd;
+}
+
+
+int del_fd(fd, ary)
+int fd;
+FdAry *ary;
+{
+ int i;
+
+ Debug((DEBUG_DEBUG,"del_fd(%d,%#x)", fd, ary));
+ if ((ary->highest == -1) || (fd < 0))
+ return -1;
+ for (i = 0; i <= ary->highest; i++)
+ if (ary->fd[i] == fd)
+ break;
+ if (i < ary->highest)
+ {
+ ary->fd[i] = ary->fd[ary->highest--];
+ return 0;
+ }
+ else if (i > ary->highest)
+ return -1;
+ ary->highest--;
+ return 0;
+}
diff --git a/ircd/list2.c b/ircd/list2.c
new file mode 100644
index 0000000..17f5ac0
--- /dev/null
+++ b/ircd/list2.c
@@ -0,0 +1,515 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/list.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Finland
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* -- Jto -- 20 Jun 1990
+ * extern void free() fixed as suggested by
+ * gruner@informatik.tu-muenchen.de
+ */
+
+/* -- Jto -- 03 Jun 1990
+ * Added chname initialization...
+ */
+
+/* -- Jto -- 24 May 1990
+ * Moved is_full() to channel.c
+ */
+
+/* -- Jto -- 10 May 1990
+ * Added #include <sys.h>
+ * Changed memset(xx,0,yy) into bzero(xx,yy)
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)list2.c 1.1 1/22/95 (C) 1988 University of Oulu, \
+Computing Center and Jarkko Oikarinen";
+#endif
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+#ifdef DBMALLOC
+#include "malloc.h"
+#endif
+void free_link __P((Link *));
+Link *make_link __P(());
+
+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;
+{
+ Reg aClient *cptr = NULL;
+ Reg 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->firsttime = time(NULL);
+ cptr->confs = NULL;
+ cptr->sockhost[0] = '\0';
+ cptr->buffer[0] = '\0';
+ cptr->authfd = -1;
+ }
+ 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;
+{
+ Reg 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;
+ 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;
+{
+ Reg 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)
+Reg 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)
+Reg 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)
+Reg Link *lp;
+Reg aClient *ptr;
+{
+ while (lp && ptr)
+ {
+ if (lp->value.cptr == ptr)
+ return (lp);
+ lp = lp->next;
+ }
+ return NULL;
+}
+
+Link *make_link()
+{
+ Reg 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)
+Reg 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()
+{
+ Reg 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)
+Reg 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()
+{
+ Reg 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);
+}
diff --git a/ircd/list_ext.h b/ircd/list_ext.h
new file mode 100644
index 0000000..db3f245
--- /dev/null
+++ b/ircd/list_ext.h
@@ -0,0 +1,66 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/list_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in ircd/list.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef LIST_C
+extern anUser *usrtop;
+extern aServer *svrtop;
+extern int numclients;
+extern const char *DefInfo;
+#endif /* LIST_C */
+
+/* External definitions for global functions.
+ */
+#ifndef LIST_C
+#define EXTERN extern
+#else /* LIST_C */
+#define EXTERN
+#endif /* LIST_C */
+EXTERN void initlists();
+EXTERN void outofmemory();
+#ifdef DEBUGMODE
+EXTERN void checklists();
+EXTERN void send_listinfo __P((aClient *cptr, char *name));
+#endif /* DEBUGMOE */
+EXTERN aClient *make_client __P((aClient *from));
+EXTERN void free_client __P((aClient *cptr));
+EXTERN anUser *make_user __P((aClient *cptr));
+EXTERN aServer *make_server __P((aClient *cptr));
+EXTERN void free_user __P((Reg anUser *user, aClient *cptr));
+EXTERN void free_server __P((aServer *serv, aClient *cptr));
+EXTERN void remove_client_from_list __P((Reg aClient *cptr));
+EXTERN void reorder_client_in_list __P((aClient *cptr));
+EXTERN void add_client_to_list __P((aClient *cptr));
+EXTERN Link *find_user_link __P((Reg Link *lp, Reg aClient *ptr));
+EXTERN Link *find_channel_link __P((Reg Link *lp, Reg aChannel *ptr));
+EXTERN Link *make_link();
+EXTERN void free_link __P((Reg Link *lp));
+EXTERN aClass *make_class();
+EXTERN void free_class __P((Reg aClass *tmp));
+EXTERN aConfItem *make_conf();
+EXTERN void delist_conf __P((aConfItem *aconf));
+EXTERN void free_conf __P((aConfItem *aconf));
+EXTERN void add_fd __P((int fd, FdAry *ary));
+EXTERN int del_fd __P((int fd, FdAry *ary));
+#undef EXTERN
diff --git a/ircd/nameser_def.h b/ircd/nameser_def.h
new file mode 100644
index 0000000..39c2ce8
--- /dev/null
+++ b/ircd/nameser_def.h
@@ -0,0 +1,330 @@
+/*
+ * ++Copyright++ 1983, 1989, 1993
+ * -
+ * Copyright (c) 1983, 1989, 1993
+ * The 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ * --Copyright--
+ */
+
+/*
+ * @(#)nameser.h 8.1 (Berkeley) 6/2/93
+ * $Id: nameser_def.h,v 1.3 1998/12/13 00:19:03 kalt Exp $
+ */
+
+/*
+ * revision information. this is the release date in YYYYMMDD format.
+ * it can change every day so the right thing to do with it is use it
+ * in preprocessor commands such as "#if (__BIND > 19931104)". do not
+ * compare for equality; rather, use it to determine whether your resolver
+ * is new enough to contain a certain feature.
+ */
+
+#define __BIND 19960801 /* interface version stamp */
+
+/*
+ * Define constants based on rfc883
+ */
+#define PACKETSZ 512 /* maximum packet size */
+#define MAXDNAME 1025 /* maximum presentation domain name */
+#define MAXCDNAME 255 /* maximum compressed domain name */
+#define MAXLABEL 63 /* maximum length of domain label */
+#define HFIXEDSZ 12 /* #/bytes of fixed data in header */
+#define QFIXEDSZ 4 /* #/bytes of fixed data in query */
+#define RRFIXEDSZ 10 /* #/bytes of fixed data in r record */
+#define INT32SZ 4 /* for systems without 32-bit ints */
+#define INT16SZ 2 /* for systems without 16-bit ints */
+#define INADDRSZ 4 /* IPv4 T_A */
+#define IN6ADDRSZ 16 /* IPv6 T_AAAA */
+
+/*
+ * 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 */
+#define NS_NOTIFY_OP 0x4 /* notify secondary of SOA change */
+/*
+ * Currently defined response codes
+ */
+#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 */
+
+/*
+ * 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 /* canonical 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 */
+#define T_RP 17 /* responsible person */
+#define T_AFSDB 18 /* AFS cell database */
+#define T_X25 19 /* X_25 calling address */
+#define T_ISDN 20 /* ISDN calling address */
+#define T_RT 21 /* router */
+#define T_NSAP 22 /* NSAP address */
+#define T_NSAP_PTR 23 /* reverse NSAP lookup (deprecated) */
+#define T_SIG 24 /* security signature */
+#define T_KEY 25 /* security key */
+#define T_PX 26 /* X.400 mail mapping */
+#define T_GPOS 27 /* geographical position (withdrawn) */
+#define T_AAAA 28 /* IP6 Address */
+#define T_LOC 29 /* Location Information */
+#define T_NXT 30 /* Next Valid Name in Zone */
+#define T_EID 31 /* Endpoint identifier */
+#define T_NIMLOC 32 /* Nimrod locator */
+#define T_SRV 33 /* Server selection */
+#define T_ATMA 34 /* ATM Address */
+#define T_NAPTR 35 /* Naming Authority PoinTeR */
+ /* 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_IXFR 251 /* incremental zone transfer */
+#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 (MIT) */
+#define C_HS 4 /* for Hesiod name server (MIT) (XXX) */
+ /* Query class values which do not appear in resource records */
+#define C_ANY 255 /* wildcard match */
+
+/*
+ * Flags field of the KEY RR rdata
+ */
+#define KEYFLAG_TYPEMASK 0xC000 /* Mask for "type" bits */
+#define KEYFLAG_TYPE_AUTH_CONF 0x0000 /* Key usable for both */
+#define KEYFLAG_TYPE_CONF_ONLY 0x8000 /* Key usable for confidentiality */
+#define KEYFLAG_TYPE_AUTH_ONLY 0x4000 /* Key usable for authentication */
+#define KEYFLAG_TYPE_NO_KEY 0xC000 /* No key usable for either; no key */
+/* The type bits can also be interpreted independently, as single bits: */
+#define KEYFLAG_NO_AUTH 0x8000 /* Key not usable for authentication */
+#define KEYFLAG_NO_CONF 0x4000 /* Key not usable for confidentiality */
+
+#define KEYFLAG_EXPERIMENTAL 0x2000 /* Security is *mandatory* if bit=0 */
+#define KEYFLAG_RESERVED3 0x1000 /* reserved - must be zero */
+#define KEYFLAG_RESERVED4 0x0800 /* reserved - must be zero */
+#define KEYFLAG_USERACCOUNT 0x0400 /* key is assoc. with a user acct */
+#define KEYFLAG_ENTITY 0x0200 /* key is assoc. with entity eg host */
+#define KEYFLAG_ZONEKEY 0x0100 /* key is zone key for the zone named */
+#define KEYFLAG_IPSEC 0x0080 /* key is for IPSEC use (host or user)*/
+#define KEYFLAG_EMAIL 0x0040 /* key is for email (MIME security) */
+#define KEYFLAG_RESERVED10 0x0020 /* reserved - must be zero */
+#define KEYFLAG_RESERVED11 0x0010 /* reserved - must be zero */
+#define KEYFLAG_SIGNATORYMASK 0x000F /* key can sign DNS RR's of same name */
+
+#define KEYFLAG_RESERVED_BITMASK ( KEYFLAG_RESERVED3 | \
+ KEYFLAG_RESERVED4 | \
+ KEYFLAG_RESERVED10| KEYFLAG_RESERVED11)
+
+/* The Algorithm field of the KEY and SIG RR's is an integer, {1..254} */
+#define ALGORITHM_MD5RSA 1 /* MD5 with RSA */
+#define ALGORITHM_EXPIRE_ONLY 253 /* No alg, no security */
+#define ALGORITHM_PRIVATE_OID 254 /* Key begins with OID indicating alg */
+
+/* Signatures */
+ /* Size of a mod or exp in bits */
+#define MIN_MD5RSA_KEY_PART_BITS 512
+#define MAX_MD5RSA_KEY_PART_BITS 2552
+ /* Total of binary mod and exp, bytes */
+#define MAX_MD5RSA_KEY_BYTES ((MAX_MD5RSA_KEY_PART_BITS+7/8)*2+3)
+ /* Max length of text sig block */
+#define MAX_KEY_BASE64 (((MAX_MD5RSA_KEY_BYTES+2)/3)*4)
+
+/*
+ * 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)
+
+/*
+ * Structure for query header. The order of the fields is machine- and
+ * compiler-dependent, depending on the byte/bit order and the layout
+ * of bit fields. We use bit fields only in int variables, as this
+ * is all ANSI requires. This requires a somewhat confusing rearrangement.
+ */
+
+typedef struct {
+ unsigned id :16; /* query identification number */
+#if WORDS_BIGENDIAN
+ /* fields in third byte */
+ unsigned qr: 1; /* response flag */
+ unsigned opcode: 4; /* purpose of message */
+ unsigned aa: 1; /* authoritive answer */
+ unsigned tc: 1; /* truncated message */
+ unsigned rd: 1; /* recursion desired */
+ /* fields in fourth byte */
+ unsigned ra: 1; /* recursion available */
+ unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */
+ unsigned ad: 1; /* authentic data from named */
+ unsigned cd: 1; /* checking disabled by resolver */
+ unsigned rcode :4; /* response code */
+#else /* WORDS_BIGENDIAN */
+ /* fields in third byte */
+ unsigned rd :1; /* recursion desired */
+ unsigned tc :1; /* truncated message */
+ unsigned aa :1; /* authoritive answer */
+ unsigned opcode :4; /* purpose of message */
+ unsigned qr :1; /* response flag */
+ /* fields in fourth byte */
+ unsigned rcode :4; /* response code */
+ unsigned cd: 1; /* checking disabled by resolver */
+ unsigned ad: 1; /* authentic data from named */
+ unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */
+ unsigned ra :1; /* recursion available */
+#endif /* WORDS_BIGENDIAN */
+ /* remaining bytes */
+ unsigned qdcount :16; /* number of question entries */
+ unsigned ancount :16; /* number of answer entries */
+ unsigned nscount :16; /* number of authority entries */
+ unsigned arcount :16; /* number of resource entries */
+} HEADER;
+
+/*
+ * Defines for handling compressed domain names
+ */
+#define INDIR_MASK 0xc0
+
+/*
+ * Inline versions of get/put short/long. Pointer is advanced.
+ *
+ * These macros demonstrate the property of C whereby it can be
+ * portable or it can be elegant but rarely both.
+ */
+#define GETSHORT(s, cp) { \
+ register u_char *t_cp = (u_char *)(cp); \
+ (s) = ((u_int16_t)t_cp[0] << 8) \
+ | ((u_int16_t)t_cp[1]) \
+ ; \
+ (cp) += INT16SZ; \
+}
+
+#define GETLONG(l, cp) { \
+ register u_char *t_cp = (u_char *)(cp); \
+ (l) = ((u_int32_t)t_cp[0] << 24) \
+ | ((u_int32_t)t_cp[1] << 16) \
+ | ((u_int32_t)t_cp[2] << 8) \
+ | ((u_int32_t)t_cp[3]) \
+ ; \
+ (cp) += INT32SZ; \
+}
+
+#define PUTSHORT(s, cp) { \
+ register u_int16_t t_s = (u_int16_t)(s); \
+ register u_char *t_cp = (u_char *)(cp); \
+ *t_cp++ = t_s >> 8; \
+ *t_cp = t_s; \
+ (cp) += INT16SZ; \
+}
+
+#define PUTLONG(l, cp) { \
+ register u_int32_t t_l = (u_int32_t)(l); \
+ register u_char *t_cp = (u_char *)(cp); \
+ *t_cp++ = t_l >> 24; \
+ *t_cp++ = t_l >> 16; \
+ *t_cp++ = t_l >> 8; \
+ *t_cp = t_l; \
+ (cp) += INT32SZ; \
+}
diff --git a/ircd/res.c b/ircd/res.c
new file mode 100644
index 0000000..1be09c7
--- /dev/null
+++ b/ircd/res.c
@@ -0,0 +1,1697 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/res.c
+ * Copyright (C) 1992 Darren Reed
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "os.h"
+#include "s_defines.h"
+#define RES_C
+#include "s_externs.h"
+#undef RES_C
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: res.c,v 1.21 1999/07/02 17:31:17 kalt Exp $";
+#endif
+
+/* #undef DEBUG /* because there is a lot of debug code in here :-) */
+
+static char hostbuf[HOSTLEN+1+100]; /* +100 for INET6 */
+static char dot[] = ".";
+static int incache = 0;
+static CacheTable hashtable[ARES_CACSIZE];
+static aCache *cachetop = NULL;
+static ResRQ *last, *first;
+
+static void rem_cache __P((aCache *));
+static void rem_request __P((ResRQ *));
+static int do_query_name __P((Link *, char *, ResRQ *));
+static int do_query_number __P((Link *, struct IN_ADDR *, ResRQ *));
+static void resend_query __P((ResRQ *));
+static int proc_answer __P((ResRQ *, HEADER *, char *, char *));
+static int query_name __P((char *, int, int, ResRQ *));
+static aCache *make_cache __P((ResRQ *)), *rem_list __P((aCache *));
+static aCache *find_cache_name __P((char *));
+static aCache *find_cache_number __P((ResRQ *, char *));
+static int add_request __P((ResRQ *));
+static ResRQ *make_request __P((Link *));
+static int send_res_msg __P((char *, int, int));
+static ResRQ *find_id __P((int));
+static int hash_number __P((unsigned char *));
+static void update_list __P((ResRQ *, aCache *));
+static int hash_name __P((char *));
+static int bad_hostname __P((char *, int));
+
+static struct cacheinfo {
+ int ca_adds;
+ int ca_dels;
+ int ca_expires;
+ int ca_lookups;
+ int ca_na_hits;
+ int ca_nu_hits;
+ int ca_updates;
+} cainfo;
+
+static struct resinfo {
+ int re_errors;
+ int re_nu_look;
+ int re_na_look;
+ int re_replies;
+ int re_requests;
+ int re_resends;
+ int re_sent;
+ int re_timeouts;
+ int re_shortttl;
+ int re_unkrep;
+} reinfo;
+
+int init_resolver(op)
+int op;
+{
+ int ret = 0;
+
+#ifdef LRAND48
+ srand48(time(NULL));
+#endif
+ if (op & RES_INITLIST)
+ {
+ bzero((char *)&reinfo, sizeof(reinfo));
+ first = last = NULL;
+ }
+ if (op & RES_CALLINIT)
+ {
+ ret = ircd_res_init();
+ if (!ircd_res.nscount)
+ {
+ ircd_res.nscount = 1;
+#ifdef INET6
+ /* still IPv4 */
+ ircd_res.nsaddr_list[0].sin_addr.s_addr =
+ inet_pton(AF_INET, "127.0.0.1",
+ &ircd_res.nsaddr_list[0].sin_addr.s_addr);
+#else
+ ircd_res.nsaddr_list[0].sin_addr.s_addr =
+ inetaddr("127.0.0.1");
+#endif
+ }
+ }
+
+ if (op & RES_INITSOCK)
+ {
+ int on = 0;
+
+#ifdef INET6
+ /* still IPv4 */
+ ret = resfd = socket(AF_INET, SOCK_DGRAM, 0);
+#else
+ ret = resfd = socket(AF_INET, SOCK_DGRAM, 0);
+#endif
+ (void) SETSOCKOPT(ret, SOL_SOCKET, SO_BROADCAST, &on, on);
+ }
+#ifdef DEBUG
+ if (op & RES_INITDEBG);
+ ircd_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;
+{
+ Reg ResRQ **rptr, *r2ptr = NULL;
+ Reg int i;
+ Reg 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((char *)r2ptr);
+
+ return;
+}
+
+/*
+ * Create a DNS request record for the server.
+ */
+static ResRQ *make_request(lp)
+Link *lp;
+{
+ Reg ResRQ *nreq;
+
+ nreq = (ResRQ *)MyMalloc(sizeof(ResRQ));
+ bzero((char *)nreq, sizeof(ResRQ));
+ nreq->next = NULL; /* where NULL is non-zero ;) */
+ nreq->sentat = timeofday;
+ 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 = AFINET;
+ 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;
+{
+ Reg ResRQ *rptr, *r2ptr;
+ Reg 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 defined(USE_IAUTH)
+ sendto_iauth("%d d", cptr->fd);
+#endif
+ ClearDNS(cptr);
+ break;
+ case ASYNC_CONNECT :
+ sendto_flag(SCH_ERROR,
+ "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;
+ }
+ 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;
+{
+ Reg 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 "ircd_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;
+{
+ Reg int i;
+ int sent = 0, max;
+
+ if (!msg)
+ return -1;
+
+ max = MIN(ircd_res.nscount, rcount);
+ if (ircd_res.options & RES_PRIMARY)
+ max = 1;
+ if (!max)
+ max = 1;
+
+ for (i = 0; i < max; i++)
+ {
+#ifdef INET6
+ /* still IPv4 */
+ ircd_res.nsaddr_list[i].sin_family = AF_INET;
+#else
+ ircd_res.nsaddr_list[i].sin_family = AF_INET;
+#endif
+#ifdef INET6
+ if (sendto(resfd, msg, len, 0,
+ (struct sockaddr *)&(ircd_res.nsaddr_list[i]),
+ sizeof(struct sockaddr)) == len)
+#else
+ if (sendto(resfd, msg, len, 0,
+ (struct sockaddr *)&(ircd_res.nsaddr_list[i]),
+ sizeof(struct sockaddr)) == len)
+#endif
+
+ {
+ 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;
+{
+ Reg 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;
+{
+ Reg 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;
+Reg ResRQ *rptr;
+{
+ char hname[HOSTLEN+1];
+ int len;
+
+ strncpyzt(hname, name, sizeof(hname));
+ len = strlen(hname);
+
+ if (rptr && !index(hname, '.') && ircd_res.options & RES_DEFNAMES)
+ {
+ (void)strncat(hname, dot, sizeof(hname) - len - 1);
+ len++;
+ (void)strncat(hname, ircd_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);
+#ifdef INET6
+ rptr->type = T_AAAA;
+#else
+ rptr->type = T_A;
+#endif
+ rptr->name = (char *)MyMalloc(strlen(name) + 1);
+ (void)strcpy(rptr->name, name);
+ }
+ Debug((DEBUG_DNS,"do_query_name(): %s ", hname));
+#ifdef INET6
+ return (query_name(hname, C_IN, T_AAAA, rptr));
+#else
+ return (query_name(hname, C_IN, T_A, rptr));
+#endif
+}
+
+/*
+ * Use this to do reverse IP# lookups.
+ */
+static int do_query_number(lp, numb, rptr)
+Link *lp;
+struct IN_ADDR *numb;
+Reg ResRQ *rptr;
+{
+ char ipbuf[128];
+ Reg u_char *cp;
+
+#ifdef INET6
+ cp = (u_char *)numb->s6_addr;
+ if (cp[0]==0 && cp[1]==0 && cp[2]==0 && cp[3]==0 && cp[4]==0 &&
+ cp[5]==0 && cp[6]==0 && cp[7]==0 && cp[8]==0 && cp[9]==0 &&
+ ((cp[10]==0 && cp[11]==0) || (cp[10]==0xff && cp[11]==0xff)))
+ {
+ (void)sprintf(ipbuf, "%u.%u.%u.%u.in-addr.arpa.",
+ (u_int)(cp[15]), (u_int)(cp[14]),
+ (u_int)(cp[13]), (u_int)(cp[12]));
+ }
+ else
+ {
+ (void)sprintf(ipbuf, "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.int.",
+ (u_int)(cp[15]&0xf), (u_int)(cp[15]>>4),
+ (u_int)(cp[14]&0xf), (u_int)(cp[14]>>4),
+ (u_int)(cp[13]&0xf), (u_int)(cp[13]>>4),
+ (u_int)(cp[12]&0xf), (u_int)(cp[12]>>4),
+ (u_int)(cp[11]&0xf), (u_int)(cp[11]>>4),
+ (u_int)(cp[10]&0xf), (u_int)(cp[10]>>4),
+ (u_int)(cp[9]&0xf), (u_int)(cp[9]>>4),
+ (u_int)(cp[8]&0xf), (u_int)(cp[8]>>4),
+ (u_int)(cp[7]&0xf), (u_int)(cp[7]>>4),
+ (u_int)(cp[6]&0xf), (u_int)(cp[6]>>4),
+ (u_int)(cp[5]&0xf), (u_int)(cp[5]>>4),
+ (u_int)(cp[4]&0xf), (u_int)(cp[4]>>4),
+ (u_int)(cp[3]&0xf), (u_int)(cp[3]>>4),
+ (u_int)(cp[2]&0xf), (u_int)(cp[2]>>4),
+ (u_int)(cp[1]&0xf), (u_int)(cp[1]>>4),
+ (u_int)(cp[0]&0xf), (u_int)(cp[0]>>4));
+ }
+#else
+ cp = (u_char *)&numb->s_addr;
+ (void)sprintf(ipbuf, "%u.%u.%u.%u.in-addr.arpa.",
+ (u_int)(cp[3]), (u_int)(cp[2]),
+ (u_int)(cp[1]), (u_int)(cp[0]));
+#endif
+
+ if (!rptr)
+ {
+ rptr = make_request(lp);
+ rptr->type = T_PTR;
+#ifdef INET6
+ bcopy(numb->s6_addr, rptr->addr.s6_addr, IN6ADDRSZ);
+ bcopy((char *)numb->s6_addr,
+ (char *)&rptr->he.h_addr, sizeof(struct in6_addr));
+#else
+ rptr->addr.s_addr = numb->s_addr;
+ bcopy((char *)&numb->s_addr,
+ (char *)&rptr->he.h_addr, sizeof(struct in_addr));
+#endif
+ 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;
+
+ bzero(buf, sizeof(buf));
+ r = ircd_res_mkquery(QUERY, name, class, type, NULL, 0, NULL,
+ (u_char *)buf, sizeof(buf));
+ if (r <= 0)
+ {
+ h_errno = NO_RECOVERY;
+ return r;
+ }
+ hptr = (HEADER *)buf;
+#ifdef LRAND48
+ do {
+ hptr->id = htons(ntohs(hptr->id) + k + lrand48() & 0xffff);
+#else
+ (void) gettimeofday(&tv, NULL);
+ do {
+ /* htons/ntohs can be assembler macros, which cannot
+ be nested. Thus two lines. -Vesa */
+ u_short nstmp = ntohs(hptr->id) + k +
+ (u_short)(tv.tv_usec & 0xffff);
+ hptr->id = htons(nstmp);
+#endif /* LRAND48 */
+ k++;
+ } while (find_id(ntohs(hptr->id)));
+ rptr->id = ntohs(hptr->id);
+ rptr->sends++;
+ s = send_res_msg(buf, r, rptr->sends);
+ if (s == -1)
+ {
+ h_errno = TRY_AGAIN;
+ return -1;
+ }
+ else
+ rptr->sent += s;
+ return 0;
+}
+
+static void resend_query(rptr)
+ResRQ *rptr;
+{
+ if (rptr->resend == 0)
+ return;
+ reinfo.re_resends++;
+ switch(rptr->type)
+ {
+ case T_PTR:
+ (void)do_query_number(NULL, &rptr->addr, rptr);
+ break;
+#ifdef INET6
+ case T_AAAA:
+#endif
+ 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;
+{
+ Reg char *cp, **alias;
+ Reg 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;
+#ifdef INET6
+ while (adr->s6_laddr[0] | adr->s6_laddr[1] | adr->s6_laddr[2] |
+ adr->s6_laddr[3])
+#else
+ while (adr->s_addr)
+#endif
+ adr++;
+ alias = hp->h_aliases;
+ while (*alias)
+ alias++;
+#if SOLARIS_2 && !defined(__GNUC__) /* brain damaged compiler it seems */
+ for (; hptr->qdcount > 0; hptr->qdcount--)
+#else
+ while (hptr->qdcount-- > 0)
+#endif
+ if ((n = __ircd_dn_skipname((u_char *)cp, (u_char *)eob)) == -1)
+ break;
+ else
+ cp += (n + QFIXEDSZ);
+ /*
+ * proccess each answer sent to us blech.
+ */
+ while (hptr->ancount-- > 0 && cp && cp < eob) {
+ n = ircd_dn_expand((u_char *)buf, (u_char *)eob, (u_char *)cp,
+ hostbuf, sizeof(hostbuf));
+ if (n <= 0)
+ break;
+
+ cp += n;
+ type = (int)ircd_getshort((u_char *)cp);
+ cp += 2; /* INT16SZ */
+ class = (int)ircd_getshort((u_char *)cp);
+ cp += 2; /* INT16SZ */
+ rptr->ttl = ircd_getlong((u_char *)cp);
+ cp += 4; /* INT32SZ */
+ dlen = (int)ircd_getshort((u_char *)cp);
+ cp += 2; /* INT16SZ */
+ rptr->type = type;
+
+ len = strlen(hostbuf);
+ /* name server never returns with trailing '.' */
+ if (!index(hostbuf,'.') && (ircd_res.options & RES_DEFNAMES))
+ {
+ (void)strcat(hostbuf, dot);
+ len++;
+ (void)strncat(hostbuf, ircd_res.defdname,
+ sizeof(hostbuf) - 1 - len);
+ len = MIN(len + strlen(ircd_res.defdname),
+ sizeof(hostbuf) - 1);
+ }
+
+ switch(type)
+ {
+#ifdef INET6
+ case T_AAAA :
+#endif
+ case T_A :
+#ifdef INET6
+ if (dlen != ((type==T_AAAA) ? sizeof(dr) :
+ sizeof(struct in_addr)))
+#else
+ if (dlen != sizeof(dr))
+#endif
+ {
+ sendto_flag(SCH_ERROR,
+ "Bad IP length (%d) returned for %s", dlen,
+ hostbuf);
+ Debug((DEBUG_DNS,
+ "Bad IP length (%d) returned for %s",
+ dlen, hostbuf));
+ return -2;
+ }
+ hp->h_length = dlen;
+ if (ans == 1)
+ hp->h_addrtype = (class == C_IN) ?
+ AFINET: AF_UNSPEC;
+#ifdef INET6
+ if (type == T_AAAA)
+ bcopy(cp, (char *)&dr, dlen);
+ else {
+ dr.s6_laddr[0]=dr.s6_laddr[1]=0;
+ dr.s6_laddr[2]=htonl(0xffff);
+ bcopy(cp, &dr.s6_laddr[3], INADDRSZ);
+ }
+ bcopy(dr.s6_addr, adr->s6_addr, IN6ADDRSZ);
+#else
+ bcopy(cp, (char *)&dr, dlen);
+ adr->s_addr = dr.s_addr;
+#endif
+#ifdef INET6
+ Debug((DEBUG_INFO,"got ip # %s for %s",
+ inet_ntop(AF_INET6, (char *)adr, mydummy,
+ MYDUMMY_SIZE),
+ hostbuf));
+#else
+ Debug((DEBUG_INFO,"got ip # %s for %s",
+ inetntoa((char *)adr),
+ hostbuf));
+#endif
+ 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 = ircd_dn_expand((u_char *)buf, (u_char *)eob,
+ (u_char *)cp, hostbuf,
+ sizeof(hostbuf) )) < 0)
+ {
+ cp = NULL;
+ break;
+ }
+ cp += n;
+ len = strlen(hostbuf);
+ Debug((DEBUG_INFO, "got host %s (%d vs %d)",
+ hostbuf, len, strlen(hostbuf)));
+ if (bad_hostname(hostbuf, len))
+ return -1;
+ /*
+ * copy the returned hostname into the host name
+ * or alias field if there is a known hostname
+ * already.
+ */
+ if (hp->h_name)
+ {
+ Debug((DEBUG_INFO, "duplicate PTR ignored"));
+ }
+ 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 (bad_hostname(hostbuf, len))
+ return -1; /* a break would be enough here */
+ 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];
+ Reg HEADER *hptr;
+ Reg ResRQ *rptr = NULL;
+ aCache *cp = NULL;
+#ifdef INET6
+ struct sockaddr_in sin;
+#else
+ struct sockaddr_in sin;
+#endif
+ int rc, a, max;
+ SOCK_LEN_TYPE len = sizeof(sin);
+
+ (void)alarm((unsigned)4);
+#ifdef INET6
+ rc = recvfrom(resfd, buf, sizeof(buf), 0, (struct sockaddr *)&sin, &len);
+#else
+ rc = recvfrom(resfd, buf, sizeof(buf), 0, (struct sockaddr *)&sin, &len);
+#endif
+
+ (void)alarm((unsigned)0);
+ if (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(ircd_res.nscount, rptr->sends);
+ if (!max)
+ max = 1;
+
+ for (a = 0; a < max; a++)
+#ifdef INET6
+ if (!ircd_res.nsaddr_list[a].sin_addr.s_addr ||
+ !bcmp((char *)&sin.sin_addr,
+ (char *)&ircd_res.nsaddr_list[a].sin_addr,
+ sizeof(struct in_addr)))
+#else
+ if (!ircd_res.nsaddr_list[a].sin_addr.s_addr ||
+ !bcmp((char *)&sin.sin_addr,
+ (char *)&ircd_res.nsaddr_list[a].sin_addr,
+ sizeof(struct in_addr)))
+#endif
+ 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);
+ if (a == -1) {
+ sendto_flag(SCH_ERROR, "Bad hostname returned from %s for %s",
+#ifdef INET6
+ inetntop(AF_INET, &sin.sin_addr, mydummy2,
+ MYDUMMY_SIZE),
+ inetntop(AF_INET6, rptr->he.h_addr.s6_addr,
+ mydummy, MYDUMMY_SIZE));
+#else
+ inetntoa((char *)&sin.sin_addr),
+ inetntoa((char *)&rptr->he.h_addr));
+#endif
+#ifdef INET6
+ Debug((DEBUG_DNS, "Bad hostname returned from %s for %s",
+ inet_ntop(AF_INET, &sin.sin_addr,mydummy2,MYDUMMY_SIZE),
+ inet_ntop(AF_INET6, rptr->he.h_addr.s6_addr, mydummy,
+ MYDUMMY_SIZE)));
+#else
+ Debug((DEBUG_DNS, "Bad hostname returned from %s for %s",
+ inetntoa((char *)&sin.sin_addr),
+ inetntoa((char *)&rptr->he.h_addr)));
+#endif
+ }
+#ifdef DEBUG
+ Debug((DEBUG_INFO,"get_res:Proc answer = %d",a));
+#endif
+ if (a > 0 && rptr->type == T_PTR)
+ {
+ struct hostent *hp2 = NULL;
+
+ if (BadPtr(rptr->he.h_name)) /* Kludge! 960907/Vesa */
+ goto getres_err;
+
+#ifdef INET6
+ Debug((DEBUG_DNS, "relookup %s <-> %s",
+ rptr->he.h_name, inet_ntop(AF_INET6,
+ (char *)&rptr->he.h_addr,
+ mydummy, MYDUMMY_SIZE)));
+#else
+ Debug((DEBUG_DNS, "relookup %s <-> %s",
+ rptr->he.h_name, inetntoa((char *)&rptr->he.h_addr)));
+#endif
+ /*
+ * 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 (ircd_res.options & RES_DEFNAMES && ++rptr->srch == 0)
+ {
+ rptr->retries = ircd_res.retry;
+ rptr->sends = 0;
+ rptr->resend = 1;
+#ifdef INET6
+/* Comment out this ifdef to get names like ::ffff:a.b.c.d */
+ if(rptr->type == T_AAAA)
+ query_name(rptr->name, C_IN, T_A, rptr);
+ Debug((DEBUG_DNS,"getres_err: didn't work with T_AAAA, now also trying with T_A for %s",rptr->name));
+#endif
+ resend_query(rptr);
+ }
+ else
+ {
+#ifdef INET6
+/* Comment out this ifdef to get names like ::ffff:a.b.c.d */
+ if(rptr->type == T_AAAA)
+ query_name(rptr->name, C_IN, T_A, rptr);
+ Debug((DEBUG_DNS,"getres_err: didn't work with T_AAAA, now also trying with T_A for %s",rptr->name));
+#endif
+ resend_query(rptr);
+ }
+ }
+ else if (lp)
+ bcopy((char *)&rptr->cinfo, lp, sizeof(Link));
+ }
+ return (struct hostent *)NULL;
+}
+
+static int hash_number(ip)
+Reg u_char *ip;
+{
+ Reg u_int hashv = 0;
+
+ /* could use loop but slower */
+ hashv += (int)*ip++;
+ hashv += hashv + (int)*ip++;
+ hashv += hashv + (int)*ip++;
+#ifdef INET6
+ hashv += hashv + (int)*ip++;
+ hashv += hashv + (int)*ip++;
+ hashv += hashv + (int)*ip++;
+ hashv += hashv + (int)*ip++;
+ hashv += hashv + (int)*ip++;
+ hashv += hashv + (int)*ip++;
+ hashv += hashv + (int)*ip++;
+ hashv += hashv + (int)*ip++;
+ hashv += hashv + (int)*ip++;
+ hashv += hashv + (int)*ip++;
+ hashv += hashv + (int)*ip++;
+ hashv += hashv + (int)*ip++;
+#endif
+ hashv += hashv + (int)*ip;
+ hashv %= ARES_CACSIZE;
+ return (hashv);
+}
+
+static int hash_name(name)
+register char *name;
+{
+ Reg u_int hashv = 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)
+Reg aCache *ocp;
+{
+ Reg aCache *cp = NULL;
+ Reg int hashv;
+
+#ifdef DEBUG
+ Debug((DEBUG_INFO,
+ "add_to_cache:ocp %#x he %#x name %#x addrl %#x 0 %#x",
+ ocp, &ocp->he, ocp->he.h_name, ocp->he.h_addr_list,
+ ocp->he.h_addr_list[0]));
+#endif
+ ocp->list_next = cachetop;
+ cachetop = ocp;
+
+ 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
+#ifdef INET6
+ Debug((DEBUG_INFO,"add_to_cache:added %s[%08x%08x%08x%08x] cache %#x.",
+ ocp->he.h_name,
+ ((struct in6_addr *)ocp->he.h_addr_list)->s6_laddr[0],
+ ((struct in6_addr *)ocp->he.h_addr_list)->s6_laddr[1],
+ ((struct in6_addr *)ocp->he.h_addr_list)->s6_laddr[2],
+ ((struct in6_addr *)ocp->he.h_addr_list)->s6_laddr[3], ocp));
+#else
+ Debug((DEBUG_INFO, "add_to_cache:added %s[%08x] cache %#x.",
+ ocp->he.h_name, ocp->he.h_addr_list[0], ocp));
+#endif
+ Debug((DEBUG_INFO,
+ "add_to_cache:h1 %d h2 %x lnext %#x namnext %#x numnext %#x",
+ hash_name(ocp->he.h_name), hashv, ocp->list_next,
+ ocp->hname_next, ocp->hnum_next));
+#endif
+
+ /*
+ * LRU deletion of excessive cache entries.
+ */
+ if (++incache > MAXCACHED)
+ {
+ for (cp = cachetop; cp->list_next; cp = cp->list_next)
+ ;
+ rem_cache(cp);
+ }
+ cainfo.ca_adds++;
+
+ return ocp;
+}
+
+/*
+** update_list does not alter the cache structure passed. It is assumed that
+** it already contains the correct expire time, if it is a new entry. Old
+** entries have the expirey time updated.
+*/
+static void update_list(rptr, cachep)
+ResRQ *rptr;
+aCache *cachep;
+{
+ Reg aCache **cpp, *cp = cachep;
+ Reg char *s, *t, **base;
+ Reg 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] = mystrdup(s);
+ base[addrcount] = NULL;
+ }
+ }
+#ifdef INET6
+ for (i = 0; cp->he.h_addr_list[i]; i++)
+#else
+ for (i = 0; cp->he.h_addr_list[i]; i++)
+#endif
+ ;
+ addrcount = i;
+
+ /*
+ * Do the same again for IP#'s.
+ */
+#ifdef INET6
+ for (s = (char *)rptr->he.h_addr.S_ADDR;
+ ((struct IN_ADDR *)s)->S_ADDR; s += sizeof(struct IN_ADDR))
+#else
+ for (s = (char *)&rptr->he.h_addr.S_ADDR;
+ ((struct IN_ADDR *)s)->S_ADDR; s += sizeof(struct IN_ADDR))
+#endif
+ {
+#ifdef INET6
+ for (i = 0; (t = cp->he.h_addr_list[i]); i++)
+#else
+ for (i = 0; (t = cp->he.h_addr_list[i]); i++)
+#endif
+ 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)
+ {
+ struct IN_ADDR **ab;
+
+ ab = (struct IN_ADDR **)cp->he.h_addr_list;
+ addrcount++;
+ t = (char *)MyRealloc((char *)*ab,
+ addrcount * sizeof(struct IN_ADDR));
+ base = (char **)MyRealloc((char *)ab,
+ (addrcount + 1) * sizeof(*ab));
+ 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--)
+ {
+ *ab++ = (struct IN_ADDR *)t;
+ t += sizeof(struct IN_ADDR);
+ }
+ *ab = NULL;
+ bcopy(s, (char *)*--ab, sizeof(struct IN_ADDR));
+ }
+ }
+ return;
+}
+
+static aCache *find_cache_name(name)
+char *name;
+{
+ Reg aCache *cp;
+ Reg char *s;
+ Reg 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;
+{
+ Reg aCache *cp;
+ Reg 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
+#ifdef INET6
+ Debug((DEBUG_DNS,
+ "find_cache_number:find %s[%08x%08x%08x%08x]: hashv = %d",
+ inet_ntop(AF_INET6, numb,mydummy,MYDUMMY_SIZE), ip->s6_laddr[0],
+ ip->s6_laddr[1], ip->s6_laddr[2], ip->s6_laddr[3], hashv));
+#else
+ Debug((DEBUG_DNS,"find_cache_number:find %s[%08x]: hashv = %d",
+ inetntoa(numb), ntohl(ip->s_addr), hashv));
+#endif
+#endif
+ for (; cp; cp = cp->hnum_next)
+ {
+#ifdef INET6
+ for (i = 0; cp->he.h_addr_list[i]; i++)
+#else
+ for (i = 0; cp->he.h_addr_list[i]; i++)
+#endif
+ {
+ 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)
+ {
+ if (!cp->he.h_addr_list && !cp->he.h_aliases)
+ {
+ cp = rem_list(cp);
+ continue;
+ }
+ /*
+ * single address entry...would have been done by hashed
+ * search above...
+ */
+#ifdef INET6
+ if (!cp->he.h_addr_list[1])
+#else
+ if (!cp->he.h_addr_list[1])
+#endif
+ continue;
+ /*
+ * if the first IP# has the same hashnumber as the IP# we
+ * are looking for, its been done already.
+ */
+ if (hashv == hash_number((u_char *)cp->he.h_addr_list[0]))
+ continue;
+#ifdef INET6
+ for (i = 1; cp->he.h_addr_list[i]; i++)
+#else
+ for (i = 1; cp->he.h_addr_list[i]; i++)
+#endif
+ 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;
+{
+ Reg aCache *cp;
+ Reg int i, n;
+ Reg struct hostent *hp;
+ Reg char *s, **t;
+
+ /*
+ ** shouldn't happen but it just might...
+ */
+ if (!rptr->he.h_name || !WHOSTENTP(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.
+ */
+ for (i = 0; WHOSTENTP(rptr->he.h_addr_list[i].S_ADDR); i++)
+ if ((cp = find_cache_number(rptr,
+#ifdef INET6
+ (char *)(rptr->he.h_addr_list[i].S_ADDR))))
+#else
+ (char *)&(rptr->he.h_addr_list[i].S_ADDR))))
+#endif
+ return cp;
+
+ /*
+ ** a matching entry wasnt found in the cache so go and make one up.
+ */
+ cp = (aCache *)MyMalloc(sizeof(aCache));
+ bzero((char *)cp, sizeof(aCache));
+ hp = &cp->he;
+ for (i = 0; i < MAXADDRS - 1; i++)
+ if (!WHOSTENTP(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,
+ sizeof(struct IN_ADDR));
+ }
+ *t = (char *)NULL;
+
+ /*
+ ** an array of pointers to CNAMEs.
+ */
+ for (i = 0; i < MAXALIASES - 1; 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 = timeofday + 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_list
+ */
+static aCache *rem_list(cp)
+aCache *cp;
+{
+ aCache **cpp, *cr = cp->list_next;
+
+ /*
+ * remove cache entry from linked list
+ */
+ for (cpp = &cachetop; *cpp; cpp = &((*cpp)->list_next))
+ if (*cpp == cp)
+ {
+ *cpp = cp->list_next;
+ MyFree((char *)cp);
+ break;
+ }
+ return cr;
+}
+
+
+/*
+ * 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;
+{
+ Reg aCache **cp;
+ Reg struct hostent *hp = &ocp->he;
+ Reg int hashv;
+ Reg 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
+# ifdef INET6
+ Debug((DEBUG_DEBUG,"rem_cache: h_addr %s hashv %d next %#x first %#x",
+ inet_ntop(AF_INET6, hp->h_addr, mydummy, MYDUMMY_SIZE),
+ hashv, ocp->hnum_next, hashtable[hashv].num_list));
+# else
+ 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
+#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;
+{
+ Reg aCache *cp, *cp2;
+ Reg 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()
+{
+ Reg aCache *cp;
+
+ while ((cp = cachetop))
+ rem_cache(cp);
+}
+
+int m_dns(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+ Reg aCache *cp;
+ Reg int i;
+
+ if (parv[1] && *parv[1] == 'l') {
+ for(cp = cachetop; cp; cp = cp->list_next)
+ {
+ sendto_one(sptr, "NOTICE %s :Ex %d ttl %d host %s(%s)",
+ parv[0], cp->expireat - timeofday, cp->ttl,
+#ifdef INET6
+ cp->he.h_name, inetntop(AF_INET6,
+ cp->he.h_addr,
+ mydummy,
+ MYDUMMY_SIZE));
+#else
+ cp->he.h_name, inetntoa(cp->he.h_addr));
+#endif
+ 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]);
+#ifdef INET6
+ for (i = 1; cp->he.h_addr_list[i]; i++) {
+#else
+ for (i = 1; cp->he.h_addr_list[i]; i++) {
+#endif
+ sendto_one(sptr,"NOTICE %s : %s = %s (IP)",
+ parv[0], cp->he.h_name,
+#ifdef INET6
+ inetntop(AF_INET6,
+ cp->he.h_addr_list[i],
+ mydummy, MYDUMMY_SIZE));
+#else
+ inetntoa(cp->he.h_addr_list[i]));
+#endif
+ }
+ }
+ return 2;
+ }
+ 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 2;
+}
+
+u_long cres_mem(sptr, nick)
+aClient *sptr;
+char *nick;
+{
+ 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;
+#ifdef INET6
+ for (i = 0; h->h_addr_list[i]; i++)
+#else
+ for (i = 0; h->h_addr_list[i]; i++)
+#endif
+ {
+ 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, nick, ts);
+ sendto_one(sptr, ":%s %d %s :Structs %d IP storage %d Name storage %d",
+ me.name, RPL_STATSDEBUG, nick, sm, im, nm);
+ return ts + sm + im + nm;
+}
+
+
+static int bad_hostname(name, len)
+char *name;
+int len;
+{
+ char *s, c;
+
+ for (s = name; (c = *s) && len; s++, len--)
+ if (isspace(c) || (c == 0x7) || (c == ':') ||
+ (c == '*') || (c == '?'))
+ return -1;
+ return 0;
+}
diff --git a/ircd/res_comp.c b/ircd/res_comp.c
new file mode 100644
index 0000000..74e517f
--- /dev/null
+++ b/ircd/res_comp.c
@@ -0,0 +1,929 @@
+/*
+ * ++Copyright++ 1985, 1993
+ * -
+ * Copyright (c) 1985, 1993
+ * The 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)res_comp.c 8.1 (Berkeley) 6/4/93";
+static char rcsid[] = "$Id: res_comp.c,v 1.6 1999/03/08 20:51:58 kalt Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "os.h"
+#include "s_defines.h"
+#define RES_COMP_C
+#include "s_externs.h"
+#undef RES_COMP_C
+
+static int ns_name_ntop __P((const u_char *, char *, size_t));
+static int ns_name_pton __P((const char *, u_char *, size_t));
+static int ns_name_unpack __P((const u_char *, const u_char *,
+ const u_char *, u_char *, size_t));
+static int ns_name_pack __P((const u_char *, u_char *, int,
+ const u_char **, const u_char **));
+static int ns_name_uncompress __P((const u_char *, const u_char *,
+ const u_char *, char *, size_t));
+static int ns_name_compress __P((const char *, u_char *, size_t,
+ const u_char **, const u_char **));
+static int ns_name_skip __P((const u_char **, const u_char *));
+
+/*
+ * 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.
+ */
+int
+ircd_dn_expand(msg, eom, src, dst, dstsiz)
+ const u_char *msg;
+ const u_char *eom;
+ const u_char *src;
+ char *dst;
+ int dstsiz;
+{
+ int n = ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz);
+
+ if (n > 0 && dst[0] == '.')
+ dst[0] = '\0';
+ return (n);
+}
+
+/*
+ * Pack domain name 'exp_dn' in presentation form into 'comp_dn'.
+ * Return the size of the compressed name or -1.
+ * 'length' is the size of the array pointed to by 'comp_dn'.
+ */
+int
+ircd_dn_comp(src, dst, dstsiz, dnptrs, lastdnptr)
+ const char *src;
+ u_char *dst;
+ int dstsiz;
+ u_char **dnptrs;
+ u_char **lastdnptr;
+{
+ return (ns_name_compress(src, dst, (size_t)dstsiz,
+ (const u_char **)dnptrs,
+ (const u_char **)lastdnptr));
+}
+
+/*
+ * Skip over a compressed domain name. Return the size or -1.
+ */
+int
+__ircd_dn_skipname(ptr, eom)
+ const u_char *ptr;
+ const u_char *eom;
+{
+ const u_char *saveptr = ptr;
+
+ if (ns_name_skip(&ptr, eom) == -1)
+ return (-1);
+ return (ptr - saveptr);
+}
+
+/*
+ * Verify that a domain name uses an acceptable character set.
+ */
+
+/*
+ * Note the conspicuous absence of ctype macros in these definitions. On
+ * non-ASCII hosts, we can't depend on string literals or ctype macros to
+ * tell us anything about network-format data. The rest of the BIND system
+ * is not careful about this, but for some reason, we're doing it right here.
+ */
+#define PERIOD 0x2e
+#define hyphenchar(c) ((c) == 0x2d)
+#define bslashchar(c) ((c) == 0x5c)
+#define periodchar(c) ((c) == PERIOD)
+#define asterchar(c) ((c) == 0x2a)
+#define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) \
+ || ((c) >= 0x61 && (c) <= 0x7a))
+#define digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
+
+#define borderchar(c) (alphachar(c) || digitchar(c))
+#define middlechar(c) (borderchar(c) || hyphenchar(c))
+#define domainchar(c) ((c) > 0x20 && (c) < 0x7f)
+
+#if 0
+/* it seems that we don't need these -krys */
+
+int
+res_hnok(dn)
+ const char *dn;
+{
+ int ppch = '\0', pch = PERIOD, ch = *dn++;
+
+ while (ch != '\0') {
+ int nch = *dn++;
+
+ if (periodchar(ch)) {
+ NULL;
+ } else if (periodchar(pch)) {
+ if (!borderchar(ch))
+ return (0);
+ } else if (periodchar(nch) || nch == '\0') {
+ if (!borderchar(ch))
+ return (0);
+ } else {
+ if (!middlechar(ch))
+ return (0);
+ }
+ ppch = pch, pch = ch, ch = nch;
+ }
+ return (1);
+}
+
+/*
+ * hostname-like (A, MX, WKS) owners can have "*" as their first label
+ * but must otherwise be as a host name.
+ */
+int
+res_ownok(dn)
+ const char *dn;
+{
+ if (asterchar(dn[0])) {
+ if (periodchar(dn[1]))
+ return (res_hnok(dn+2));
+ if (dn[1] == '\0')
+ return (1);
+ }
+ return (res_hnok(dn));
+}
+
+/*
+ * SOA RNAMEs and RP RNAMEs can have any printable character in their first
+ * label, but the rest of the name has to look like a host name.
+ */
+int
+res_mailok(dn)
+ const char *dn;
+{
+ int ch, escaped = 0;
+
+ /* "." is a valid missing representation */
+ if (*dn == '\0')
+ return(1);
+
+ /* otherwise <label>.<hostname> */
+ while ((ch = *dn++) != '\0') {
+ if (!domainchar(ch))
+ return (0);
+ if (!escaped && periodchar(ch))
+ break;
+ if (escaped)
+ escaped = 0;
+ else if (bslashchar(ch))
+ escaped = 1;
+ }
+ if (periodchar(ch))
+ return (res_hnok(dn));
+ return(0);
+}
+
+/*
+ * This function is quite liberal, since RFC 1034's character sets are only
+ * recommendations.
+ */
+int
+res_dnok(dn)
+ const char *dn;
+{
+ int ch;
+
+ while ((ch = *dn++) != '\0')
+ if (!domainchar(ch))
+ return (0);
+ return (1);
+}
+#endif
+
+/*
+ * Routines to insert/extract short/long's.
+ */
+
+u_int16_t
+ircd_getshort(msgp)
+ register const u_char *msgp;
+{
+ register u_int16_t u;
+
+ GETSHORT(u, msgp);
+ return (u);
+}
+
+u_int32_t
+ircd_getlong(msgp)
+ register const u_char *msgp;
+{
+ register u_int32_t u;
+
+ GETLONG(u, msgp);
+ return (u);
+}
+
+void
+#if __STDC__
+ircd__putshort(register u_int16_t s, register u_char *msgp) /* must match proto */
+#else
+ircd__putshort(s, msgp)
+ register u_int16_t s;
+ register u_char *msgp;
+#endif
+{
+ PUTSHORT(s, msgp);
+}
+
+void
+ircd__putlong(l, msgp)
+ register u_int32_t l;
+ register u_char *msgp;
+{
+ PUTLONG(l, msgp);
+}
+
+/* ++ From BIND 8.1.1. ++ */
+/*
+ * Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*"Id: ns_name.c,v 1.1 1997/12/13 02:41:13 vixie Exp vixie"*/
+
+/*#include "port_before.h"*/
+
+/*#include <sys/types.h>*/
+
+/*#include <netinet/in.h>*/
+/*#include <arpa/nameser.h>*/
+
+/*#include <errno.h>*/
+/*#include <resolv.h>*/
+/*#include <string.h>*/
+
+/*#include "port_after.h"*/
+
+#define NS_CMPRSFLGS 0xc0 /* Flag bits indicating name compression. */
+#define NS_MAXCDNAME 255 /* maximum compressed domain name */
+
+/* Data. */
+
+static char digits[] = "0123456789";
+
+/* Forward. */
+
+static int special __P((int));
+static int printable __P((int));
+static int dn_find __P((const u_char *, const u_char *,
+ const u_char * const *,
+ const u_char * const *));
+
+/* Public. */
+
+/*
+ * ns_name_ntop(src, dst, dstsiz)
+ * Convert an encoded domain name to printable ascii as per RFC1035.
+ * return:
+ * Number of bytes written to buffer, or -1 (with errno set)
+ * notes:
+ * The root is returned as "."
+ * All other domains are returned in non absolute form
+ */
+static int
+ns_name_ntop(src, dst, dstsiz)
+ const u_char *src;
+ char *dst;
+ size_t dstsiz;
+{
+ const u_char *cp;
+ char *dn, *eom;
+ u_char c;
+ u_int n;
+
+ cp = src;
+ dn = dst;
+ eom = dst + dstsiz;
+
+ while ((n = *cp++) != 0) {
+ if ((n & NS_CMPRSFLGS) != 0) {
+ /* Some kind of compression pointer. */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (dn != dst) {
+ if (dn >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '.';
+ }
+ if (dn + n >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ for ((void)NULL; n > 0; n--) {
+ c = *cp++;
+ if (special(c)) {
+ if (dn + 1 >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '\\';
+ *dn++ = (char)c;
+ } else if (!printable(c)) {
+ if (dn + 3 >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '\\';
+ *dn++ = digits[c / 100];
+ *dn++ = digits[(c % 100) / 10];
+ *dn++ = digits[c % 10];
+ } else {
+ if (dn >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = (char)c;
+ }
+ }
+ }
+ if (dn == dst) {
+ if (dn >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '.';
+ }
+ if (dn >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dn++ = '\0';
+ return (dn - dst);
+}
+
+/*
+ * ns_name_pton(src, dst, dstsiz)
+ * Convert a ascii string into an encoded domain name as per RFC1035.
+ * return:
+ * -1 if it fails
+ * 1 if string was fully qualified
+ * 0 is string was not fully qualified
+ * notes:
+ * Enforces label and domain length limits.
+ */
+
+static int
+ns_name_pton(src, dst, dstsiz)
+ const char *src;
+ u_char *dst;
+ size_t dstsiz;
+{
+ u_char *label, *bp, *eom;
+ int c, n, escaped;
+ char *cp;
+
+ escaped = 0;
+ bp = dst;
+ eom = dst + dstsiz;
+ label = bp++;
+
+ while ((c = *src++) != 0) {
+ if (escaped) {
+ if ((cp = strchr(digits, c)) != NULL) {
+ n = (cp - digits) * 100;
+ if ((c = *src++) == 0 ||
+ (cp = strchr(digits, c)) == NULL) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ n += (cp - digits) * 10;
+ if ((c = *src++) == 0 ||
+ (cp = strchr(digits, c)) == NULL) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ n += (cp - digits);
+ if (n > 255) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ c = n;
+ }
+ escaped = 0;
+ } else if (c == '\\') {
+ escaped = 1;
+ continue;
+ } else if (c == '.') {
+ c = (bp - label - 1);
+ if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (label >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *label = c;
+ /* Fully qualified ? */
+ if (*src == '\0') {
+ if (c != 0) {
+ if (bp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *bp++ = '\0';
+ }
+ if ((bp - dst) > MAXCDNAME) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ return (1);
+ }
+ if (c == 0) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ label = bp++;
+ continue;
+ }
+ if (bp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *bp++ = (u_char)c;
+ }
+ c = (bp - label - 1);
+ if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (label >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *label = c;
+ if (c != 0) {
+ if (bp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *bp++ = 0;
+ }
+ if ((bp - dst) > MAXCDNAME) { /* src too big */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ return (0);
+}
+
+/*
+ * ns_name_unpack(msg, eom, src, dst, dstsiz)
+ * Unpack a domain name from a message, source may be compressed.
+ * return:
+ * -1 if it fails, or consumed octets if it succeeds.
+ */
+static int
+ns_name_unpack(msg, eom, src, dst, dstsiz)
+ const u_char *msg;
+ const u_char *eom;
+ const u_char *src;
+ u_char *dst;
+ size_t dstsiz;
+{
+ const u_char *srcp, *dstlim;
+ u_char *dstp;
+ int n, c, len, checked;
+
+ len = -1;
+ checked = 0;
+ dstp = dst;
+ srcp = src;
+ dstlim = dst + dstsiz;
+ if (srcp < msg || srcp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ /* Fetch next label in domain name. */
+ while ((n = *srcp++) != 0) {
+ /* Check for indirection. */
+ switch (n & NS_CMPRSFLGS) {
+ case 0:
+ /* Limit checks. */
+ if (dstp + n + 1 >= dstlim || srcp + n >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ checked += n + 1;
+ *dstp++ = n;
+ memcpy(dstp, srcp, n);
+ dstp += n;
+ srcp += n;
+ break;
+
+ case NS_CMPRSFLGS:
+ if (srcp >= eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (len < 0)
+ len = srcp - src + 1;
+ srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
+ if (srcp < msg || srcp >= eom) { /* Out of range. */
+ errno = EMSGSIZE;
+ 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 >= eom - msg) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ break;
+
+ default:
+ errno = EMSGSIZE;
+ return (-1); /* flag error */
+ }
+ }
+ *dstp = '\0';
+ if (len < 0)
+ len = srcp - src;
+ return (len);
+}
+
+/*
+ * ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr)
+ * Pack domain name 'domain' into 'comp_dn'.
+ * return:
+ * Size of the compressed name, or -1.
+ * notes:
+ * 'dnptrs' is an array of pointers to previous compressed names.
+ * dnptrs[0] is a pointer to the beginning of the message. The array
+ * ends with NULL.
+ * 'lastdnptr' is a pointer to the end of the array pointed to
+ * by 'dnptrs'.
+ * Side effects:
+ * The list of pointers in dnptrs is updated 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.
+ */
+static int
+ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr)
+ const u_char *src;
+ u_char *dst;
+ int dstsiz;
+ const u_char **dnptrs;
+ const u_char **lastdnptr;
+{
+ u_char *dstp;
+ const u_char **cpp, **lpp, *eob, *msg;
+ const u_char *srcp;
+ int n, l;
+
+ srcp = src;
+ dstp = dst;
+ eob = dstp + dstsiz;
+ lpp = cpp = NULL;
+ if (dnptrs != NULL) {
+ if ((msg = *dnptrs++) != NULL) {
+ for (cpp = dnptrs; *cpp != NULL; cpp++)
+ (void)NULL;
+ lpp = cpp; /* end of list to search */
+ }
+ } else
+ msg = NULL;
+
+ /* make sure the domain we are about to add is legal */
+ l = 0;
+ do {
+ n = *srcp;
+ if ((n & NS_CMPRSFLGS) != 0) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ l += n + 1;
+ if (l > MAXCDNAME) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ srcp += n + 1;
+ } while (n != 0);
+
+ srcp = src;
+ do {
+ /* Look to see if we can use pointers. */
+ n = *srcp;
+ if (n != 0 && msg != NULL) {
+ l = dn_find(srcp, msg, (const u_char * const *)dnptrs,
+ (const u_char * const *)lpp);
+ if (l >= 0) {
+ if (dstp + 1 >= eob) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *dstp++ = (l >> 8) | NS_CMPRSFLGS;
+ *dstp++ = l % 256;
+ return (dstp - dst);
+ }
+ /* Not found, save it. */
+ if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
+ (dstp - msg) < 0x4000) {
+ *cpp++ = dstp;
+ *cpp = NULL;
+ }
+ }
+ /* copy label to buffer */
+ if (n & NS_CMPRSFLGS) { /* Should not happen. */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (dstp + 1 + n >= eob) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ memcpy(dstp, srcp, n + 1);
+ srcp += n + 1;
+ dstp += n + 1;
+ } while (n != 0);
+
+ if (dstp > eob) {
+ if (msg != NULL)
+ *lpp = NULL;
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ return (dstp - dst);
+}
+
+/*
+ * ns_name_uncompress(msg, eom, src, dst, dstsiz)
+ * Expand compressed domain name to presentation format.
+ * return:
+ * Number of bytes read out of `src', or -1 (with errno set).
+ * note:
+ * Root domain returns as "." not "".
+ */
+static int
+ns_name_uncompress(msg, eom, src, dst, dstsiz)
+ const u_char *msg;
+ const u_char *eom;
+ const u_char *src;
+ char *dst;
+ size_t dstsiz;
+{
+ u_char tmp[NS_MAXCDNAME];
+ int n;
+
+ if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1)
+ return (-1);
+ if (ns_name_ntop(tmp, dst, dstsiz) == -1)
+ return (-1);
+ return (n);
+}
+
+/*
+ * ns_name_compress(src, dst, dstsiz, dnptrs, lastdnptr)
+ * Compress a domain name into wire format, using compression pointers.
+ * return:
+ * Number of bytes consumed in `dst' or -1 (with errno set).
+ * notes:
+ * 'dnptrs' is an array 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
+ * array 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.
+ */
+static int
+ns_name_compress(src, dst, dstsiz, dnptrs, lastdnptr)
+ const char *src;
+ u_char *dst;
+ size_t dstsiz;
+ const u_char **dnptrs;
+ const u_char **lastdnptr;
+{
+ u_char tmp[NS_MAXCDNAME];
+
+ if (ns_name_pton(src, tmp, sizeof tmp) == -1)
+ return (-1);
+ return (ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr));
+}
+
+/*
+ * ns_name_skip(ptrptr, eom)
+ * Advance *ptrptr to skip over the compressed name it points at.
+ * return:
+ * 0 on success, -1 (with errno set) on failure.
+ */
+static int
+ns_name_skip(ptrptr, eom)
+ const u_char **ptrptr;
+ const u_char *eom;
+{
+ const u_char *cp;
+ u_int n;
+
+ cp = *ptrptr;
+ while (cp < eom && (n = *cp++) != 0) {
+ /* Check for indirection. */
+ switch (n & NS_CMPRSFLGS) {
+ case 0: /* normal case, n == len */
+ cp += n;
+ continue;
+ case NS_CMPRSFLGS: /* indirection */
+ cp++;
+ break;
+ default: /* illegal type */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ break;
+ }
+ if (cp > eom) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ *ptrptr = cp;
+ return (0);
+}
+
+/* Private. */
+
+/*
+ * special(ch)
+ * Thinking in noninternationalized USASCII (per the DNS spec),
+ * is this characted special ("in need of quoting") ?
+ * return:
+ * boolean.
+ */
+static int
+special(ch)
+ int ch;
+{
+ switch (ch) {
+ case 0x22: /* '"' */
+ case 0x2E: /* '.' */
+ case 0x3B: /* ';' */
+ case 0x5C: /* '\\' */
+ /* Special modifiers in zone files. */
+ case 0x40: /* '@' */
+ case 0x24: /* '$' */
+ return (1);
+ default:
+ return (0);
+ }
+}
+
+/*
+ * printable(ch)
+ * Thinking in noninternationalized USASCII (per the DNS spec),
+ * is this character visible and not a space when printed ?
+ * return:
+ * boolean.
+ */
+static int
+printable(ch)
+ int ch;
+{
+ return (ch > 0x20 && ch < 0x7f);
+}
+
+/*
+ * Thinking in noninternationalized USASCII (per the DNS spec),
+ * convert this character to lower case if it's upper case.
+ */
+static int
+mklower(ch)
+ int ch;
+{
+ if (ch >= 0x41 && ch <= 0x5A)
+ return (ch + 0x20);
+ return (ch);
+}
+
+/*
+ * dn_find(domain, msg, dnptrs, lastdnptr)
+ * Search for the counted-label name in an array of compressed names.
+ * return:
+ * offset from msg if found, or -1.
+ * notes:
+ * dnptrs is the pointer to the first name on the list,
+ * not the pointer to the start of the message.
+ */
+static int
+dn_find(domain, msg, dnptrs, lastdnptr)
+ const u_char *domain;
+ const u_char *msg;
+ const u_char * const *dnptrs;
+ const u_char * const *lastdnptr;
+{
+ const u_char *dn, *cp, *sp;
+ const u_char * const *cpp;
+ u_int n;
+
+ for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
+ dn = domain;
+ sp = cp = *cpp;
+ while ((n = *cp++) != 0) {
+ /*
+ * check for indirection
+ */
+ switch (n & NS_CMPRSFLGS) {
+ case 0: /* normal case, n == len */
+ if (n != *dn++)
+ goto next;
+ for ((void)NULL; n > 0; n--)
+ if (mklower(*dn++) != mklower(*cp++))
+ goto next;
+ /* Is next root for both ? */
+ if (*dn == '\0' && *cp == '\0')
+ return (sp - msg);
+ if (*dn)
+ continue;
+ goto next;
+
+ case NS_CMPRSFLGS: /* indirection */
+ cp = msg + (((n & 0x3f) << 8) | *cp);
+ break;
+
+ default: /* illegal type */
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ }
+ next: ;
+ }
+ errno = ENOENT;
+ return (-1);
+}
+
+/* -- From BIND 8.1.1. -- */
diff --git a/ircd/res_comp_ext.h b/ircd/res_comp_ext.h
new file mode 100644
index 0000000..273bf05
--- /dev/null
+++ b/ircd/res_comp_ext.h
@@ -0,0 +1,44 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/res_comp_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in ircd/res_comp.c.
+ */
+
+/* External definitions for global functions.
+ */
+#ifndef RES_COMP_C
+#define EXTERN extern
+#else /* RES_COMP_C */
+#define EXTERN
+#endif /* RES_COMP_C */
+EXTERN int ircd_dn_expand __P((const u_char *msg, const u_char *eomorig,
+ const u_char *comp_dn, char *exp_dn,
+ int length));
+EXTERN int ircd_dn_comp __P((const char *exp_dn, u_char *comp_dn, int length,
+ u_char **dnptrs, u_char **lastdnptr));
+EXTERN int __ircd_dn_skipname __P((const u_char *comp_dn, const u_char *eom));
+EXTERN u_int16_t ircd_getshort __P((register const u_char *msgp));
+EXTERN u_int32_t ircd_getlong __P((register const u_char *msgp));
+EXTERN void ircd__putshort __P((register u_int16_t s, register u_char *msgp));
+EXTERN void ircd__putlong __P((register u_int32_t l, register u_char *msgp));
+#ifdef NEXT
+EXTERN u_int16_t res_getshort __P((register const u_char *msgp));
+#endif /* NEXT */
+#undef EXTERN
diff --git a/ircd/res_def.h b/ircd/res_def.h
new file mode 100644
index 0000000..689b36f
--- /dev/null
+++ b/ircd/res_def.h
@@ -0,0 +1,59 @@
+/*
+ * ircd/res_def.h (C)opyright 1992 Darren Reed.
+ */
+
+#define RES_INITLIST 1
+#define RES_CALLINIT 2
+#define RES_INITSOCK 4
+#define RES_INITDEBG 8
+#define RES_INITCACH 16
+
+#define MAXPACKET 1024
+#define MAXALIASES 35
+#define MAXADDRS 35
+
+#define AR_TTL 600 /* TTL in seconds for dns cache entries */
+
+struct hent {
+ char *h_name; /* official name of host */
+ char *h_aliases[MAXALIASES]; /* alias list */
+ int h_addrtype; /* host address type */
+ int h_length; /* length of address */
+ /* list of addresses from name server */
+ struct IN_ADDR h_addr_list[MAXADDRS];
+#define h_addr h_addr_list[0] /* address, for backward compatiblity */
+};
+
+typedef struct reslist {
+ int id;
+ int sent; /* number of requests sent */
+ int srch;
+ time_t ttl;
+ char type;
+ char retries; /* retry counter */
+ char sends; /* number of sends (>1 means resent) */
+ char resend; /* send flag. 0 == dont resend */
+ time_t sentat;
+ time_t timeout;
+ struct IN_ADDR addr;
+ char *name;
+ struct reslist *next;
+ Link cinfo;
+ 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
diff --git a/ircd/res_ext.h b/ircd/res_ext.h
new file mode 100644
index 0000000..9e4c8eb
--- /dev/null
+++ b/ircd/res_ext.h
@@ -0,0 +1,41 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/res_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in ircd/res.c.
+ */
+
+/* External definitions for global functions.
+ */
+#ifndef RES_C
+#define EXTERN extern
+#else /* RES_C */
+#define EXTERN
+#endif /* RES_C */
+extern int init_resolver __P((int op));
+EXTERN time_t timeout_query_list __P((time_t now));
+EXTERN void del_queries __P((char *cp));
+EXTERN struct hostent *gethost_byname __P((char *name, Link *lp));
+EXTERN struct hostent *gethost_byaddr __P((char *addr, Link *lp));
+EXTERN struct hostent *get_res __P((char *lp));
+EXTERN time_t expire_cache __P((time_t now));
+EXTERN void flush_cache();
+EXTERN int m_dns __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN u_long cres_mem __P((aClient *sptr, char *nick));
+#undef EXTERN
diff --git a/ircd/res_init.c b/ircd/res_init.c
new file mode 100644
index 0000000..126144a
--- /dev/null
+++ b/ircd/res_init.c
@@ -0,0 +1,642 @@
+/*
+ * ++Copyright++ 1985, 1989, 1993
+ * -
+ * Copyright (c) 1985, 1989, 1993
+ * The 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)res_init.c 8.1 (Berkeley) 6/7/93";
+static char rcsid[] = "$Id: res_init.c,v 1.10 1999/01/20 01:33:08 kalt Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "os.h"
+#include "s_defines.h"
+#define RES_INIT_C
+#include "s_externs.h"
+#undef RES_INIT_C
+
+/*-------------------------------------- info about "sortlist" --------------
+ * Marc Majka 1994/04/16
+ * Allan Nathanson 1994/10/29 (BIND 4.9.3.x)
+ *
+ * NetInfo resolver configuration directory support.
+ *
+ * Allow a NetInfo directory to be created in the hierarchy which
+ * contains the same information as the resolver configuration file.
+ *
+ * - The local domain name is stored as the value of the "domain" property.
+ * - The Internet address(es) of the name server(s) are stored as values
+ * of the "nameserver" property.
+ * - The name server addresses are stored as values of the "nameserver"
+ * property.
+ * - The search list for host-name lookup is stored as values of the
+ * "search" property.
+ * - The sortlist comprised of IP address netmask pairs are stored as
+ * values of the "sortlist" property. The IP address and optional netmask
+ * should be seperated by a slash (/) or ampersand (&) character.
+ * - Internal resolver variables can be set from the value of the "options"
+ * property.
+ */
+#if defined(NEXT)
+# define NI_PATH_RESCONF "/locations/resolver"
+# define NI_TIMEOUT 10
+static int ircd_netinfo_res_init __P((int *haveenv, int *havesearch));
+#endif
+
+static void ircd_res_setoptions __P((char *, char *));
+
+#ifdef RESOLVSORT
+static const char sort_mask[] = "/&";
+#define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL)
+#ifdef INET6
+static u_int32_t ircd_net_mask __P((struct in_addr));
+#else
+static u_int32_t ircd_net_mask __P((struct in_addr));
+#endif
+#endif
+
+#if !defined(isascii) /* XXX - could be a function */
+# define isascii(c) (!(c & 0200))
+#endif
+
+/*
+ * Resolver state default settings.
+ */
+
+struct __res_state ircd_res
+# if defined(__BIND_RES_TEXT)
+ = { RES_TIMEOUT, } /* Motorola, et al. */
+# endif
+ ;
+
+/*
+ * 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().
+ *
+ * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
+ * rather than INADDR_ANY ("0.0.0.0") as the default name server address
+ * since it was noted that INADDR_ANY actually meant ``the first interface
+ * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
+ * it had to be "up" in order for you to reach your own name server. It
+ * was later decided that since the recommended practice is to always
+ * install local static routes through 127.0.0.1 for all your network
+ * interfaces, that we could solve this problem without a code change.
+ *
+ * The configuration file should always be used, since it is the only way
+ * to specify a default domain. If you are running a server on your local
+ * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
+ * in the configuration file.
+ *
+ * Return 0 if completes successfully, -1 on error
+ */
+int
+ircd_res_init()
+{
+ register FILE *fp;
+ register char *cp, **pp;
+ register int n;
+ char buf[MAXDNAME];
+ int nserv = 0; /* number of nameserver records read from file */
+ int haveenv = 0;
+ int havesearch = 0;
+#ifdef RESOLVSORT
+ int nsort = 0;
+ char *net;
+#endif
+#ifndef RFC1535
+ int dots;
+#endif
+
+ /*
+ * These three fields used to be statically initialized. This made
+ * it hard to use this code in a shared library. It is necessary,
+ * now that we're doing dynamic initialization here, that we preserve
+ * the old semantics: if an application modifies one of these three
+ * fields of _res before res_init() is called, res_init() will not
+ * alter them. Of course, if an application is setting them to
+ * _zero_ before calling res_init(), hoping to override what used
+ * to be the static default, we can't detect it and unexpected results
+ * will follow. Zero for any of these fields would make no sense,
+ * so one can safely assume that the applications were already getting
+ * unexpected results.
+ *
+ * _res.options is tricky since some apps were known to diddle the bits
+ * before res_init() was first called. We can't replicate that semantic
+ * with dynamic initialization (they may have turned bits off that are
+ * set in RES_DEFAULT). Our solution is to declare such applications
+ * "broken". They could fool us by setting RES_INIT but none do (yet).
+ */
+ if (!ircd_res.retrans)
+ ircd_res.retrans = RES_TIMEOUT;
+ if (!ircd_res.retry)
+ ircd_res.retry = 4;
+ if (!(ircd_res.options & RES_INIT))
+ ircd_res.options = RES_DEFAULT;
+
+ /*
+ * This one used to initialize implicitly to zero, so unless the app
+ * has set it to something in particular, we can randomize it now.
+ */
+ if (!ircd_res.id)
+ ircd_res.id = ircd_res_randomid();
+
+/*ifdef INET6 not, because of IPv4 DNS serving */
+#ifdef USELOOPBACK
+ ircd_res.nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1);
+#else
+ ircd_res.nsaddr.sin_addr.s_addr = INADDR_ANY;
+#endif
+ ircd_res.nsaddr.sin_family = AF_INET;
+ ircd_res.nsaddr.sin_port = htons(NAMESERVER_PORT);
+ ircd_res.nscount = 1;
+ ircd_res.ndots = 1;
+ ircd_res.pfcode = 0;
+
+ /* Allow user to override the local domain definition */
+ if ((cp = getenv("LOCALDOMAIN")) != NULL) {
+ strncpyzt(ircd_res.defdname, cp, sizeof(ircd_res.defdname));
+ haveenv++;
+
+ /*
+ * Set search list to be blank-separated strings
+ * from rest of env value. Permits users of LOCALDOMAIN
+ * to still have a search list, and anyone to set the
+ * one that they want to use as an individual (even more
+ * important now that the rfc1535 stuff restricts searches)
+ */
+ cp = ircd_res.defdname;
+ pp = ircd_res.dnsrch;
+ *pp++ = cp;
+ for (n = 0; *cp && pp < ircd_res.dnsrch + MAXDNSRCH; cp++) {
+ if (*cp == '\n') /* silly backwards compat */
+ break;
+ else if (*cp == ' ' || *cp == '\t') {
+ *cp = 0;
+ n = 1;
+ } else if (n) {
+ *pp++ = cp;
+ n = 0;
+ havesearch = 1;
+ }
+ }
+ /* null terminate last domain if there are excess */
+ while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n')
+ cp++;
+ *cp = '\0';
+ *pp++ = 0;
+ }
+
+#define MATCH(line, name) \
+ (!strncmp(line, name, sizeof(name) - 1) && \
+ (line[sizeof(name) - 1] == ' ' || \
+ line[sizeof(name) - 1] == '\t'))
+
+#ifdef NEXT
+ if (ircd_netinfo_res_init(&haveenv, &havesearch) == 0)
+#endif
+ if ((fp = fopen(IRC_RESCONF, "r")) != NULL) {
+ /* read the config file */
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ /* skip comments */
+ if (*buf == ';' || *buf == '#')
+ continue;
+ /* read default domain name */
+ if (MATCH(buf, "domain")) {
+ if (haveenv) /* skip if have from environ */
+ continue;
+ cp = buf + sizeof("domain") - 1;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if ((*cp == '\0') || (*cp == '\n'))
+ continue;
+ strncpyzt(ircd_res.defdname, cp, sizeof(ircd_res.defdname));
+ if ((cp = strpbrk(ircd_res.defdname, " \t\n")) != NULL)
+ *cp = '\0';
+ havesearch = 0;
+ continue;
+ }
+ /* set search list */
+ if (MATCH(buf, "search")) {
+ if (haveenv) /* skip if have from environ */
+ continue;
+ cp = buf + sizeof("search") - 1;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if ((*cp == '\0') || (*cp == '\n'))
+ continue;
+ strncpyzt(ircd_res.defdname, cp, sizeof(ircd_res.defdname));
+ if ((cp = strchr(ircd_res.defdname, '\n')) != NULL)
+ *cp = '\0';
+ /*
+ * Set search list to be blank-separated strings
+ * on rest of line.
+ */
+ cp = ircd_res.defdname;
+ pp = ircd_res.dnsrch;
+ *pp++ = cp;
+ for (n = 0; *cp && pp < ircd_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 (MATCH(buf, "nameserver") && nserv < MAXNS) {
+ struct in_addr a;
+
+ cp = buf + sizeof("nameserver") - 1;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if ((*cp != '\0') && (*cp != '\n') && inetaton(cp, &a)) {
+ ircd_res.nsaddr_list[nserv].sin_addr = a;
+ ircd_res.nsaddr_list[nserv].sin_family = AF_INET;
+ ircd_res.nsaddr_list[nserv].sin_port =
+ htons(NAMESERVER_PORT);
+ nserv++;
+ }
+ continue;
+ }
+#ifdef RESOLVSORT
+ if (MATCH(buf, "sortlist")) {
+ struct in_addr a;
+
+ cp = buf + sizeof("sortlist") - 1;
+ while (nsort < MAXRESOLVSORT) {
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if (*cp == '\0' || *cp == '\n' || *cp == ';')
+ break;
+ net = cp;
+ while (*cp && !ISSORTMASK(*cp) && *cp != ';' &&
+ isascii(*cp) && !isspace(*cp))
+ cp++;
+ n = *cp;
+ *cp = 0;
+ if (inetaton(net, &a)) {
+ ircd_res.sort_list[nsort].addr = a;
+ if (ISSORTMASK(n)) {
+ *cp++ = n;
+ net = cp;
+ while (*cp && *cp != ';' &&
+ isascii(*cp) && !isspace(*cp))
+ cp++;
+ n = *cp;
+ *cp = 0;
+ if (inetaton(net, &a)) {
+ ircd_res.sort_list[nsort].mask = a.s_addr;
+ } else {
+ ircd_res.sort_list[nsort].mask =
+ ircd_net_mask(ircd_res.sort_list[nsort].addr);
+ }
+ } else {
+ ircd_res.sort_list[nsort].mask =
+ ircd_net_mask(ircd_res.sort_list[nsort].addr);
+ }
+ nsort++;
+ }
+ *cp = n;
+ }
+ continue;
+ }
+#endif
+ if (MATCH(buf, "options")) {
+ ircd_res_setoptions(buf + sizeof("options") - 1, "conf");
+ continue;
+ }
+ }
+ if (nserv > 1)
+ ircd_res.nscount = nserv;
+#ifdef RESOLVSORT
+ ircd_res.nsort = nsort;
+#endif
+ (void) fclose(fp);
+ }
+ if (ircd_res.defdname[0] == 0 &&
+ gethostname(buf, sizeof(ircd_res.defdname) - 1) == 0 &&
+ (cp = strchr(buf, '.')) != NULL)
+ strcpy(ircd_res.defdname, cp + 1);
+
+ /* find components of local domain that might be searched */
+ if (havesearch == 0) {
+ pp = ircd_res.dnsrch;
+ *pp++ = ircd_res.defdname;
+ *pp = NULL;
+
+#ifndef RFC1535
+ dots = 0;
+ for (cp = ircd_res.defdname; *cp; cp++)
+ dots += (*cp == '.');
+
+ cp = ircd_res.defdname;
+ while (pp < ircd_res.dnsrch + MAXDFLSRCH) {
+ if (dots < LOCALDOMAINPARTS)
+ break;
+ cp = strchr(cp, '.') + 1; /* we know there is one */
+ *pp++ = cp;
+ dots--;
+ }
+ *pp = NULL;
+#ifdef DEBUG
+ if (ircd_res.options & RES_DEBUG) {
+ printf(";; res_init()... default dnsrch list:\n");
+ for (pp = ircd_res.dnsrch; *pp; pp++)
+ printf(";;\t%s\n", *pp);
+ printf(";;\t..END..\n");
+ }
+#endif /* DEBUG */
+#endif /* !RFC1535 */
+ }
+
+ if ((cp = getenv("RES_OPTIONS")) != NULL)
+ ircd_res_setoptions(cp, "env");
+ ircd_res.options |= RES_INIT;
+ return (0);
+}
+
+static void
+ircd_res_setoptions(options, source)
+ char *options, *source;
+{
+ char *cp = options;
+ int i;
+
+#ifdef DEBUG
+ if (ircd_res.options & RES_DEBUG)
+ printf(";; ircd_res_setoptions(\"%s\", \"%s\")...\n",
+ options, source);
+#endif
+ while (*cp) {
+ /* skip leading and inner runs of spaces */
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ /* search for and process individual options */
+ if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) {
+ i = atoi(cp + sizeof("ndots:") - 1);
+ if (i <= RES_MAXNDOTS)
+ ircd_res.ndots = i;
+ else
+ ircd_res.ndots = RES_MAXNDOTS;
+#ifdef DEBUG
+ if (ircd_res.options & RES_DEBUG)
+ printf(";;\tndots=%d\n", ircd_res.ndots);
+#endif
+ } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) {
+#ifdef DEBUG
+ if (!(ircd_res.options & RES_DEBUG)) {
+ printf(";; ircd_res_setoptions(\"%s\", \"%s\")..\n",
+ options, source);
+ ircd_res.options |= RES_DEBUG;
+ }
+ printf(";;\tdebug\n");
+#endif
+ } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) {
+ ircd_res.options |= RES_USE_INET6;
+ } else {
+ /* XXX - print a warning here? */
+ }
+ /* skip to next run of spaces */
+ while (*cp && *cp != ' ' && *cp != '\t')
+ cp++;
+ }
+}
+
+#ifdef RESOLVSORT
+/* XXX - should really support CIDR which means explicit masks always. */
+static u_int32_t
+ircd_net_mask(in) /* XXX - should really use system's version of this */
+ struct in_addr in;
+{
+ register u_int32_t i = ntohl(in.s_addr);
+
+ if (IN_CLASSA(i))
+ return (htonl(IN_CLASSA_NET));
+ else if (IN_CLASSB(i))
+ return (htonl(IN_CLASSB_NET));
+ return (htonl(IN_CLASSC_NET));
+}
+#endif
+
+#ifdef NEXT
+static int
+ircd_netinfo_res_init(haveenv, havesearch)
+ int *haveenv;
+ int *havesearch;
+{
+ register int n;
+ void *domain, *parent;
+ ni_id dir;
+ ni_status status;
+ ni_namelist nl;
+ int nserv = 0;
+#ifdef RESOLVSORT
+ int nsort = 0;
+#endif
+
+ status = ni_open(NULL, ".", &domain);
+ if (status == NI_OK) {
+ ni_setreadtimeout(domain, NI_TIMEOUT);
+ ni_setabort(domain, 1);
+
+ /* climb the NetInfo hierarchy to find a resolver directory */
+ while (status == NI_OK) {
+ status = ni_pathsearch(domain, &dir, NI_PATH_RESCONF);
+ if (status == NI_OK) {
+ /* found a resolver directory */
+
+ if (*haveenv == 0) {
+ /* get the default domain name */
+ status = ni_lookupprop(domain, &dir, "domain", &nl);
+ if (status == NI_OK && nl.ni_namelist_len > 0) {
+ (void)strncpy(ircd_res.defdname,
+ nl.ni_namelist_val[0],
+ sizeof(ircd_res.defdname) - 1);
+ ircd_res.defdname[sizeof(ircd_res.defdname) - 1] = '\0';
+ ni_namelist_free(&nl);
+ *havesearch = 0;
+ }
+
+ /* get search list */
+ status = ni_lookupprop(domain, &dir, "search", &nl);
+ if (status == NI_OK && nl.ni_namelist_len > 0) {
+ (void)strncpy(ircd_res.defdname,
+ nl.ni_namelist_val[0],
+ sizeof(ircd_res.defdname) - 1);
+ ircd_res.defdname[sizeof(ircd_res.defdname) - 1] = '\0';
+ /* copy */
+ for (n = 0;
+ n < nl.ni_namelist_len && n < MAXDNSRCH;
+ n++) {
+ /* duplicate up to MAXDNSRCH servers */
+ char *cp = nl.ni_namelist_val[n];
+ ircd_res.dnsrch[n] =
+ strcpy((char *)malloc(strlen(cp) + 1), cp);
+ }
+ ni_namelist_free(&nl);
+ *havesearch = 1;
+ }
+ }
+
+ /* get list of nameservers */
+ status = ni_lookupprop(domain, &dir, "nameserver", &nl);
+ if (status == NI_OK && nl.ni_namelist_len > 0) {
+ /* copy up to MAXNS servers */
+ for (n = 0;
+ n < nl.ni_namelist_len && nserv < MAXNS;
+ n++) {
+ struct in_addr a;
+
+ if (inetaton(nl.ni_namelist_val[n], &a)) {
+ ircd_res.nsaddr_list[nserv].sin_addr = a;
+ ircd_res.nsaddr_list[nserv].sin_family = AF_INET;
+ ircd_res.nsaddr_list[nserv].sin_port =
+ htons(NAMESERVER_PORT);
+ nserv++;
+ }
+ }
+ ni_namelist_free(&nl);
+ }
+
+ if (nserv > 1)
+ ircd_res.nscount = nserv;
+
+#ifdef RESOLVSORT
+ /* get sort order */
+ status = ni_lookupprop(domain, &dir, "sortlist", &nl);
+ if (status == NI_OK && nl.ni_namelist_len > 0) {
+
+ /* copy up to MAXRESOLVSORT address/netmask pairs */
+ for (n = 0;
+ n < nl.ni_namelist_len && nsort < MAXRESOLVSORT;
+ n++) {
+ char ch;
+ char *cp;
+ const char *sp;
+ struct in_addr a;
+
+ cp = NULL;
+ for (sp = sort_mask; *sp; sp++) {
+ char *cp1;
+ cp1 = strchr(nl.ni_namelist_val[n], *sp);
+ if (cp && cp1)
+ cp = (cp < cp1)? cp : cp1;
+ else if (cp1)
+ cp = cp1;
+ }
+ if (cp != NULL) {
+ ch = *cp;
+ *cp = '\0';
+ break;
+ }
+ if (inetaton(nl.ni_namelist_val[n], &a)) {
+ ircd_res.sort_list[nsort].addr = a;
+ if (*cp && ISSORTMASK(ch)) {
+ *cp++ = ch;
+ if (inetaton(cp, &a)) {
+ ircd_res.sort_list[nsort].mask = a.s_addr;
+ } else {
+ ircd_res.sort_list[nsort].mask =
+ ircd_net_mask(ircd_res.sort_list[nsort].addr);
+ }
+ } else {
+ ircd_res.sort_list[nsort].mask =
+ ircd_net_mask(ircd_res.sort_list[nsort].addr);
+ }
+ nsort++;
+ }
+ }
+ ni_namelist_free(&nl);
+ }
+
+ ircd_res.nsort = nsort;
+#endif
+
+ /* get resolver options */
+ status = ni_lookupprop(domain, &dir, "options", &nl);
+ if (status == NI_OK && nl.ni_namelist_len > 0) {
+ ircd_res_setoptions(nl.ni_namelist_val[0], "conf");
+ ni_namelist_free(&nl);
+ }
+
+ ni_free(domain);
+ return(1); /* using DNS configuration from NetInfo */
+ }
+
+ status = ni_open(domain, "..", &parent);
+ ni_free(domain);
+ if (status == NI_OK)
+ domain = parent;
+ }
+ }
+ return(0); /* if not using DNS configuration from NetInfo */
+}
+#endif /* NEXT */
+
+u_int
+ircd_res_randomid()
+{
+ struct timeval now;
+
+ gettimeofday(&now, NULL);
+ return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid()));
+}
diff --git a/ircd/res_init_ext.h b/ircd/res_init_ext.h
new file mode 100644
index 0000000..8537269
--- /dev/null
+++ b/ircd/res_init_ext.h
@@ -0,0 +1,39 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/res_init_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in ircd/res_init.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef RES_INIT_C
+extern struct __res_state ircd_res;
+#endif /* RES_INIT_C */
+
+/* External definitions for global functions.
+ */
+#ifndef RES_INIT_C
+#define EXTERN extern
+#else /* RES_INIT_C */
+#define EXTERN
+#endif /* RES_INIT_C */
+EXTERN int ircd_res_init();
+EXTERN u_int ircd_res_randomid();
+#undef EXTERN
diff --git a/ircd/res_mkquery.c b/ircd/res_mkquery.c
new file mode 100644
index 0000000..a0fb2fc
--- /dev/null
+++ b/ircd/res_mkquery.c
@@ -0,0 +1,178 @@
+/*
+ * ++Copyright++ 1985, 1993
+ * -
+ * Copyright (c) 1985, 1993
+ * The 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)res_mkquery.c 8.1 (Berkeley) 6/4/93";
+static char rcsid[] = "$Id: res_mkquery.c,v 1.4 1997/09/03 17:45:55 kalt Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "os.h"
+#include "s_defines.h"
+#define RES_MKQUERY_C
+#include "s_externs.h"
+#undef RES_MKQUERY_C
+
+/*
+ * Form all types of queries.
+ * Returns the size of the result or -1.
+ */
+int
+ircd_res_mkquery(op, dname, class, type, data, datalen, newrr_in, buf, buflen)
+ int op; /* opcode of query */
+ const char *dname; /* domain name */
+ int class, type; /* class and type of query */
+ const u_char *data; /* resource record data */
+ int datalen; /* length of data */
+ const u_char *newrr_in; /* new rr for modify or append */
+ u_char *buf; /* buffer to put query */
+ int buflen; /* size of buffer */
+{
+ register HEADER *hp;
+ register u_char *cp;
+ register int n;
+ u_char *dnptrs[20], **dpp, **lastdnptr;
+
+ if ((ircd_res.options & RES_INIT) == 0 && ircd_res_init() == -1) {
+ h_errno = NETDB_INTERNAL;
+ return (-1);
+ }
+#ifdef DEBUG
+ if (ircd_res.options & RES_DEBUG)
+ printf(";; res_mkquery(%d, %s, %d, %d)\n",
+ op, dname, class, type);
+#endif
+ /*
+ * Initialize header fields.
+ */
+ if ((buf == NULL) || (buflen < HFIXEDSZ))
+ return (-1);
+ bzero(buf, HFIXEDSZ);
+ hp = (HEADER *) buf;
+ hp->id = htons(++ircd_res.id);
+ hp->opcode = op;
+ hp->rd = (ircd_res.options & RES_RECURSE) != 0;
+ hp->rcode = NOERROR;
+ cp = buf + HFIXEDSZ;
+ buflen -= HFIXEDSZ;
+ dpp = dnptrs;
+ *dpp++ = buf;
+ *dpp++ = NULL;
+ lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
+ /*
+ * perform opcode specific processing
+ */
+ switch (op) {
+ case QUERY: /*FALLTHROUGH*/
+ case NS_NOTIFY_OP:
+ if ((buflen -= QFIXEDSZ) < 0)
+ return (-1);
+ if ((n = ircd_dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
+ return (-1);
+ cp += n;
+ buflen -= n;
+ ircd__putshort(type, cp);
+ cp += INT16SZ;
+ ircd__putshort(class, cp);
+ cp += INT16SZ;
+ hp->qdcount = htons(1);
+ if (op == QUERY || data == NULL)
+ break;
+ /*
+ * Make an additional record for completion domain.
+ */
+ buflen -= RRFIXEDSZ;
+ n = ircd_dn_comp((char *)data, cp, buflen, dnptrs, lastdnptr);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ buflen -= n;
+ ircd__putshort(T_NULL, cp);
+ cp += INT16SZ;
+ ircd__putshort(class, cp);
+ cp += INT16SZ;
+ ircd__putlong(0, cp);
+ cp += INT32SZ;
+ ircd__putshort(0, cp);
+ cp += INT16SZ;
+ hp->arcount = htons(1);
+ break;
+
+ case IQUERY:
+ /*
+ * Initialize answer section
+ */
+ if (buflen < 1 + RRFIXEDSZ + datalen)
+ return (-1);
+ *cp++ = '\0'; /* no domain name */
+ ircd__putshort(type, cp);
+ cp += INT16SZ;
+ ircd__putshort(class, cp);
+ cp += INT16SZ;
+ ircd__putlong(0, cp);
+ cp += INT32SZ;
+ ircd__putshort(datalen, cp);
+ cp += INT16SZ;
+ if (datalen) {
+ bcopy(data, cp, datalen);
+ cp += datalen;
+ }
+ hp->ancount = htons(1);
+ break;
+
+ default:
+ return (-1);
+ }
+ return (cp - buf);
+}
diff --git a/ircd/res_mkquery_ext.h b/ircd/res_mkquery_ext.h
new file mode 100644
index 0000000..7441ead
--- /dev/null
+++ b/ircd/res_mkquery_ext.h
@@ -0,0 +1,35 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/res_mkquery_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in ircd/res_mkquery.c.
+ */
+
+/* External definitions for global functions.
+ */
+#ifndef RES_MKQUERY_C
+#define EXTERN extern
+#else /* RES_MKQUERY_C */
+#define EXTERN
+#endif /* RES_MKQUERY_C */
+EXTERN int ircd_res_mkquery __P((int op, const char *dname, int class,
+ int type, const u_char *data, int datalen,
+ const u_char *newrr_in, u_char *buf,
+ int buflen));
+#undef EXTERN
diff --git a/ircd/resolv_def.h b/ircd/resolv_def.h
new file mode 100644
index 0000000..3cc74eb
--- /dev/null
+++ b/ircd/resolv_def.h
@@ -0,0 +1,220 @@
+/*
+ * ++Copyright++ 1983, 1987, 1989, 1993
+ * -
+ * Copyright (c) 1983, 1987, 1989, 1993
+ * The 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+/*
+ * @(#)resolv.h 8.1 (Berkeley) 6/2/93
+ * $Id: resolv_def.h,v 1.5 1999/01/20 01:33:08 kalt Exp $
+ */
+
+/*
+ * Revision information. This is the release date in YYYYMMDD format.
+ * It can change every day so the right thing to do with it is use it
+ * in preprocessor commands such as "#if (__RES > 19931104)". Do not
+ * compare for equality; rather, use it to determine whether your resolver
+ * is new enough to contain a certain feature.
+ */
+
+#define __RES 19960801
+
+/*
+ * 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 RES_TIMEOUT 5 /* min. seconds between retries */
+#define MAXRESOLVSORT 10 /* number of net to sort on */
+#define RES_MAXNDOTS 15 /* should reflect bit field size */
+
+struct __res_state {
+ int retrans; /* retransmition time interval */
+ int retry; /* number of times to retransmit */
+ u_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 */
+ u_short id; /* current message id */
+ char *dnsrch[MAXDNSRCH+1]; /* components of domain to search */
+ char defdname[256]; /* default domain (deprecated) */
+ u_long pfcode; /* RES_PRF_ flags - see below. */
+ unsigned ndots:4; /* threshold for initial abs. query */
+ unsigned nsort:4; /* number of elements in sort_list[] */
+ char unused[3];
+ struct {
+ struct in_addr addr;
+ u_int32_t mask;
+ } sort_list[MAXRESOLVSORT];
+ char pad[72]; /* on an i386 this means 512b total */
+};
+
+/*
+ * Resolver options (keep these in synch with res_debug.c, please)
+ */
+#define RES_INIT 0x00000001 /* address initialized */
+#define RES_DEBUG 0x00000002 /* print debug messages */
+#define RES_AAONLY 0x00000004 /* authoritative answers only (!IMPL)*/
+#define RES_USEVC 0x00000008 /* use virtual circuit */
+#define RES_PRIMARY 0x00000010 /* query primary server only (!IMPL) */
+#define RES_IGNTC 0x00000020 /* ignore trucation errors */
+#define RES_RECURSE 0x00000040 /* recursion desired */
+#define RES_DEFNAMES 0x00000080 /* use default domain name */
+#define RES_STAYOPEN 0x00000100 /* Keep TCP socket open */
+#define RES_DNSRCH 0x00000200 /* search up local domain tree */
+#define RES_INSECURE1 0x00000400 /* type 1 security disabled */
+#define RES_INSECURE2 0x00000800 /* type 2 security disabled */
+#define RES_NOALIASES 0x00001000 /* shuts off HOSTALIASES feature */
+#define RES_USE_INET6 0x00002000 /* use/map IPv6 in gethostbyname() */
+
+#define RES_DEFAULT (RES_RECURSE | RES_DEFNAMES | RES_DNSRCH)
+
+/*
+ * Resolver "pfcode" values. Used by dig.
+ */
+#define RES_PRF_STATS 0x00000001
+/* 0x00000002 */
+#define RES_PRF_CLASS 0x00000004
+#define RES_PRF_CMD 0x00000008
+#define RES_PRF_QUES 0x00000010
+#define RES_PRF_ANS 0x00000020
+#define RES_PRF_AUTH 0x00000040
+#define RES_PRF_ADD 0x00000080
+#define RES_PRF_HEAD1 0x00000100
+#define RES_PRF_HEAD2 0x00000200
+#define RES_PRF_TTLID 0x00000400
+#define RES_PRF_HEADX 0x00000800
+#define RES_PRF_QUERY 0x00001000
+#define RES_PRF_REPLY 0x00002000
+#define RES_PRF_INIT 0x00004000
+/* 0x00008000 */
+
+/* hooks are still experimental as of 4.9.2 */
+#if defined(INET6) && defined(__GNUC__)
+
+#else
+
+typedef enum { res_goahead, res_nextns, res_modified, res_done, res_error }
+ res_sendhookact;
+
+typedef res_sendhookact (*res_send_qhook)__P((struct SOCKADDR_IN * const *ns,
+ const u_char **query,
+ int *querylen,
+ u_char *ans,
+ int anssiz,
+ int *resplen));
+
+typedef res_sendhookact (*res_send_rhook)__P((const struct SOCKADDR_IN *ns,
+ const u_char *query,
+ int querylen,
+ u_char *ans,
+ int anssiz,
+ int *resplen));
+#endif
+
+struct res_sym {
+ int number; /* Identifying number, like T_MX */
+ char * name; /* Its symbolic name, like "MX" */
+ char * humanname; /* Its fun name, like "mail exchanger" */
+};
+
+/* Private routines shared between libc/net, named, nslookup and others. */
+#define res_hnok __res_hnok
+#define res_ownok __res_ownok
+#define res_mailok __res_mailok
+#define res_dnok __res_dnok
+#define sym_ston __sym_ston
+#define sym_ntos __sym_ntos
+#define sym_ntop __sym_ntop
+#define b64_ntop __b64_ntop
+#define b64_pton __b64_pton
+#define loc_ntoa __loc_ntoa
+#define loc_aton __loc_aton
+#define dn_skipname __dn_skipname
+#define fp_resstat __fp_resstat
+#define fp_query __fp_query
+#define fp_nquery __fp_nquery
+#define hostalias __hostalias
+#define putlong __putlong
+#define putshort __putshort
+#define p_class __p_class
+#define p_time __p_time
+#define p_type __p_type
+#define p_query __p_query
+#define p_cdnname __p_cdnname
+#define p_cdname __p_cdname
+#define p_fqnname __p_fqnname
+#define p_fqname __p_fqname
+#define p_rr __p_rr
+#define p_option __p_option
+#define p_secstodate __p_secstodate
+#define dn_count_labels __dn_count_labels
+#define dn_comp __dn_comp
+#define res_randomid __res_randomid
+#define res_isourserver __res_isourserver
+#define res_nameinquery __res_nameinquery
+#define res_queriesmatch __res_queriesmatch
+#define res_close __res_close
+
+#ifdef BIND_RES_POSIX3
+#define dn_expand __dn_expand
+#define res_init __res_init
+#define res_query __res_query
+#define res_search __res_search
+#define res_querydomain __res_querydomain
+#define res_mkquery __res_mkquery
+#define res_send __res_send
+#endif
diff --git a/ircd/s_auth.c b/ircd/s_auth.c
new file mode 100644
index 0000000..89d19ed
--- /dev/null
+++ b/ircd/s_auth.c
@@ -0,0 +1,804 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/s_auth.c
+ * Copyright (C) 1992 Darren Reed
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: s_auth.c,v 1.43 1999/07/02 16:38:21 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "s_defines.h"
+#define S_AUTH_C
+#include "s_externs.h"
+#undef S_AUTH_C
+
+/*
+ * set_clean_username
+ *
+ * As non OTHER type of usernames retrieved via ident lookup are forced as
+ * usernames for the user, one has to be careful not to allow potentially
+ * damaging characters in the username.
+ * This procedure fills up cptr->username based on cptr->auth
+ * Characters disallowed:
+ * leading : for obvious reasons
+ * spaces for obvious reasons
+ * @ because of how get_sockhost() is implemented,
+ * and because it's used from attached_Iline()
+ * [ /trace parsing is impossible
+ */
+static void
+set_clean_username(cptr)
+aClient *cptr;
+{
+ int i = 0, dirty = 0;
+ char *s;
+
+ if (cptr->auth == NULL)
+ return;
+ s = cptr->auth;
+ if (index(cptr->auth, '[') || index(cptr->auth, '@') ||
+ strlen(cptr->auth) > USERLEN)
+ dirty = 1;
+ else if (cptr->auth[0] == ':')
+ {
+ dirty = 1;
+ s += 1;
+ }
+ else
+ {
+ char *r = cptr->auth;
+
+ while (*r)
+ if (isspace(*(r++)))
+ break;
+ if (*r)
+ dirty = 1;
+ }
+ if (dirty)
+ cptr->username[i++] = '-';
+ while (i < USERLEN && *s)
+ {
+ if (*s != '@' && *s != '[' && !isspace(*s))
+ cptr->username[i++] = *s;
+ s += 1;
+ }
+ cptr->username[i] = '\0';
+ if (!strcmp(cptr->username, cptr->auth))
+ {
+ MyFree(cptr->auth);
+ cptr->auth = cptr->username;
+ }
+ else
+ {
+ istat.is_authmem += sizeof(cptr->auth);
+ istat.is_auth += 1;
+ }
+}
+
+#if defined(USE_IAUTH)
+
+u_char iauth_options = 0;
+u_int iauth_spawn = 0;
+char *iauth_version = NULL;
+
+static aExtCf *iauth_conf = NULL;
+static aExtData *iauth_stats = NULL;
+
+/*
+ * sendto_iauth
+ *
+ * Send the buffer to the authentication slave process.
+ * Return 0 if everything went well, -1 otherwise.
+ */
+#if ! USE_STDARG
+int
+sendto_iauth(pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)
+char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10;
+#else
+int
+vsendto_iauth(char *pattern, va_list va)
+#endif
+{
+ static char abuf[BUFSIZ];
+
+#if ! USE_STDARG
+ sprintf(abuf, pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
+#else
+ vsprintf(abuf, pattern, va);
+#endif
+ strcat(abuf, "\n");
+
+ if (adfd < 0)
+ return -1;
+ if (write(adfd, abuf, strlen(abuf)) != strlen(abuf))
+ {
+ sendto_flag(SCH_AUTH, "Aiiie! lost slave authentication process");
+ close(adfd);
+ adfd = -1;
+ start_iauth(0);
+ return -1;
+ }
+ return 0;
+}
+
+# if USE_STDARG
+int
+sendto_iauth(char *pattern, ...)
+{
+ int i;
+
+ va_list va;
+ va_start(va, pattern);
+ i = vsendto_iauth(pattern, va);
+ va_end(va);
+ return i;
+}
+# endif
+
+/*
+ * read_iauth
+ *
+ * read and process data from the authentication slave process.
+ */
+void
+read_iauth()
+{
+ static char obuf[READBUF_SIZE+1], last = '?';
+ static int olen = 0, ia_dbg = 0;
+ char buf[READBUF_SIZE+1], *start, *end, tbuf[BUFSIZ];
+ aClient *cptr;
+ int i;
+
+ if (adfd == -1)
+ {
+ olen = 0;
+ return;
+ }
+ while (1)
+ {
+ if (olen)
+ bcopy(obuf, buf, olen);
+ if ((i = recv(adfd, buf+olen, READBUF_SIZE-olen, 0)) <= 0)
+ {
+ if (errno != EAGAIN && errno != EWOULDBLOCK)
+ {
+ sendto_flag(SCH_AUTH, "Aiiie! lost slave authentication process (errno = %d)", errno);
+ close(adfd);
+ adfd = -1;
+ start_iauth(0);
+ }
+ break;
+ }
+ olen += i;
+ buf[olen] = '\0';
+ start = buf;
+ while (end = index(start, '\n'))
+ {
+ *end++ = '\0';
+ last = *start;
+ if (*start == '>')
+ {
+ sendto_flag(SCH_AUTH, "%s", start+1);
+ start = end;
+ continue;
+ }
+ if (*start == 'G')
+ {
+ ia_dbg = atoi(start+2);
+ if (ia_dbg)
+ sendto_flag(SCH_AUTH,"ia_dbg = %d",ia_dbg);
+ start = end;
+ continue;
+ }
+ if (*start == 'O') /* options */
+ {
+ iauth_options = 0;
+ if (strchr(start+2, 'A'))
+ iauth_options |= XOPT_EARLYPARSE;
+ if (strchr(start+2, 'R'))
+ iauth_options |= XOPT_REQUIRED;
+ if (strchr(start+2, 'T'))
+ iauth_options |= XOPT_NOTIMEOUT;
+ if (strchr(start+2, 'W'))
+ iauth_options |= XOPT_EXTWAIT;
+ if (iauth_options)
+ sendto_flag(SCH_AUTH, "iauth options: %x",
+ iauth_options);
+ start = end;
+ continue;
+ }
+ if (*start == 'V') /* version */
+ {
+ if (iauth_version)
+ MyFree(iauth_version);
+ iauth_version = mystrdup(start+2);
+ sendto_flag(SCH_AUTH, "iauth version %s running.",
+ iauth_version);
+ start = end;
+ continue;
+ }
+ if (*start == 'a')
+ {
+ aExtCf *ectmp;
+
+ while (ectmp = iauth_conf)
+ {
+ iauth_conf = iauth_conf->next;
+ MyFree(ectmp->line);
+ MyFree(ectmp);
+ }
+ /* little lie.. ;) */
+ sendto_flag(SCH_AUTH, "New iauth configuration.");
+ start = end;
+ continue;
+ }
+ if (*start == 'A')
+ {
+ aExtCf **ectmp = &iauth_conf;
+
+ while (*ectmp)
+ ectmp = &((*ectmp)->next);
+ *ectmp = (aExtCf *) MyMalloc(sizeof(aExtCf));
+ (*ectmp)->line = mystrdup(start+2);
+ (*ectmp)->next = NULL;
+ start = end;
+ continue;
+ }
+ if (*start == 's')
+ {
+ aExtData *ectmp;
+
+ while (ectmp = iauth_stats)
+ {
+ iauth_stats = iauth_stats->next;
+ MyFree(ectmp->line);
+ MyFree(ectmp);
+ }
+ iauth_stats = (aExtData *)
+ MyMalloc(sizeof(aExtData));
+ iauth_stats->line = MyMalloc(60);
+ sprintf(iauth_stats->line,
+ "iauth modules statistics (%s)",
+ myctime(timeofday));
+ iauth_stats->next = (aExtData *)
+ MyMalloc(sizeof(aExtData));
+ iauth_stats->next->line = MyMalloc(60);
+ sprintf(iauth_stats->next->line,
+ "spawned: %d, current options: %X (%.11s)",
+ iauth_spawn, iauth_options,
+ (iauth_version) ? iauth_version : "???");
+ iauth_stats->next->next = NULL;
+ start = end;
+ continue;
+ }
+ if (*start == 'S')
+ {
+ aExtData **ectmp = &iauth_stats;
+
+ while (*ectmp)
+ ectmp = &((*ectmp)->next);
+ *ectmp = (aExtData *) MyMalloc(sizeof(aExtData));
+ (*ectmp)->line = mystrdup(start+2);
+ (*ectmp)->next = NULL;
+ start = end;
+ continue;
+ }
+ if (*start != 'U' && *start != 'u' && *start != 'o' &&
+ *start != 'K' && *start != 'k' &&
+ *start != 'D')
+ {
+ sendto_flag(SCH_AUTH, "Garbage from iauth [%s]",
+ start);
+ sendto_iauth("-1 E Garbage [%s]", start);
+ /*
+ ** The above should never happen, but i've seen it
+ ** occasionnally, so let's try to get more info
+ ** about it! -kalt
+ */
+ sendto_flag(SCH_AUTH,
+ "last=%u start=%x end=%x buf=%x olen=%d i=%d",
+ last, start, end, buf, olen, i);
+ sendto_iauth(
+ "-1 E last=%u start=%x end=%x buf=%x olen=%d i=%d",
+ last, start, end, buf, olen, i);
+ start = end;
+ continue;
+ }
+ if ((cptr = local[i = atoi(start+2)]) == NULL)
+ {
+ /* this is fairly common and can be ignored */
+ if (ia_dbg)
+ {
+ sendto_flag(SCH_AUTH, "Client %d is gone.",
+ i);
+ sendto_iauth("%d E Gone [%s]", i, start);
+ }
+ start = end;
+ continue;
+ }
+ sprintf(tbuf, "%c %d %s %u ", start[0], i,
+ inetntoa((char *)&cptr->ip), cptr->port);
+ if (strncmp(tbuf, start, strlen(tbuf)))
+ {
+ /* this is fairly common and can be ignored */
+ if (ia_dbg)
+ {
+ sendto_flag(SCH_AUTH,
+ "Client mismatch: %d [%s] != [%s]",
+ i, start, tbuf);
+ sendto_iauth("%d E Mismatch [%s] != [%s]",
+ i, start, tbuf);
+ }
+ start = end;
+ continue;
+ }
+ if (start[0] == 'U')
+ {
+ if (*(start+strlen(tbuf)) == '\0')
+ {
+ sendto_flag(SCH_AUTH,
+ "Null U message! %d [%s]",
+ i, start);
+ sendto_iauth("%d E Null U [%s]", i, start);
+ start = end;
+ continue;
+ }
+ if (cptr->auth != cptr->username)
+ {
+ istat.is_authmem -= sizeof(cptr->auth);
+ istat.is_auth -= 1;
+ MyFree(cptr->auth);
+ }
+ cptr->auth = mystrdup(start+strlen(tbuf));
+ set_clean_username(cptr);
+ cptr->flags |= FLAGS_GOTID;
+ }
+ else if (start[0] == 'u')
+ {
+ if (*(start+strlen(tbuf)) == '\0')
+ {
+ sendto_flag(SCH_AUTH,
+ "Null u message! %d [%s]",
+ i, start);
+ sendto_iauth("%d E Null u [%s]", i, start);
+ start = end;
+ continue;
+ }
+ if (cptr->auth != cptr->username)
+ {
+ istat.is_authmem -= sizeof(cptr->auth);
+ istat.is_auth -= 1;
+ MyFree(cptr->auth);
+ }
+ cptr->auth = MyMalloc(strlen(start+strlen(tbuf))
+ + 2);
+ *cptr->auth = '-';
+ strcpy(cptr->auth+1, start+strlen(tbuf));
+ set_clean_username(cptr);
+ cptr->flags |= FLAGS_GOTID;
+ }
+ else if (start[0] == 'o')
+ {
+ if (!WaitingXAuth(cptr))
+ {
+ sendto_flag(SCH_AUTH,
+ "Early o message discarded!");
+ sendto_iauth("%d E Early o [%s]", i,start);
+ start = end;
+ continue;
+ }
+ if (cptr->user == NULL)
+ {
+ /* just to be safe */
+ sendto_flag(SCH_AUTH,
+ "Ack! cptr->user is NULL");
+ start = end;
+ continue;
+ }
+ strncpyzt(cptr->user->username, tbuf, USERLEN+1);
+ }
+ else if (start[0] == 'D')
+ {
+ /*authentication finished*/
+ ClearXAuth(cptr);
+ SetDoneXAuth(cptr);
+ if (WaitingXAuth(cptr))
+ {
+ ClearWXAuth(cptr);
+ register_user(cptr, cptr, cptr->name,
+ cptr->user->username);
+ }
+ else
+ ClearWXAuth(cptr);
+ }
+ else
+ {
+ /*
+ ** mark for kill, because it cannot be killed
+ ** yet: we don't even know if this is a server
+ ** or a user connection!
+ */
+ if (start[0] == 'K')
+ cptr->exitc = EXITC_AREF;
+ else
+ cptr->exitc = EXITC_AREFQ;
+ /* should also check to make sure it's still
+ an unregistered client.. */
+ /* should be extended to work after registration */
+ }
+ start = end;
+ }
+ if (start != buf+olen)
+ bcopy(start, obuf, olen = (buf+olen)-start+1);
+ else
+ olen = 0;
+ }
+}
+
+/*
+ * report_iauth_conf
+ *
+ * called from m_stats(), this is the reply to /stats a
+ */
+void
+report_iauth_conf(sptr, to)
+aClient *sptr;
+char *to;
+{
+ aExtCf *ectmp = iauth_conf;
+
+ if (adfd < 0)
+ return;
+ while (ectmp)
+ {
+ sendto_one(sptr, ":%s %d %s :%s",
+ ME, RPL_STATSIAUTH, to, ectmp->line);
+ ectmp = ectmp->next;
+ }
+}
+
+/*
+ * report_iauth_stats
+ *
+ * called from m_stats(), this is part of the reply to /stats t
+ */
+void
+report_iauth_stats(sptr, to)
+aClient *sptr;
+char *to;
+{
+ aExtData *ectmp = iauth_stats;
+
+ while (ectmp)
+ {
+ sendto_one(sptr, ":%s %d %s :%s",
+ ME, RPL_STATSDEBUG, to, ectmp->line);
+ ectmp = ectmp->next;
+ }
+}
+#endif
+
+/*
+ * start_auth
+ *
+ * Flag the client to show that an attempt to contact the ident server on
+ * the client's host. The connect and subsequently the socket are all put
+ * into 'non-blocking' mode. Should the connect or any later phase of the
+ * identifing process fail, it is aborted and the user is given a username
+ * of "unknown".
+ */
+void start_auth(cptr)
+Reg aClient *cptr;
+{
+#ifndef NO_IDENT
+ struct SOCKADDR_IN us, them;
+
+ SOCK_LEN_TYPE ulen, tlen;
+
+# if defined(USE_IAUTH)
+ if ((iauth_options & XOPT_REQUIRED) && adfd < 0)
+ return;
+# endif
+ Debug((DEBUG_NOTICE,"start_auth(%x) fd %d status %d",
+ cptr, cptr->fd, cptr->status));
+ if ((cptr->authfd = socket(AFINET, SOCK_STREAM, 0)) == -1)
+ {
+# ifdef USE_SYSLOG
+ syslog(LOG_ERR, "Unable to create auth socket for %s:%m",
+ get_client_name(cptr,TRUE));
+# endif
+ Debug((DEBUG_ERROR, "Unable to create auth socket for %s:%s",
+ get_client_name(cptr, TRUE),
+ strerror(get_sockerr(cptr))));
+ ircstp->is_abad++;
+ return;
+ }
+ if (cptr->authfd >= (MAXCONNECTIONS - 2))
+ {
+ sendto_flag(SCH_ERROR, "Can't allocate fd for auth on %s",
+ get_client_name(cptr, TRUE));
+ (void)close(cptr->authfd);
+ return;
+ }
+
+ set_non_blocking(cptr->authfd, cptr);
+
+ /* get remote host peer - so that we get right interface -- jrg */
+ tlen = ulen = sizeof(us);
+ if (getpeername(cptr->fd, (struct sockaddr *)&them, &tlen) < 0)
+ {
+ /* we probably don't need this error message -kalt */
+ report_error("getpeername for auth request %s:%s", cptr);
+ close(cptr->authfd);
+ cptr->authfd = -1;
+ return;
+ }
+ them.SIN_FAMILY = AFINET;
+
+ /* We must bind the local end to the interface that they connected
+ to: The local system might have more than one network address,
+ and RFC931 check only sends port numbers: server takes IP addresses
+ from query socket -- jrg */
+ (void)getsockname(cptr->fd, (struct sockaddr *)&us, &ulen);
+ us.SIN_FAMILY = AFINET;
+# if defined(USE_IAUTH)
+ if (adfd >= 0)
+ {
+ char abuf[BUFSIZ];
+# ifdef INET6
+ sprintf(abuf, "%d C %s %u ", cptr->fd,
+ inetntop(AF_INET6, (char *)&them.sin6_addr, mydummy,
+ MYDUMMY_SIZE), ntohs(them.SIN_PORT));
+ sprintf(abuf+strlen(abuf), "%s %u",
+ inetntop(AF_INET6, (char *)&us.sin6_addr, mydummy,
+ MYDUMMY_SIZE), ntohs(us.SIN_PORT));
+# else
+ sprintf(abuf, "%d C %s %u ", cptr->fd,
+ inetntoa((char *)&them.sin_addr),ntohs(them.SIN_PORT));
+ sprintf(abuf+strlen(abuf), "%s %u",
+ inetntoa((char *)&us.sin_addr), ntohs(us.SIN_PORT));
+# endif
+ if (sendto_iauth(abuf) == 0)
+ {
+ close(cptr->authfd);
+ cptr->authfd = -1;
+ cptr->flags |= FLAGS_XAUTH;
+ return;
+ }
+ }
+# endif
+# ifdef INET6
+ Debug((DEBUG_NOTICE,"auth(%x) from %s %x %x",
+ cptr, inet_ntop(AF_INET6, (char *)&us.sin6_addr, mydummy,
+ MYDUMMY_SIZE), us.sin6_addr.s6_addr[14],
+ us.sin6_addr.s6_addr[15]));
+# else
+ Debug((DEBUG_NOTICE,"auth(%x) from %s",
+ cptr, inetntoa((char *)&us.sin_addr)));
+# endif
+ them.SIN_PORT = htons(113);
+ us.SIN_PORT = htons(0); /* bind assigns us a port */
+ if (bind(cptr->authfd, (struct SOCKADDR *)&us, ulen) >= 0)
+ {
+ (void)getsockname(cptr->fd, (struct SOCKADDR *)&us, &ulen);
+# ifdef INET6
+ Debug((DEBUG_NOTICE,"auth(%x) to %s",
+ cptr, inet_ntop(AF_INET6, (char *)&them.sin6_addr,
+ mydummy, MYDUMMY_SIZE)));
+# else
+ Debug((DEBUG_NOTICE,"auth(%x) to %s",
+ cptr, inetntoa((char *)&them.sin_addr)));
+# endif
+ (void)alarm((unsigned)4);
+ if (connect(cptr->authfd, (struct SOCKADDR *)&them,
+ tlen) == -1 && errno != EINPROGRESS)
+ {
+# ifdef INET6
+ Debug((DEBUG_ERROR,
+ "auth(%x) connect failed to %s - %d", cptr,
+ inet_ntop(AF_INET6, (char *)&them.sin6_addr,
+ mydummy, MYDUMMY_SIZE), errno));
+# else
+ Debug((DEBUG_ERROR,
+ "auth(%x) connect failed to %s - %d", cptr,
+ inetntoa((char *)&them.sin_addr), errno));
+# endif
+ ircstp->is_abad++;
+ /*
+ * No error report from this...
+ */
+ (void)alarm((unsigned)0);
+ (void)close(cptr->authfd);
+ cptr->authfd = -1;
+ return;
+ }
+ (void)alarm((unsigned)0);
+ }
+ else
+ {
+ report_error("binding stream socket for auth request %s:%s",
+ cptr);
+# ifdef INET6
+ Debug((DEBUG_ERROR,"auth(%x) bind failed on %s port %d - %d",
+ cptr, inet_ntop(AF_INET6, (char *)&us.sin6_addr,
+ mydummy, MYDUMMY_SIZE),
+ ntohs(us.SIN_PORT), errno));
+# else
+ Debug((DEBUG_ERROR,"auth(%x) bind failed on %s port %d - %d",
+ cptr, inetntoa((char *)&us.sin_addr),
+ ntohs(us.SIN_PORT), errno));
+# endif
+ }
+
+ cptr->flags |= (FLAGS_WRAUTH|FLAGS_AUTH);
+ if (cptr->authfd > highest_fd)
+ highest_fd = cptr->authfd;
+#endif
+ return;
+}
+
+/*
+ * send_authports
+ *
+ * Send the ident server a query giving "theirport , ourport".
+ * The write is only attempted *once* so it is deemed to be a fail if the
+ * entire write doesn't write all the data given. This shouldnt be a
+ * problem since the socket should have a write buffer far greater than
+ * this message to store it in should problems arise. -avalon
+ */
+void send_authports(cptr)
+aClient *cptr;
+{
+ struct SOCKADDR_IN us, them;
+
+ char authbuf[32];
+ SOCK_LEN_TYPE ulen, tlen;
+
+ Debug((DEBUG_NOTICE,"write_authports(%x) fd %d authfd %d stat %d",
+ cptr, cptr->fd, cptr->authfd, cptr->status));
+ tlen = ulen = sizeof(us);
+ if (getsockname(cptr->fd, (struct SOCKADDR *)&us, &ulen) ||
+ getpeername(cptr->fd, (struct SOCKADDR *)&them, &tlen))
+ {
+#ifdef USE_SYSLOG
+ syslog(LOG_ERR, "auth get{sock,peer}name error for %s:%m",
+ get_client_name(cptr, TRUE));
+#endif
+ goto authsenderr;
+ }
+
+ SPRINTF(authbuf, "%u , %u\r\n",
+ (unsigned int)ntohs(them.SIN_PORT),
+ (unsigned int)ntohs(us.SIN_PORT));
+
+#ifdef INET6
+ Debug((DEBUG_SEND, "sending [%s] to auth port %s.113",
+ authbuf, inet_ntop,(AF_INET6, (char *)&them.sin6_addr,
+ mydummy, MYDUMMY_SIZE)));
+#else
+ Debug((DEBUG_SEND, "sending [%s] to auth port %s.113",
+ authbuf, inetntoa((char *)&them.sin_addr)));
+#endif
+ if (write(cptr->authfd, authbuf, strlen(authbuf)) != strlen(authbuf))
+ {
+authsenderr:
+ ircstp->is_abad++;
+ (void)close(cptr->authfd);
+ if (cptr->authfd == highest_fd)
+ while (!local[highest_fd])
+ highest_fd--;
+ cptr->authfd = -1;
+ cptr->flags &= ~(FLAGS_AUTH|FLAGS_WRAUTH);
+ return;
+ }
+ cptr->flags &= ~FLAGS_WRAUTH;
+ return;
+}
+
+/*
+ * read_authports
+ *
+ * read the reply (if any) from the ident server we connected to.
+ * The actual read processijng here is pretty weak - no handling of the reply
+ * if it is fragmented by IP.
+ */
+void read_authports(cptr)
+Reg aClient *cptr;
+{
+ Reg char *s, *t;
+ Reg int len;
+ char ruser[513], system[8];
+ u_short remp = 0, locp = 0;
+
+ *system = *ruser = '\0';
+ Debug((DEBUG_NOTICE,"read_authports(%x) fd %d authfd %d stat %d",
+ cptr, cptr->fd, cptr->authfd, cptr->status));
+ /*
+ * Nasty. Can't allow any other reads from client fd while we're
+ * waiting on the authfd to return a full valid string. Use the
+ * client's input buffer to buffer the authd reply.
+ * Oh. this is needed because an authd reply may come back in more
+ * than 1 read! -avalon
+ */
+ if ((len = read(cptr->authfd, cptr->buffer + cptr->count,
+ sizeof(cptr->buffer) - 1 - cptr->count)) >= 0)
+ {
+ cptr->count += len;
+ cptr->buffer[cptr->count] = '\0';
+ }
+
+ if ((len > 0) && (cptr->count != (sizeof(cptr->buffer) - 1)) &&
+ (sscanf(cptr->buffer, "%hd , %hd : USERID : %*[^:]: %512s",
+ &remp, &locp, ruser) == 3))
+ {
+ s = rindex(cptr->buffer, ':');
+ *s++ = '\0';
+ for (t = (rindex(cptr->buffer, ':') + 1); *t; t++)
+ if (!isspace(*t))
+ break;
+ strncpyzt(system, t, sizeof(system));
+ for (t = ruser; *s && (t < ruser + sizeof(ruser)); s++)
+ if (!isspace(*s) && *s != ':')
+ *t++ = *s;
+ *t = '\0';
+ Debug((DEBUG_INFO,"auth reply ok [%s] [%s]", system, ruser));
+ }
+ else if (len != 0)
+ {
+ if (!index(cptr->buffer, '\n') && !index(cptr->buffer, '\r'))
+ return;
+ Debug((DEBUG_ERROR,"local %d remote %d s %x",
+ locp, remp, ruser));
+ Debug((DEBUG_ERROR,"bad auth reply in [%s]", cptr->buffer));
+ *ruser = '\0';
+ }
+ (void)close(cptr->authfd);
+ if (cptr->authfd == highest_fd)
+ while (!local[highest_fd])
+ highest_fd--;
+ cptr->count = 0;
+ cptr->authfd = -1;
+ ClearAuth(cptr);
+ if (len > 0)
+ Debug((DEBUG_INFO,"ident reply: [%s]", cptr->buffer));
+
+ if (!locp || !remp || !*ruser)
+ {
+ ircstp->is_abad++;
+ return;
+ }
+ ircstp->is_asuc++;
+ if (cptr->auth != cptr->username)/*impossible, but...*/
+ {
+ istat.is_authmem -= sizeof(cptr->auth);
+ istat.is_auth -= 1;
+ MyFree(cptr->auth);
+ }
+ if (!strncmp(system, "OTHER", 5))
+ { /* OTHER type of identifier */
+ cptr->auth = MyMalloc(strlen(ruser) + 2);
+ *cptr->auth = '-';
+ strcpy(cptr->auth+1, ruser);
+ }
+ else
+ cptr->auth = mystrdup(ruser);
+ set_clean_username(cptr);
+ cptr->flags |= FLAGS_GOTID;
+ Debug((DEBUG_INFO, "got username [%s]", ruser));
+ return;
+}
diff --git a/ircd/s_auth_ext.h b/ircd/s_auth_ext.h
new file mode 100644
index 0000000..4a6a3d1
--- /dev/null
+++ b/ircd/s_auth_ext.h
@@ -0,0 +1,52 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/s_auth_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in ircd/s_auth.c.
+ */
+
+/* External definitions for global functions.
+ */
+#ifndef S_AUTH_C
+# if defined(USE_IAUTH)
+extern u_char iauth_options;
+extern u_int iauth_spawn;
+# endif
+#
+# define EXTERN extern
+#else /* S_AUTH_C */
+# define EXTERN
+#endif /* S_AUTH_C */
+
+#if defined(USE_IAUTH)
+# if ! USE_STDARG
+EXTERN int sendto_iauth();
+# else /* USE_STDARG */
+EXTERN int vsendto_iauth (char *pattern, va_list va);
+EXTERN int sendto_iauth (char *pattern, ...);
+# endif
+EXTERN void read_iauth();
+EXTERN void report_iauth_conf __P((aClient *, char *));
+EXTERN void report_iauth_stats __P((aClient *, char *));
+#endif
+EXTERN void start_auth __P((Reg aClient *cptr));
+EXTERN void send_authports __P((aClient *cptr));
+EXTERN void read_authports __P((Reg aClient *cptr));
+
+#undef EXTERN
diff --git a/ircd/s_bsd.c b/ircd/s_bsd.c
new file mode 100644
index 0000000..f10e459
--- /dev/null
+++ b/ircd/s_bsd.c
@@ -0,0 +1,3243 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/s_bsd.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* -- Jto -- 07 Jul 1990
+ * Added jlp@hamblin.byu.edu's debugtty fix
+ */
+
+/* -- Armin -- Jun 18 1990
+ * Added setdtablesize() for more socket connections
+ * (sequent OS Dynix only) -- maybe select()-call must be changed ...
+ */
+
+/* -- Jto -- 13 May 1990
+ * Added several fixes from msa:
+ * Better error messages
+ * Changes in check_access
+ * Added SO_REUSEADDR fix from zessel@informatik.uni-kl.de
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: s_bsd.c,v 1.73 1999/07/23 17:15:14 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "s_defines.h"
+#define S_BSD_C
+#include "s_externs.h"
+#undef S_BSD_C
+
+#ifndef IN_LOOPBACKNET
+#define IN_LOOPBACKNET 0x7f
+#endif
+
+aClient *local[MAXCONNECTIONS];
+FdAry fdas, fdall;
+int highest_fd = 0, readcalls = 0, udpfd = -1, resfd = -1, adfd = -1;
+time_t timeofday;
+static struct SOCKADDR_IN mysk;
+static void polludp();
+
+static struct SOCKADDR *connect_inet __P((aConfItem *, aClient *, int *));
+static int completed_connection __P((aClient *));
+static int check_init __P((aClient *, char *));
+static int check_ping __P((char *, int));
+static void do_dns_async __P(());
+static int set_sock_opts __P((int, aClient *));
+#ifdef UNIXPORT
+static struct SOCKADDR *connect_unix __P((aConfItem *, aClient *, int *));
+static void add_unixconnection __P((aClient *, int));
+static char unixpath[256];
+#endif
+static char readbuf[READBUF_SIZE];
+
+#define CFLAG (CONF_CONNECT_SERVER|CONF_ZCONNECT_SERVER)
+#define NFLAG CONF_NOCONNECT_SERVER
+
+/*
+ * 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 (!(ircd_res.options & RES_INIT))
+ {
+ Debug((DEBUG_DNS,"ircd_res_init()"));
+ ircd_res_init();
+ }
+ if (ircd_res.defdname[0])
+ {
+ (void)strncat(hname, ".", size-1);
+ (void)strncat(hname, ircd_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;
+{
+ Reg int errtmp = errno; /* debug may change 'errno' */
+ Reg char *host;
+ int err;
+ SOCK_LEN_TYPE len = sizeof(err);
+ extern char *strerror();
+
+ 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 (!IsMe(cptr) && cptr->fd >= 0)
+ if (!GETSOCKOPT(cptr->fd, SOL_SOCKET, SO_ERROR, &err, &len))
+ if (err)
+ errtmp = err;
+#endif
+ sendto_flag(SCH_ERROR, 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. If 'ip' has a value, use it as vif to listen.
+ * Connections are accepted to this socket depending on the IP# mask given
+ * by 'ipmask'. Returns the fd of the socket created or -1 on error.
+ */
+int inetport(cptr, ip, ipmask, port)
+aClient *cptr;
+char *ipmask, *ip;
+int port;
+{
+ static struct SOCKADDR_IN server;
+ int ad[4];
+ SOCK_LEN_TYPE len = sizeof(server);
+ char ipname[20];
+
+ 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(ipmask, "%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]);
+
+ (void)sprintf(cptr->sockhost, "%-.42s.%u", ip ? ip : ME,
+ (unsigned int)port);
+ (void)strcpy(cptr->name, ME);
+ DupString(cptr->auth, ipname);
+ /*
+ * At first, open a new socket
+ */
+ if (cptr->fd == -1)
+ cptr->fd = socket(AFINET, SOCK_STREAM, 0);
+ if (cptr->fd < 0)
+ {
+ report_error("opening stream socket %s:%s", cptr);
+ return -1;
+ }
+ else if (cptr->fd >= MAXCLIENTS)
+ {
+ sendto_flag(SCH_ERROR,
+ "No more connections allowed (%s)", cptr->name);
+ (void)close(cptr->fd);
+ return -1;
+ }
+ (void)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 = AFINET;
+#ifdef INET6
+ if (!ip || (!isxdigit(*ip) && *ip != ':'))
+ server.sin6_addr = in6addr_any;
+ else
+ if(!inet_pton(AF_INET6, ip, server.sin6_addr.s6_addr))
+ bcopy(minus_one, server.sin6_addr.s6_addr,
+ IN6ADDRSZ);
+#else
+ if (!ip || !isdigit(*ip))
+ server.sin_addr.s_addr = INADDR_ANY;
+ else
+ server.sin_addr.s_addr = inetaddr(ip);
+#endif
+ server.SIN_PORT = htons(port);
+ /*
+ * Try 10 times to bind the socket with an interval of 20
+ * seconds. Do this so we don't have to keep 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, (SAP)&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, "*"),
+ ntohs(server.SIN_PORT));
+ (void)write(0, buf, strlen(buf));
+ }
+
+ if (cptr->fd > highest_fd)
+ highest_fd = cptr->fd;
+#ifdef INET6
+ bcopy(server.sin6_addr.s6_addr, cptr->ip.s6_addr, IN6ADDRSZ);
+#else
+ cptr->ip.s_addr = server.sin_addr.s_addr; /* broken on linux at least*/
+#endif
+ cptr->port = port;
+ (void)listen(cptr->fd, LISTENQUEUE);
+ 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);
+ cptr->flags = FLAGS_LISTEN;
+ cptr->acpt = cptr;
+ cptr->from = cptr;
+ cptr->firsttime = time(NULL);
+ SetMe(cptr);
+#ifdef UNIXPORT
+ if (*aconf->host == '/')
+ {
+ strncpyzt(cptr->name, aconf->host, sizeof(cptr->name));
+ if (unixport(cptr, aconf->host, aconf->port))
+ cptr->fd = -2;
+ }
+ else
+#endif
+ if (inetport(cptr, aconf->host, aconf->name, aconf->port))
+ cptr->fd = -2;
+
+ if (cptr->fd >= 0)
+ {
+ cptr->confs = make_link();
+ cptr->confs->next = NULL;
+ cptr->confs->value.aconf = aconf;
+ add_fd(cptr->fd, &fdas);
+ add_fd(cptr->fd, &fdall);
+ set_non_blocking(cptr->fd, cptr);
+ }
+ else
+ free_client(cptr);
+ return 0;
+}
+
+#ifdef UNIXPORT
+/*
+ * unixport
+ *
+ * Create a socket and bind it to a filename which is comprised of the path
+ * (directory where file is placed) and port (actual filename created).
+ * Set directory permissions as rwxr-xr-x so other users can connect to the
+ * file which is 'forced' to rwxrwxrwx (different OS's have different need of
+ * modes so users can connect to the socket).
+ */
+int unixport(cptr, path, port)
+aClient *cptr;
+char *path;
+int port;
+{
+ struct sockaddr_un un;
+
+ if ((cptr->fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+ {
+ report_error("error opening unix domain socket %s:%s", cptr);
+ return -1;
+ }
+ else if (cptr->fd >= MAXCLIENTS)
+ {
+ sendto_flag(SCH_ERROR,
+ "No more connections allowed (%s)", cptr->name);
+ (void)close(cptr->fd);
+ return -1;
+ }
+
+ un.sun_family = AF_UNIX;
+ (void)mkdir(path, 0755);
+ SPRINTF(unixpath, "%s/%d", path, port);
+ (void)unlink(unixpath);
+ strncpyzt(un.sun_path, unixpath, sizeof(un.sun_path));
+ (void)strcpy(cptr->name, ME);
+ errno = 0;
+ get_sockhost(cptr, unixpath);
+
+ if (bind(cptr->fd, (SAP)&un, strlen(unixpath)+2) == -1)
+ {
+ report_error("error binding unix socket %s:%s", cptr);
+ (void)close(cptr->fd);
+ return -1;
+ }
+ if (cptr->fd > highest_fd)
+ highest_fd = cptr->fd;
+ (void)listen(cptr->fd, LISTENQUEUE);
+ (void)chmod(path, 0755);
+ (void)chmod(unixpath, 0777);
+ cptr->flags |= FLAGS_UNIX;
+ cptr->port = 0;
+ local[cptr->fd] = cptr;
+
+ return 0;
+}
+#endif
+
+/*
+ * 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()
+{
+ Reg aClient *cptr;
+ Reg int i;
+ Reg 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 (cptr == &me || !IsListening(cptr))
+ continue;
+ aconf = cptr->confs->value.aconf;
+
+ if (IsIllegal(aconf) && aconf->clients == 0)
+ {
+#ifdef UNIXPORT
+ if (IsUnixSocket(cptr))
+ {
+ SPRINTF(unixpath, "%s/%d",
+ aconf->host, aconf->port);
+ (void)unlink(unixpath);
+ }
+#endif
+ close_connection(cptr);
+ }
+ }
+}
+
+void
+start_iauth(rcvdsig)
+int rcvdsig;
+{
+#if defined(USE_IAUTH)
+ static time_t last = 0;
+ static char first = 1;
+ int sp[2], fd;
+
+ if ((bootopt & BOOT_NOIAUTH) != 0)
+ return;
+ if (adfd >= 0)
+ {
+ if (rcvdsig)
+ sendto_flag(SCH_AUTH,
+ "iauth is already running, restart canceled");
+ return;
+ }
+ if ((time(NULL) - last) > 90 || rcvdsig)
+ {
+ sendto_flag(SCH_AUTH, "Starting iauth...");
+ last = time(NULL);
+ read_iauth(); /* to reset olen */
+ iauth_spawn += 1;
+ }
+ else
+ return;
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) < 0)
+ {
+ sendto_flag(SCH_ERROR, "socketpair() failed!");
+ sendto_flag(SCH_AUTH, "Failed to restart iauth!");
+ }
+ adfd = sp[0];
+ set_non_blocking(sp[0], NULL);
+ set_non_blocking(sp[1], NULL); /* less to worry about in iauth */
+ switch (vfork())
+ {
+ case -1:
+ sendto_flag(SCH_ERROR, "vfork() failed!");
+ sendto_flag(SCH_AUTH, "Failed to restart iauth!");
+ close(sp[0]); close(sp[1]);
+ adfd = -1;
+ return;
+ case 0:
+ for (fd = 0; fd < MAXCONNECTIONS; fd++)
+ if (fd != sp[1])
+ (void)close(fd);
+ if (sp[1] != 0)
+ {
+ (void)dup2(sp[1], 0);
+ close(sp[1]);
+ }
+ if (execl(IAUTH_PATH, IAUTH, NULL) < 0)
+ _exit(-1); /* should really not happen.. */
+ default:
+ close(sp[1]);
+ }
+
+ if (first)
+ first = 0;
+ else
+ {
+ int i;
+ aClient *cptr;
+
+ for (i = 0; i <= highest_fd; i++)
+ {
+ if (!(cptr = local[i]))
+ continue;
+ if (IsServer(cptr) || IsService(cptr))
+ continue;
+ sendto_iauth("%d O", i);
+ }
+ }
+#endif
+}
+
+/*
+ * init_sys
+ */
+void init_sys()
+{
+ Reg int fd;
+
+#ifdef RLIMIT_FD_MAX
+ struct rlimit limit;
+
+ if (!getrlimit(RLIMIT_FD_MAX, &limit))
+ {
+ if (limit.rlim_max < MAXCONNECTIONS)
+ {
+ (void)fprintf(stderr, "ircd fd table is too big\n");
+ (void)fprintf(stderr, "Hard Limit: %d IRC max: %d\n",
+ (int) limit.rlim_max, MAXCONNECTIONS);
+ (void)fprintf(stderr,
+ "Fix MAXCONNECTIONS and recompile.\n");
+ exit(-1);
+ }
+ 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
+#if ! USE_POLL
+# 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
+#endif /* USE_POLL */
+
+#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(SVR4)
+ (void)setlinebuf(stderr);
+# endif
+# endif
+#endif
+
+ bzero((char *)&fdas, sizeof(fdas));
+ bzero((char *)&fdall, sizeof(fdall));
+ fdas.highest = fdall.highest = -1;
+
+ for (fd = 3; fd < MAXCONNECTIONS; fd++)
+ {
+ (void)close(fd);
+ local[fd] = NULL;
+ }
+ local[1] = NULL;
+ (void) fclose(stdout);
+ (void)close(1);
+
+ if (bootopt & BOOT_TTY) /* debugging is going to a tty */
+ goto init_dgram;
+ if (!(bootopt & BOOT_DEBUG))
+ (void)close(2);
+
+ if (((bootopt & BOOT_CONSOLE) || isatty(0)) &&
+ !(bootopt & (BOOT_INETD|BOOT_OPER)))
+ {
+#ifndef __CYGWIN32__
+ if (fork())
+ exit(0);
+#endif
+#ifdef TIOCNOTTY
+ if ((fd = open("/dev/tty", O_RDWR)) >= 0)
+ {
+ (void)ioctl(fd, TIOCNOTTY, (char *)NULL);
+ (void)close(fd);
+ }
+#endif
+#if defined(HPUX) || defined(SVR4) || defined(DYNIXPTX) || \
+ defined(_POSIX_SOURCE) || defined(SGI)
+ (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);
+
+ start_iauth(0);
+}
+
+void write_pidfile()
+{
+ int fd;
+ char buff[20];
+ (void)truncate(IRCDPID_PATH, 0);
+ if ((fd = open(IRCDPID_PATH, 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",
+ IRCDPID_PATH));
+ (void)close(fd);
+ return;
+ }
+# ifdef DEBUGMODE
+ else
+ Debug((DEBUG_NOTICE,"Error opening pid file %s",
+ IRCDPID_PATH));
+# 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)
+Reg aClient *cptr;
+Reg char *sockn;
+{
+ struct SOCKADDR_IN sk;
+ SOCK_LEN_TYPE len = sizeof(struct SOCKADDR_IN);
+
+#ifdef UNIXPORT
+ if (IsUnixSocket(cptr))
+ {
+ strncpyzt(sockn, cptr->acpt->sockhost, HOSTLEN+1);
+ get_sockhost(cptr, sockn);
+ return 0;
+ }
+#endif
+
+ /* 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, (SAP)&sk, &len) == -1)
+ {
+ report_error("connect failure: %s %s", cptr);
+ return -1;
+ }
+#ifdef INET6
+ inetntop(AF_INET6, (char *)&sk.sin6_addr, sockn, MYDUMMY_SIZE);
+ Debug((DEBUG_DNS,"sockn %x",sockn));
+ Debug((DEBUG_DNS,"sockn %s",sockn));
+#else
+ (void)strcpy(sockn, (char *)inetntoa((char *)&sk.sin_addr));
+#endif
+#ifdef INET6
+ if (IN6_IS_ADDR_LOOPBACK(&sk.SIN_ADDR))
+#else
+ if (inetnetof(sk.SIN_ADDR) == IN_LOOPBACKNET)
+#endif
+ {
+ cptr->hostp = me.hostp;
+ }
+ 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 = Bad socket.
+ * -2 = Access denied
+ */
+int check_client(cptr)
+Reg aClient *cptr;
+{
+ static char sockname[HOSTLEN+1];
+ Reg struct hostent *hp = NULL;
+ Reg int i;
+
+#ifdef INET6
+ Debug((DEBUG_DNS, "ch_cl: check access for %s[%s]",
+ cptr->name, inet_ntop(AF_INET6, (char *)&cptr->ip, mydummy,
+ MYDUMMY_SIZE)));
+#else
+ Debug((DEBUG_DNS, "ch_cl: check access for %s[%s]",
+ cptr->name, inetntoa((char *)&cptr->ip)));
+#endif
+
+ if (check_init(cptr, sockname))
+ return -1;
+
+ 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.
+ * We shouldn't check it for localhost, because hp is fake in that
+ * case. -Toor
+ */
+ if (hp && (hp != me.hostp))
+ {
+ 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])
+ {
+#ifdef INET6
+ sendto_flag(SCH_ERROR,
+ "IP# Mismatch: %s != %s[%08x%08x%08x%08x]",
+ inetntop(AF_INET6, (char *)&cptr->ip,
+ mydummy,MYDUMMY_SIZE),hp->h_name,
+ ((unsigned long *)hp->h_addr)[0],
+ ((unsigned long *)hp->h_addr)[1],
+ ((unsigned long *)hp->h_addr)[2],
+ ((unsigned long *)hp->h_addr)[3]);
+#else
+ sendto_flag(SCH_ERROR, "IP# Mismatch: %s != %s[%08x]",
+ inetntoa((char *)&cptr->ip), hp->h_name,
+ *((unsigned long *)hp->h_addr));
+#endif
+ 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));
+
+#ifdef INET6
+ if (IN6_IS_ADDR_LOOPBACK(&cptr->ip) || IsUnixSocket(cptr) ||
+ (cptr->ip.s6_laddr[0]==mysk.sin6_addr.s6_laddr[0] &&
+ cptr->ip.s6_laddr[1]==mysk.sin6_addr.s6_laddr[1])
+/* ||
+ IN6_ARE_ADDR_SAMEPREFIX(&cptr->ip, &mysk.SIN_ADDR))
+ about the same, I think NOT */
+ )
+#else
+ if (inetnetof(cptr->ip) == IN_LOOPBACKNET || IsUnixSocket(cptr) ||
+ inetnetof(cptr->ip) == inetnetof(mysk.SIN_ADDR))
+#endif
+ {
+
+ ircstp->is_loc++;
+ cptr->flags |= FLAGS_LOCAL;
+ }
+ return 0;
+}
+
+/*
+ * 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;
+{
+ Reg char *name;
+ Reg 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_flag(SCH_ERROR, "Connecting Error: %s[%s]",
+ name, cptr->sockhost);
+ det_confs_butmask(cptr, 0);
+ return -1;
+ }
+ }
+#ifdef UNIXPORT
+ if (IsUnixSocket(cptr))
+ {
+ if (!c_conf)
+ c_conf = find_conf(lp, name, CFLAG);
+ if (!n_conf)
+ n_conf = find_conf(lp, name, NFLAG);
+ }
+#endif
+
+ /*
+ ** If the servername is a hostname, either an alias (CNAME) or
+ ** real name, then check with it as the host. Use gethostbyname()
+ ** to check for servername as hostname.
+ */
+ if (!IsUnixSocket(cptr) && !cptr->hostp)
+ {
+ Reg aConfItem *aconf;
+
+ aconf = count_cnlines(lp);
+ if (aconf)
+ {
+ Reg 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 can't interrupt that very
+ ** well.
+ */
+ 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;
+Reg aConfItem *n_conf, *c_conf;
+Reg struct hostent *hp;
+int estab;
+{
+ Reg char *name;
+ char abuff[HOSTLEN+USERLEN+2];
+ char sockname[HOSTLEN+1], fullname[HOSTLEN+1];
+ Link *lp = cptr->confs;
+ int i;
+
+ 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])
+ {
+#ifdef INET6
+ sendto_flag(SCH_ERROR,
+ "IP# Mismatch: %s != %s[%08x%08x%08x%08x]",
+ inetntop(AF_INET6, (char *)&cptr->ip,
+ mydummy,MYDUMMY_SIZE),hp->h_name,
+ ((unsigned long *)hp->h_addr)[0],
+ ((unsigned long *)hp->h_addr)[1],
+ ((unsigned long *)hp->h_addr)[2],
+ ((unsigned long *)hp->h_addr)[3]);
+#else
+ sendto_flag(SCH_ERROR, "IP# Mismatch: %s != %s[%08x]",
+ inetntoa((char *)&cptr->ip), hp->h_name,
+ *((unsigned long *)hp->h_addr));
+#endif
+ 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));
+ 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))
+ {
+ 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->auth, cptr->sockhost,
+ c_conf, n_conf));
+ return -1;
+ }
+ /*
+ * attach the C and N lines to the client structure for later use.
+ */
+ (void)attach_conf(cptr, n_conf);
+ (void)attach_conf(cptr, c_conf);
+ (void)attach_confs(cptr, name, CONF_HUB|CONF_LEAF);
+
+#ifdef INET6
+ if ((AND16(c_conf->ipnum.s6_addr) == 255) && !IsUnixSocket(cptr))
+#else
+ if ((c_conf->ipnum.s_addr == -1) && !IsUnixSocket(cptr))
+#endif
+ 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;
+}
+
+/*
+** 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, CFLAG);
+ if (!aconf)
+ {
+ sendto_flag(SCH_NOTICE,
+ "Lost C-Line for %s", get_client_name(cptr,FALSE));
+ return -1;
+ }
+ if (!BadPtr(aconf->passwd))
+#ifndef ZIP_LINKS
+ sendto_one(cptr, "PASS %s %s IRC|%s %s", aconf->passwd,
+ pass_version, serveropts,
+ (bootopt & BOOT_STRICTPROT) ? "P" : "");
+#else
+ sendto_one(cptr, "PASS %s %s IRC|%s %s%s", aconf->passwd,
+ pass_version, serveropts,
+ (bootopt & BOOT_STRICTPROT) ? "P" : "",
+ (aconf->status == CONF_ZCONNECT_SERVER) ? "Z" : "");
+#endif
+
+ aconf = find_conf(cptr->confs, cptr->name, CONF_NOCONNECT_SERVER);
+ if (!aconf)
+ {
+ sendto_flag(SCH_NOTICE,
+ "Lost N-Line for %s", get_client_name(cptr,FALSE));
+ return -1;
+ }
+ sendto_one(cptr, "SERVER %s 1 :%s",
+ my_name_for_link(ME, aconf->port), me.info);
+ if (!IsDead(cptr))
+ {
+ start_auth(cptr);
+#if defined(USE_IAUTH)
+ /*
+ ** This could become a bug.. but I don't think iauth needs the
+ ** hostname/aliases in this case. -kalt
+ */
+ sendto_iauth("%d d", cptr->fd);
+#endif
+ }
+
+ return (IsDead(cptr)) ? -1 : 0;
+}
+
+int hold_server(cptr)
+aClient *cptr;
+{
+ return -1; /* needs to be fixed, don't forget virtual hosts */
+
+#if 0 /* code and variables declarations are removed, this
+ avoids compiler warnings */
+
+ struct SOCKADDR_IN sin;
+ aConfItem *aconf;
+ aClient *acptr;
+ int fd;
+
+#ifdef ZIP_LINKS
+ /*
+ * reconnecting will not work with compressed links,
+ * unless someones fixes reconnect and implements what's needed
+ * to have it work for compressed links. -krys
+ */
+ return -1;
+#else
+ if (!IsServer(cptr) ||
+ !(aconf = find_conf_name(cptr->name, CFLAG)))
+ return -1;
+
+ if (!aconf->port)
+ return -1;
+
+ fd = socket(AFINET, SOCK_STREAM, 0);
+
+ if (fd >= MAXCLIENTS)
+ {
+ (void)close(fd);
+ sendto_flag(SCH_ERROR,
+ "Can't reconnect - all connections in use");
+ return -1;
+ }
+
+ cptr->flags |= FLAGS_HELD;
+ (void)close(cptr->fd);
+ del_fd(cptr->fd, &fdall);
+ del_fd(cptr->fd, &fdas);
+ cptr->fd = -2;
+
+ acptr = make_client(NULL);
+ acptr->fd = fd;
+ acptr->port = aconf->port;
+ set_non_blocking(acptr->fd, acptr);
+ (void)set_sock_opts(acptr->fd, acptr);
+ bzero((char *)&sin, sizeof(sin));
+ sin.SIN_FAMILY = AFINET;
+ sin.SIN_PORT = htons(aconf->port);
+ bcopy((char *)&cptr->ip, (char *)&sin.SIN_ADDR, sizeof(cptr->ip));
+ bcopy((char *)&cptr->ip, (char *)&acptr->ip, sizeof(cptr->ip));
+
+ if (connect(acptr->fd, (SAP)&sin, sizeof(sin)) < 0 &&
+ errno != EINPROGRESS)
+ {
+ report_error("Connect to host %s failed: %s", acptr); /*buggy*/
+ (void)close(acptr->fd);
+ MyFree((char *)acptr);
+ return -1;
+ }
+
+ acptr->status = STAT_RECONNECT;
+ if (acptr->fd > highest_fd)
+ highest_fd = acptr->fd;
+ add_fd(acptr->fd, &fdall);
+ local[acptr->fd] = acptr;
+ acptr->acpt = &me;
+ add_client_to_list(acptr);
+ (void)strcpy(acptr->name, cptr->name);
+ /* broken syntax
+ sendto_one(acptr, "PASS %s %s", aconf->passwd, pass_version);
+ */
+ sendto_one(acptr, "RECONNECT %s %d", acptr->name, cptr->sendM);
+ sendto_flag(SCH_NOTICE, "Reconnecting to %s", acptr->name);
+ Debug((DEBUG_NOTICE, "Reconnect %s %#x via %#x %d", cptr->name, cptr,
+ acptr, acptr->fd));
+ return 0;
+#endif
+#endif
+}
+
+/*
+** close_connection
+** Close the physical connection. This function must make
+** MyConnect(cptr) == FALSE, and set cptr->from == NULL.
+*/
+void close_connection(cptr)
+aClient *cptr;
+{
+ Reg aConfItem *aconf;
+ Reg int i,j;
+#ifdef SO_LINGER
+ struct linger sockling;
+
+ sockling.l_onoff = 0;
+#endif
+
+ 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 += timeofday - 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 += timeofday - 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.
+ */
+ if ((aconf = find_conf_exact(cptr->name, cptr->username,
+ cptr->sockhost, CFLAG)))
+ {
+ /*
+ * 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 = timeofday;
+ aconf->hold += (aconf->hold - cptr->since > HANGONGOODLINK) ?
+ HANGONRETRYDELAY : ConfConFreq(aconf);
+ if (nextconnect > aconf->hold)
+ nextconnect = aconf->hold;
+ }
+
+ if (cptr->authfd >= 0)
+ {
+#ifdef SO_LINGER
+ if (cptr->exitc == EXITC_PING)
+ if (SETSOCKOPT(cptr->authfd, SOL_SOCKET, SO_LINGER,
+ &sockling, sockling))
+ report_error("setsockopt(SO_LINGER) %s:%s",
+ cptr);
+#endif
+ (void)close(cptr->authfd);
+ }
+
+ if ((i = cptr->fd) >= 0)
+ {
+#if defined(USE_IAUTH)
+ sendto_iauth("%d D", cptr->fd);
+#endif
+ flush_connections(i);
+ if (IsServer(cptr) || IsListening(cptr))
+ {
+ del_fd(i, &fdas);
+#ifdef ZIP_LINKS
+ /*
+ ** the connection might have zip data (even if
+ ** FLAGS_ZIP is not set)
+ */
+ zip_free(cptr);
+#endif
+ }
+ else if (IsClient(cptr))
+ {
+#ifdef SO_LINGER
+ if (cptr->exitc == EXITC_PING)
+ if (SETSOCKOPT(i, SOL_SOCKET, SO_LINGER,
+ &sockling, sockling))
+ report_error("setsockopt(SO_LINGER) %s:%s",
+ cptr);
+#endif
+ }
+ del_fd(i, &fdall);
+ local[i] = NULL;
+ (void)close(i);
+
+ /*
+ * fd remap to keep local[i] filled at the bottom.
+ * don't *ever* move descriptors for
+ * + log file
+ * + sockets bound to listen() ports
+ * --Yegg
+ */
+ if (i >= 0 && (j = highest_fd) > i)
+ {
+ while (!local[j])
+ j--;
+ if (j > i && local[j] &&
+ !(IsLog(local[j]) || IsMe(local[j])))
+ {
+ if (dup2(j,i) == -1)
+ return;
+ local[i] = local[j];
+ local[i]->fd = i;
+ local[j] = NULL;
+ (void)close(j);
+ del_fd(j, &fdall);
+ add_fd(i, &fdall);
+ if (IsServer(local[i]) || IsMe(local[i]))
+ {
+ del_fd(j, &fdas);
+ add_fd(i, &fdas);
+ }
+ while (!local[highest_fd])
+ highest_fd--;
+#if defined(USE_IAUTH)
+ sendto_iauth("%d R %d", j, i);
+#endif
+ }
+ }
+ cptr->fd = -2;
+ DBufClear(&cptr->sendQ);
+ DBufClear(&cptr->recvQ);
+ bzero(cptr->passwd, sizeof(cptr->passwd));
+ /*
+ * clean up extra sockets from P-lines which have been
+ * discarded.
+ */
+ if (cptr->acpt != &me)
+ {
+ aconf = cptr->acpt->confs->value.aconf;
+ if (aconf->clients > 0)
+ aconf->clients--;
+ if (!aconf->clients && IsIllegal(aconf))
+ close_connection(cptr->acpt);
+ }
+ }
+
+ det_confs_butmask(cptr, 0);
+ cptr->from = NULL; /* ...this should catch them! >:) --msa */
+ return;
+}
+
+/*
+** set_sock_opts
+*/
+static int set_sock_opts(fd, cptr)
+int fd;
+aClient *cptr;
+{
+ int opt, ret = 0;
+#ifdef SO_REUSEADDR
+ opt = 1;
+ if (SETSOCKOPT(fd, SOL_SOCKET, SO_REUSEADDR, &opt, opt) < 0)
+ report_error("setsockopt(SO_REUSEADDR) %s:%s", cptr);
+#endif
+#if defined(SO_DEBUG) && defined(DEBUGMODE) && 0
+/* Solaris 2.x with SO_DEBUG writes to syslog by default */
+#if ! SOLARIS_2 || defined(USE_SYSLOG)
+ opt = 1;
+ if (SETSOCKOPT(fd, SOL_SOCKET, SO_DEBUG, &opt, opt) < 0)
+ report_error("setsockopt(SO_DEBUG) %s:%s", cptr);
+#endif /* SOLARIS_2 */
+#endif
+#ifdef SO_USELOOPBACK
+ opt = 1;
+ if (SETSOCKOPT(fd, SOL_SOCKET, SO_USELOOPBACK, &opt, opt) < 0)
+ report_error("setsockopt(SO_USELOOPBACK) %s:%s", cptr);
+#endif
+#ifdef SO_RCVBUF
+ opt = 8192;
+ if (SETSOCKOPT(fd, SOL_SOCKET, SO_RCVBUF, &opt, 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).
+ */
+# endif
+ opt = 8192;
+ if (SETSOCKOPT(fd, SOL_SOCKET, SO_SNDBUF, &opt, opt) < 0)
+ report_error("setsockopt(SO_SNDBUF) %s:%s", cptr);
+# ifdef SO_SNDLOWAT
+ /*
+ * Setting the low water mark should improve performence by avoiding
+ * early returns from select()/poll(). It shouldn't delay sending
+ * data, provided that io_loop() combines read_message() and
+ * flush_fdary/connections() calls properly. -kalt
+ * This call isn't always implemented, even when defined.. so be quiet
+ * about errors. -kalt
+ */
+ opt = 8192;
+ SETSOCKOPT(fd, SOL_SOCKET, SO_SNDLOWAT, &opt, opt);
+# endif
+#endif
+#if defined(IP_OPTIONS) && defined(IPPROTO_IP) && !defined(AIX) && \
+ !defined(SUN_GSO_BUG) && !defined(INET6)
+ /*
+ * Mainly to turn off and alert us to source routing, here.
+ * Method borrowed from Wietse Venema's TCP wrapper.
+ */
+ {
+ if (!IsUnixSocket(cptr) && !IsListening(cptr))
+ {
+ u_char opbuf[256], *t = opbuf;
+ char *s = readbuf;
+
+ opt = sizeof(opbuf);
+ if (GETSOCKOPT(fd, IPPROTO_IP, IP_OPTIONS, t, &opt) == -1)
+ report_error("getsockopt(IP_OPTIONS) %s:%s", cptr);
+ else if (opt > 0)
+ {
+ for (; opt > 0; opt--, s+= 3)
+ (void)sprintf(s, " %02x", *t++);
+ *s = '\0';
+ sendto_flag(SCH_NOTICE,
+ "Connection %s with IP opts%s",
+ get_client_name(cptr, TRUE), readbuf);
+ Debug((DEBUG_NOTICE,
+ "Connection %s with IP opts%s",
+ get_client_name(cptr, TRUE), readbuf));
+ ret = -1;
+ }
+ }
+ }
+#endif
+ return ret;
+}
+
+int get_sockerr(cptr)
+aClient *cptr;
+{
+ int errtmp = errno, err = 0;
+ SOCK_LEN_TYPE len = sizeof(err);
+
+#ifdef SO_ERROR
+ if (cptr->fd >= 0)
+ if (!GETSOCKOPT(cptr->fd, SOL_SOCKET, SO_ERROR, &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.
+ */
+#if NBLOCK_POSIX
+ nonb |= O_NONBLOCK;
+#endif
+#if NBLOCK_BSD
+ nonb |= O_NDELAY;
+#endif
+#if 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;
+}
+
+#ifdef CLONE_CHECK
+/*
+ * check_clones
+ * adapted by jecete 4 IRC Ptnet
+ */
+static int check_clones(cptr)
+aClient *cptr;
+{
+ struct abacklog {
+ struct IN_ADDR ip;
+ time_t PT;
+ struct abacklog *next;
+ };
+ static struct abacklog *backlog = NULL;
+ register struct abacklog **blscn = &backlog,
+ *blptr;
+ register int count = 0;
+
+ /* First, ditch old entries */
+ while (*blscn != NULL)
+ {
+ if ((*blscn)->PT+CLONE_PERIOD < timeofday)
+ {
+ blptr= *blscn;
+ *blscn=blptr->next;
+ MyFree((char *)blptr);
+ }
+ else
+ blscn = &(*blscn)->next;
+ }
+ /* Now add new item to the list */
+ blptr = (struct abacklog *) MyMalloc(sizeof(struct abacklog));
+#ifdef INET6
+ bcopy(cptr->ip.s6_addr, blptr->ip.s6_addr, IN6ADDRSZ);
+#else
+ blptr->ip.s_addr = cptr->ip.s_addr;
+#endif
+ blptr->PT = timeofday;
+ blptr->next = backlog;
+ backlog = blptr;
+
+ /* Count the number of entries from the same host */
+ blptr = backlog;
+ while (blptr != NULL)
+ {
+#ifdef INET6
+ if (bcmp(blptr->ip.s6_addr, cptr->ip.s6_addr, IN6ADDRSZ) == 0)
+#else
+ if (blptr->ip.s_addr == cptr->ip.s_addr)
+#endif
+ count++;
+ blptr = blptr->next;
+ }
+ return (count);
+}
+#endif
+
+/*
+ * Creates a client which has just connected to us on the given fd.
+ * The sockhost field is initialized with the ip# of the host.
+ * The client is added to the linked list of clients but isnt added to any
+ * hash tables yet since it doesnt have a name.
+ */
+aClient *add_connection(cptr, fd)
+aClient *cptr;
+int fd;
+{
+ Link lin;
+ aClient *acptr;
+ aConfItem *aconf = NULL;
+ acptr = make_client(NULL);
+
+ 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;
+ SOCK_LEN_TYPE len = sizeof(struct SOCKADDR_IN);
+
+ if (getpeername(fd, (SAP)&addr, &len) == -1)
+ {
+#if defined(linux)
+ if (errno != ENOTCONN)
+#endif
+ 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...
+ */
+#ifdef INET6
+ inetntop(AF_INET6, (char *)&addr.sin6_addr, mydummy,
+ MYDUMMY_SIZE);
+ get_sockhost(acptr, (char *)mydummy);
+#else
+ get_sockhost(acptr, (char *)inetntoa((char *)&addr.sin_addr));
+#endif
+ bcopy ((char *)&addr.SIN_ADDR, (char *)&acptr->ip,
+ sizeof(struct IN_ADDR));
+ acptr->port = ntohs(addr.SIN_PORT);
+
+ lin.flags = ASYNC_CLIENT;
+ lin.value.cptr = acptr;
+#ifdef INET6
+ Debug((DEBUG_DNS, "lookup %s",
+ inet_ntop(AF_INET6, (char *)&addr.sin6_addr,
+ mydummy, MYDUMMY_SIZE)));
+#else
+ Debug((DEBUG_DNS, "lookup %s",
+ inetntoa((char *)&addr.sin_addr)));
+#endif
+ acptr->hostp = gethost_byaddr((char *)&acptr->ip, &lin);
+ if (!acptr->hostp)
+ SetDNS(acptr);
+ nextdnscheck = 1;
+ }
+
+#ifdef CLONE_CHECK
+ if (check_clones(acptr) > CLONE_MAX)
+ {
+ sendto_flag(SCH_LOCAL, "Rejecting connection from %s[%s].",
+ (acptr->hostp) ? acptr->hostp->h_name : "",
+ acptr->sockhost);
+ sendto_flog(acptr, " ?Clone? ", 0, "<none>",
+ (acptr->hostp) ? acptr->hostp->h_name :
+ acptr->sockhost);
+ del_queries((char *)acptr);
+# ifdef INET6
+ (void)sendto(acptr->fd,
+ "ERROR :Too rapid connections from your host\r\n",
+ 46, 0, 0, 0);
+# else
+ (void)send(acptr->fd,
+ "ERROR :Too rapid connections from your host\r\n",
+ 46, 0);
+# endif
+ goto add_con_refuse;
+ }
+#endif
+ acptr->fd = fd;
+ set_non_blocking(acptr->fd, acptr);
+ if (set_sock_opts(acptr->fd, acptr) == -1)
+ goto add_con_refuse;
+ if (aconf)
+ aconf->clients++;
+ if (fd > highest_fd)
+ highest_fd = fd;
+ local[fd] = acptr;
+ add_fd(fd, &fdall);
+ acptr->acpt = cptr;
+ add_client_to_list(acptr);
+ start_auth(acptr);
+#if defined(USE_IAUTH)
+ if (!isatty(fd) && !DoingDNS(acptr))
+ {
+ int i = 0;
+
+ while (acptr->hostp->h_aliases[i])
+ sendto_iauth("%d A %s", acptr->fd,
+ acptr->hostp->h_aliases[i++]);
+ if (acptr->hostp->h_name)
+ sendto_iauth("%d N %s",acptr->fd,acptr->hostp->h_name);
+ else if (acptr->hostp->h_aliases[0])
+ sendto_iauth("%d n", acptr->fd);
+ }
+#endif
+ return acptr;
+}
+
+#ifdef UNIXPORT
+static void add_unixconnection(cptr, fd)
+aClient *cptr;
+int fd;
+{
+ aClient *acptr;
+ aConfItem *aconf = NULL;
+
+ acptr = make_client(NULL);
+
+ /* Copy ascii address to 'sockhost' just in case. Then we
+ * have something valid to put into error messages...
+ */
+ get_sockhost(acptr, me.sockhost);
+ aconf = cptr->confs->value.aconf;
+ if (aconf)
+ {
+ if (IsIllegal(aconf))
+ {
+ ircstp->is_ref++;
+ acptr->fd = -2;
+ free_client(acptr);
+ (void)close(fd);
+ return;
+ }
+ else
+ aconf->clients++;
+ }
+ acptr->fd = fd;
+ if (fd > highest_fd)
+ highest_fd = fd;
+ local[fd] = acptr;
+ add_fd(fd, &fdall);
+ acptr->acpt = cptr;
+ SetUnixSock(acptr);
+ bcopy((char *)&me.ip, (char *)&acptr->ip, sizeof(struct IN_ADDR));
+
+ add_client_to_list(acptr);
+ set_non_blocking(acptr->fd, acptr);
+ (void)set_sock_opts(acptr->fd, acptr);
+ return;
+}
+#endif
+
+/*
+** read_listener
+**
+** Accept incoming connections, extracted from read_message() 98/12 -kalt
+** Up to 10 connections will be accepted, unless SLOW_ACCEPT is defined.
+*/
+static void
+read_listener(cptr)
+aClient *cptr;
+{
+ int fdnew, max = 10;
+
+#if defined(SLOW_ACCEPT)
+ max = 1;
+#endif
+ while (max--)
+ {
+ /*
+ ** 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 ((fdnew = accept(cptr->fd, NULL, NULL)) < 0)
+ {
+ if (errno != EWOULDBLOCK)
+ report_error("Cannot accept connections %s:%s",
+ cptr);
+ break;
+ }
+ ircstp->is_ac++;
+ if (fdnew >= MAXCLIENTS)
+ {
+ ircstp->is_ref++;
+ sendto_flag(SCH_ERROR, "All connections in use. (%s)",
+ get_client_name(cptr, TRUE));
+ find_bounce(NULL, 0, fdnew);
+#ifdef INET6
+ (void)sendto(fdnew,
+ "ERROR :All connections in use\r\n",
+ 32, 0, 0, 0);
+#else
+ (void)send(fdnew, "ERROR :All connections in use\r\n",
+ 32, 0);
+#endif
+ (void)close(fdnew);
+ continue;
+ }
+ /*
+ * Use of add_connection (which never fails :) meLazy
+ * Never say never. MrMurphy visited here. -Vesa
+ */
+#ifdef UNIXPORT
+ if (IsUnixSocket(cptr))
+ add_unixconnection(cptr, fdnew);
+ else
+#endif
+ if (!add_connection(cptr, fdnew))
+ continue;
+ nextping = timeofday; /* isn't this abusive? -kalt */
+ istat.is_unknown++;
+ }
+}
+
+/*
+** client_packet
+**
+** Process data from receive buffer to client.
+** Extracted from read_packet() 960804/291p3/Vesa
+*/
+static int client_packet(cptr)
+Reg aClient *cptr;
+{
+ Reg int dolen = 0;
+
+ while (DBufLength(&cptr->recvQ) && !NoNewLine(cptr) &&
+ ((cptr->status < STAT_UNKNOWN) ||
+ (cptr->since - timeofday < MAXPENALTY)))
+ {
+ /*
+ ** 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;
+ dolen = dopacket(cptr, readbuf, dolen);
+ if (dolen == 2 && cptr->since == cptr->lasttime)
+ cptr->since += 5;
+ if (dolen)
+ return dolen;
+ 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, &me,
+ "dbuf_getmsg fail");
+ if (DBufLength(&cptr->recvQ) < 510)
+ { /* hmm? */
+ cptr->flags |= FLAGS_NONL;
+ break;
+ }
+ dolen = dbuf_get(&cptr->recvQ, readbuf, 511);
+ if (dolen > 0 && DBufLength(&cptr->recvQ))
+ DBufClear(&cptr->recvQ);
+ }
+
+ /* Is it okay not to test for other return values? -krys */
+ if (dolen > 0 &&
+ (dopacket(cptr, readbuf, dolen) == FLUSH_BUFFER))
+ return FLUSH_BUFFER;
+ }
+ return 1;
+}
+
+/*
+** 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, msg_ready)
+Reg aClient *cptr;
+int msg_ready;
+{
+ Reg int length = 0, done;
+
+ if (msg_ready &&
+ !(IsPerson(cptr) && DBufLength(&cptr->recvQ) > 6090))
+ {
+ errno = 0;
+#ifdef INET6
+ length = recvfrom(cptr->fd, readbuf, sizeof(readbuf), 0, 0, 0);
+#else
+ length = recv(cptr->fd, readbuf, sizeof(readbuf), 0);
+#endif
+#if defined(DEBUGMODE) && defined(DEBUG_READ)
+ if (length > 0)
+ Debug((DEBUG_READ,
+ "recv = %d bytes from %d[%s]:[%*.*s]\n",
+ length, cptr->fd, cptr->name, length, length,
+ readbuf));
+#endif
+
+ Debug((DEBUG_DEBUG, "Received %d(%d-%s) bytes from %d %s",
+ length, errno, strerror(errno),
+ cptr->fd, get_client_name(cptr, TRUE)));
+ cptr->lasttime = timeofday;
+ 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;
+ }
+ else if (msg_ready)
+ return exit_client(cptr, cptr, &me, "EOF From Client");
+
+ /*
+ ** 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)
+ {
+ done = dopacket(cptr, readbuf, length);
+ if (done && done != 2)
+ 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 (length && dbuf_put(&cptr->recvQ, readbuf, length) < 0)
+ return exit_client(cptr, cptr, &me, "dbuf_put fail");
+
+ if (IsPerson(cptr) &&
+ DBufLength(&cptr->recvQ) > CLIENT_FLOOD)
+ {
+ cptr->exitc = EXITC_FLOOD;
+ return exit_client(cptr, cptr, &me, "Excess Flood");
+ }
+
+ return client_packet(cptr);
+ }
+ 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, fdp, ro)
+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
+ * Actually, ZERO is NOT ZERO anymore.. see below -kalt
+ */
+FdAry *fdp;
+int ro;
+{
+#if ! USE_POLL
+# define SET_READ_EVENT( thisfd ) FD_SET( thisfd, &read_set)
+# define SET_WRITE_EVENT( thisfd ) FD_SET( thisfd, &write_set)
+# define CLR_READ_EVENT( thisfd ) FD_CLR( thisfd, &read_set)
+# define CLR_WRITE_EVENT( thisfd ) FD_CLR( thisfd, &write_set)
+# define TST_READ_EVENT( thisfd ) FD_ISSET( thisfd, &read_set)
+# define TST_WRITE_EVENT( thisfd ) FD_ISSET( thisfd, &write_set)
+
+ fd_set read_set, write_set;
+ int highfd = -1;
+#else
+/* most of the following use pfd */
+# define POLLSETREADFLAGS (POLLIN|POLLRDNORM)
+# define POLLREADFLAGS (POLLSETREADFLAGS|POLLHUP|POLLERR)
+# define POLLSETWRITEFLAGS (POLLOUT|POLLWRNORM)
+# define POLLWRITEFLAGS (POLLOUT|POLLWRNORM|POLLHUP|POLLERR)
+
+# define SET_READ_EVENT( thisfd ){ CHECK_PFD( thisfd );\
+ pfd->events |= POLLSETREADFLAGS;}
+# define SET_WRITE_EVENT( thisfd ){ CHECK_PFD( thisfd );\
+ pfd->events |= POLLSETWRITEFLAGS;}
+
+# define CLR_READ_EVENT( thisfd ) pfd->revents &= ~POLLSETREADFLAGS
+# define CLR_WRITE_EVENT( thisfd ) pfd->revents &= ~POLLSETWRITEFLAGS
+# define TST_READ_EVENT( thisfd ) pfd->revents & POLLREADFLAGS
+# define TST_WRITE_EVENT( thisfd ) pfd->revents & POLLWRITEFLAGS
+
+# define CHECK_PFD( thisfd ) \
+ if ( pfd->fd != thisfd ) { \
+ pfd = &poll_fdarray[nbr_pfds++];\
+ pfd->fd = thisfd; \
+ pfd->events = 0; \
+ }
+
+ struct pollfd poll_fdarray[MAXCONNECTIONS];
+ struct pollfd * pfd = poll_fdarray;
+ struct pollfd * res_pfd = NULL;
+ struct pollfd * udp_pfd = NULL;
+ struct pollfd * ad_pfd = NULL;
+ aClient * authclnts[MAXCONNECTIONS]; /* mapping of auth fds to client ptrs */
+ int nbr_pfds = 0;
+#endif
+
+ aClient *cptr;
+ int nfds, ret = 0;
+ struct timeval wait;
+ time_t delay2 = delay;
+ int res, length, fd, i;
+ int auth;
+
+ for (res = 0;;)
+ {
+#if ! USE_POLL
+ FD_ZERO(&read_set);
+ FD_ZERO(&write_set);
+#else
+ /* set up such that CHECK_FD works */
+ nbr_pfds = 0;
+ pfd = poll_fdarray;
+ pfd->fd = -1;
+ res_pfd = NULL;
+ udp_pfd = NULL;
+ ad_pfd = NULL;
+#endif /* USE_POLL */
+ auth = 0;
+
+#if USE_POLL
+ if ( auth == 0 )
+ bzero((char *) authclnts, sizeof( authclnts ));
+#endif
+ for (i = fdp->highest; i >= 0; i--)
+ {
+ if (!(cptr = local[fd = fdp->fd[i]]) ||
+ IsLog(cptr) || IsHeld(cptr))
+ continue;
+ Debug((DEBUG_L11, "fd %d cptr %#x %d %#x %s",
+ fd, cptr, cptr->status, cptr->flags,
+ get_client_name(cptr,TRUE)));
+ /* authentication fd's */
+ if (DoingAuth(cptr))
+ {
+ auth++;
+ SET_READ_EVENT(cptr->authfd);
+ Debug((DEBUG_NOTICE,"auth on %x %d", cptr,
+ fd));
+ if (cptr->flags & FLAGS_WRAUTH)
+ SET_WRITE_EVENT(cptr->authfd);
+#if USE_POLL
+ authclnts[cptr->authfd] = cptr;
+#else
+ if (cptr->authfd > highfd)
+ highfd = cptr->authfd;
+#endif
+ }
+ /*
+ ** if any of these is true, data won't be parsed
+ ** so no need to check for anything!
+ */
+#if defined(USE_IAUTH)
+ if (DoingDNS(cptr) || DoingAuth(cptr) ||
+ WaitingXAuth(cptr) ||
+ (DoingXAuth(cptr) &&
+ !(iauth_options & XOPT_EARLYPARSE)))
+#else
+ if (DoingDNS(cptr) || DoingAuth(cptr))
+#endif
+ continue;
+#if ! USE_POLL
+ if (fd > highfd)
+ highfd = fd;
+#endif
+ /*
+ ** Checking for new connections is only done up to
+ ** once per second.
+ */
+ if (IsListening(cptr))
+ {
+ if (timeofday > cptr->lasttime + 1 && ro == 0)
+ {
+ SET_READ_EVENT( fd );
+ }
+ else if (delay2 > 1)
+ delay2 = 1;
+ continue;
+ }
+
+ /*
+ ** This is very approximate, it should take
+ ** cptr->since into account. -kalt
+ */
+ if (DBufLength(&cptr->recvQ) && delay2 > 2)
+ delay2 = 1;
+
+ if (IsRegisteredUser(cptr))
+ {
+ if (cptr->since - timeofday < MAXPENALTY+1)
+ SET_READ_EVENT( fd );
+ }
+ else if (DBufLength(&cptr->recvQ) < 4088)
+ SET_READ_EVENT( fd );
+
+ /*
+ ** If we have anything in the sendQ, check if there is
+ ** room to write data.
+ */
+ if (DBufLength(&cptr->sendQ) || IsConnecting(cptr) ||
+#ifdef ZIP_LINKS
+ ((cptr->flags & FLAGS_ZIP) &&
+ (cptr->zip->outcount > 0)) ||
+#endif
+ IsReconnect(cptr))
+ if (IsServer(cptr) || IsConnecting(cptr) ||
+ ro == 0)
+ SET_WRITE_EVENT( fd );
+ }
+
+ if (udpfd >= 0)
+ {
+ SET_READ_EVENT(udpfd);
+#if ! USE_POLL
+ if (udpfd > highfd)
+ highfd = udpfd;
+#else
+ udp_pfd = pfd;
+#endif
+ }
+ if (resfd >= 0)
+ {
+ SET_READ_EVENT(resfd);
+#if ! USE_POLL
+ if (resfd > highfd)
+ highfd = resfd;
+#else
+ res_pfd = pfd;
+#endif
+ }
+#if defined(USE_IAUTH)
+ if (adfd >= 0)
+ {
+ SET_READ_EVENT(adfd);
+# if ! USE_POLL
+ if (adfd > highfd)
+ highfd = adfd;
+# else
+ ad_pfd = pfd;
+# endif
+ }
+#endif
+ Debug((DEBUG_L11, "udpfd %d resfd %d adfd %d", udpfd, resfd,
+ adfd));
+#if ! USE_POLL
+ Debug((DEBUG_L11, "highfd %d", highfd));
+#endif
+
+ wait.tv_sec = MIN(delay2, delay);
+ wait.tv_usec = (delay == 0) ? 200000 : 0;
+#if ! USE_POLL
+ nfds = select(highfd + 1, (SELECT_FDSET_TYPE *)&read_set,
+ (SELECT_FDSET_TYPE *)&write_set, 0, &wait);
+#else
+ nfds = poll( poll_fdarray, nbr_pfds,
+ wait.tv_sec * 1000 + wait.tv_usec/1000 );
+#endif
+ ret = nfds;
+ if (nfds == -1 && errno == EINTR)
+ return -1;
+ else if (nfds >= 0)
+ break;
+#if ! USE_POLL
+ report_error("select %s:%s", &me);
+#else
+ report_error("poll %s:%s", &me);
+#endif
+ res++;
+ if (res > 5)
+ restart("too many select()/poll() errors");
+ sleep(10);
+ timeofday = time(NULL);
+ } /* for(res=0;;) */
+
+ timeofday = time(NULL);
+ if (nfds > 0 &&
+#if ! USE_POLL
+ resfd >= 0 &&
+#else
+ (pfd = res_pfd) &&
+#endif
+ TST_READ_EVENT(resfd))
+ {
+ CLR_READ_EVENT(resfd);
+ nfds--;
+ do_dns_async();
+ }
+ if (nfds > 0 &&
+#if ! USE_POLL
+ udpfd >= 0 &&
+#else
+ (pfd = udp_pfd) &&
+#endif
+ TST_READ_EVENT(udpfd))
+ {
+ CLR_READ_EVENT(udpfd);
+ nfds--;
+ polludp();
+ }
+#if defined(USE_IAUTH)
+ if (nfds > 0 &&
+# if ! USE_POLL
+ adfd >= 0 &&
+# else
+ (pfd = ad_pfd) &&
+# endif
+ TST_READ_EVENT(adfd))
+ {
+ CLR_READ_EVENT(adfd);
+ nfds--;
+ read_iauth();
+ }
+#endif
+
+#if ! USE_POLL
+ for (i = fdp->highest; i >= 0; i--)
+#else
+ for (pfd = poll_fdarray, i = 0; i < nbr_pfds; i++, pfd++ )
+#endif
+ {
+#if ! USE_POLL
+ if (!(cptr = local[fd = fdp->fd[i]]))
+ continue;
+#else
+ fd = pfd->fd;
+ if ((cptr = authclnts[fd]))
+ {
+#endif
+ /*
+ * check for the auth fd's
+ */
+ if (auth > 0 && nfds > 0
+#if ! USE_POLL
+ && cptr->authfd >= 0
+#endif
+ )
+ {
+ auth--;
+ if (TST_WRITE_EVENT(cptr->authfd))
+ {
+ nfds--;
+ send_authports(cptr);
+ }
+ else if (TST_READ_EVENT(cptr->authfd))
+ {
+ nfds--;
+ read_authports(cptr);
+ }
+ continue;
+ }
+#if USE_POLL
+ }
+ fd = pfd->fd;
+ if (!(cptr = local[fd]))
+ continue;
+#else
+ fd = cptr->fd;
+#endif
+ /*
+ * accept connections
+ */
+ if (TST_READ_EVENT(fd) && IsListening(cptr))
+ {
+ CLR_READ_EVENT(fd);
+ cptr->lasttime = timeofday;
+ read_listener(cptr);
+ continue;
+ }
+ if (IsMe(cptr))
+ continue;
+ if (TST_WRITE_EVENT(fd))
+ {
+ int write_err = 0;
+ /*
+ ** ...room for writing, empty some queue then...
+ */
+ if (IsConnecting(cptr))
+ write_err = completed_connection(cptr);
+ if (!write_err)
+ (void)send_queued(cptr);
+ if (IsDead(cptr) || write_err)
+ {
+deadsocket:
+ if (TST_READ_EVENT(fd))
+ CLR_READ_EVENT(fd);
+ cptr->exitc = EXITC_ERROR;
+ (void)exit_client(cptr, cptr, &me,
+ strerror(get_sockerr(cptr)));
+ continue;
+ }
+ }
+ length = 1; /* for fall through case */
+ if (!NoNewLine(cptr) || TST_READ_EVENT(fd))
+ {
+ if (!DoingAuth(cptr))
+ length = read_packet(cptr, TST_READ_EVENT(fd));
+ }
+ readcalls++;
+ if (length == FLUSH_BUFFER)
+ continue;
+ else if (length > 0)
+ flush_connections(cptr->fd);
+ if (IsDead(cptr))
+ goto deadsocket;
+ if (length > 0)
+ continue;
+
+ /* Ghost! Unknown users are tagged in parse() since 2.9.
+ * Let's not drop the uplink but just the ghost's message.
+ */
+ if (length == -3)
+ continue;
+
+ /*
+ ** NB: This following section has been modified to *expect*
+ ** cptr to be valid (ie if (length == FLUSH_BUFFER) is
+ ** above and stays there). - avalon 24/9/94
+ */
+ /*
+ ** ...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",
+ cptr->fd, errno, length));
+
+ if (IsServer(cptr) || IsHandshake(cptr))
+ {
+ int timeconnected = timeofday - cptr->firsttime;
+
+ if (length == 0)
+ sendto_flag(SCH_NOTICE,
+ "Server %s closed the connection (%d, %2d:%02d:%02d)",
+ get_client_name(cptr, FALSE),
+ timeconnected / 86400,
+ (timeconnected % 86400) / 3600,
+ (timeconnected % 3600)/60,
+ timeconnected % 60);
+ else /* this must be for -1 */
+ {
+ report_error("Lost connection to %s:%s",cptr);
+ sendto_flag(SCH_NOTICE,
+ "%s had been connected for %d, %2d:%02d:%02d",
+ get_client_name(cptr, FALSE),
+ timeconnected / 86400,
+ (timeconnected % 86400) / 3600,
+ (timeconnected % 3600)/60,
+ timeconnected % 60);
+ if (hold_server(cptr) == 0)
+ continue;
+ }
+ }
+ (void)exit_client(cptr, cptr, &me, length >= 0 ?
+ "EOF From client" :
+ strerror(get_sockerr(cptr)));
+ } /* for(i) */
+ return ret;
+}
+
+/*
+ * connect_server
+ */
+int connect_server(aconf, by, hp)
+aConfItem *aconf;
+aClient *by;
+struct hostent *hp;
+{
+ Reg struct SOCKADDR *svp;
+ Reg aClient *cptr, *c2ptr;
+ Reg char *s;
+ int i, len;
+
+#ifdef INET6
+ Debug((DEBUG_NOTICE,"Connect to %s[%s] @%s",
+ aconf->name, aconf->host,
+ inet_ntop(AF_INET6, (char *)&aconf->ipnum, mydummy,
+ MYDUMMY_SIZE)));
+#else
+ Debug((DEBUG_NOTICE,"Connect to %s[%s] @%s",
+ aconf->name, aconf->host,
+ inetntoa((char *)&aconf->ipnum)));
+#endif
+
+ if ((c2ptr = find_server(aconf->name, NULL)))
+ {
+ sendto_flag(SCH_NOTICE, "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, by->name, aconf->name,
+ get_client_name(c2ptr, TRUE));
+ return -1;
+ }
+
+ /*
+ * If we don't know the IP# for this host and it is a hostname and
+ * not a ip# string, then try and find the appropriate host record.
+ */
+ if (!aconf->ipnum.S_ADDR && *aconf->host != '/')
+ {
+ Link lin;
+
+ lin.flags = ASYNC_CONNECT;
+ lin.value.aconf = aconf;
+ nextdnscheck = 1;
+ s = (char *)index(aconf->host, '@');
+ s++; /* should NEVER be NULL */
+#ifdef INET6
+ if (!inet_pton(AF_INET6, s, aconf->ipnum.s6_addr))
+#else
+ if ((aconf->ipnum.s_addr = inetaddr(s)) == -1)
+#endif
+ {
+#ifdef INET6
+ bzero(aconf->ipnum.s6_addr, IN6ADDRSZ);
+#else
+ aconf->ipnum.s_addr = 0;
+#endif
+ 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);
+ 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);
+
+#ifdef UNIXPORT
+ if (*aconf->host == '/') /* (/ starts a 2), Unix domain -- dl*/
+ svp = connect_unix(aconf, cptr, &len);
+ else
+ svp = connect_inet(aconf, cptr, &len);
+#else
+ svp = connect_inet(aconf, cptr, &len);
+#endif
+
+ if (!svp)
+ {
+ if (cptr->fd != -1)
+ (void)close(cptr->fd);
+ cptr->fd = -2;
+ free_client(cptr);
+ return -1;
+ }
+
+ set_non_blocking(cptr->fd, cptr);
+ (void)set_sock_opts(cptr->fd, cptr);
+ (void)signal(SIGALRM, dummy);
+ (void)alarm(4);
+ if (connect(cptr->fd, (SAP)svp, len) < 0 && errno != EINPROGRESS)
+ {
+ i = errno; /* other system calls may eat errno */
+ (void)alarm(0);
+ 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, by->name, cptr);
+ (void)close(cptr->fd);
+ cptr->fd = -2;
+ free_client(cptr);
+ errno = i;
+ if (errno == EINTR)
+ errno = ETIMEDOUT;
+ return -1;
+ }
+ (void)alarm(0);
+
+ /* Attach config entries to client here rather than in
+ * completed_connection. This to avoid null pointer references
+ * when name returned by gethostbyaddr matches no C lines
+ * (could happen in 2.6.1a when host and servername differ).
+ * No need to check access and do gethostbyaddr calls.
+ * There must at least be one as we got here C line... meLazy
+ */
+ (void)attach_confs_host(cptr, aconf->host, CFLAG|NFLAG);
+
+ if (!find_conf_host(cptr->confs, aconf->host, NFLAG) ||
+ !find_conf_host(cptr->confs, aconf->host, CFLAG))
+ {
+ sendto_flag(SCH_NOTICE,
+ "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, 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);
+ cptr->serv->user = by->user;
+ by->user->refcnt++;
+ }
+ else
+ (void)strcpy(cptr->serv->by, "AutoConn.");
+ cptr->serv->up = ME;
+ cptr->serv->nline = aconf;
+ if (cptr->fd > highest_fd)
+ highest_fd = cptr->fd;
+ add_fd(cptr->fd, &fdall);
+ local[cptr->fd] = cptr;
+ cptr->acpt = &me;
+ SetConnecting(cptr);
+
+ get_sockhost(cptr, aconf->host);
+ add_client_to_list(cptr);
+ nextping = timeofday;
+ istat.is_unknown++;
+
+ return 0;
+}
+
+static struct SOCKADDR *connect_inet(aconf, cptr, lenp)
+Reg aConfItem *aconf;
+Reg aClient *cptr;
+int *lenp;
+{
+ static struct SOCKADDR_IN server;
+ Reg struct hostent *hp;
+ aClient *acptr;
+ int i;
+
+ /*
+ * Might as well get sockhost from here, the connection is attempted
+ * with it so if it fails its useless.
+ */
+ cptr->fd = socket(AFINET, SOCK_STREAM, 0);
+ if (cptr->fd >= MAXCLIENTS)
+ {
+ sendto_flag(SCH_NOTICE,
+ "No more connections allowed (%s)", cptr->name);
+ return NULL;
+ }
+ mysk.SIN_PORT = 0;
+ bzero((char *)&server, sizeof(server));
+ server.SIN_FAMILY = AFINET;
+ get_sockhost(cptr, aconf->host);
+
+ if (cptr->fd == -1)
+ {
+ report_error("opening stream socket to server %s:%s", cptr);
+ return NULL;
+ }
+ /*
+ ** 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#.
+ ** With VIFs, M:line defines outgoing IP# and initialises mysk.
+ */
+ if (bind(cptr->fd, (SAP)&mysk, sizeof(mysk)) == -1)
+ {
+ report_error("error binding to local port for %s:%s", cptr);
+ return NULL;
+ }
+ /*
+ * 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 don't know it, then the connect fails.
+ */
+#ifdef INET6
+ if (isdigit(*aconf->host) && (AND16(aconf->ipnum.s6_addr) == 255))
+ if (!inet_pton(AF_INET6, aconf->host,aconf->ipnum.s6_addr))
+ bcopy(minus_one, aconf->ipnum.s6_addr, IN6ADDRSZ);
+ if (AND16(aconf->ipnum.s6_addr) == 255)
+#else
+ if (isdigit(*aconf->host) && (aconf->ipnum.s_addr == -1))
+ aconf->ipnum.s_addr = inetaddr(aconf->host);
+ if (aconf->ipnum.s_addr == -1)
+#endif
+ {
+ 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));
+ cptr->port = (aconf->port > 0) ? aconf->port : portnum;
+ server.SIN_PORT = htons(cptr->port);
+ /*
+ * Look for a duplicate IP#,port pair among already open connections
+ * (This caters for unestablished connections).
+ */
+ for (i = highest_fd; i >= 0; i--)
+ if ((acptr = local[i]) &&
+ !bcmp((char *)&cptr->ip, (char *)&acptr->ip,
+ sizeof(cptr->ip)) && server.SIN_PORT == acptr->port)
+ return NULL;
+ *lenp = sizeof(server);
+ return (struct SOCKADDR *)&server;
+}
+
+#ifdef UNIXPORT
+/* connect_unix
+ *
+ * Build a socket structure for cptr so that it can connet to the unix
+ * socket defined by the conf structure aconf.
+ */
+static struct SOCKADDR *connect_unix(aconf, cptr, lenp)
+aConfItem *aconf;
+aClient *cptr;
+int *lenp;
+{
+ static struct sockaddr_un sock;
+
+ if ((cptr->fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+ {
+ report_error("Unix domain connect to host %s failed: %s", cptr);
+ return NULL;
+ }
+ else if (cptr->fd >= MAXCLIENTS)
+ {
+ sendto_flag(SCH_NOTICE,
+ "No more connections allowed (%s)", cptr->name);
+ return NULL;
+ }
+
+ get_sockhost(cptr, aconf->host);
+ strncpyzt(sock.sun_path, aconf->host + 2, sizeof(sock.sun_path));
+ sock.sun_family = AF_UNIX;
+ *lenp = strlen(sock.sun_path) + 2;
+
+ SetUnixSock(cptr);
+ return (struct sockaddr *)&sock;
+}
+#endif
+
+/*
+ * The following section of code performs summoning of users to irc.
+ */
+#if defined(ENABLE_SUMMON) || defined(ENABLE_USERS)
+int utmp_open()
+{
+#ifdef O_NOCTTY
+ return (open(UTMP, O_RDONLY|O_NOCTTY));
+#else
+ return (open(UTMP, O_RDONLY));
+#endif
+}
+
+int utmp_read(fd, name, line, host, hlen)
+int fd, hlen;
+char *name, *line, *host;
+{
+ struct utmp ut;
+ while (read(fd, (char *)&ut, sizeof (struct utmp))
+ == sizeof (struct utmp))
+ {
+ strncpyzt(name, ut.ut_name, 9);
+ strncpyzt(line, ut.ut_line, 10);
+#ifdef USER_PROCESS
+# if defined(HPUX) || defined(AIX)
+ strncpyzt(host,(ut.ut_host[0]) ? (ut.ut_host) : ME, 16);
+# else
+ strncpyzt(host, ME, 9);
+# endif
+ if (ut.ut_type == USER_PROCESS)
+ return 0;
+#else
+ strncpyzt(host, (ut.ut_host[0]) ? (ut.ut_host) : ME,
+ hlen);
+ if (ut.ut_name[0])
+ return 0;
+#endif
+ }
+ return -1;
+}
+
+int utmp_close(fd)
+int fd;
+{
+ return(close(fd));
+}
+
+#ifdef ENABLE_SUMMON
+void summon(who, namebuf, linebuf, chname)
+aClient *who;
+char *namebuf, *linebuf, *chname;
+{
+ static char wrerr[] = "NOTICE %s :Write error. Couldn't summon.";
+ int fd;
+ char line[120];
+ struct tm *tp;
+
+ tp = localtime(&timeofday);
+ if (strlen(linebuf) > (size_t) 9)
+ {
+ sendto_one(who,"NOTICE %s :Serious fault in SUMMON.",
+ who->name);
+ sendto_one(who,
+ "NOTICE %s :linebuf too long. Inform Administrator",
+ who->name);
+ return;
+ }
+ /*
+ * Following line added to prevent cracking to e.g. /dev/kmem if
+ * UTMP is for some silly reason writable to everyone...
+ */
+ if ((linebuf[0] != 't' || linebuf[1] != 't' || linebuf[2] != 'y')
+ && (linebuf[0] != 'c' || linebuf[1] != 'o' || linebuf[2] != 'n')
+#ifdef HPUX
+ && (linebuf[0] != 'p' || linebuf[1] != 't' || linebuf[2] != 'y' ||
+ linebuf[3] != '/')
+#endif
+ )
+ {
+ sendto_one(who,
+ "NOTICE %s :Looks like mere mortal souls are trying to",
+ who->name);
+ sendto_one(who,"NOTICE %s :enter the twilight zone... ",
+ who->name);
+ Debug((0, "%s (%s@%s, nick %s, %s)",
+ "FATAL: major security hack. Notify Administrator !",
+ who->username, who->user->host,
+ who->name, who->info));
+ return;
+ }
+
+ SPRINTF(line,"/dev/%s", linebuf);
+ (void)alarm(5);
+#ifdef O_NOCTTY
+ if ((fd = open(line, O_WRONLY | O_NDELAY | O_NOCTTY)) == -1)
+#else
+ if ((fd = open(line, O_WRONLY | O_NDELAY)) == -1)
+#endif
+ {
+ (void)alarm(0);
+ sendto_one(who,
+ "NOTICE %s :%s seems to have disabled summoning...",
+ who->name, namebuf);
+ return;
+ }
+#if !defined(O_NOCTTY) && defined(TIOCNOTTY)
+ (void)ioctl(fd, TIOCNOTTY, NULL);
+#endif
+ (void)alarm(0);
+ (void)sprintf(line,"\n\r\007Message from IRC_Daemon@%s at %d:%02d\n\r",
+ ME, tp->tm_hour, tp->tm_min);
+ if (write(fd, line, strlen(line)) != strlen(line))
+ {
+ (void)alarm(0);
+ (void)close(fd);
+ sendto_one(who, wrerr, who->name);
+ return;
+ }
+ (void)alarm(0);
+ (void)strcpy(line, "ircd: You are being summoned to Internet Relay \
+Chat on\n\r");
+ (void)alarm(5);
+ if (write(fd, line, strlen(line)) != strlen(line))
+ {
+ (void)alarm(0);
+ (void)close(fd);
+ sendto_one(who, wrerr, who->name);
+ return;
+ }
+ (void)alarm(0);
+ SPRINTF(line, "ircd: Channel %s, by %s@%s (%s) %s\n\r", chname,
+ who->user->username, who->user->host, who->name, who->info);
+ (void)alarm(5);
+ if (write(fd, line, strlen(line)) != strlen(line))
+ {
+ (void)alarm(0);
+ (void)close(fd);
+ sendto_one(who, wrerr, who->name);
+ return;
+ }
+ (void)alarm(0);
+ (void)strcpy(line,"ircd: Respond with irc\n\r");
+ (void)alarm(5);
+ if (write(fd, line, strlen(line)) != strlen(line))
+ {
+ (void)alarm(0);
+ (void)close(fd);
+ sendto_one(who, wrerr, who->name);
+ return;
+ }
+ (void)close(fd);
+ (void)alarm(0);
+ sendto_one(who, rpl_str(RPL_SUMMONING, who->name), namebuf);
+ return;
+}
+# endif
+#endif /* ENABLE_SUMMON */
+
+/*
+** find the real hostname for the host running the server (or one which
+** matches the server's name) and its primary IP#. Hostname is stored
+** in the client structure passed as a pointer.
+*/
+void get_my_name(cptr, name, len)
+aClient *cptr;
+char *name;
+int len;
+{
+ static char tmp[HOSTLEN+1];
+ struct hostent *hp;
+ char *cname = cptr->name;
+ aConfItem *aconf;
+
+ /*
+ ** Setup local socket structure to use for binding to.
+ */
+ bzero((char *)&mysk, sizeof(mysk));
+ mysk.SIN_FAMILY = AFINET;
+
+ if ((aconf = find_me())->passwd && isdigit(*aconf->passwd))
+#ifdef INET6
+ if(!inet_pton(AF_INET6, aconf->passwd, mysk.sin6_addr.s6_addr))
+ bcopy(minus_one, mysk.sin6_addr.s6_addr, IN6ADDRSZ);
+#else
+ mysk.sin_addr.s_addr = inetaddr(aconf->passwd);
+#endif
+
+ if (gethostname(name, len) == -1)
+ return;
+ name[len] = '\0';
+
+ /* assume that a name containing '.' is a FQDN */
+ if (!index(name,'.'))
+ add_local_domain(name, len - strlen(name));
+
+ /*
+ ** If hostname gives another name than cname, then check if there is
+ ** a CNAME record for cname pointing to hostname. If so accept
+ ** cname as our name. meLazy
+ */
+ if (BadPtr(cname))
+ return;
+ if ((hp = gethostbyname(cname)) || (hp = gethostbyname(name)))
+ {
+ char *hname;
+ int i = 0;
+
+ for (hname = hp->h_name; hname; hname = hp->h_aliases[i++])
+ {
+ strncpyzt(tmp, hname, sizeof(tmp));
+ add_local_domain(tmp, sizeof(tmp) - strlen(tmp));
+
+ /*
+ ** Copy the matching name over and store the
+ ** 'primary' IP# as 'myip' which is used
+ ** later for making the right one is used
+ ** for connecting to other hosts.
+ */
+ if (!mycmp(ME, tmp))
+ break;
+ }
+ if (mycmp(ME, tmp))
+ strncpyzt(name, hp->h_name, len);
+ else
+ strncpyzt(name, tmp, len);
+ if (!aconf->passwd)
+ bcopy(hp->h_addr, (char *)&mysk.SIN_ADDR,
+ sizeof(struct IN_ADDR));
+ Debug((DEBUG_DEBUG,"local name is %s",
+ get_client_name(&me,TRUE)));
+ }
+ return;
+}
+
+/*
+** setup a UDP socket and listen for incoming packets
+*/
+int setup_ping(aconf)
+aConfItem *aconf;
+{
+ struct SOCKADDR_IN from;
+ int on = 1;
+
+ if (udpfd != -1)
+ return udpfd;
+ bzero((char *)&from, sizeof(from));
+ if (aconf->passwd && isdigit(*aconf->passwd))
+#ifdef INET6
+ if(!inet_pton(AF_INET6, aconf->passwd,from.sin6_addr.s6_addr))
+ bcopy(minus_one, from.sin6_addr.s6_addr, IN6ADDRSZ);
+#else
+ from.sin_addr.s_addr = inetaddr(aconf->passwd);
+#endif
+ else
+#ifdef INET6
+ from.SIN_ADDR = in6addr_any;
+#else
+ from.sin_addr.s_addr = htonl(INADDR_ANY); /* hmmpf */
+#endif
+ from.SIN_PORT = htons((u_short) aconf->port);
+ from.SIN_FAMILY = AFINET;
+
+ if ((udpfd = socket(AFINET, SOCK_DGRAM, 0)) == -1)
+ {
+ Debug((DEBUG_ERROR, "socket udp : %s", strerror(errno)));
+ return -1;
+ }
+ if (SETSOCKOPT(udpfd, SOL_SOCKET, SO_REUSEADDR, &on, 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);
+ return udpfd = -1;
+ }
+ on = 0;
+ (void) SETSOCKOPT(udpfd, SOL_SOCKET, SO_BROADCAST, &on, on);
+ if (bind(udpfd, (SAP)&from, sizeof(from))==-1)
+ {
+#ifdef USE_SYSLOG
+ syslog(LOG_ERR, "bind udp.%d fd %d : %m",
+ ntohs(from.SIN_PORT), udpfd);
+#endif
+ Debug((DEBUG_ERROR, "bind : %s", strerror(errno)));
+ (void)close(udpfd);
+ return udpfd = -1;
+ }
+ if (fcntl(udpfd, F_SETFL, FNDELAY)==-1)
+ {
+ Debug((DEBUG_ERROR, "fcntl fndelay : %s", strerror(errno)));
+ (void)close(udpfd);
+ return udpfd = -1;
+ }
+ Debug((DEBUG_INFO, "udpfd = %d, port %d", udpfd,ntohs(from.SIN_PORT)));
+ return udpfd;
+}
+
+
+void send_ping(aconf)
+aConfItem *aconf;
+{
+ Ping pi;
+ struct SOCKADDR_IN sin;
+ aCPing *cp = aconf->ping;
+
+#ifdef INET6
+ if (!aconf->ipnum.s6_addr || AND16(aconf->ipnum.s6_addr) == 255 || !cp->port)
+#else
+ if (!aconf->ipnum.s_addr || aconf->ipnum.s_addr == -1 || !cp->port)
+#endif
+ return;
+ if (aconf->class->conFreq == 0) /* avoid flooding */
+ return;
+ pi.pi_cp = aconf;
+ pi.pi_id = htonl(PING_CPING);
+ pi.pi_seq = cp->lseq++;
+ cp->seq++;
+ /*
+ * Only recognise stats from the last 20 minutes as significant...
+ * Try and fake sliding along a "window" here.
+ */
+ if (cp->seq > 1 && cp->seq * aconf->class->conFreq > 1200)
+ {
+ if (cp->recvd)
+ {
+ cp->ping -= (cp->ping / cp->recvd);
+ if (cp->recvd == cp->seq)
+ cp->recvd--;
+ }
+ else
+ cp->ping = 0;
+ cp->seq--;
+ }
+
+ bzero((char *)&sin, sizeof(sin));
+#ifdef INET6
+ bcopy(aconf->ipnum.s6_addr, sin.sin6_addr.s6_addr, IN6ADDRSZ);
+#else
+ sin.sin_addr.s_addr = aconf->ipnum.s_addr;
+#endif
+ sin.SIN_PORT = htons(cp->port);
+ sin.SIN_FAMILY = AFINET;
+ (void)gettimeofday(&pi.pi_tv, NULL);
+#ifdef INET6
+ Debug((DEBUG_SEND,"Send ping to %s,%d fd %d, %d bytes",
+ inet_ntop(AF_INET6, (char *)&aconf->ipnum,mydummy,MYDUMMY_SIZE),
+ cp->port, udpfd, sizeof(pi)));
+#else
+ Debug((DEBUG_SEND,"Send ping to %s,%d fd %d, %d bytes",
+ inetntoa((char *)&aconf->ipnum),
+ cp->port, udpfd, sizeof(pi)));
+#endif
+ (void)sendto(udpfd, (char *)&pi, sizeof(pi), 0,(SAP)&sin,sizeof(sin));
+}
+
+static int check_ping(buf, len)
+char *buf;
+int len;
+{
+ Ping pi;
+ aConfItem *aconf;
+ struct timeval tv;
+ double d;
+ aCPing *cp = NULL;
+ u_long rtt;
+
+ (void)gettimeofday(&tv, NULL);
+
+ if (len < sizeof(pi) + 8)
+ return -1;
+
+ bcopy(buf, (char *)&pi, sizeof(pi)); /* ensure nice byte align. */
+
+ for (aconf = conf; aconf; aconf = aconf->next)
+ if (pi.pi_cp == aconf && (cp = aconf->ping))
+ break;
+ if (!aconf || match(aconf->name, buf + sizeof(pi)))
+ return -1;
+
+ cp->recvd++;
+ cp->lrecvd++;
+ rtt = ((tv.tv_sec - pi.pi_tv.tv_sec) * 1000 +
+ (tv.tv_usec - pi.pi_tv.tv_usec) / 1000);
+ cp->ping += rtt;
+ cp->rtt += rtt;
+ if (cp->rtt > 1000000)
+ {
+ cp->ping = (cp->rtt /= cp->lrecvd);
+ cp->recvd = cp->lrecvd = 1;
+ cp->seq = cp->lseq = 1;
+ }
+ d = (double)cp->recvd / (double)cp->seq;
+ d = pow(d, (double)20.0);
+ d = (double)cp->ping / (double)cp->recvd / d;
+ if (d > 10000.0)
+ d = 10000.0;
+ aconf->pref = (int) (d * 100.0);
+
+ return 0;
+}
+
+/*
+ * max # of pings set to 15/sec.
+ */
+static void polludp()
+{
+ static time_t last = 0;
+ static int cnt = 0, mlen = 0, lasterr = 0;
+ Reg char *s;
+ struct SOCKADDR_IN from;
+ Ping pi;
+ int n;
+ SOCK_LEN_TYPE fromlen = sizeof(from);
+
+ /*
+ * find max length of data area of packet.
+ */
+ if (!mlen)
+ {
+ mlen = sizeof(readbuf) - strlen(ME) - strlen(version);
+ mlen -= 6;
+ if (mlen < 0)
+ mlen = 0;
+ }
+ Debug((DEBUG_DEBUG,"udp poll"));
+
+ n = recvfrom(udpfd, readbuf, mlen, 0, (SAP)&from, &fromlen);
+ if (n == -1)
+ {
+ ircstp->is_udperr++;
+ if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
+ return;
+ else
+ {
+ report_error("udp port recvfrom (%s): %s", &me);
+ return;
+ }
+ }
+
+ if (timeofday == last)
+ {
+ if (++cnt > 14)
+ {
+ if (timeofday > lasterr + 30)
+ {
+ sendto_flag(SCH_NOTICE,
+ "udp packet dropped: %d bytes from %s.%d",
+#ifdef INET6
+ n, inetntop(AF_INET6,
+ (char *)&from.sin6_addr, mydummy,
+ MYDUMMY_SIZE),
+#else
+ n,inetntoa((char *)&from.sin_addr),
+#endif
+ ntohs(from.SIN_PORT));
+ lasterr = timeofday;
+ }
+ ircstp->is_udpdrop++;
+ return;
+ }
+ }
+ else
+ cnt = 0, last = timeofday;
+
+#ifdef INET6
+ Debug((DEBUG_NOTICE, "udp (%d) %d bytes from %s,%d", cnt, n,
+ inet_ntop(AF_INET6, (char *)&from.sin6_addr, mydummy,
+ MYDUMMY_SIZE),
+ ntohs(from.SIN_PORT)));
+#else
+ Debug((DEBUG_NOTICE, "udp (%d) %d bytes from %s,%d", cnt, n,
+ inetntoa((char *)&from.sin_addr),
+ ntohs(from.SIN_PORT)));
+#endif
+
+ readbuf[n] = '\0';
+ ircstp->is_udpok++;
+ if (n < 8)
+ return;
+
+ bcopy(s = readbuf, (char *)&pi, MIN(n, sizeof(pi)));
+ pi.pi_id = ntohl(pi.pi_id);
+ Debug((DEBUG_INFO, "\tpi_id %#x pi_seq %d pi_cp %#x",
+ pi.pi_id, pi.pi_seq, pi.pi_cp));
+
+ if ((pi.pi_id == (PING_CPING|PING_REPLY) ||
+ pi.pi_id == (PING_CPING|(PING_REPLY << 24))) && n >= sizeof(pi))
+ {
+ check_ping(s, n);
+ return;
+ }
+ else if (pi.pi_id & PING_REPLY)
+ return;
+ /*
+ * attach my name and version for the reply
+ */
+ pi.pi_id |= PING_REPLY;
+ pi.pi_id = htonl(pi.pi_id);
+ bcopy((char *)&pi, s, MIN(n, sizeof(pi)));
+ s += n;
+ (void)strcpy(s, ME);
+ s += strlen(s)+1;
+ (void)strcpy(s, version);
+ s += strlen(s);
+ (void)sendto(udpfd, readbuf, s-readbuf, 0, (SAP)&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;
+ int bytes, pkts;
+
+ pkts = 0;
+
+ do {
+ ln.flags = -1;
+ hp = get_res((char *)&ln);
+
+ 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);
+ ClearDNS(cptr);
+ cptr->hostp = hp;
+#if defined(USE_IAUTH)
+ if (hp)
+ {
+ int i = 0;
+
+ while (hp->h_aliases[i])
+ sendto_iauth("%d A %s",
+ cptr->fd,
+ hp->h_aliases[i++]);
+ if (hp->h_name)
+ sendto_iauth("%d N %s",
+ cptr->fd, hp->h_name);
+ else if (hp->h_aliases[0])
+ sendto_iauth("%d n", cptr->fd);
+ }
+ else
+ sendto_iauth("%d d", cptr->fd);
+ if (iauth_options & XOPT_EXTWAIT)
+ cptr->lasttime = timeofday;
+#endif
+ }
+ 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_flag(SCH_ERROR,
+ "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;
+ default :
+ break;
+ }
+ pkts++;
+ if (ioctl(resfd, FIONREAD, &bytes) == -1)
+ bytes = 0;
+ } while ((bytes > 0) && (pkts < 10));
+}
diff --git a/ircd/s_bsd_ext.h b/ircd/s_bsd_ext.h
new file mode 100644
index 0000000..6209e8e
--- /dev/null
+++ b/ircd/s_bsd_ext.h
@@ -0,0 +1,77 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/s_bsd_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in ircd/s_bsd.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef S_BSD_C
+extern aClient *local[];
+extern FdAry fdas, fdaa, fdall;
+extern int highest_fd, readcalls, udpfd, resfd, adfd;
+extern time_t timeofday;
+#endif /* S_BSD_C */
+
+/* External definitions for global functions.
+ */
+#ifndef S_BSD_C
+#define EXTERN extern
+#else /* S_BSD_C */
+#define EXTERN
+#endif /* S_BSD_C */
+EXTERN void add_local_domain __P((char *hname, int size));
+EXTERN void report_error __P((char *text, aClient *cptr));
+EXTERN int inetport __P((aClient *cptr, char *ip, char *ipmask, int port));
+EXTERN int add_listener __P((aConfItem *aconf));
+EXTERN void close_listeners();
+EXTERN void start_iauth __P((int));
+EXTERN void init_sys();
+EXTERN void write_pidfile();
+EXTERN int check_client __P((Reg aClient *cptr));
+EXTERN int check_server_init __P((aClient *cptr));
+EXTERN int check_server __P((aClient *cptr, Reg struct hostent *hp,
+ Reg aConfItem *c_conf, Reg aConfItem *n_conf,
+ int estab));
+EXTERN int hold_server __P((aClient *cptr));
+EXTERN void close_connection __P((aClient *cptr));
+EXTERN int get_sockerr __P((aClient *cptr));
+EXTERN void set_non_blocking __P((int fd, aClient *cptr));
+EXTERN aClient *add_connection __P((aClient *cptr, int fd));
+EXTERN int read_message __P((time_t delay, FdAry *fdp, int ro));
+EXTERN int connect_server __P((aConfItem *aconf, aClient *by,
+ struct hostent *hp));
+EXTERN void get_my_name __P((aClient *cptr, char *name, int len));
+EXTERN int setup_ping __P((aConfItem *aconf));
+EXTERN void send_ping __P((aConfItem *aconf));
+#if defined(ENABLE_SUMMON) || defined(ENABLE_USERS)
+EXTERN int utmp_open();
+EXTERN int utmp_read __P((int fd, char *name, char *line, char *host,
+ int hlen));
+EXTERN int utmp_close(int fd);
+#ifdef ENABLE_SUMMON
+EXTERN void summon __P((aClient *who, char *namebuf, char *linebuf,
+ char *chname));
+#endif /* ENABLE_SUMMON */
+#endif /* ENABLE_SUMMON || ENABLE_USERS */
+#ifdef UNIXPORT
+EXTERN int unixport __P((aClient *cptr, char *path, int port));
+#endif
+#undef EXTERN
diff --git a/ircd/s_conf.c b/ircd/s_conf.c
new file mode 100644
index 0000000..2abbbd3
--- /dev/null
+++ b/ircd/s_conf.c
@@ -0,0 +1,1684 @@
+/************************************************************************
+ * 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.
+ */
+
+/* -- avalon -- 20 Feb 1992
+ * Reversed the order of the params for attach_conf().
+ * detach_conf() and attach_conf() are now the same:
+ * function_conf(aClient *, aConfItem *)
+ */
+
+/* -- Jto -- 20 Jun 1990
+ * Added gruner's overnight fix..
+ */
+
+/* -- Jto -- 16 Jun 1990
+ * Moved matches to ../common/match.c
+ */
+
+/* -- Jto -- 03 Jun 1990
+ * Added Kill fixes from gruner@lan.informatik.tu-muenchen.de
+ * Added jarlek's msgbase fix (I still don't understand it... -- Jto)
+ */
+
+/* -- Jto -- 13 May 1990
+ * Added fixes from msa:
+ * Comments and return value to init_conf()
+ */
+
+/*
+ * -- Jto -- 12 May 1990
+ * Added close() into configuration file (was forgotten...)
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: s_conf.c,v 1.42 1999/05/01 21:29:13 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "s_defines.h"
+#define S_CONF_C
+#include "s_externs.h"
+#undef S_CONF_C
+
+static int check_time_interval __P((char *, char *));
+static int lookup_confhost __P((aConfItem *));
+
+aConfItem *conf = NULL;
+aConfItem *kconf = NULL;
+
+/*
+ * 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;
+{
+ Reg 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);
+ }
+}
+
+/*
+ * Match address by #IP bitmask (10.11.12.128/27)
+ */
+int match_ipmask(mask, cptr)
+char *mask;
+aClient *cptr;
+{
+ int i1, i2, i3, i4, m;
+ u_long lmask, baseip;
+ char *at;
+
+ if (at = index(mask, '@'))
+ mask = at + 1;
+ if (sscanf(mask, "%d.%d.%d.%d/%d", &i1, &i2, &i3, &i4, &m) != 5 ||
+ m < 1 || m > 31) {
+ sendto_flag(SCH_LOCAL, "Ignoring bad mask: %s", mask);
+ return -1;
+ }
+ lmask = htonl((u_long)0xffffffffL << (32 - m)); /* /24->0xffffff00ul */
+ baseip = htonl(i1 * 0x1000000 + i2 * 0x10000 + i3 * 0x100 + i4);
+#ifdef INET6
+ return 1;
+/* return ((cptr->ip.s6_addr & lmask) == baseip) ? 0 : 1;*/
+#else
+ return ((cptr->ip.s_addr & lmask) == baseip) ? 0 : 1;
+#endif
+}
+
+/*
+ * find the first (best) I line to attach.
+ */
+int attach_Iline(cptr, hp, sockhost)
+aClient *cptr;
+Reg struct hostent *hp;
+char *sockhost;
+{
+ Reg aConfItem *aconf;
+ Reg char *hname;
+ Reg 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) &&
+ (aconf->status != CONF_RCLIENT))
+ 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++])
+ {
+ strncpyzt(fullname, hname,
+ sizeof(fullname));
+ 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 (strchr(aconf->host, '/')) /* 1.2.3.0/24 */
+ {
+ if (match_ipmask(aconf->host, cptr))
+ continue;
+ } else if (match(aconf->host, uhost)) /* 1.2.3.* */
+ continue;
+ if (*aconf->name == '\0' && hp)
+ {
+ strncpyzt(uhost, hp->h_name, sizeof(uhost));
+ add_local_domain(uhost, sizeof(uhost) - strlen(uhost));
+ }
+attach_iline:
+ if (aconf->status & CONF_RCLIENT)
+ SetRestricted(cptr);
+ get_sockhost(cptr, uhost);
+ if ((i = attach_conf(cptr, aconf)) < -1)
+ find_bounce(cptr, ConfClass(aconf), -1);
+ return i;
+ }
+ find_bounce(cptr, 0, -2);
+ return -2; /* used in register_user() */
+}
+
+/*
+ * Find the single N line and return pointer to it (from list).
+ * If more than one then return NULL pointer.
+ */
+aConfItem *count_cnlines(lp)
+Reg Link *lp;
+{
+ Reg 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 ||
+ aconf->status == CONF_ZCONNECT_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;
+{
+ Reg 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);
+ istat.is_conflink--;
+ return 0;
+ }
+ else
+ lp = &((*lp)->next);
+ }
+ return -1;
+}
+
+static int is_attached(aconf, cptr)
+aConfItem *aconf;
+aClient *cptr;
+{
+ Reg 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;
+{
+ Reg Link *lp;
+
+ if (is_attached(aconf, cptr))
+ return 1;
+ if (IsIllegal(aconf))
+ return -1;
+ if ((aconf->status & (CONF_LOCOP | CONF_OPERATOR | CONF_CLIENT |
+ CONF_RCLIENT)))
+ {
+ if (aconf->clients >= ConfMaxLinks(aconf) &&
+ ConfMaxLinks(aconf) > 0)
+ return -3; /* Use this for printing error message */
+ }
+ if ((aconf->status & (CONF_CLIENT | CONF_RCLIENT)))
+ {
+ int hcnt = 0, ucnt = 0;
+
+ /* check on local/global limits per host and per user@host */
+
+ /*
+ ** local limits first to save CPU if any is hit.
+ ** host check is done on the IP address.
+ ** user check is done on the IDENT reply.
+ */
+ if (ConfMaxHLocal(aconf) > 0 || ConfMaxUHLocal(aconf) > 0) {
+ Reg aClient *acptr;
+ Reg int i;
+
+ for (i = highest_fd; i >= 0; i--)
+ if ((acptr = local[i]) && (cptr != acptr) &&
+ !IsListening(acptr) &&
+ !bcmp((char *)&cptr->ip,(char *)&acptr->ip,
+ sizeof(cptr->ip)))
+ {
+ hcnt++;
+ if (!strncasecmp(acptr->auth,
+ cptr->auth, USERLEN))
+ ucnt++;
+ }
+ if (ConfMaxHLocal(aconf) > 0 &&
+ hcnt >= ConfMaxHLocal(aconf))
+ return -4; /* for error message */
+ if (ConfMaxUHLocal(aconf) > 0 &&
+ ucnt >= ConfMaxUHLocal(aconf))
+ return -5; /* for error message */
+ }
+ /*
+ ** Global limits
+ ** host check is done on the hostname (IP if unresolved)
+ ** user check is done on username
+ */
+ if (ConfMaxHGlobal(aconf) > 0 || ConfMaxUHGlobal(aconf) > 0)
+ {
+ Reg aClient *acptr;
+ Reg int ghcnt = hcnt, gucnt = ucnt;
+
+ for (acptr = client; acptr; acptr = acptr->next)
+ {
+ if (!IsPerson(acptr))
+ continue;
+ if (MyConnect(acptr) &&
+ (ConfMaxHLocal(aconf) > 0 ||
+ ConfMaxUHLocal(aconf) > 0))
+ continue;
+ if (!strcmp(cptr->sockhost, acptr->user->host))
+ {
+ if (ConfMaxHGlobal(aconf) > 0 &&
+ ++ghcnt >= ConfMaxHGlobal(aconf))
+ return -6;
+ if (ConfMaxUHGlobal(aconf) > 0 &&
+ !strcmp(cptr->user->username,
+ acptr->user->username) &&
+ (++gucnt >=ConfMaxUHGlobal(aconf)))
+ return -7;
+ }
+ }
+ }
+ }
+
+ lp = make_link();
+ istat.is_conflink++;
+ 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()
+ {
+ Reg aConfItem *aconf;
+
+ for (aconf = conf; aconf; aconf = aconf->next)
+ if (aconf->status & CONF_ADMIN)
+ break;
+
+ return (aconf);
+ }
+
+aConfItem *find_me()
+ {
+ Reg 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;
+{
+ Reg 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;
+{
+ Reg 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;
+{
+ Reg aConfItem *tmp;
+ char userhost[USERLEN+HOSTLEN+3];
+
+ 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;
+{
+ Reg 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(lp, name, statmask)
+char *name;
+Link *lp;
+int statmask;
+{
+ Reg 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)
+Reg Link *lp;
+char *host;
+Reg int statmask;
+{
+ Reg 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;
+{
+ Reg aConfItem *tmp;
+ Reg 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;
+{
+ Reg 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;
+}
+
+/*
+ * 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;
+{
+ Reg aConfItem **tmp = &conf, *tmp2 = NULL;
+ Reg aClass *cltmp;
+ Reg aClient *acptr;
+ Reg int i;
+ int ret = 0;
+
+ if (sig == 1)
+ {
+ sendto_flag(SCH_NOTICE,
+ "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;
+#if defined(R_LINES_REHASH) && !defined(R_LINES_OFTEN)
+ if (find_restrict(acptr))
+ {
+ sendto_flag(SCH_NOTICE,
+ "Restricting %s, closing lp",
+ get_client_name(acptr,FALSE));
+ acptr->exitc = EXITC_RLINE;
+ if (exit_client(cptr,acptr,&me,"R-lined") ==
+ FLUSH_BUFFER)
+ ret = FLUSH_BUFFER;
+ }
+#endif
+ }
+
+ while ((tmp2 = *tmp))
+ if (tmp2->clients || tmp2->status & CONF_LISTEN_PORT)
+ {
+ /*
+ ** Configuration entry is still in use by some
+ ** local clients, cannot delete it--mark it so
+ ** that it will be deleted when the last client
+ ** exits...
+ */
+ if (!(tmp2->status & (CONF_LISTEN_PORT|CONF_CLIENT)))
+ {
+ *tmp = tmp2->next;
+ tmp2->next = NULL;
+ }
+ else
+ tmp = &tmp2->next;
+ tmp2->status |= CONF_ILLEGAL;
+ }
+ else
+ {
+ *tmp = tmp2->next;
+ free_conf(tmp2);
+ }
+
+ tmp = &kconf;
+ while ((tmp2 = *tmp))
+ {
+ *tmp = tmp2->next;
+ free_conf(tmp2);
+ }
+
+ /*
+ * We don't delete the class table, rather mark all entries
+ * for deletion. The table is cleaned up by check_class. - avalon
+ */
+ for (cltmp = NextClass(FirstClass()); cltmp; cltmp = NextClass(cltmp))
+ MaxLinks(cltmp) = -1;
+
+ if (sig != 2)
+ flush_cache();
+ (void) initconf(0);
+ 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);
+ }
+#ifdef CACHED_MOTD
+ read_motd(IRCDMOTD_PATH);
+#endif
+ rehashed = 1;
+ 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 the 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(vfork())
+ {
+ 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", IRCDM4_PATH, 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
+}
+
+/*
+** 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}};
+ Reg char *tmp, *s;
+ int fd, i;
+ char line[512], c[80], *tmp2 = NULL, *tmp3 = NULL, *tmp4 = NULL;
+ int ccount = 0, ncount = 0;
+ aConfItem *aconf = NULL;
+
+ Debug((DEBUG_DEBUG, "initconf(): ircd.conf = %s", configfile));
+ if ((fd = openconf()) == -1)
+ {
+#if defined(M4_PREPROC) && !defined(USE_IAUTH)
+ (void)wait(0);
+#endif
+ return -1;
+ }
+ (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
+ while ((i = dgets(fd, line, sizeof(line) - 1)) > 0)
+ {
+ line[i] = '\0';
+ if ((tmp = (char *)index(line, '\n')))
+ *tmp = 0;
+ else while(dgets(fd, c, sizeof(c) - 1) > 0)
+ if ((tmp = (char *)index(c, '\n')))
+ {
+ *tmp = 0;
+ break;
+ }
+ /*
+ * Do quoting of characters and # detection.
+ */
+ for (tmp = line; *tmp; tmp++)
+ {
+ if (*tmp == '\\')
+ {
+ for (i = 0; quotes[i][0]; i++)
+ if (quotes[i][0] == *(tmp+1))
+ {
+ *tmp = quotes[i][1];
+ break;
+ }
+ if (!quotes[i][0])
+ *tmp = *(tmp+1);
+ if (!*(tmp+1))
+ break;
+ else
+ for (s = tmp; (*s = *(s+1)); s++)
+ ;
+ }
+ else if (*tmp == '#')
+ {
+ *tmp = '\0';
+ break; /* Ignore the rest of the line */
+ }
+ }
+ 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] != IRCDCONF_DELIMITER)
+ {
+ Debug((DEBUG_ERROR, "Bad config line: %s", line));
+ continue;
+ }
+ if (aconf)
+ free_conf(aconf);
+ aconf = make_conf();
+
+ if (tmp2)
+ MyFree(tmp2);
+ tmp3 = tmp4 = NULL;
+ tmp = getfield(line);
+ if (!tmp)
+ continue;
+ switch (*tmp)
+ {
+ case 'A': /* Name, e-mail address of administrator */
+ case 'a': /* of this server. */
+ aconf->status = CONF_ADMIN;
+ break;
+ case 'B': /* Name of alternate servers */
+ case 'b':
+ aconf->status = CONF_BOUNCE;
+ break;
+ case 'C': /* Server where I should try to connect */
+ /* in case of lp failures */
+ ccount++;
+ aconf->status = CONF_CONNECT_SERVER;
+ break;
+ case 'c':
+ ccount++;
+ aconf->status = CONF_ZCONNECT_SERVER;
+ break;
+ case 'D': /* auto connect restrictions */
+ case 'd':
+ aconf->status = CONF_DENY;
+ break;
+ case 'H': /* Hub server line */
+ case 'h':
+ aconf->status = CONF_HUB;
+ break;
+ case 'I': /* Just plain normal irc client trying */
+ /* to connect me */
+ aconf->status = CONF_CLIENT;
+ break;
+ case 'i' : /* Restricted client */
+ aconf->status = CONF_RCLIENT;
+ break;
+ case 'K': /* Kill user line on irc.conf */
+ aconf->status = CONF_KILL;
+ break;
+ case 'k':
+ aconf->status = CONF_OTHERKILL;
+ break;
+ /* Operator. Line should contain at least */
+ /* password and host where connection is */
+ case 'L': /* guaranteed leaf server */
+ case 'l':
+ aconf->status = CONF_LEAF;
+ break;
+ /* Me. Host field is name used for this host */
+ /* and port number is the number of the port */
+ case 'M':
+ case 'm':
+ aconf->status = CONF_ME;
+ break;
+ case 'N': /* Server where I should NOT try to */
+ case 'n': /* connect in case of lp failures */
+ /* but which tries to connect ME */
+ ++ncount;
+ aconf->status = CONF_NOCONNECT_SERVER;
+ break;
+ case 'O':
+ aconf->status = CONF_OPERATOR;
+ break;
+ /* Local Operator, (limited privs --SRB) */
+ case 'o':
+ aconf->status = CONF_LOCOP;
+ break;
+ case 'P': /* listen port line */
+ case 'p':
+ aconf->status = CONF_LISTEN_PORT;
+ break;
+ case 'Q': /* a server that you don't want in your */
+ case 'q': /* network. USE WITH CAUTION! */
+ aconf->status = CONF_QUARANTINED_SERVER;
+ break;
+#ifdef R_LINES
+ case 'R': /* extended K line */
+ case 'r': /* Offers more options of how to restrict */
+ aconf->status = CONF_RESTRICT;
+ break;
+#endif
+ case 'S': /* Service. Same semantics as */
+ case 's': /* CONF_OPERATOR */
+ aconf->status = CONF_SERVICE;
+ break;
+#if 0
+ case 'U': /* Uphost, ie. host where client reading */
+ case 'u': /* this should connect. */
+ /* This is for client only, I must ignore this */
+ /* ...U-line should be removed... --msa */
+ break;
+#endif
+ case 'V': /* Server link version requirements */
+ aconf->status = CONF_VER;
+ break;
+ case 'Y':
+ case 'y':
+ aconf->status = CONF_CLASS;
+ break;
+ default:
+ Debug((DEBUG_ERROR, "Error in config file: %s", line));
+ break;
+ }
+ if (IsIllegal(aconf))
+ continue;
+
+ for (;;) /* Fake loop, that I can use break here --msa */
+ {
+ 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;
+ aconf->port = 0;
+ if (sscanf(tmp, "0x%x", &aconf->port) != 1 ||
+ aconf->port == 0)
+ aconf->port = atoi(tmp);
+ if (aconf->status == CONF_CONNECT_SERVER)
+ DupString(tmp2, tmp);
+ if (aconf->status == CONF_ZCONNECT_SERVER)
+ DupString(tmp2, tmp);
+ if ((tmp = getfield(NULL)) == NULL)
+ break;
+ Class(aconf) = find_class(atoi(tmp));
+ /* the following are only used for Y: */
+ if ((tmp3 = getfield(NULL)) == NULL)
+ break;
+ tmp4 = getfield(NULL);
+ break;
+ }
+ istat.is_confmem += aconf->host ? strlen(aconf->host)+1 : 0;
+ istat.is_confmem += aconf->passwd ? strlen(aconf->passwd)+1 :0;
+ istat.is_confmem += aconf->name ? strlen(aconf->name)+1 : 0;
+
+ /*
+ ** Bounce line fields are mandatory
+ */
+ if (aconf->status == CONF_BOUNCE && aconf->port == 0)
+ continue;
+ /*
+ ** 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 (atoi(aconf->host) >= 0)
+ add_class(atoi(aconf->host),
+ atoi(aconf->passwd),
+ atoi(aconf->name), aconf->port,
+ tmp ? atoi(tmp) : 0,
+/* tmp3 ? atoi(tmp3) : 0,
+** tmp3 && index(tmp3, '.') ?
+** atoi(index(tmp3, '.') + 1) : 0,
+** the next 3 lines should be replaced by the previous sometime in the
+** future. It is only kept for "backward" compatibility and not needed,
+** but I'm in good mood today -krys
+*/
+ tmp3 ? atoi(tmp3) : (atoi(aconf->name) > 0) ? atoi(aconf->name) : 0,
+ tmp3 && index(tmp3, '.') ?
+ atoi(index(tmp3, '.') + 1) : (atoi(aconf->name) < 0) ? -1 * atoi(aconf->name) : 0,
+/* end of backward compatibility insanity */
+ tmp4 ? atoi(tmp4) : 0,
+ tmp4 && index(tmp4, '.') ?
+ atoi(index(tmp4, '.') + 1) : 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;
+ 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_SERVICE)
+ aconf->port &= SERVICE_MASK_ALL;
+ if (aconf->status & (CONF_SERVER_MASK|CONF_SERVICE))
+ 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|CONF_SERVICE))
+ if (!index(aconf->host, '@') && *aconf->host != '/')
+ {
+ char *newhost;
+ int len = 3; /* *@\0 = 3 */
+
+ len += strlen(aconf->host);
+ newhost = (char *)MyMalloc(len);
+ SPRINTF(newhost, "*@%s", aconf->host);
+ MyFree(aconf->host);
+ aconf->host = newhost;
+ istat.is_confmem += 2;
+ }
+ if (aconf->status & CONF_SERVER_MASK)
+ {
+ if (BadPtr(aconf->passwd))
+ continue;
+ else if (!(opt & BOOT_QUICK))
+ (void)lookup_confhost(aconf);
+ }
+ if (aconf->status & (CONF_CONNECT_SERVER | CONF_ZCONNECT_SERVER))
+ {
+ aconf->ping = (aCPing *)MyMalloc(sizeof(aCPing));
+ bzero((char *)aconf->ping, sizeof(*aconf->ping));
+ istat.is_confmem += sizeof(*aconf->ping);
+ if (tmp2 && index(tmp2, '.'))
+ aconf->ping->port = atoi(index(tmp2, '.') + 1);
+ else
+ aconf->ping->port = aconf->port;
+ if (tmp2)
+ {
+ MyFree(tmp2);
+ tmp2 = NULL;
+ }
+
+ }
+ /*
+ ** 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)
+ {
+ if (me.info != DefInfo)
+ MyFree(me.info);
+ me.info = MyMalloc(REALLEN+1);
+ strncpyzt(me.info, aconf->name, REALLEN+1);
+ if (ME[0] == '\0' && aconf->host[0])
+ strncpyzt(ME, aconf->host,
+ sizeof(ME));
+ if (aconf->port)
+ setup_ping(aconf);
+ }
+ (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,
+ aconf->class ? ConfClass(aconf) : 0));
+
+ if (aconf->status & (CONF_KILL|CONF_OTHERKILL))
+ {
+ aconf->next = kconf;
+ kconf = aconf;
+ }
+ else
+ {
+ 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);
+#if defined(M4_PREPROC) && !defined(USE_IAUTH)
+ (void)wait(0);
+#endif
+ check_class();
+ nextping = nextconnect = timeofday;
+ 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)
+Reg aConfItem *aconf;
+{
+ Reg char *s;
+ Reg 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))
+#ifdef INET6
+ if(!inet_pton(AF_INET6, s, aconf->ipnum.s6_addr))
+ bcopy(minus_one, aconf->ipnum.s6_addr, IN6ADDRSZ);
+#else
+ aconf->ipnum.s_addr = inetaddr(s);
+#endif
+ else if ((hp = gethost_byname(s, &ln)))
+ bcopy(hp->h_addr, (char *)&(aconf->ipnum),
+ sizeof(struct IN_ADDR));
+
+#ifdef INET6
+ if (AND16(aconf->ipnum.s6_addr) == 255)
+#else
+ if (aconf->ipnum.s_addr == -1)
+#endif
+ goto badlookup;
+ return 0;
+badlookup:
+#ifdef INET6
+ if (AND16(aconf->ipnum.s6_addr) == 255)
+#else
+ if (aconf->ipnum.s_addr == -1)
+#endif
+ 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, doall, comment)
+aClient *cptr;
+int doall;
+char **comment;
+{
+ static char reply[256];
+ char *host, *ip, *name, *ident, *check;
+ aConfItem *tmp;
+ int now;
+
+ if (!cptr->user)
+ return 0;
+
+ host = cptr->sockhost;
+#ifdef INET6
+ ip = (char *) inetntop(AF_INET6, (char *)&cptr->ip, mydummy,
+ MYDUMMY_SIZE);
+#else
+ ip = (char *) inetntoa((char *)&cptr->ip);
+#endif
+ if (!strcmp(host, ip))
+ ip = NULL; /* we don't have a name for the ip# */
+ name = cptr->user->username;
+ ident = cptr->auth;
+
+ if (strlen(host) > (size_t) HOSTLEN ||
+ (name ? strlen(name) : 0) > (size_t) HOSTLEN)
+ return (0);
+
+ *reply = '\0';
+
+ for (tmp = kconf; tmp; tmp = tmp->next)
+ {
+ if (!doall && (BadPtr(tmp->passwd) || !isdigit(*tmp->passwd)))
+ continue;
+ if (!(tmp->status & (CONF_KILL | CONF_OTHERKILL)))
+ continue; /* should never happen with kconf */
+ if (!tmp->host || !tmp->name)
+ continue;
+ if (tmp->status == CONF_KILL)
+ check = name;
+ else
+ check = ident;
+ /* host & IP matching.. */
+ if (!ip) /* unresolved */
+ {
+ if (strchr(tmp->host, '/'))
+ {
+ if (match_ipmask((*tmp->host == '=') ?
+ tmp->host+1: tmp->host, cptr))
+ continue;
+ }
+ else
+ if (match((*tmp->host == '=') ? tmp->host+1 :
+ tmp->host, host))
+ continue;
+ }
+ else if (*tmp->host == '=') /* numeric only */
+ continue;
+ else /* resolved */
+ if (strchr(tmp->host, '/'))
+ {
+ if (match_ipmask(tmp->host, cptr))
+ continue;
+ }
+ else
+ if (match(tmp->host, ip) &&
+ match(tmp->host, host))
+ continue;
+
+ /* user & port matching */
+ if ((!check || match(tmp->name, check) == 0) &&
+ (!tmp->port || (tmp->port == cptr->acpt->port)))
+ {
+ now = 0;
+ if (!BadPtr(tmp->passwd) && isdigit(*tmp->passwd) &&
+ !(now = check_time_interval(tmp->passwd, reply)))
+ continue;
+ if (now == ERR_YOUWILLBEBANNED)
+ tmp = NULL;
+ break;
+ }
+ }
+
+ if (*reply)
+ sendto_one(cptr, reply, ME, now, cptr->name);
+ else if (tmp)
+ sendto_one(cptr, ":%s %d %s :%s%s", ME,
+ ERR_YOUREBANNEDCREEP, cptr->name,
+ BadPtr(tmp->passwd) ?
+ "You are not welcome to this server" :
+ "You are not welcome to this server: ",
+ BadPtr(tmp->passwd) ? "" : tmp->passwd);
+
+ if (tmp && !BadPtr(tmp->passwd))
+ *comment = tmp->passwd;
+ else
+ *comment = NULL;
+
+ return (tmp ? -1 : 0);
+}
+
+/*
+ * For type stat, check if both name and host masks match.
+ * Return -1 for match, 0 for no-match.
+ */
+int find_two_masks(name, host, stat)
+char *name, *host;
+int stat;
+{
+ aConfItem *tmp;
+
+ for (tmp = conf; tmp; tmp = tmp->next)
+ if ((tmp->status == stat) && tmp->host && tmp->name &&
+ (match(tmp->host, host) == 0) &&
+ (match(tmp->name, name) == 0))
+ break;
+ return (tmp ? -1 : 0);
+}
+
+/*
+ * For type stat, check if name matches and any char from key matches
+ * to chars in passwd field.
+ * Return -1 for match, 0 for no-match.
+ */
+int find_conf_flags(name, key, stat)
+char *name, *key;
+int stat;
+{
+ aConfItem *tmp;
+ int l;
+
+ if (index(key, '/') == NULL)
+ return 0;
+ l = ((char *)index(key, '/') - key) + 1;
+ for (tmp = conf; tmp; tmp = tmp->next)
+ if ((tmp->status == stat) && tmp->passwd && tmp->name &&
+ (strncasecmp(key, tmp->passwd, l) == 0) &&
+ (match(tmp->name, name) == 0) &&
+ (strpbrk(key + l, tmp->passwd + l)))
+ break;
+ return (tmp ? -1 : 0);
+}
+
+#ifdef R_LINES
+/* find_restrict works against host/name and calls an outside program
+ * to determine whether a client is allowed to connect. This allows
+ * more freedom to determine who is legal and who isn't, for example
+ * machine load considerations. The outside program is expected to
+ * return a reply line where the first word is either 'Y' or 'N' meaning
+ * "Yes Let them in" or "No don't let them in." If the first word
+ * begins with neither 'Y' or 'N' the default is to let the person on.
+ * It returns a value of 0 if the user is to be let through -Hoppie
+ */
+int find_restrict(cptr)
+aClient *cptr;
+{
+ aConfItem *tmp;
+ char reply[80], temprpl[80];
+ char *rplhold = reply, *host, *name, *s;
+ char rplchar = 'Y';
+ int pi[2], rc = 0, n;
+
+ if (!cptr->user)
+ return 0;
+ name = cptr->user->username;
+ host = cptr->sockhost;
+ Debug((DEBUG_INFO, "R-line check for %s[%s]", name, host));
+
+ for (tmp = conf; tmp; tmp = tmp->next)
+ {
+ if (tmp->status != CONF_RESTRICT ||
+ (tmp->host && host && match(tmp->host, host)) ||
+ (tmp->name && name && match(tmp->name, name)))
+ continue;
+
+ if (BadPtr(tmp->passwd))
+ continue;
+
+ if (pipe(pi) == -1)
+ {
+ report_error("Error creating pipe for R-line %s:%s",
+ &me);
+ return 0;
+ }
+ switch (rc = vfork())
+ {
+ case -1 :
+ report_error("Error forking for R-line %s:%s", &me);
+ return 0;
+ case 0 :
+ {
+ Reg int i;
+
+ (void)close(pi[0]);
+ for (i = 2; i < MAXCONNECTIONS; i++)
+ if (i != pi[1])
+ (void)close(i);
+ if (pi[1] != 2)
+ (void)dup2(pi[1], 2);
+ (void)dup2(2, 1);
+ if (pi[1] != 2 && pi[1] != 1)
+ (void)close(pi[1]);
+ (void)execlp(tmp->passwd, tmp->passwd, name, host,
+ cptr->username, 0);
+ _exit(-1);
+ }
+ default :
+ (void)close(pi[1]);
+ break;
+ }
+ *reply = '\0';
+ (void)dgets(-1, NULL, 0); /* make sure buffer marked empty */
+ while ((n = dgets(pi[0], temprpl, sizeof(temprpl)-1)) > 0)
+ {
+ temprpl[n] = '\0';
+ if ((s = (char *)index(temprpl, '\n')))
+ *s = '\0';
+ if (strlen(temprpl) + strlen(reply) < sizeof(reply)-2)
+ SPRINTF(rplhold,"%s %s", rplhold, temprpl);
+ else
+ {
+ sendto_flag(SCH_ERROR,
+ "R-line %s/%s: reply too long!",
+ name, host);
+ break;
+ }
+ }
+ (void)dgets(-1, NULL, 0); /* make sure buffer marked empty */
+ (void)close(pi[0]);
+ (void)kill(rc, SIGKILL); /* cleanup time */
+#if !defined(USE_IAUTH)
+ (void)wait(0);
+#endif
+
+ rc = 0;
+ while (*rplhold == ' ')
+ rplhold++;
+ rplchar = *rplhold; /* Pull out the yes or no */
+ while (*rplhold != ' ')
+ rplhold++;
+ while (*rplhold == ' ')
+ rplhold++;
+ (void)strcpy(reply,rplhold);
+ rplhold = reply;
+
+ if ((rc = (rplchar == 'n' || rplchar == 'N')))
+ break;
+ }
+ if (rc)
+ {
+ sendto_one(cptr, ":%s %d %s :Restriction: %s",
+ ME, ERR_YOUREBANNEDCREEP, cptr->name, reply);
+ return -1;
+ }
+ return 0;
+}
+#endif
+
+
+/*
+** check against a set of time intervals
+*/
+
+static int check_time_interval(interval, reply)
+char *interval, *reply;
+{
+ struct tm *tptr;
+ char *p;
+ int perm_min_hours, perm_min_minutes,
+ perm_max_hours, perm_max_minutes;
+ int now, perm_min, perm_max;
+
+ tptr = localtime(&timeofday);
+ now = tptr->tm_hour * 60 + tptr->tm_min;
+
+ while (interval)
+ {
+ p = (char *)index(interval, ',');
+ if (p)
+ *p = '\0';
+ if (sscanf(interval, "%2d%2d-%2d%2d",
+ &perm_min_hours, &perm_min_minutes,
+ &perm_max_hours, &perm_max_minutes) != 4)
+ {
+ if (p)
+ *p = ',';
+ return(0);
+ }
+ if (p)
+ *(p++) = ',';
+ perm_min = 60 * perm_min_hours + perm_min_minutes;
+ perm_max = 60 * perm_max_hours + perm_max_minutes;
+ /*
+ ** The following check allows intervals over midnight ...
+ */
+ if ((perm_min < perm_max)
+ ? (perm_min <= now && now <= perm_max)
+ : (perm_min <= now || now <= perm_max))
+ {
+ (void)sprintf(reply,
+ ":%%s %%d %%s :%s %d:%02d to %d:%02d.",
+ "You are not allowed to connect from",
+ perm_min_hours, perm_min_minutes,
+ perm_max_hours, perm_max_minutes);
+ return(ERR_YOUREBANNEDCREEP);
+ }
+ if ((perm_min < perm_max)
+ ? (perm_min <= now + 5 && now + 5 <= perm_max)
+ : (perm_min <= now + 5 || now + 5 <= perm_max))
+ {
+ (void)sprintf(reply, ":%%s %%d %%s :%d minute%s%s",
+ perm_min-now,(perm_min-now)>1?"s ":" ",
+ "and you will be denied for further access");
+ return(ERR_YOUWILLBEBANNED);
+ }
+ interval = p;
+ }
+ return(0);
+}
+
+/*
+** find_bounce
+** send a bounce numeric to a client.
+** fd is optional, and only makes sense if positive and when cptr is NULL
+** fd == -1 : not fd, class is a class number.
+** fd == -2 : not fd, class isn't a class number.
+*/
+void find_bounce(cptr, class, fd)
+aClient *cptr;
+int class, fd;
+ {
+ Reg aConfItem *aconf;
+
+ for (aconf = conf; aconf; aconf = aconf->next)
+ {
+ if (aconf->status != CONF_BOUNCE)
+ continue;
+
+ if (fd >= 0)
+ /*
+ ** early rejection,
+ ** connection class and hostname are unknown
+ */
+ if (*aconf->host == '\0')
+ {
+ char rpl[BUFSIZE];
+
+ SPRINTF(rpl, rpl_str(RPL_BOUNCE,"unknown"),
+ aconf->name, aconf->port);
+ strcat(rpl, "\r\n");
+#ifdef INET6
+ sendto(class, rpl, strlen(rpl), 0, 0, 0);
+#else
+ send(class, rpl, strlen(rpl), 0);
+#endif
+ return;
+ }
+ else
+ continue;
+
+ /* fd < 0 */
+ /*
+ ** "too many" type rejection, class is known.
+ ** check if B line is for a class #,
+ ** and if it is for a hostname.
+ */
+ if (fd != -2 &&
+ !strchr(aconf->host, '.') && isdigit(*aconf->host))
+ {
+ if (class != atoi(aconf->host))
+ continue;
+ }
+ else
+ if (strchr(aconf->host, '/'))
+ {
+ if (match_ipmask(aconf->host, cptr))
+ continue;
+ }
+ else if (match(aconf->host, cptr->sockhost))
+ continue;
+
+ sendto_one(cptr, rpl_str(RPL_BOUNCE, cptr->name), aconf->name,
+ aconf->port);
+ return;
+ }
+
+ }
+
+/*
+** find_denied
+** for a given server name, make sure no D line matches any of the
+** servers currently present on the net.
+*/
+aConfItem *
+find_denied(name, class)
+ char *name;
+ int class;
+{
+ aConfItem *aconf;
+
+ for (aconf = conf; aconf; aconf = aconf->next)
+ {
+ if (aconf->status != CONF_DENY)
+ continue;
+ if (!aconf->name)
+ continue;
+ if (match(aconf->name, name) && aconf->port != class)
+ continue;
+ if (isdigit(*aconf->passwd))
+ {
+ aConfItem *aconf2;
+ int ck = atoi(aconf->passwd);
+
+ for (aconf2 = conf; aconf2; aconf2 = aconf2->next)
+ {
+ if (aconf2->status != CONF_NOCONNECT_SERVER)
+ continue;
+ if (!aconf2->class || ConfClass(aconf2) != ck)
+ continue;
+ if (find_client(aconf2->host, NULL))
+ return aconf2;
+ }
+ }
+ if (aconf->host)
+ {
+ aServer *asptr;
+
+ for (asptr = svrtop; asptr; asptr = asptr->nexts)
+ if (aconf->host &&
+ !match(aconf->host, asptr->bcptr->name))
+ return aconf;
+ }
+ }
+ return NULL;
+}
diff --git a/ircd/s_conf_ext.h b/ircd/s_conf_ext.h
new file mode 100644
index 0000000..8257254
--- /dev/null
+++ b/ircd/s_conf_ext.h
@@ -0,0 +1,66 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/s_conf_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in ircd/s_conf.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef S_CONF_C
+extern aConfItem *conf, *kconf;
+#endif /* S_CONF_C */
+
+/* External definitions for global functions.
+ */
+#ifndef S_CONF_C
+#define EXTERN extern
+#else /* S_CONF_C */
+#define EXTERN
+#endif /* S_CONF_C */
+EXTERN void det_confs_butmask __P((aClient *cptr, int mask));
+EXTERN int attach_Iline __P((aClient *cptr, Reg struct hostent *hp,
+ char *sockhost));
+EXTERN aConfItem *count_cnlines __P((Reg Link *lp));
+EXTERN int detach_conf __P((aClient *cptr, aConfItem *aconf));
+EXTERN int attach_conf __P((aClient *cptr, aConfItem *aconf));
+EXTERN aConfItem *find_admin();
+EXTERN aConfItem *find_me();
+EXTERN aConfItem *attach_confs __P((aClient *cptr, char *name, int statmask));
+EXTERN aConfItem *attach_confs_host __P((aClient *cptr, char *host,
+ int statmask));
+EXTERN aConfItem *find_conf_exact __P((char *name, char *user, char *host,
+ int statmask));
+EXTERN aConfItem *find_conf_name __P((char *name, int statmask));
+EXTERN aConfItem *find_conf __P((Link *lp, char *name, int statmask));
+EXTERN aConfItem *find_conf_host __P((Reg Link *lp, char *host,
+ Reg int statmask));
+EXTERN aConfItem *find_conf_ip __P((Link *lp, char *ip, char *user,
+ int statmask));
+EXTERN aConfItem *find_conf_entry __P((aConfItem *aconf, u_int mask));
+EXTERN int rehash __P((aClient *cptr, aClient *sptr, int sig));
+EXTERN int openconf();
+EXTERN int initconf __P((int opt));
+EXTERN int find_kill __P((aClient *cptr, int doall, char **comment));
+EXTERN int find_two_masks __P((char *name, char *host, int stat));
+EXTERN int find_conf_flags __P((char *name, char *key, int stat));
+EXTERN int find_restrict __P((aClient *cptr));
+EXTERN void find_bounce __P((aClient *cptr, int class, int fd));
+EXTERN aConfItem *find_denied __P((char *name, int class));
+#undef EXTERN
diff --git a/ircd/s_debug.c b/ircd/s_debug.c
new file mode 100644
index 0000000..c3d9c4f
--- /dev/null
+++ b/ircd/s_debug.c
@@ -0,0 +1,668 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/s_debug.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: s_debug.c,v 1.28 1999/07/11 22:11:17 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "s_defines.h"
+#define S_DEBUG_C
+#include "s_externs.h"
+#undef S_DEBUG_C
+
+/*
+ * Option string. Must be before #ifdef DEBUGMODE.
+ * spaces are not allowed.
+ */
+char serveropts[] = {
+#ifndef NO_IDENT
+'a',
+#endif
+#ifdef CHROOTDIR
+'c',
+#endif
+#ifdef CMDLINE_CONFIG
+'C',
+#endif
+#ifdef DEBUGMODE
+'D',
+#endif
+#ifdef RANDOM_NDELAY
+'d',
+#endif
+#if defined(LOCOP_REHASH) && defined(OPER_REHASH)
+'e',
+#endif
+#ifdef OPER_REHASH
+'E',
+#endif
+#ifdef SLOW_ACCEPT
+'f',
+#endif
+#ifdef CLONE_CHECK
+'F',
+#endif
+#ifdef SUN_GSO_BUG
+'g',
+#endif
+#ifdef HUB
+'H',
+#endif
+#ifdef BETTER_CDELAY
+'h',
+#endif
+#ifdef SHOW_INVISIBLE_LUSERS
+'i',
+#endif
+#ifndef NO_DEFAULT_INVISIBLE
+'I',
+#endif
+#if defined(LOCOP_DIE) && defined(OPER_DIE)
+'j',
+#endif
+#ifdef OPER_DIE
+'J',
+#endif
+#ifdef OPER_KILL
+# ifdef LOCAL_KILL_ONLY
+'k',
+# else
+'K',
+# endif
+#endif
+#ifdef LEAST_IDLE
+'L',
+#endif
+#ifdef M4_PREPROC
+'m',
+#endif
+#ifdef IDLE_FROM_MSG
+'M',
+#endif
+#ifdef NPATH /* gone */
+'N',
+#endif
+#ifdef BETTER_NDELAY
+'n',
+#endif
+#ifdef CRYPT_OPER_PASSWORD
+'p',
+#endif
+#ifdef CRYPT_LINK_PASSWORD
+'P',
+#endif
+#if defined(LOCOP_RESTART) && defined(OPER_RESTART)
+'r',
+#endif
+#ifdef OPER_RESTART
+'R',
+#endif
+#ifdef USE_SERVICES
+'s',
+#endif
+#ifdef ENABLE_SUMMON
+'S',
+#endif
+#ifdef OPER_REMOTE
+'t',
+#endif
+#ifndef NO_PREFIX
+'u',
+#endif
+#ifdef ENABLE_USERS
+'U',
+#endif
+#ifdef VALLOC
+'V',
+#endif
+#ifdef NOWRITEALARM
+'w',
+#endif
+#ifdef UNIXPORT
+'X',
+#endif
+#ifdef USE_SYSLOG
+'Y',
+#endif
+#ifdef ZIP_LINKS
+'Z',
+#endif
+#ifdef INET6
+'6',
+#endif
+'\0'};
+
+#ifdef DEBUGMODE
+static char debugbuf[2*READBUF_SIZE]; /* needs to be big.. */
+
+#if ! USE_STDARG
+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;
+#else
+void debug(int level, char *form, ...)
+#endif
+{
+ int err = errno;
+
+#ifdef USE_SYSLOG
+ if (level == DEBUG_ERROR)
+ {
+#if ! USE_STDARG
+ syslog(LOG_ERR, form, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
+#else
+# if HAVE_VSYSLOG
+ va_list va;
+ va_start(va, form);
+ vsyslog(LOG_ERR, form, va);
+ va_end(va);
+# else
+ va_list va;
+ va_start(va, form);
+ vsprintf(debugbuf, form, va);
+ va_end(va);
+ syslog(LOG_ERR, debugbuf);
+# endif
+#endif
+ }
+#endif
+ if ((debuglevel >= 0) && (level <= debuglevel))
+ {
+#if ! USE_STDARG
+ (void)sprintf(debugbuf, form,
+ p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
+#else
+ va_list va;
+ va_start(va, form);
+ (void)vsprintf(debugbuf, form, va);
+ va_end(va);
+#endif
+ if (local[2])
+ {
+ local[2]->sendM++;
+ local[2]->sendB += strlen(debugbuf);
+ }
+ (void)fprintf(stderr, "%s", debugbuf);
+ (void)fputc('\n', stderr);
+ }
+ errno = err;
+}
+#endif /* DEBUGMODE */
+
+/*
+ * 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;
+{
+#if HAVE_GETRUSAGE
+ struct rusage rus;
+ time_t secs, rup;
+#ifdef hz
+# define hzz hz
+#else
+# ifdef HZ
+# define hzz HZ
+# else
+ int hzz = 1;
+# ifdef HPUX
+ hzz = (int)sysconf(_SC_CLK_TCK);
+# endif
+# endif
+#endif
+
+ if (getrusage(RUSAGE_SELF, &rus) == -1)
+ {
+ 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 = timeofday - 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);
+ if (rup && hzz)
+ 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 /* HAVE_GETRUSAGE */
+# if HAVE_TIMES
+ struct tms tmsbuf;
+ time_t secs, mins;
+ int hzz = 1, ticpermin;
+ int umin, smin, usec, ssec;
+
+# ifdef HPUX
+ hzz = sysconf(_SC_CLK_TCK);
+# endif
+ ticpermin = hzz * 60;
+
+ umin = tmsbuf.tms_utime / ticpermin;
+ usec = (tmsbuf.tms_utime%ticpermin)/(float)hzz;
+ smin = tmsbuf.tms_stime / ticpermin;
+ ssec = (tmsbuf.tms_stime%ticpermin)/(float)hzz;
+ secs = usec + ssec;
+ mins = (secs/60) + umin + smin;
+ secs %= hzz;
+
+ if (times(&tmsbuf) == -1)
+ {
+ sendto_one(cptr, ":%s %d %s :times(2) error: %s.",
+ me.name, RPL_STATSDEBUG, nick, strerror(errno));
+ return;
+ }
+ secs = tmsbuf.tms_utime + tmsbuf.tms_stime;
+
+ sendto_one(cptr,
+ ":%s %d %s :CPU Secs %d:%d User %d:%d System %d:%d",
+ me.name, RPL_STATSDEBUG, nick, mins, secs, umin, usec,
+ smin, ssec);
+# endif /* HAVE_TIMES */
+#endif /* HAVE_GETRUSAGE */
+ sendto_one(cptr, ":%s %d %s :DBUF alloc %d blocks %d",
+ me.name, RPL_STATSDEBUG, nick, istat.is_dbufuse,
+ istat.is_dbufnow);
+#ifdef DEBUGMODE
+ sendto_one(cptr, ":%s %d %s :Reads %d Writes %d",
+ me.name, RPL_STATSDEBUG, nick, readcalls, writecalls);
+ 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]);
+#endif
+ return;
+}
+
+void send_defines(cptr, nick)
+aClient *cptr;
+char *nick;
+{
+ sendto_one(cptr, ":%s %d %s :HUB:%s MS:%d",
+ ME, RPL_STATSDEFINE, nick,
+#ifdef HUB
+ "yes",
+#else
+ "no",
+#endif
+ MAXSERVERS);
+ sendto_one(cptr,
+ ":%s %d %s :LQ:%d MXC:%d TS:%d HRD:%d HGL:%d WWD:%d ATO:%d",
+ ME, RPL_STATSDEFINE, nick, LISTENQUEUE, MAXCONNECTIONS,
+ TIMESEC, HANGONRETRYDELAY, HANGONGOODLINK, WRITEWAITDELAY,
+ ACCEPTTIMEOUT);
+ sendto_one(cptr, ":%s %d %s :KCTL:%d DCTL:%d LDCTL: %d CF:%d MCPU:%d",
+ ME, RPL_STATSDEFINE, nick, KILLCHASETIMELIMIT,
+ DELAYCHASETIMELIMIT, LDELAYCHASETIMELIMIT,
+ CLIENT_FLOOD, MAXCHANNELSPERUSER);
+ sendto_one(cptr, ":%s %d %s :H:%d N:%d U:%d R:%d T:%d C:%d P:%d K:%d",
+ ME, RPL_STATSDEFINE, nick, HOSTLEN, NICKLEN, USERLEN,
+ REALLEN, TOPICLEN, CHANNELLEN, PASSWDLEN, KEYLEN);
+ sendto_one(cptr, ":%s %d %s :BS:%d MXR:%d MXB:%d MXBL:%d PY:%d",
+ ME, RPL_STATSDEFINE, nick, BUFSIZE, MAXRECIPIENTS, MAXBANS,
+ MAXBANLENGTH, MAXPENALTY);
+ sendto_one(cptr, ":%s %d %s :ZL:%d CM:%d CP:%d",
+ ME, RPL_STATSDEFINE, nick,
+#ifdef ZIP_LINKS
+ ZIP_LEVEL,
+#else
+ -1,
+#endif
+#ifdef CLONE_CHECK
+ CLONE_MAX, CLONE_PERIOD
+#else
+ -1, -1
+#endif
+ );
+}
+
+void count_memory(cptr, nick, debug)
+aClient *cptr;
+char *nick;
+int debug;
+{
+ extern aChannel *channel;
+ extern aClass *classes;
+ extern aConfItem *conf;
+ extern int _HASHSIZE, _CHANNELHASHSIZE;
+
+ Reg aClient *acptr;
+ Reg Link *link;
+ Reg aChannel *chptr;
+ Reg aConfItem *aconf;
+ Reg aClass *cltmp;
+
+ int lc = 0, d_lc = 0, /* local clients */
+ ch = 0, d_ch = 0, /* channels */
+ lcc = 0, d_lcc = 0, /* local client conf links */
+ rc = 0, d_rc = 0, /* remote clients */
+ us = 0, d_us = 0, /* user structs */
+ chu = 0, d_chu = 0, /* channel users */
+ chi = 0, d_chi = 0, /* channel invites */
+ chb = 0, d_chb = 0, /* channel bans */
+ chh = 0, d_chh = 0, /* channel in history */
+ wwu = 0, d_wwu = 0, /* whowas users */
+ cl = 0, d_cl = 0, /* classes */
+ co = 0, d_co = 0; /* conf lines */
+
+ int usi = 0, d_usi = 0, /* users invited */
+ usc = 0, d_usc = 0, /* users in channels */
+ aw = 0, d_aw = 0, /* aways set */
+ wwa = 0, d_wwa = 0, /* whowas aways */
+ wwuw = 0, d_wwuw = 0; /* whowas uwas */
+
+ u_long chm = 0, d_chm = 0, /* memory used by channels */
+ chhm = 0, d_chhm = 0, /* memory used by channel in history */
+ chbm = 0, d_chbm = 0, /* memory used by channel bans */
+ lcm = 0, d_lcm = 0, /* memory used by local clients */
+ rcm = 0, d_rcm = 0, /* memory used by remote clients */
+ awm = 0, d_awm = 0, /* memory used by aways */
+ wwam = 0, d_wwam = 0, /* whowas away memory used */
+ wwm = 0, d_wwm = 0, /* whowas array memory used */
+ dm = 0, d_dm = 0, /* delay array memory used */
+ com = 0, d_com = 0, /* memory used by conf lines */
+ db = 0, d_db = 0, /* memory used by dbufs */
+ rm = 0, d_rm = 0, /* res memory used */
+ totcl = 0, d_totcl = 0,
+ totch = 0, d_totch = 0,
+ totww = 0, d_totww = 0,
+ tot = 0, d_tot = 0;
+ time_t start = 0;
+
+ if (debug)
+ {
+ start = time(NULL);
+ count_whowas_memory(&d_wwu, &d_wwa, &d_wwam, &d_wwuw);
+ d_wwm = sizeof(aName) * ww_size;
+ d_dm = sizeof(aLock) * lk_size;
+ }
+ wwu = istat.is_wwusers;
+ wwa = istat.is_wwaways;
+ wwam = istat.is_wwawaysmem;
+ wwuw = istat.is_wwuwas;
+ wwm = sizeof(aName) * ww_size;
+ dm = sizeof(aLock) * lk_size;
+
+ /*lc = istat.is_unknown + istat.is_myclnt + istat.is_serv;*/
+ lc = istat.is_localc;
+ lcc = istat.is_conflink;
+ rc = istat.is_remc;
+ us = istat.is_users;
+ usi = istat.is_useri;
+ usc = istat.is_userc;
+ aw = istat.is_away;
+ awm = istat.is_awaymem;
+
+ if (debug)
+ for (acptr = client; acptr; acptr = acptr->next)
+ {
+ if (MyConnect(acptr))
+ {
+ d_lc++;
+ for (link =acptr->confs; link; link=link->next)
+ d_lcc++;
+ }
+ else
+ d_rc++;
+ if (acptr->user)
+ {
+ d_us++;
+ for (link = acptr->user->invited; link;
+ link = link->next)
+ d_usi++;
+ d_usc += acptr->user->joined;
+ if (acptr->user->away)
+ {
+ d_aw++;
+ d_awm += (strlen(acptr->user->away)+1);
+ }
+ }
+ }
+
+ lcm = lc * CLIENT_LOCAL_SIZE;
+ rcm = rc * CLIENT_REMOTE_SIZE;
+
+ d_lcm = d_lc * CLIENT_LOCAL_SIZE;
+ d_rcm = d_rc * CLIENT_REMOTE_SIZE;
+
+ ch = istat.is_chan;
+ chm = istat.is_chanmem;
+ chh = istat.is_hchan;
+ chhm = istat.is_hchanmem;
+ chi = istat.is_invite;
+ chb = istat.is_bans;
+ chbm = istat.is_banmem + chb * sizeof(Link);
+ chu = istat.is_chanusers;
+
+ if (debug)
+ {
+ for (chptr = channel; chptr; chptr = chptr->nextch)
+ {
+ if (chptr->users == 0)
+ {
+ d_chh++;
+ d_chhm+=strlen(chptr->chname)+sizeof(aChannel);
+ }
+ else
+ {
+ d_ch++;
+ d_chm += (strlen(chptr->chname) +
+ sizeof(aChannel));
+ }
+ for (link = chptr->members; link; link = link->next)
+ d_chu++;
+ for (link = chptr->invites; link; link = link->next)
+ d_chi++;
+ for (link = chptr->mlist; link; link = link->next)
+ {
+ d_chb++;
+ d_chbm += strlen(link->value.cp) + 1;
+ }
+ }
+ d_chbm += d_chb * sizeof(Link);
+ }
+
+ co = istat.is_conf;
+ com = istat.is_confmem;
+ cl = istat.is_class;
+
+ if (debug)
+ {
+ for (aconf = conf; aconf; aconf = aconf->next)
+ {
+ d_co++;
+ d_com += aconf->host ? strlen(aconf->host)+1 : 0;
+ d_com += aconf->passwd ? strlen(aconf->passwd)+1 : 0;
+ d_com += aconf->name ? strlen(aconf->name)+1 : 0;
+ d_com += aconf->ping ? sizeof(*aconf->ping) : 0;
+ d_com += sizeof(aConfItem);
+ }
+ for (cltmp = classes; cltmp; cltmp = cltmp->next)
+ d_cl++;
+ }
+
+ if (debug)
+ sendto_one(cptr, ":%s %d %s :Request processed in %u seconds",
+ me.name, RPL_STATSDEBUG, nick, time(NULL) - start);
+
+ sendto_one(cptr,
+ ":%s %d %s :Client Local %d(%d) Remote %d(%d) Auth %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, lc, lcm, rc, rcm,
+ istat.is_auth, istat.is_authmem);
+ if (debug
+ && (lc != d_lc || lcm != d_lcm || rc != d_rc || rcm != d_rcm))
+ sendto_one(cptr,
+ ":%s %d %s :Client Local %d(%d) Remote %d(%d) [REAL]",
+ me.name, RPL_STATSDEBUG, nick, d_lc, d_lcm, d_rc,
+ d_rcm);
+ sendto_one(cptr,
+ ":%s %d %s :Users %d in/visible %d/%d(%d) Invites %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, us, istat.is_user[1],
+ istat.is_user[0], us*sizeof(anUser), usi,
+ usi*sizeof(Link));
+ if (debug && (us != d_us || usi != d_usi))
+ sendto_one(cptr,
+ ":%s %d %s :Users %d(%d) Invites %d(%d) [REAL]",
+ me.name, RPL_STATSDEBUG, nick, d_us,
+ d_us*sizeof(anUser), d_usi, d_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);
+ if (debug && (usc != d_usc || aw != d_aw || awm != d_awm))
+ sendto_one(cptr,
+ ":%s %d %s :User channels %d(%d) Aways %d(%d) [REAL]",
+ me.name, RPL_STATSDEBUG, nick, d_usc,
+ d_usc*sizeof(Link), d_aw, d_awm);
+ sendto_one(cptr, ":%s %d %s :Attached confs %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, lcc, lcc*sizeof(Link));
+ if (debug && lcc != d_lcc)
+ sendto_one(cptr, ":%s %d %s :Attached confs %d(%d) [REAL]",
+ me.name, RPL_STATSDEBUG, nick, d_lcc,
+ d_lcc*sizeof(Link));
+
+ totcl = lcm + rcm + us*sizeof(anUser) + usc*sizeof(Link) + awm;
+ totcl += lcc*sizeof(Link) + usi*sizeof(Link);
+ d_totcl = d_lcm + d_rcm + d_us*sizeof(anUser) + d_usc*sizeof(Link);
+ d_totcl += d_awm + d_lcc*sizeof(Link) + d_usi*sizeof(Link);
+
+ sendto_one(cptr, ":%s %d %s :Conflines %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, co, com);
+ if (debug && (co != d_co || com != d_com))
+ sendto_one(cptr, ":%s %d %s :Conflines %d(%d) [REAL]",
+ me.name, RPL_STATSDEBUG, nick, d_co, d_com);
+
+ sendto_one(cptr, ":%s %d %s :Classes %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, cl, cl*sizeof(aClass));
+ if (debug && cl != d_cl)
+ sendto_one(cptr, ":%s %d %s :Classes %d(%d) [REAL]",
+ me.name, RPL_STATSDEBUG, nick, d_cl,
+ d_cl*sizeof(aClass));
+
+ sendto_one(cptr,
+ ":%s %d %s :Channels %d(%d) Modes %d(%d) History %d(%d) Cache %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, ch, chm, chb, chbm, chh,
+ chhm, istat.is_cchan, istat.is_cchanmem);
+ if (debug && (ch != d_ch || chm != d_chm || chb != d_chb
+ || chbm != d_chbm || chh != d_chh || chhm != d_chhm))
+ sendto_one(cptr,
+ ":%s %d %s :Channels %d(%d) Modes %d(%d) History %d(%d) [REAL]",
+ me.name, RPL_STATSDEBUG, nick, d_ch, d_chm, d_chb,
+ d_chbm, d_chh, d_chhm);
+ sendto_one(cptr, ":%s %d %s :Channel members %d(%d) invite %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, chu, chu*sizeof(Link),
+ chi, chi*sizeof(Link));
+ if (debug && (chu != d_chu || chi != d_chi))
+ sendto_one(cptr,
+ ":%s %d %s :Channel members %d(%d) invite %d(%d) [REAL]",
+ me.name, RPL_STATSDEBUG, nick, d_chu, d_chu*sizeof(Link),
+ d_chi, d_chi*sizeof(Link));
+
+ totch = chm + chhm + chbm + chu*sizeof(Link) + chi*sizeof(Link);
+ d_totch = d_chm + d_chhm + d_chbm + d_chu*sizeof(Link)
+ + d_chi*sizeof(Link);
+
+ sendto_one(cptr,
+ ":%s %d %s :Whowas users %d(%d) away %d(%d) links %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, wwu, wwu*sizeof(anUser),
+ wwa, wwam, wwuw, wwuw*sizeof(Link));
+ if (debug && (wwu != d_wwu || wwa != d_wwa || wwam != d_wwam
+ || wwuw != d_wwuw))
+ sendto_one(cptr,
+ ":%s %d %s :Whowas users %d(%d) away %d(%d) links %d(%d) [REAL]",
+ me.name, RPL_STATSDEBUG, nick, d_wwu, d_wwu*sizeof(anUser),
+ d_wwa, d_wwam, d_wwuw, d_wwuw*sizeof(Link));
+ sendto_one(cptr, ":%s %d %s :Whowas array %d(%d) Delay array %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, ww_size, wwm, lk_size, dm);
+ if (debug && (wwm != d_wwm || dm != d_dm))
+ sendto_one(cptr,
+ ":%s %d %s :Whowas array %d(%d) Delay array %d(%d) [REAL]",
+ me.name, RPL_STATSDEBUG, nick, ww_size, d_wwm, lk_size,
+ d_dm);
+
+ totww = wwu*sizeof(anUser) + wwam + wwm;
+ d_totww = d_wwu*sizeof(anUser) + d_wwam + d_wwm;
+
+ sendto_one(cptr, ":%s %d %s :Hash: client %d(%d) chan %d(%d)",
+ me.name, RPL_STATSDEBUG, nick, _HASHSIZE,
+ sizeof(aHashEntry) * _HASHSIZE,
+ _CHANNELHASHSIZE, sizeof(aHashEntry) * _CHANNELHASHSIZE);
+ d_db = db = istat.is_dbufnow * sizeof(dbufbuf);
+ db = istat.is_dbufnow * sizeof(dbufbuf);
+ sendto_one(cptr,
+ ":%s %d %s :Dbuf blocks %u(%d) (> %u [%u]) (%u < %u) [%u]",
+ me.name, RPL_STATSDEBUG, nick, istat.is_dbufnow, db,
+ istat.is_dbuf,
+ (u_int) (((u_int)BUFFERPOOL) / ((u_int)sizeof(dbufbuf))),
+ istat.is_dbufuse, istat.is_dbufmax, istat.is_dbufmore);
+
+ d_rm = rm = cres_mem(cptr, nick);
+
+ tot = totww + totch + totcl + com + cl*sizeof(aClass) + db + rm;
+ tot += sizeof(aHashEntry) * _HASHSIZE;
+ tot += sizeof(aHashEntry) * _CHANNELHASHSIZE;
+ d_tot = d_totww + d_totch + d_totcl + d_com + d_cl*sizeof(aClass);
+ d_tot += d_db + d_rm;
+ d_tot += sizeof(aHashEntry) * _HASHSIZE;
+ d_tot += sizeof(aHashEntry) * _CHANNELHASHSIZE;
+
+ sendto_one(cptr, ":%s %d %s :Total: ww %d ch %d cl %d co %d db %d",
+ me.name, RPL_STATSDEBUG, nick, totww, totch, totcl, com,db);
+ if (debug && tot != d_tot)
+ {
+ sendto_one(cptr,
+ ":%s %d %s :Total: ww %d ch %d cl %d co %d db %d [REAL]",
+ me.name, RPL_STATSDEBUG, nick, d_totww, d_totch, d_totcl,
+ d_com, d_db);
+ sendto_one(cptr, ":%s %d %s :TOTAL: %d [REAL]",
+ me.name, RPL_STATSDEBUG, nick, d_tot);
+ }
+ sendto_one(cptr, ":%s %d %s :TOTAL: %d sbrk(0)-etext: %u",
+ me.name, RPL_STATSDEBUG, nick, tot,
+ (u_long)sbrk((size_t)0)-(u_long)sbrk0);
+ return;
+}
diff --git a/ircd/s_debug_ext.h b/ircd/s_debug_ext.h
new file mode 100644
index 0000000..a2b2df5
--- /dev/null
+++ b/ircd/s_debug_ext.h
@@ -0,0 +1,45 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/s_debug_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in ircd/s_debug.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef S_DEBUG_C
+extern char serveropts[];
+#endif /* S_DEBUG_C */
+
+/* External definitions for global functions.
+ */
+#ifndef S_DEBUG_C
+#define EXTERN extern
+#else /* S_DEBUG_C */
+#define EXTERN
+#endif /* S_DEBUG_C */
+#if ! USE_STDARG
+EXTERN void debug();
+#else /* USE_STDARG */
+EXTERN void debug (int level, char *form, ...);
+#endif /* USE_STDARG */
+EXTERN void send_usage __P((aClient *cptr, char *nick));
+EXTERN void send_defines __P((aClient *cptr, char *nick));
+EXTERN void count_memory __P((aClient *cptr, char *nick, int debug));
+#undef EXTERN
diff --git a/ircd/s_defines.h b/ircd/s_defines.h
new file mode 100644
index 0000000..19f0d07
--- /dev/null
+++ b/ircd/s_defines.h
@@ -0,0 +1,41 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/s_defines.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 includes all files defining constants, macros and types
+ definitions used by the IRC server.
+ */
+
+#include "config.h"
+#include "patchlevel.h"
+
+#include "common_def.h"
+#include "dbuf_def.h"
+#include "class_def.h"
+#include "struct_def.h"
+#include "msg_def.h"
+#include "numeric_def.h"
+#include "support_def.h"
+#include "channel_def.h"
+#include "hash_def.h"
+#include "res_def.h"
+#include "whowas_def.h"
+#include "service_def.h"
+#include "sys_def.h"
+#include "resolv_def.h"
+#include "nameser_def.h"
diff --git a/ircd/s_err.c b/ircd/s_err.c
new file mode 100644
index 0000000..319e7b5
--- /dev/null
+++ b/ircd/s_err.c
@@ -0,0 +1,436 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/s_err.c
+ * Copyright (C) 1992 Darren Reed
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: s_err.c,v 1.24 1999/02/22 21:38:33 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "s_defines.h"
+#define S_ERR_C
+#include "s_externs.h"
+#undef S_ERR_C
+
+typedef struct {
+ int num_val;
+ char *num_form;
+} Numeric;
+
+static char *prepbuf __P((char *, char *, char *, int, char *));
+static char numbuff[512];
+
+static Numeric local_replies[] = {
+/* 000 */ { 0, (char *)NULL },
+/* 001 */ { RPL_WELCOME, ":Welcome to the Internet Relay Network %s" },
+/* 002 */ { RPL_YOURHOST, ":Your host is %s, running version %s" },
+/* 003 */ { RPL_CREATED, ":This server was created %s" },
+/* 004 */ { RPL_MYINFO, "%s %s aoOirw abeiIklmnoOpqrstv" },
+/* 005 */ { RPL_BOUNCE, ":Try server %s, port %d" },
+ { 0, (char *)NULL }
+};
+
+static Numeric numeric_errors[] = {
+/* 401 */ { ERR_NOSUCHNICK, "%s :No such nick/channel" },
+/* 402 */ { ERR_NOSUCHSERVER, "%s :No such server" },
+/* 403 */ { ERR_NOSUCHCHANNEL, "%s :No such channel" },
+/* 404 */ { ERR_CANNOTSENDTOCHAN, "%s :Cannot send to channel" },
+/* 405 */ { ERR_TOOMANYCHANNELS, "%s :You have joined too many channels" },
+/* 406 */ { ERR_WASNOSUCHNICK, "%s :There was no such nickname" },
+/* 407 */ { ERR_TOOMANYTARGETS,
+ "%s :%s recipients. %s" },
+/* 408 */ { ERR_NOSUCHSERVICE, "%s :No such service" },
+/* 409 */ { ERR_NOORIGIN, ":No origin specified" },
+ { 0, (char *)NULL },
+/* 411 */ { ERR_NORECIPIENT, ":No recipient given (%s)" },
+/* 412 */ { ERR_NOTEXTTOSEND, ":No text to send" },
+/* 413 */ { ERR_NOTOPLEVEL, "%s :No toplevel domain specified" },
+/* 414 */ { ERR_WILDTOPLEVEL, "%s :Wildcard in toplevel Domain" },
+/* 415 */ { ERR_BADMASK, "%s :Bad Server/host mask" },
+/* 416 */ { ERR_TOOMANYMATCHES, "%s %s :Output too long (try locally)" },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+/* 421 */ { ERR_UNKNOWNCOMMAND, "%s :Unknown command" },
+/* 422 */ { ERR_NOMOTD, ":MOTD File is missing" },
+/* 423 */ { ERR_NOADMININFO,
+ "%s :No administrative info available" },
+/* 424 */ { ERR_FILEERROR, ":File error doing %s on %s" },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+/* 431 */ { ERR_NONICKNAMEGIVEN, ":No nickname given" },
+/* 432 */ { ERR_ERRONEUSNICKNAME, "%s :Erroneous Nickname" },
+/* 433 */ { ERR_NICKNAMEINUSE, "%s :Nickname is already in use." },
+/* 434 */ { ERR_SERVICENAMEINUSE, (char *)NULL },
+/* 435 */ { ERR_SERVICECONFUSED, (char *)NULL },
+/* 436 */ { ERR_NICKCOLLISION, "%s :Nickname collision KILL from %s@%s" },
+/* 437 */ { ERR_UNAVAILRESOURCE,
+ "%s :Nick/channel is temporarily unavailable" },
+/* 438 */ { 0, (char *)NULL }, /* reserved for later use -krys */
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { ERR_USERNOTINCHANNEL, "%s %s :They aren't on that channel" },
+ { ERR_NOTONCHANNEL, "%s :You're not on that channel" },
+/* 443 */ { ERR_USERONCHANNEL, "%s %s :is already on channel" },
+/* 444 */ { ERR_NOLOGIN, "%s :User not logged in" },
+#ifndef ENABLE_SUMMON
+/* 445 */ { ERR_SUMMONDISABLED, ":SUMMON has been disabled" },
+#else
+ { 0, (char *)NULL },
+#endif
+#ifndef ENABLE_USERS
+/* 446 */ { ERR_USERSDISABLED, ":USERS has been disabled" },
+#else
+ { 0, (char *)NULL },
+#endif
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+/* 451 */ { ERR_NOTREGISTERED, ":You have not registered" },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+/* 461 */ { ERR_NEEDMOREPARAMS, "%s :Not enough parameters" },
+/* 462 */ { ERR_ALREADYREGISTRED,
+ ":Unauthorized command (already registered)" },
+/* 463 */ { ERR_NOPERMFORHOST, ":Your host isn't among the privileged" },
+/* 464 */ { ERR_PASSWDMISMATCH, ":Password Incorrect" },
+/* 465 */ { ERR_YOUREBANNEDCREEP, ":You are banned from this server" },
+/* 466 */ { ERR_YOUWILLBEBANNED, (char *)NULL },
+/* 467 */ { ERR_KEYSET, "%s :Channel key already set" },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+/* 471 */ { ERR_CHANNELISFULL, "%s :Cannot join channel (+l)" },
+/* 472 */ { ERR_UNKNOWNMODE , "%c :is unknown mode char to me for %s" },
+/* 473 */ { ERR_INVITEONLYCHAN, "%s :Cannot join channel (+i)" },
+/* 474 */ { ERR_BANNEDFROMCHAN, "%s :Cannot join channel (+b)" },
+/* 475 */ { ERR_BADCHANNELKEY, "%s :Cannot join channel (+k)" },
+/* 476 */ { ERR_BADCHANMASK, "%s :Bad Channel Mask" },
+/* 477 */ { ERR_NOCHANMODES, "%s :Channel doesn't support modes" },
+/* 478 */ { ERR_BANLISTFULL, "%s %s :Channel list is full" },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+/* 481 */ { ERR_NOPRIVILEGES,
+ ":Permission Denied- You're not an IRC operator" },
+/* 482 */ { ERR_CHANOPRIVSNEEDED, "%s :You're not channel operator" },
+/* 483 */ { ERR_CANTKILLSERVER, "%s :You can't kill a server!" },
+/* 484 */ { ERR_RESTRICTED, ":Your connection is restricted!" },
+/* 485 */ { ERR_UNIQOPRIVSNEEDED,
+ ":You're not the original channel operator" },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+/* 491 */ { ERR_NOOPERHOST, ":No O-lines for your host" },
+/* 492 */ { ERR_NOSERVICEHOST, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+/* 501 */ { ERR_UMODEUNKNOWNFLAG, ":Unknown MODE flag" },
+/* 502 */ { ERR_USERSDONTMATCH, ":Can't change mode for other users" },
+ { 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" },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+/* 311 */ { RPL_WHOISUSER, "%s %s %s * :%s" },
+/* 312 */ { RPL_WHOISSERVER, "%s %s :%s" },
+/* 313 */ { RPL_WHOISOPERATOR, "%s :is an IRC Operator" },
+/* 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 :seconds idle" },
+/* 318 */ { RPL_ENDOFWHOIS, "%s :End of WHOIS list." },
+/* 319 */ { RPL_WHOISCHANNELS, "%s :%s" },
+ { 0, (char *)NULL },
+/* 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 */ { RPL_UNIQOPIS, "%s %s" },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+/* 331 */ { RPL_NOTOPIC, "%s :No topic is set." },
+/* 332 */ { RPL_TOPIC, "%s :%s" },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+/* 341 */ { RPL_INVITING, "%s %s" },
+/* 342 */ { RPL_SUMMONING, "%s :User summoned to irc" },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+/* 346 */ { RPL_INVITELIST, "%s %s" },
+/* 347 */ { RPL_ENDOFINVITELIST, "%s :End of Channel Invite List" },
+/* 348 */ { RPL_EXCEPTLIST, "%s %s" },
+/* 349 */ { RPL_ENDOFEXCEPTLIST, "%s :End of Channel Exception List" },
+ { 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" },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+/* 361 */ { RPL_KILLDONE, (char *)NULL },
+/* 362 */ { RPL_CLOSING, "%s :Closed. Status = %d" },
+/* 363 */ { RPL_CLOSEEND, "%d: Connections Closed" },
+/* 364 */ { RPL_LINKS, "%s %s :%d %s" },
+/* 365 */ { RPL_ENDOFLINKS, "%s :End of LINKS list." },
+/* 366 */ { RPL_ENDOFNAMES, "%s :End of NAMES list." },
+/* 367 */ { RPL_BANLIST, "%s %s" },
+/* 368 */ { RPL_ENDOFBANLIST, "%s :End of Channel Ban List" },
+/* 369 */ { RPL_ENDOFWHOWAS, "%s :End of WHOWAS" },
+ { 0, (char *)NULL },
+/* 371 */ { RPL_INFO, ":%s" },
+/* 372 */ { RPL_MOTD, ":- %s" },
+/* 373 */ { RPL_INFOSTART, ":Server INFO" },
+/* 374 */ { RPL_ENDOFINFO, ":End of INFO list." },
+/* 375 */ { RPL_MOTDSTART, ":- %s Message of the Day - " },
+/* 376 */ { RPL_ENDOFMOTD, ":End of MOTD command." },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+/* 381 */ { RPL_YOUREOPER, ":You are now an IRC Operator" },
+/* 382 */ { RPL_REHASHING, "%s :Rehashing" },
+/* 383 */ { RPL_YOURESERVICE, ":You are service %s" },
+/* 384 */ { RPL_MYPORTIS, "%d :Port to local server is\r\n" },
+/* 385 */ { RPL_NOTOPERANYMORE, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+/* 391 */ { RPL_TIME, "%s :%s" },
+#ifdef ENABLE_USERS
+/* 392 */ { RPL_USERSSTART, ":UserID Terminal Host" },
+/* 393 */ { RPL_USERS, ":%-8s %-9s %-8s" },
+/* 394 */ { RPL_ENDOFUSERS, ":End of Users" },
+/* 395 */ { RPL_NOUSERS, ":Nobody logged in." },
+#else
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+#endif
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+/* 200 */ { RPL_TRACELINK, "Link %s%s %s %s V%X%s %d %d %d" },
+/* 201 */ { RPL_TRACECONNECTING, "Try. %d %s" },
+/* 202 */ { RPL_TRACEHANDSHAKE, "H.S. %d %s" },
+/* 203 */ { RPL_TRACEUNKNOWN, "???? %d %s" },
+/* 204 */ { RPL_TRACEOPERATOR, "Oper %d %s" },
+/* 205 */ { RPL_TRACEUSER, "User %d %s" },
+/* 206 */ { RPL_TRACESERVER, "Serv %d %dS %dC %s %s!%s@%s V%X%s" },
+/* 207 */ { RPL_TRACESERVICE, "Service %d %s 0x%X 0x%X" },
+/* 208 */ { RPL_TRACENEWTYPE, "<newtype> 0 %s" },
+/* 209 */ { RPL_TRACECLASS, "Class %d %d" },
+/* 210 */ { RPL_TRACERECONNECT, "Retry. %d %s" },
+/* 211 */ { RPL_STATSLINKINFO, (char *)NULL },
+/* 212 */ { RPL_STATSCOMMANDS, "%s %u %u %u" },
+/* 213 */ { RPL_STATSCLINE, "%c %s %s %s %d %d" },
+/* 214 */ { RPL_STATSNLINE, "%c %s %s %s %d %d" },
+/* 215 */ { RPL_STATSILINE, "%c %s %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 %d.%d %d.%d" },
+/* 219 */ { RPL_ENDOFSTATS, "%c :End of STATS report" },
+ { 0, (char *)NULL },
+/* 221 */ { RPL_UMODEIS, "%s" },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+/* 231 */ { RPL_SERVICEINFO, (char *)NULL },
+/* 232 */ { RPL_ENDOFSERVICES, (char *)NULL },
+/* 233 */ { RPL_SERVICE, (char *)NULL },
+/* 234 */ { RPL_SERVLIST, "%s %s %s 0x%X %d :%s" },
+/* 235 */ { RPL_SERVLISTEND, "%s %d :End of service listing" },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+ { 0, (char *)NULL },
+/* 240 */ { RPL_STATSVLINE, "%c %s %s %s %d %d" },
+/* 241 */ { RPL_STATSLLINE, "%c %s %s %s %d %d" },
+/* 242 */ { RPL_STATSUPTIME, ":Server Up %d days, %d:%02d:%02d" },
+/* 243 */ { RPL_STATSOLINE, "%c %s %s %s %d %d" },
+/* 244 */ { RPL_STATSHLINE, "%c %s %s %s %d %d" },
+/* 245 */ { RPL_STATSSLINE, "%c %s %s %s 0x%X %d" },
+/* 246 */ { RPL_STATSPING, "%s %d %d %d %d" },
+/* 247 */ { RPL_STATSBLINE, "%c %s %s %s %d %d" },
+ { 0, (char *)NULL }, /* RPL_STATSDEFINE */
+ { 0, (char *)NULL }, /* RPL_STATSDEBUG */
+/* 250 */ { RPL_STATSDLINE, "%c %s %s %s %d %d" },
+/* 251 */ { RPL_LUSERCLIENT,
+ ":There are %d users and %d services on %d servers" },
+/* 252 */ { RPL_LUSEROP, "%d :operators online" },
+/* 253 */ { RPL_LUSERUNKNOWN, "%d :unknown connections" },
+/* 254 */ { RPL_LUSERCHANNELS, "%d :channels formed" },
+/* 255 */ { RPL_LUSERME, ":I have %d clients, %d services and %d servers" },
+/* 256 */ { RPL_ADMINME, ":Administrative info about %s" },
+/* 257 */ { RPL_ADMINLOC1, ":%s" },
+/* 258 */ { RPL_ADMINLOC2, ":%s" },
+/* 259 */ { RPL_ADMINEMAIL, ":%s" },
+ { 0, (char *)NULL },
+/* 261 */ { RPL_TRACELOG, "File %s %d" },
+/* 262 */ { RPL_TRACEEND, "%s %s.%s :End of TRACE" },
+/* 263 */ { RPL_TRYAGAIN, "%s :Please wait a while and try again." },
+ { 0, (char *)NULL }
+};
+
+char *err_str(numeric, to)
+int numeric;
+char *to;
+{
+ Reg Numeric *nptr;
+ Reg int num = numeric;
+
+ if (BadPtr(to)) /* for unregistered clients */
+ to = "*";
+
+ num -= numeric_errors[0].num_val;
+ if (num < 0 || num > ERR_USERSDONTMATCH)
+ SPRINTF(numbuff,
+ ":%%s %d %%s :INTERNAL ERROR: BAD NUMERIC! %d",
+ numeric, num);
+ else
+ {
+ nptr = &numeric_errors[num];
+ Debug((DEBUG_NUM,
+ "err_str: to %s #%d num %d nptr %#x %d [%s]", to,
+ numeric, num, nptr, nptr->num_val, nptr->num_form));
+ if (!nptr->num_form || !nptr->num_val)
+ SPRINTF(numbuff,
+ ":%%s %d %%s :NO ERROR FOR NUMERIC ERROR %d",
+ numeric, num);
+ else
+ (void)prepbuf(numbuff, ME, to, nptr->num_val,
+ nptr->num_form);
+ }
+ return numbuff;
+}
+
+
+char *rpl_str(numeric, to)
+int numeric;
+char *to;
+{
+ Reg Numeric *nptr;
+ Reg int num = numeric;
+
+ if (num > 5)
+ num -= (num > 300) ? 300 : 100;
+
+ if (BadPtr(to)) /* for unregistered clients */
+ to = "*";
+
+ if (num < 0 || num > 200)
+ SPRINTF(numbuff,
+ ":%%s %d %%s :INTERNAL REPLY ERROR: BAD NUMERIC! %d",
+ numeric, num);
+ else
+ {
+ if (numeric > 99)
+ nptr = &numeric_replies[num];
+ else
+ nptr = &local_replies[num];
+ Debug((DEBUG_NUM,
+ "rpl_str: to %s #%d num %d nptr %#x %d [%s]", to,
+ numeric, num, nptr, nptr->num_val, nptr->num_form));
+ if (!nptr->num_form || !nptr->num_val)
+ SPRINTF(numbuff,
+ ":%%s %d %%s :NO REPLY FOR NUMERIC ERROR %d",
+ numeric, num);
+ else
+ (void)prepbuf(numbuff, ME, to, nptr->num_val,
+ nptr->num_form);
+ }
+ return numbuff;
+}
+
+static char *prepbuf(buffer, from, to, num, tail)
+char *buffer;
+Reg int num;
+char *from, *to, *tail;
+{
+ Reg char *s = buffer;
+
+ *s++ = ':';
+ (void)strcpy(s, from);
+ (void)strcat(s, " ");
+ s += strlen(s);
+
+ *s++ = '0' + num/100;
+ num %= 100;
+ *s++ = '0' + num/10;
+ *s++ = '0' + num%10;
+ *s++ = ' ';
+ (void)strcpy(s, to);
+ s += strlen(s);
+ *s++ = ' ';
+ (void)strcpy(s, tail);
+ return buffer;
+}
diff --git a/ircd/s_err_ext.h b/ircd/s_err_ext.h
new file mode 100644
index 0000000..e5d0534
--- /dev/null
+++ b/ircd/s_err_ext.h
@@ -0,0 +1,33 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/s_err_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in ircd/s_err.c.
+ */
+
+/* External definitions for global functions.
+ */
+#ifndef S_ERR_C
+#define EXTERN extern
+#else /* S_ERR_C */
+#define EXTERN
+#endif /* S_ERR_C */
+EXTERN char *err_str __P((int numeric, char *to));
+EXTERN char *rpl_str __P((int numeric, char *to));
+#undef EXTERN
diff --git a/ircd/s_externs.h b/ircd/s_externs.h
new file mode 100644
index 0000000..d0ef238
--- /dev/null
+++ b/ircd/s_externs.h
@@ -0,0 +1,53 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/s_externs.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 includes all *_ext.h files containing external declarations
+ * for the IRC server.
+ */
+
+#include "bsd_ext.h"
+#include "channel_ext.h"
+#include "class_ext.h"
+#include "dbuf_ext.h"
+#include "hash_ext.h"
+#include "ircd_ext.h"
+#include "list_ext.h"
+#include "match_ext.h"
+#include "packet_ext.h"
+#include "parse_ext.h"
+#include "res_comp_ext.h"
+#include "res_ext.h"
+#include "res_init_ext.h"
+#include "res_mkquery_ext.h"
+#include "s_auth_ext.h"
+#include "s_bsd_ext.h"
+#include "s_conf_ext.h"
+#include "s_debug_ext.h"
+#include "s_err_ext.h"
+#include "s_misc_ext.h"
+#include "s_numeric_ext.h"
+#include "s_serv_ext.h"
+#include "s_service_ext.h"
+#include "s_user_ext.h"
+#include "s_zip_ext.h"
+#include "s_id_ext.h"
+#include "send_ext.h"
+#include "support_ext.h"
+#include "version_ext.h"
+#include "whowas_ext.h"
diff --git a/ircd/s_id.c b/ircd/s_id.c
new file mode 100644
index 0000000..5feb948
--- /dev/null
+++ b/ircd/s_id.c
@@ -0,0 +1,208 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/s_id.c
+ * Copyright (C) 1998 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: s_id.c,v 1.9 1999/07/27 11:26:37 chopin Exp $";
+#endif
+
+#include "os.h"
+#include "s_defines.h"
+#define S_ID_C
+#include "s_externs.h"
+#undef S_ID_C
+
+/*
+ * channel IDs
+ */
+#define CHIDNB 36
+
+static unsigned char id_alphabet[CHIDNB+1] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890A";
+
+static unsigned int alphabet_id[256] =
+ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ /* 0 */ 35, /* 1 */ 26, /* 2 */ 27, /* 3 */ 28, /* 4 */ 29,
+ /* 5 */ 30, /* 6 */ 31, /* 7 */ 32, /* 8 */ 33, /* 9 */ 34,
+ -1, -1, -1, -1, -1, -1, -1,
+ /* A */ 0, /* B */ 1, /* C */ 2, /* D */ 3, /* E */ 4, /* F */ 5,
+ /* G */ 6, /* H */ 7, /* I */ 8, /* J */ 9, /* K */ 10, /* L */ 11,
+ /* M */ 12, /* N */ 13, /* O */ 14, /* P */ 15, /* Q */ 16,
+ /* R */ 17, /* S */ 18, /* T */ 19, /* U */ 20, /* V */ 21,
+ /* W */ 22, /* X */ 23, /* Y */ 24, /* Z */ 25,
+ -1, -1, -1, -1, -1, -1,
+ /* a */ 0, /* b */ 1, /* c */ 2, /* d */ 3, /* e */ 4, /* f */ 5,
+ /* g */ 6, /* h */ 7, /* i */ 8, /* j */ 9, /* k */ 10, /* l */ 11,
+ /* m */ 12, /* n */ 13, /* o */ 14, /* p */ 15, /* q */ 16,
+ /* r */ 17, /* s */ 18, /* t */ 19, /* u */ 20, /* v */ 21,
+ /* w */ 22, /* x */ 23, /* y */ 24, /* z */ 25,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1 };
+
+/* ltoid: base 10 -> base 36 conversion */
+static char *
+ltoid(l)
+time_t l;
+{
+ static char idrpl[CHIDLEN+1];
+ char c = CHIDLEN-1;
+
+ idrpl[CHIDLEN] = '\0';
+ do
+ {
+ idrpl[c] = id_alphabet[1 + l % CHIDNB];
+ l /= CHIDNB;
+ }
+ while (c-- > 0);
+ return (char *) idrpl;
+}
+
+/* idtol: base 36 -> base 10 conversion */
+static unsigned long
+idtol(id)
+char *id;
+{
+ unsigned long l = 0;
+ char c = CHIDLEN-1;
+
+ l = alphabet_id[*id++];
+ while (c-- > 0)
+ l = l * CHIDNB + alphabet_id[*id++];
+ return l;
+}
+
+/* get_chid: give the current id */
+char *
+get_chid()
+{
+ return ltoid(time(NULL));
+}
+
+/* close_chid: is the ID in the close future? (written for CHIDLEN == 5) */
+int
+close_chid(id)
+char *id;
+{
+ static time_t last = 0;
+ static char current;
+ char *curid;
+
+ if (timeofday - last > 900 || id[0] == current)
+ {
+ last = timeofday;
+ curid = get_chid();
+ current = curid[0];
+ }
+ if (id_alphabet[1 + alphabet_id[current]] == id[1])
+ return 1;
+ if (id[0] == current &&
+ idtol(id) >= (timeofday % (u_int) pow(CHIDNB, CHIDLEN)))
+ return 1;
+ return 0;
+}
+
+aChannel *idcache = NULL;
+
+/* cache_chid: add a channel to the list of cached names */
+void
+cache_chid(chptr)
+aChannel *chptr;
+{
+ /*
+ ** caching should be limited to the minimum,
+ ** for memory reasons, but most importantly for
+ ** user friendly-ness.
+ ** Is the logic here right, tho?
+ */
+ if (chptr->history == 0 ||
+ (timeofday - chptr->history) >LDELAYCHASETIMELIMIT+DELAYCHASETIMELIMIT)
+ {
+ MyFree((char *)chptr);
+ return;
+ }
+
+ chptr->nextch = idcache;
+ idcache = chptr;
+ istat.is_cchan++;
+ istat.is_cchanmem -= sizeof(aChannel) + strlen(chptr->chname);
+}
+
+/* check_chid: checks if a (short) channel name is in the cache
+ * returns: 0 if not, 1 if yes
+ */
+int
+check_chid(name)
+char *name;
+{
+ aChannel *chptr = idcache;
+
+ while (chptr)
+ {
+ if (!strcasecmp(name, chptr->chname+1+CHIDLEN))
+ return 1;
+ chptr = chptr->nextch;
+ }
+ return 0;
+}
+
+/* collect_chid: remove expired entries from the cache */
+void
+collect_chid()
+{
+ aChannel **chptr = &idcache, *del;
+
+ while (*chptr)
+ {
+ if (close_chid((*chptr)->chname) == 0)
+ {
+ del = *chptr;
+ *chptr = del->nextch;
+ istat.is_cchan--;
+ istat.is_cchanmem -= sizeof(aChannel) +strlen(del->chname);
+ MyFree((char *)del);
+ }
+ else
+ chptr = &((*chptr)->nextch);
+ }
+}
+
+/* checks wether the ID is valid */
+int
+cid_ok(name)
+char *name;
+{
+ int l = 1;
+
+ while (l <= CHIDLEN)
+ {
+ if (alphabet_id[name[l]] == -1)
+ return 0;
+ l += 1;
+ }
+ if (l != CHIDLEN+1)
+ return 0;
+ return 1;
+}
diff --git a/ircd/s_id_ext.h b/ircd/s_id_ext.h
new file mode 100644
index 0000000..e55ca33
--- /dev/null
+++ b/ircd/s_id_ext.h
@@ -0,0 +1,43 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/s_id_ext.h
+ * Copyright (C) 1998 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.
+ */
+
+/* This file contains external definitions for global variables and functions
+ defined in ircd/s_id.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef S_ID_C
+/* none */
+#endif /* S_ID_C */
+
+/* External definitions for global functions.
+ */
+#ifndef S_ID_C
+#define EXTERN extern
+#else /* S_ID_C */
+#define EXTERN
+#endif /* S_ID_C */
+EXTERN char *get_chid __P(());
+EXTERN int close_chid __P((char *));
+EXTERN void cache_chid __P((aChannel *));
+EXTERN int check_chid __P((char *));
+EXTERN void collect_chid __P(());
+EXTERN int cid_ok __P((char *));
+#undef EXTERN
diff --git a/ircd/s_misc.c b/ircd/s_misc.c
new file mode 100644
index 0000000..17c9946
--- /dev/null
+++ b/ircd/s_misc.c
@@ -0,0 +1,998 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/s_misc.c (formerly ircd/date.c)
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: s_misc.c,v 1.30 1999/07/21 22:57:39 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "s_defines.h"
+#define S_MISC_C
+#include "s_externs.h"
+#undef S_MISC_C
+
+static void exit_one_client __P((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;
+ Reg 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 = ((lt->tm_hour + 24) - gm->tm_hour) * 60;
+
+ plus = (minswest > 0) ? '-' : '+';
+ if (minswest < 0)
+ minswest = -minswest;
+
+ (void)sprintf(buf, "%s %s %d %d -- %02d:%02d %c%02d:%02d",
+ weekdays[lt->tm_wday], months[lt->tm_mon],lt->tm_mday,
+ lt->tm_year + 1900, lt->tm_hour, lt->tm_min,
+ plus, minswest/60, minswest%60);
+
+ 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, "*"));
+ 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, "*"));
+ return -1;
+ }
+ return 0;
+}
+
+/*
+** check_registered_service cancels message, if 'x' is not
+** a registered service.
+*/
+int check_registered_service(sptr)
+aClient *sptr;
+{
+ if (!IsService(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOTREGISTERED, "*"));
+ 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[username@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)
+ SPRINTF(nbuf, "%s[%s]",
+ sptr->name, sptr->sockhost);
+ else
+ SPRINTF(nbuf, "%s[%s]",
+ sptr->name, me.sockhost);
+ }
+ else
+ {
+ if (showip)
+ (void)sprintf(nbuf, "%s[%.*s@%s]",
+ sptr->name, USERLEN,
+ (!(sptr->flags & FLAGS_GOTID)) ? "" :
+ sptr->auth,
+#ifdef INET6
+ inetntop(AF_INET6,
+ (char *)&sptr->ip,
+ mydummy, MYDUMMY_SIZE));
+#else
+ inetntoa((char *)&sptr->ip));
+#endif
+ else
+ {
+ if (mycmp(sptr->name, sptr->sockhost))
+ /* Show username for clients and
+ * ident for others.
+ */
+ SPRINTF(nbuf, "%s[%.*s@%s]",
+ sptr->name, USERLEN,
+ IsPerson(sptr) ?
+ sptr->user->username :
+ sptr->auth,
+ 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))
+ SPRINTF(nbuf, "%s[%s]", cptr->name, ME);
+ else
+ (void)sprintf(nbuf, "%s[%-.*s@%-.*s]",
+ cptr->name, USERLEN,
+ (!(cptr->flags & FLAGS_GOTID)) ? "" : cptr->auth,
+ 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)
+Reg aClient *cptr;
+Reg char *host;
+{
+ Reg char *s;
+ if ((s = (char *)index(host, '@')))
+ s++;
+ else
+ s = host;
+ strncpyzt(cptr->sockhost, s, sizeof(cptr->sockhost));
+ Debug((DEBUG_DNS,"get_sockhost %s",s));
+}
+
+/*
+ * Return wildcard name of my server name according to given config entry
+ * --Jto
+ */
+char *my_name_for_link(name, count)
+char *name;
+Reg int count;
+{
+ static char namebuf[HOSTLEN];
+ Reg 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;
+}
+
+/*
+ * Goes thru the list of locally connected servers (except cptr),
+ * check if my neighbours can see the server "name" (or if it is hidden
+ * by a hostmask)
+ * Returns the number of marked servers
+ */
+int
+mark_blind_servers (cptr, name)
+aClient *cptr;
+char *name;
+{
+ Reg int i, j = 0;
+ Reg aClient *acptr;
+ Reg aConfItem *aconf;
+
+ for (i = fdas.highest; i >= 0; i--)
+ {
+ if (!(acptr = local[fdas.fd[i]]) || !IsServer(acptr))
+ continue;
+ if (acptr == cptr || IsMe(acptr))
+ {
+ acptr->flags &= ~FLAGS_HIDDEN;
+ continue;
+ }
+ if ((aconf = acptr->serv->nline) &&
+ (match(my_name_for_link(ME, aconf->port), name) == 0))
+ {
+ acptr->flags |= FLAGS_HIDDEN;
+ j++;
+ }
+ }
+ return j;
+}
+
+/*
+** 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 */
+ {
+ Reg aClient *acptr;
+ Reg aClient *next;
+ Reg aServer *asptr;
+ Reg aService *asvptr;
+#if defined(FNAME_USERLOG) || defined(USE_SYSLOG) || defined(USE_SERVICES)
+ time_t on_for;
+#endif
+ char comment1[HOSTLEN + HOSTLEN + 2];
+ int flags = 0;
+
+ if (MyConnect(sptr) || (sptr->flags & FLAGS_HELD))
+ {
+ if (sptr->flags & FLAGS_KILLED)
+ {
+ sendto_flag(SCH_LOCAL, "Killed: %s.",
+ get_client_name(sptr, TRUE));
+ sptr->exitc = EXITC_KILL;
+ }
+
+ sptr->flags |= FLAGS_CLOSING;
+#if (defined(FNAME_USERLOG) || defined(FNAME_CONNLOG) \
+ || defined(USE_SERVICES)) \
+ || (defined(USE_SYSLOG) && (defined(SYSLOG_USERS) || defined(SYSLOG_CONN)))
+ if (IsPerson(sptr))
+ {
+ /* It's ugly, it's simple, it's not so important */
+ on_for = timeofday - sptr->firsttime + 1;
+# if defined(USE_SYSLOG) && defined(SYSLOG_USERS)
+ syslog(LOG_NOTICE,
+ "%s (%3d:%02d:%02d): %s@%s [%s] %c\n",
+ myctime(sptr->firsttime),
+ on_for / 3600, (on_for % 3600)/60,
+ on_for % 60,
+ sptr->user->username, sptr->user->host,
+ sptr->auth, sptr->exitc);
+# endif
+# if defined(FNAME_USERLOG) || defined(USE_SERVICES)
+ sendto_flog(sptr, NULL, on_for, sptr->user->username,
+ sptr->user->host);
+# endif
+ }
+ else if (sptr->exitc != EXITC_REF && sptr->exitc != EXITC_AREF)
+ {
+# if defined(USE_SYSLOG) && defined(SYSLOG_CONN)
+ syslog(LOG_NOTICE,
+ "%s ( Unknown ): <none>@%s [%s] %c\n",
+ myctime(sptr->firsttime),
+ (IsUnixSocket(sptr)) ? me.sockhost :
+ ((sptr->hostp) ? sptr->hostp->h_name :
+ sptr->sockhost), sptr->auth, sptr->exitc);
+# endif
+# if defined(FNAME_CONNLOG) || defined(USE_SERVICES)
+ sendto_flog(sptr, " Unknown ", 0, "<none>",
+ (IsUnixSocket(sptr)) ? me.sockhost :
+ ((sptr->hostp) ? sptr->hostp->h_name :
+ sptr->sockhost));
+# endif
+ }
+#endif
+ if (MyConnect(sptr))
+ {
+ if (IsPerson(sptr))
+ istat.is_myclnt--;
+ else if (IsServer(sptr))
+ istat.is_myserv--;
+ else if (IsService(sptr))
+ istat.is_myservice--;
+ else
+ istat.is_unknown--;
+
+ 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);
+
+ if (sptr->auth != sptr->username)
+ {
+ istat.is_authmem -= sizeof(sptr->auth);
+ istat.is_auth -= 1;
+ MyFree(sptr->auth);
+ sptr->auth = sptr->username;
+ }
+ }
+ /*
+ ** 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...
+ ** now, I think it harms big client servers... - krys
+ **
+ ** 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);
+
+ if (IsServer(sptr))
+ {
+ /*
+ ** First QUIT all NON-servers which are behind this link
+ **
+ ** Note There is no danger of 'cptr' being exited in
+ ** the following loops. 'cptr' is a *local* client,
+ ** all dependants are *remote* clients.
+ */
+
+ /* This next bit is a a bit ugly but all it does is take the
+ ** name of us.. me.name and tack it together with the name of
+ ** the server sptr->name that just broke off and puts this
+ ** together into exit_one_client() to provide some useful
+ ** information about where the net is broken. Ian
+ */
+ (void)strcpy(comment1, ME);
+ (void)strcat(comment1," ");
+ (void)strcat(comment1, sptr->name);
+
+ /* This will quit all the *users*, without checking the
+ ** whole list of clients.
+ */
+ for (asptr = svrtop; asptr; asptr = (aServer *)next)
+ {
+ next = (aClient *)asptr->nexts;
+ if ((asptr->bcptr == NULL) ||
+ (asptr->bcptr->from != sptr
+ && asptr->bcptr != sptr))
+ continue;
+ /*
+ ** This version doesn't need QUITs to be
+ ** propagaged unless the remote server is
+ ** hidden (by a hostmask)
+ */
+ if (mark_blind_servers(NULL,
+ asptr->bcptr->name))
+ flags |= FLAGS_SPLIT | FLAGS_HIDDEN;
+ else
+ flags |= FLAGS_SPLIT;
+ while (GotDependantClient(asptr->bcptr))
+ {
+ acptr = asptr->bcptr->prev;
+ acptr->flags |= flags;
+ exit_one_client(NULL, acptr, &me,
+ comment1);
+ }
+ }
+ /*
+ ** Second SQUIT all servers behind this link
+ */
+ for (asptr = svrtop; asptr; asptr = (aServer *)next)
+ {
+ next = (aClient *)asptr->nexts;
+ if ((acptr = asptr->bcptr) &&
+ acptr->from == sptr)
+ {
+ sendto_flag(SCH_SERVER,
+ "Sending SQUIT %s (%s)",
+ acptr->name, comment);
+ exit_one_client(NULL, acptr, &me, ME);
+ }
+ }
+ } /* If (IsServer(sptr)) */
+ } /* if (MyConnect(sptr) || (sptr->flags & FLAGS_HELD)) */
+
+ if (IsServer(sptr) && GotDependantClient(sptr))
+ {
+ /*
+ ** generate QUITs locally when receiving a SQUIT
+ ** check for hostmasking.
+ */
+ if (mark_blind_servers(cptr, sptr->name))
+ flags = FLAGS_SPLIT | FLAGS_HIDDEN;
+ else
+ flags = FLAGS_SPLIT;
+
+ if (IsServer(from))
+ /* this is a guess */
+ (void)strcpy(comment1, from->name);
+ else
+ /* this is right */
+ (void)strcpy(comment1, sptr->serv->up);
+ (void)strcat(comment1, " ");
+ (void)strcat(comment1, sptr->name);
+
+ while (GotDependantClient(sptr))
+ {
+ acptr = sptr->prev;
+ acptr->flags |= flags;
+ exit_one_client(cptr, acptr, &me, comment1);
+ }
+ }
+
+ /*
+ ** Try to guess from comment if the client is exiting
+ ** normally (KILL or issued QUIT), or if it is splitting
+ ** It requires comment for splitting users to be
+ ** "server.some.where splitting.some.where"
+ */
+ comment1[0] = '\0';
+ if (!IsServer(sptr) && ((sptr->flags & FLAGS_KILLED) == 0))
+ {
+ char *c = comment;
+ int i = 0;
+ while (*c && *c != ' ')
+ if (*c++ == '.')
+ i++;
+ if (*c++ && i)
+ {
+ i = 0;
+ while (*c && *c != ' ')
+ if (*c++ == '.')
+ i++;
+ if (!i || *c)
+ sptr->flags |= FLAGS_QUIT;
+ }
+ else
+ sptr->flags |= FLAGS_QUIT;
+
+ if (sptr == cptr && !(sptr->flags & FLAGS_QUIT))
+ {
+ /*
+ ** This will avoid nick delay to be abused by
+ ** letting local users put a comment looking
+ ** like a server split.
+ */
+ strncpyzt(comment1, comment, HOSTLEN + HOSTLEN);
+ strcat(comment1, " ");
+ sptr->flags |= FLAGS_QUIT;
+ }
+ }
+
+ if (IsServer(sptr) && (cptr == sptr))
+ sendto_flag(SCH_SERVER, "Sending SQUIT %s (%s)",
+ cptr->name, comment);
+
+ exit_one_client(cptr, sptr, from, (*comment1) ? comment1 : 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.
+*/
+static void exit_one_client(cptr, sptr, from, comment)
+aClient *sptr;
+aClient *cptr;
+aClient *from;
+char *comment;
+{
+ Reg aClient *acptr;
+ Reg int i;
+ Reg 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_flag(SCH_ERROR,
+ "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)
+ */
+ istat.is_serv--;
+ for (i = fdas.highest; i >= 0; i--)
+ {
+ Reg aConfItem *aconf;
+
+ if (!(acptr = local[fdas.fd[i]]) || !IsServer(acptr) ||
+ acptr == cptr || IsMe(acptr))
+ continue;
+ if ((aconf = acptr->serv->nline) &&
+ (match(my_name_for_link(ME, aconf->port),
+ sptr->name) == 0))
+ continue;
+ sendto_one(acptr, ":%s SQUIT %s :%s",
+ from->name, sptr->name, comment);
+ }
+#ifdef USE_SERVICES
+ check_services_butone(SERVICE_WANT_SQUIT, sptr->name, sptr,
+ ":%s SQUIT %s :%s", from->name,
+ sptr->name, comment);
+#endif
+ (void) del_from_server_hash_table(sptr->serv, cptr ? cptr :
+ sptr->from);
+ } 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] && !IsService(sptr)) /* clean with QUIT... */
+ {
+ /*
+ ** If this exit is generated from "m_kill", then there
+ ** is no sense in sending the QUIT--KILL's have been
+ ** sent instead.
+ */
+ if ((sptr->flags & FLAGS_KILLED) == 0)
+ {
+ if ((sptr->flags & FLAGS_SPLIT) == 0)
+ {
+ sendto_serv_butone(cptr, ":%s QUIT :%s",
+ sptr->name, comment);
+#ifdef USE_SERVICES
+ check_services_butone(SERVICE_WANT_QUIT|
+ SERVICE_WANT_RQUIT,
+ (sptr->user) ?
+ sptr->user->server
+ : NULL, cptr,
+ ":%s QUIT :%s",
+ sptr->name, comment);
+#endif
+ }
+ else
+ {
+ if (sptr->flags & FLAGS_HIDDEN)
+ /* joys of hostmasking */
+ for (i = fdas.highest; i >= 0; i--)
+ {
+ if (!(acptr =local[fdas.fd[i]])
+ || !IsServer(acptr)
+ || acptr == cptr
+ || IsMe(acptr))
+ continue;
+ if (acptr->flags &FLAGS_HIDDEN)
+ sendto_one(acptr,
+ ":%s QUIT :%s",
+ sptr->name,
+ comment);
+ }
+#ifdef USE_SERVICES
+ check_services_butone(SERVICE_WANT_QUIT,
+ (sptr->user) ? sptr->user->server
+ : NULL, cptr,
+ ":%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)
+ {
+ if (IsInvisible(sptr))
+ istat.is_user[1]--;
+ else
+ istat.is_user[0]--;
+ if (IsAnOper(sptr))
+ istat.is_oper--;
+ sendto_common_channels(sptr, ":%s QUIT :%s",
+ sptr->name, comment);
+
+ if (!(acptr = cptr ? cptr : sptr->from))
+ acptr = sptr;
+ while ((lp = sptr->user->channel))
+ {
+ /*
+ ** Mark channels from where remote chop left,
+ ** this will eventually lock the channel.
+ ** close_connection() has already been called,
+ ** it makes MyConnect == False - krys
+ */
+ if (sptr != cptr)
+ if (*lp->value.chptr->chname == '!')
+ {
+ if (!(sptr->flags &FLAGS_QUIT))
+ lp->value.chptr->history = timeofday + LDELAYCHASETIMELIMIT;
+ }
+ else if (
+#ifndef BETTER_CDELAY
+ !(sptr->flags & FLAGS_QUIT) &&
+#endif
+ is_chan_op(sptr, lp->value.chptr))
+ lp->value.chptr->history = timeofday + DELAYCHASETIMELIMIT;
+ if (IsAnonymous(lp->value.chptr) &&
+ !IsQuiet(lp->value.chptr))
+ sendto_channel_butserv(lp->value.chptr, sptr, ":%s PART %s :None", sptr->name, lp->value.chptr->chname);
+ 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 */
+
+ /* Add user to history */
+#ifndef BETTER_NDELAY
+ add_history(sptr, (sptr->flags & FLAGS_QUIT) ?
+ &me : NULL);
+#else
+ add_history(sptr, (sptr == cptr) ? &me : NULL);
+#endif
+ off_history(sptr);
+ }
+ }
+ else if (sptr->name[0] && IsService(sptr))
+ {
+ /*
+ ** 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)
+ {
+ /*
+ ** A service quitting is annoying, It has to be sent
+ ** to connected servers depending on
+ ** sptr->service->dist
+ */
+ for (i = fdas.highest; i >= 0; i--)
+ {
+ if (!(acptr = local[fdas.fd[i]])
+ || !IsServer(acptr) || acptr == cptr
+ || IsMe(acptr))
+ continue;
+ if (match(sptr->service->dist, acptr->name))
+ continue;
+ sendto_one(acptr, ":%s QUIT :%s", sptr->name,
+ comment);
+ }
+ }
+#ifdef USE_SERVICES
+ check_services_butone(SERVICE_WANT_SERVICE, NULL, NULL,
+ ":%s QUIT :%s", sptr->name, comment);
+#endif
+ /* MyConnect(sptr) is always FALSE here */
+ if (cptr == sptr)
+ sendto_flag(SCH_NOTICE, "Service %s disconnected",
+ get_client_name(sptr, TRUE));
+ sendto_flag(SCH_SERVICE, "Received QUIT %s from %s (%s)",
+ sptr->name, from->name, comment);
+ istat.is_service--;
+ }
+
+ /* 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));
+ remove_client_from_list(sptr);
+ return;
+}
+
+void checklist()
+{
+ Reg aClient *acptr;
+ Reg 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 *)&istat, sizeof(istat));
+ istat.is_serv = 1;
+ istat.is_remc = 1; /* don't ask me why, I forgot. */
+ bzero((char *)&ircst, sizeof(ircst));
+}
+
+void tstats(cptr, name)
+aClient *cptr;
+char *name;
+{
+ Reg aClient *acptr;
+ Reg int i;
+ Reg struct stats *sp;
+ struct stats tmp;
+
+ 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 += timeofday - 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 += timeofday - 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, RPL_STATSDEBUG, name, sp->is_ac, sp->is_ref);
+ sendto_one(cptr, ":%s %d %s :unknown: commands %u prefixes %u",
+ ME, RPL_STATSDEBUG, name, sp->is_unco, sp->is_unpf);
+ sendto_one(cptr, ":%s %d %s :nick collisions %u unknown closes %u",
+ ME, RPL_STATSDEBUG, name, sp->is_kill, sp->is_ni);
+ sendto_one(cptr, ":%s %d %s :wrong direction %u empty %u",
+ ME, RPL_STATSDEBUG, name, sp->is_wrdi, sp->is_empt);
+ sendto_one(cptr, ":%s %d %s :users without servers %u ghosts N/A",
+ ME, RPL_STATSDEBUG, name, sp->is_nosrv);
+ sendto_one(cptr, ":%s %d %s :numerics seen %u mode fakes %u",
+ ME, RPL_STATSDEBUG, name, sp->is_num, sp->is_fake);
+ sendto_one(cptr, ":%s %d %s :auth: successes %u fails %u",
+ ME, RPL_STATSDEBUG, name, sp->is_asuc, sp->is_abad);
+ sendto_one(cptr,":%s %d %s :local connections %u udp packets %u",
+ ME, RPL_STATSDEBUG, name, sp->is_loc, sp->is_udpok);
+ sendto_one(cptr,":%s %d %s :udp errors %u udp dropped %u",
+ ME, RPL_STATSDEBUG, name, sp->is_udperr, sp->is_udpdrop);
+ sendto_one(cptr,
+ ":%s %d %s :link checks %u passed %u 15s/%u 30s dropped %uSq/%uYg/%uFl",
+ ME, RPL_STATSDEBUG, name, sp->is_ckl, sp->is_cklq,
+ sp->is_cklok, sp->is_cklQ, sp->is_ckly, sp->is_cklno);
+ if (sp->is_wwcnt)
+ sendto_one(cptr, ":%s %d %s :whowas turnover %u/%u/%u [%u]",
+ ME, RPL_STATSDEBUG, name, sp->is_wwmt,
+ (u_int) (sp->is_wwt / sp->is_wwcnt), sp->is_wwMt,
+ KILLCHASETIMELIMIT);
+ if (sp->is_lkcnt)
+ sendto_one(cptr, ":%s %d %s :ndelay turnover %u/%u/%u [%u]",
+ ME, RPL_STATSDEBUG, name, sp->is_lkmt,
+ (u_int) (sp->is_lkt / sp->is_lkcnt), sp->is_lkMt,
+ DELAYCHASETIMELIMIT);
+ sendto_one(cptr, ":%s %d %s :abuse protections %u strict %u", ME,
+ RPL_STATSDEBUG, name, (bootopt & BOOT_PROT) ? 1 : 0,
+ (bootopt & BOOT_STRICTPROT) ? 1 : 0);
+ sendto_one(cptr, ":%s %d %s :Client - Server",
+ ME, RPL_STATSDEBUG, name);
+ sendto_one(cptr, ":%s %d %s :connected %u %u",
+ ME, RPL_STATSDEBUG, name, sp->is_cl, sp->is_sv);
+ sendto_one(cptr, ":%s %d %s :bytes sent %u.%uK %u.%uK",
+ ME, 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, 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, RPL_STATSDEBUG, name, sp->is_cti, sp->is_sti);
+#if defined(USE_IAUTH)
+ report_iauth_stats(cptr, name);
+#endif
+}
+
+#ifdef CACHED_MOTD
+aMotd *motd = NULL;
+struct tm motd_tm;
+
+void read_motd(filename)
+char *filename;
+{
+ int fd;
+ register aMotd *temp, *last;
+ struct stat Sb;
+ char line[80];
+ register char *tmp;
+
+ if ((fd = open(filename, O_RDONLY)) == -1)
+ return;
+ if (fstat(fd, &Sb) == -1)
+ {
+ close(fd);
+ return;
+ }
+ for(;motd != NULL;motd=last)
+ {
+ last = motd->next;
+ MyFree(motd->line);
+ MyFree((char *)motd);
+ }
+ motd_tm = *localtime(&Sb.st_mtime);
+ (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
+ last = NULL;
+ while (dgets(fd, line, sizeof(line)-1) > 0)
+ {
+ if ((tmp = strchr(line, '\n')) != NULL)
+ *tmp = (char) 0;
+ if ((tmp = strchr(line, '\r')) != NULL)
+ *tmp = (char) 0;
+ temp = (aMotd *)MyMalloc(sizeof(aMotd));
+ if (!temp)
+ outofmemory();
+ temp->line = mystrdup(line);
+ temp->next = NULL;
+ if (!motd)
+ motd = temp;
+ else
+ last->next = temp;
+ last = temp;
+ }
+ (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
+ close(fd);
+}
+#endif
diff --git a/ircd/s_misc_ext.h b/ircd/s_misc_ext.h
new file mode 100644
index 0000000..3c4f572
--- /dev/null
+++ b/ircd/s_misc_ext.h
@@ -0,0 +1,58 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/s_misc_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in ircd/s_misc.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef S_MISC_C
+extern struct stats ircst, *ircstp;
+#ifdef CACHED_MOTD
+extern aMotd *motd;
+extern struct tm motd_tm;
+#endif /* CACHED_MOTD */
+#endif /* S_MISC_C */
+
+/* External definitions for global functions.
+ */
+#ifndef S_MISC_C
+#define EXTERN extern
+#else /* S_MISC_C */
+#define EXTERN
+#endif /* S_MISC_C */
+EXTERN char *date __P((time_t clock));
+EXTERN int check_registered_user __P((aClient *sptr));
+EXTERN int check_registered __P((aClient *sptr));
+EXTERN int check_registered_service __P((aClient *sptr));
+EXTERN char *get_client_name __P((aClient *sptr, int showip));
+EXTERN char *get_client_host __P((aClient *cptr));
+EXTERN void get_sockhost __P((Reg aClient *cptr, Reg char *host));
+EXTERN char *my_name_for_link __P((char *name, Reg int count));
+EXTERN int mark_blind_servers __P((aClient *cptr, char *name));
+EXTERN int exit_client __P((aClient *cptr, aClient *sptr, aClient *from,
+ char *comment));
+EXTERN void checklist();
+EXTERN void initstats();
+EXTERN void tstats __P((aClient *cptr, char *name));
+#ifdef CACHED_MOTD
+EXTERN void read_motd __P((char *filename));
+#endif /* CACHED_MOTD */
+#undef EXTERN
diff --git a/ircd/s_numeric.c b/ircd/s_numeric.c
new file mode 100644
index 0000000..bed99c1
--- /dev/null
+++ b/ircd/s_numeric.c
@@ -0,0 +1,127 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/s_numeric.c
+ * Copyright (C) 1990 Jarkko Oikarinen
+ *
+ * Numerous fixes by Markku Savela
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: s_numeric.c,v 1.4 1998/12/12 23:48:17 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "s_defines.h"
+#define S_NUMERIC_C
+#include "s_externs.h"
+#undef S_NUMERIC_C
+
+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 1;
+ /* 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 > 1)
+ {
+ for (i = 2; i < (parc - 1); i++)
+ {
+ (void)strcat(buffer, " ");
+ (void)strcat(buffer, parv[i]);
+ }
+ (void)strcat(buffer, " :");
+ (void)strcat(buffer, parv[parc-1]);
+ }
+ 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. Don't 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) || acptr->from == cptr)
+ sendto_flag(SCH_NUM,
+ "From %s for %s: %s %d %s %s.",
+ get_client_name(cptr, TRUE),
+ acptr->name, sptr->name,
+ numeric, nick, buffer);
+ else if (IsPerson(acptr) || IsServer(acptr) ||
+ IsService(acptr))
+ sendto_prefix_one(acptr, sptr,":%s %d %s%s",
+ parv[0], numeric, nick, buffer);
+ }
+ /* any reason why no cptr == acptr->from checks here? -krys */
+/* because these are not used.. -Vesa
+ else if ((acptr = find_service(nick, (aClient *)NULL)))
+ 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);
+ }
+..nuke them */
+ 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 1;
+}
diff --git a/ircd/s_numeric_ext.h b/ircd/s_numeric_ext.h
new file mode 100644
index 0000000..c17cd94
--- /dev/null
+++ b/ircd/s_numeric_ext.h
@@ -0,0 +1,33 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/s_numeric_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in ircd/s_numeric.c.
+ */
+
+/* External definitions for global functions.
+ */
+#ifndef S_NUMERIC_C
+#define EXTERN extern
+#else /* S_NUMERIC_C */
+#define EXTERN
+#endif /* S_NUMERIC_C */
+EXTERN int do_numeric __P((int numeric, aClient *cptr, aClient *sptr, int parc,
+ char *parv[]));
+#undef EXTERN
diff --git a/ircd/s_serv.c b/ircd/s_serv.c
new file mode 100644
index 0000000..67c857d
--- /dev/null
+++ b/ircd/s_serv.c
@@ -0,0 +1,2489 @@
+/************************************************************************
+ * 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: s_serv.c,v 1.65 1999/07/02 16:49:37 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "s_defines.h"
+#define S_SERV_C
+#include "s_externs.h"
+#undef S_SERV_C
+
+static char buf[BUFSIZE];
+
+static int check_link __P((aClient *));
+
+/*
+** 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[];
+{
+ if (hunt_server(cptr,sptr,":%s VERSION :%s",1,parc,parv)==HUNTED_ISME)
+ sendto_one(sptr, rpl_str(RPL_VERSION, parv[0]),
+ version, debugmode, ME, serveropts);
+ return 2;
+}
+
+/*
+** m_squit
+** parv[0] = sender prefix
+** parv[1] = server name
+** parv[2] = comment
+*/
+int m_squit(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+ {
+ Reg aConfItem *aconf;
+ char *server;
+ Reg aClient *acptr;
+ char *comment = (parc > 2 && parv[2]) ? parv[2] : cptr->name;
+
+ 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, aconf->port)))
+ 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->name;
+ 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, parv[0]), server);
+ return 1;
+ }
+ if (MyConnect(sptr) && !MyConnect(acptr) && parc < 3)
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS,parv[0]), "SQUIT");
+ return 0;
+ }
+ if (IsLocOp(sptr) && !MyConnect(acptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES, parv[0]));
+ return 1;
+ }
+ if (!MyConnect(acptr) && (cptr != acptr->from))
+ {
+ /*
+ ** The following is an awful kludge, but I don't see any other
+ ** way to change the pre 2.10.3 behaviour. I'm probably going
+ ** to regret it.. -kalt
+ */
+ if ((acptr->from->serv->version & SV_OLDSQUIT) == 0)
+ {
+ /* better server: just propagate upstream */
+ sendto_one(acptr->from, ":%s SQUIT %s :%s", parv[0],
+ acptr->name, comment);
+ sendto_flag(SCH_SERVER,
+ "Forwarding SQUIT %s from %s (%s)",
+ acptr->name, parv[0], comment);
+ sendto_flag(SCH_DEBUG,
+ "Forwarding SQUIT %s to %s from %s (%s)",
+ acptr->name, acptr->from->name,
+ parv[0], comment);
+ return 1;
+ }
+ /*
+ ** ack, bad server encountered!
+ ** must send back to other good servers which were trying to
+ ** do the right thing, and fake the yet to come SQUIT which
+ ** will never be received from the bad servers.
+ */
+ if (IsServer(cptr) &&
+ (cptr->serv->version & SV_OLDSQUIT) == 0)
+ {
+ sendto_one(cptr, ":%s SQUIT %s :%s (Bounced for %s)",
+ ME, acptr->name, comment, parv[0]);
+ sendto_flag(SCH_DEBUG, "Bouncing SQUIT %s back to %s",
+ acptr->name, acptr->from->name);
+ }
+ }
+ /*
+ ** Notify all opers, if my local link is remotely squitted
+ */
+ if (MyConnect(acptr) && !IsAnOper(cptr))
+ {
+ sendto_ops_butone(NULL, &me,
+ ":%s WALLOPS :Received SQUIT %s from %s (%s)",
+ ME, server, parv[0], comment);
+#if defined(USE_SYSLOG) && defined(SYSLOG_SQUIT)
+ syslog(LOG_DEBUG,"SQUIT From %s : %s (%s)",
+ parv[0], server, comment);
+#endif
+ }
+ if (MyConnect(acptr))
+ {
+ int timeconnected = timeofday - acptr->firsttime;
+ sendto_flag(SCH_NOTICE,
+ "Closing link to %s (%d, %2d:%02d:%02d)",
+ get_client_name(acptr, FALSE),
+ timeconnected / 86400,
+ (timeconnected % 86400) / 3600,
+ (timeconnected % 3600)/60,
+ timeconnected % 60);
+ }
+ sendto_flag(SCH_SERVER, "Received SQUIT %s from %s (%s)",
+ acptr->name, parv[0], comment);
+
+ if (MyConnect(acptr) &&
+ IsServer(cptr) && (cptr->serv->version & SV_OLDSQUIT) == 0)
+ {
+ sendto_one(cptr, ":%s SQUIT %s :%s", ME, acptr->name, comment);
+ sendto_flag(SCH_DEBUG, "Issuing additionnal SQUIT %s for %s",
+ acptr->name, acptr->from->name);
+ }
+ return exit_client(cptr, acptr, sptr, comment);
+ }
+
+/*
+** check_version
+** The PASS command delivers additional information about incoming
+** connection. The data is temporarily stored to info/name/username
+** in m_pass() and processed here before the fields are natively used.
+** Return: < 1: exit/error, > 0: no error
+*/
+int check_version(cptr)
+aClient *cptr;
+{
+ char *id, *misc = NULL, *link = NULL;
+
+ Debug((DEBUG_INFO,"check_version: %s", cptr->info));
+
+ if (cptr->info == DefInfo)
+ {
+ cptr->hopcount = SV_OLD;
+ return 1; /* no version checked (e.g. older than 2.9) */
+ }
+ if (id = index(cptr->info, ' '))
+ {
+ *id++ = '\0';
+ if (link = index(id, ' '))
+ *link++ = '\0';
+ if (misc = index(id, '|'))
+ *misc++ = '\0';
+ else
+ {
+ misc = id;
+ id = "";
+ }
+ }
+ else
+ id = "";
+
+ if (!strncmp(cptr->info, "021", 3))
+ cptr->hopcount = SV_29|SV_NJOIN|SV_NMODE|SV_NCHAN; /* SV_2_10*/
+ else if (!strncmp(cptr->info, "0209", 4))
+ cptr->hopcount = SV_29|SV_OLDSQUIT; /* 2.9+ protocol */
+ else
+ cptr->hopcount = SV_OLD; /* uhuh */
+
+ if (!strcmp("IRC", id) && !strncmp(cptr->info, "02100", 5) &&
+ atoi(cptr->info+5) < 20600)
+ /* before 2.10.3a6 ( 2.10.3a5 is just broken ) */
+ cptr->hopcount |= SV_OLDSQUIT;
+
+ /* Check version number/mask from conf */
+ sprintf(buf, "%s/%s", id, cptr->info);
+ if (find_two_masks(cptr->name, buf, CONF_VER))
+ {
+ sendto_flag(SCH_ERROR, "Bad version %s %s from %s", id,
+ cptr->info, get_client_name(cptr, TRUE));
+ return exit_client(cptr, cptr, &me, "Bad version");
+ }
+
+ if (misc)
+ {
+ sprintf(buf, "%s/%s", id, misc);
+ /* Check version flags from conf */
+ if (find_conf_flags(cptr->name, buf, CONF_VER))
+ {
+ sendto_flag(SCH_ERROR, "Bad flags %s (%s) from %s",
+ misc, id, get_client_name(cptr, TRUE));
+ return exit_client(cptr, cptr, &me, "Bad flags");
+ }
+ }
+
+ /* right now, I can't code anything good for this */
+ /* Stop whining, and do it! ;) */
+ if (link && strchr(link, 'Z')) /* Compression requested */
+ cptr->flags |= FLAGS_ZIPRQ;
+ /*
+ * If server was started with -p strict, be careful about the
+ * other server mode.
+ */
+ if (link && strncmp(cptr->info, "020", 3) &&
+ (bootopt & BOOT_STRICTPROT) && !strchr(link, 'P'))
+ return exit_client(cptr, cptr, &me, "Unsafe mode");
+
+ return 2;
+}
+
+/*
+** m_server
+** parv[0] = sender prefix
+** parv[1] = servername
+** parv[2] = serverinfo/hopcount
+** parv[3] = token/serverinfo (2.9)
+** parv[4] = serverinfo
+*/
+int m_server(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+ Reg char *ch;
+ Reg int i;
+ char info[REALLEN+1], *inpath, *host, *stok;
+ aClient *acptr, *bcptr;
+ aConfItem *aconf;
+ int hop = 0, token = 0;
+
+ if (sptr->user) /* in case NICK hasn't been received yet */
+ {
+ sendto_one(sptr, err_str(ERR_ALREADYREGISTRED, parv[0]));
+ return 1;
+ }
+ info[0] = info[REALLEN] = '\0'; /* strncpy() doesn't guarantee NULL */
+ inpath = get_client_name(cptr, FALSE);
+ if (parc < 2 || *parv[1] == '\0')
+ {
+ sendto_one(cptr,"ERROR :No servername");
+ return 1;
+ }
+ host = parv[1];
+ if (parc > 3 && (hop = atoi(parv[2])))
+ {
+ if (parc > 4 && (token = atoi(parv[3])))
+ (void)strncpy(info, parv[4], REALLEN);
+ else
+ (void)strncpy(info, parv[3], REALLEN);
+ }
+ else if (parc > 2)
+ {
+ (void)strncpy(info, parv[2], REALLEN);
+ i = strlen(info);
+ if (parc > 3 && ((i+2) < REALLEN))
+ {
+ (void)strncat(info, " ", REALLEN - i - 1);
+ (void)strncat(info, parv[3], REALLEN - i - 2);
+ }
+ }
+ /*
+ ** 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) > (size_t) 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)", host);
+ sendto_flag(SCH_ERROR, "Bogus server name (%s) from %s", host,
+ get_client_name(cptr, TRUE));
+ return 2;
+ }
+
+ /* *WHEN* can it be that "cptr != sptr" ????? --msa */
+ /* When SERVER command (like now) has prefix. -avalon */
+
+ if (IsRegistered(cptr) && ((acptr = find_name(host, NULL))
+ || (acptr = find_mask(host, NULL))))
+ {
+ /*
+ ** 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
+ */
+ bcptr = (cptr->firsttime > acptr->from->firsttime) ? cptr :
+ acptr->from;
+ sendto_one(bcptr, "ERROR :Server %s already exists", host);
+ /* in both cases the bcptr (the youngest is killed) */
+ if (bcptr == cptr)
+ {
+ sendto_flag(SCH_ERROR,
+ "Link %s cancelled, server %s already exists",
+ get_client_name(bcptr, TRUE), host);
+ return exit_client(bcptr, bcptr, &me, "Server Exists");
+ }
+ else
+ {
+ /*
+ ** in this case, we are not dropping the link from
+ ** which we got the SERVER message. Thus we canNOT
+ ** `return' yet! -krys
+ */
+ strcpy(buf, get_client_name(bcptr, TRUE));
+ sendto_flag(SCH_ERROR,
+ "Link %s cancelled, server %s reintroduced by %s",
+ buf, host, get_client_name(cptr, TRUE));
+ (void) exit_client(bcptr, bcptr, &me, "Server Exists");
+ }
+ }
+ if ((acptr = find_person(host, NULL)) && (acptr != cptr))
+ {
+ /*
+ ** 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_flag(SCH_ERROR,
+ "Link %s cancelled: Server/nick collision on %s",
+ inpath, host);
+ sendto_serv_butone(NULL, /* all servers */
+ ":%s KILL %s :%s (%s <- %s)",
+ ME, acptr->name, ME,
+ acptr->from->name, host);
+ acptr->flags |= FLAGS_KILLED;
+ (void)exit_client(NULL, acptr, &me, "Nick collision");
+ return exit_client(cptr, cptr, &me, "Nick as Server");
+ }
+
+ if (IsServer(cptr))
+ {
+ /* A server can only be introduced by another server. */
+ if (!IsServer(sptr))
+ {
+ sendto_flag(SCH_LOCAL,
+ "Squitting %s brought by %s (introduced by %s)",
+ host, get_client_name(cptr, FALSE),
+ sptr->name);
+ sendto_one(cptr,
+ ":%s SQUIT %s :(Introduced by %s from %s)",
+ me.name, host, sptr->name,
+ get_client_name(cptr, FALSE));
+ return 1;
+ }
+ /*
+ ** 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);
+ sendto_flag(SCH_ERROR, "No server info for %s from %s",
+ host, get_client_name(cptr, TRUE));
+ return 1;
+ }
+
+ /*
+ ** See if the newly found server is behind a guaranteed
+ ** leaf (L-line). If so, close the link.
+ */
+ if ((aconf = find_conf_host(cptr->confs, host, CONF_LEAF)) &&
+ (!aconf->port || (hop > aconf->port)))
+ {
+ sendto_flag(SCH_ERROR,
+ "Leaf-only link %s->%s - Closing",
+ get_client_name(cptr, TRUE),
+ aconf->host ? aconf->host : "*");
+ sendto_one(cptr, "ERROR :Leaf-only link, sorry.");
+ return exit_client(cptr, cptr, &me, "Leaf Only");
+ }
+ /*
+ **
+ */
+ if (!(aconf = find_conf_host(cptr->confs, host, CONF_HUB)) ||
+ (aconf->port && (hop > aconf->port)) )
+ {
+ sendto_flag(SCH_ERROR,
+ "Non-Hub link %s introduced %s(%s).",
+ get_client_name(cptr, TRUE), host,
+ aconf ? (aconf->host ? aconf->host : "*") :
+ "!");
+ return exit_client(cptr, cptr, &me,
+ "Too many servers");
+ }
+ /*
+ ** See if the newly found server has a Q line for it in
+ ** our conf. If it does, lose the link that brought it
+ ** into our network. Format:
+ **
+ ** Q:<unused>:<reason>:<servername>
+ **
+ ** Example: Q:*:for the hell of it:eris.Berkeley.EDU
+ */
+ if ((aconf = find_conf_name(host, CONF_QUARANTINED_SERVER)))
+ {
+ sendto_ops_butone(NULL, &me,
+ ":%s WALLOPS * :%s brought in %s, %s %s",
+ ME, get_client_name(cptr, TRUE),
+ host, "closing link because",
+ BadPtr(aconf->passwd) ? "reason unspecified" :
+ aconf->passwd);
+
+ sendto_one(cptr,
+ "ERROR :%s is not welcome: %s. %s",
+ host, BadPtr(aconf->passwd) ?
+ "reason unspecified" : aconf->passwd,
+ "Go away and get a life");
+
+ return exit_client(cptr, cptr, &me, "Q-Lined Server");
+ }
+
+ acptr = make_client(cptr);
+ (void)make_server(acptr);
+ acptr->hopcount = hop;
+ strncpyzt(acptr->name, host, sizeof(acptr->name));
+ if (acptr->info != DefInfo)
+ MyFree(acptr->info);
+ acptr->info = mystrdup(info);
+ acptr->serv->up = sptr->name;
+ acptr->serv->stok = token;
+ acptr->serv->snum = find_server_num(acptr->name);
+ SetServer(acptr);
+ istat.is_serv++;
+ add_client_to_list(acptr);
+ (void)add_to_client_hash_table(acptr->name, acptr);
+ (void)add_to_server_hash_table(acptr->serv, cptr);
+ /*
+ ** Old sendto_serv_but_one() call removed because we now
+ ** need to send different names to different servers
+ ** (domain name matching)
+ */
+ for (i = fdas.highest; i >= 0; i--)
+ {
+ if (!(bcptr = local[fdas.fd[i]]) || !IsServer(bcptr) ||
+ bcptr == cptr || IsMe(bcptr))
+ continue;
+ if (!(aconf = bcptr->serv->nline))
+ {
+ sendto_flag(SCH_NOTICE,
+ "Lost N-line for %s on %s:Closing",
+ get_client_name(cptr, TRUE), host);
+ return exit_client(cptr, cptr, &me,
+ "Lost N line");
+ }
+ if (match(my_name_for_link(ME, aconf->port),
+ acptr->name) == 0)
+ continue;
+ stok = acptr->serv->tok;
+ sendto_one(bcptr, ":%s SERVER %s %d %s :%s", parv[0],
+ acptr->name, hop+1, stok, acptr->info);
+ }
+#ifdef USE_SERVICES
+ check_services_butone(SERVICE_WANT_SERVER, acptr->name, acptr,
+ ":%s SERVER %s %d %s :%s", parv[0],
+ acptr->name, hop+1, acptr->serv->tok,
+ acptr->info);
+#endif
+ sendto_flag(SCH_SERVER, "Received SERVER %s from %s (%d %s)",
+ acptr->name, parv[0], hop+1, acptr->info);
+ return 0;
+ }
+
+ if ((!IsUnknown(cptr) && !IsHandshake(cptr)) ||
+ (cptr->flags & FLAGS_UNKCMD))
+ return 1;
+ /*
+ ** 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));
+ /* cptr->name has to exist before check_version(), and cptr->info
+ * may not be filled before check_version(). */
+ if ((hop = check_version(cptr)) < 1)
+ return hop; /* from exit_client() */
+ if (cptr->info != DefInfo)
+ MyFree(cptr->info);
+ cptr->info = mystrdup(info[0] ? info : ME);
+
+ switch (check_server_init(cptr))
+ {
+ case 0 :
+ return m_server_estab(cptr);
+ case 1 :
+ sendto_flag(SCH_NOTICE, "Checking access for %s",
+ get_client_name(cptr,TRUE));
+ return 1;
+ default :
+ ircstp->is_ref++;
+ sendto_flag(SCH_NOTICE, "Unauthorized server from %s.",
+ get_client_host(cptr));
+ return exit_client(cptr, cptr, &me, "No C/N conf lines");
+ }
+}
+
+int m_server_estab(cptr)
+Reg aClient *cptr;
+{
+ Reg aClient *acptr;
+ Reg aConfItem *aconf, *bconf;
+ char mlname[HOSTLEN+1], *inpath, *host, *s, *encr, *stok;
+ int split, i;
+
+ host = cptr->name;
+ inpath = get_client_name(cptr,TRUE); /* "refresh" inpath with host */
+ split = mycmp(cptr->name, cptr->sockhost);
+
+ if (!(aconf = find_conf(cptr->confs, host, CONF_NOCONNECT_SERVER)))
+ {
+ ircstp->is_ref++;
+ sendto_one(cptr,
+ "ERROR :Access denied. No N line for server %s",
+ inpath);
+ sendto_flag(SCH_ERROR,
+ "Access denied. No N line for server %s", inpath);
+ return exit_client(cptr, cptr, &me, "No N line for server");
+ }
+ if (!(bconf = find_conf(cptr->confs, host, CONF_CONNECT_SERVER|
+ CONF_ZCONNECT_SERVER)))
+ {
+ ircstp->is_ref++;
+ sendto_one(cptr, "ERROR :Only N (no C) field for server %s",
+ inpath);
+ sendto_flag(SCH_ERROR,
+ "Only N (no C) field for server %s",inpath);
+ return exit_client(cptr, cptr, &me, "No C line for server");
+ }
+
+ if (cptr->hopcount == SV_OLD) /* lame test, should be == 0 */
+ {
+ sendto_one(cptr, "ERROR :Server version is too old.");
+ sendto_flag(SCH_ERROR, "Old version for %s", inpath);
+ return exit_client(cptr, cptr, &me, "Old version");
+ }
+
+#ifdef CRYPT_LINK_PASSWORD
+ /* use first two chars of the password they send in as salt */
+
+ /* passwd may be NULL. Head it off at the pass... */
+ if (*cptr->passwd)
+ {
+ char salt[3];
+ extern char *crypt();
+
+ /* Determine if MD5 or DES */
+ if (strncmp(aconf->passwd, "$1$", 3))
+ {
+ salt[0] = aconf->passwd[0];
+ salt[1] = aconf->passwd[1];
+ }
+ else
+ {
+ salt[0] = aconf->passwd[3];
+ salt[1] = aconf->passwd[4];
+ }
+ salt[2] = '\0';
+ encr = crypt(cptr->passwd, salt);
+ }
+ else
+ encr = "";
+#else
+ encr = cptr->passwd;
+#endif /* CRYPT_LINK_PASSWORD */
+ if (*aconf->passwd && !StrEq(aconf->passwd, encr))
+ {
+ ircstp->is_ref++;
+ sendto_one(cptr, "ERROR :No Access (passwd mismatch) %s",
+ inpath);
+ sendto_flag(SCH_ERROR,
+ "Access denied (passwd mismatch) %s", inpath);
+ return exit_client(cptr, cptr, &me, "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_flag(SCH_ERROR, "I'm a leaf, cannot link %s",
+ get_client_name(cptr, TRUE));
+ return exit_client(cptr, cptr, &me, "I'm a leaf");
+ }
+#endif
+ (void) strcpy(mlname, my_name_for_link(ME, aconf->port));
+ if (IsUnknown(cptr))
+ {
+ if (bconf->passwd[0])
+#ifndef ZIP_LINKS
+ sendto_one(cptr, "PASS %s %s IRC|%s %s", bconf->passwd,
+ pass_version, serveropts,
+ (bootopt & BOOT_STRICTPROT) ? "P" : "");
+#else
+ sendto_one(cptr, "PASS %s %s IRC|%s %s%s",
+ bconf->passwd, pass_version, serveropts,
+ (bconf->status == CONF_ZCONNECT_SERVER) ? "Z" : "",
+ (bootopt & BOOT_STRICTPROT) ? "P" : "");
+#endif
+ /*
+ ** Pass my info to the new server
+ */
+ sendto_one(cptr, "SERVER %s 1 :%s", mlname, me.info);
+
+ /*
+ ** If we get a connection which has been authorized to be
+ ** an already existing connection, remove the already
+ ** existing connection if it has a sendq else remove the
+ ** new and duplicate server. -avalon
+ ** Remove existing link only if it has been linked for longer
+ ** and has sendq higher than a threshold. -Vesa
+ */
+ if ((acptr = find_name(host, NULL))
+ || (acptr = find_mask(host, NULL)))
+ {
+ if (MyConnect(acptr) &&
+ DBufLength(&acptr->sendQ) > CHREPLLEN &&
+ timeofday - acptr->firsttime > TIMESEC)
+ (void) exit_client(acptr, acptr, &me,
+ "New Server");
+ else
+ return exit_client(cptr, cptr, &me,
+ "Server Exists");
+ }
+ }
+ 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_flag(SCH_ERROR,
+ "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, &me, "Bad User");
+ }
+ *s = '@';
+ }
+
+#ifdef ZIP_LINKS
+ if ((cptr->flags & FLAGS_ZIPRQ) &&
+ (bconf->status == CONF_ZCONNECT_SERVER))
+ {
+ if (zip_init(cptr) == -1)
+ {
+ zip_free(cptr);
+ sendto_flag(SCH_ERROR,
+ "Unable to setup compressed link for %s",
+ get_client_name(cptr, TRUE));
+ return exit_client(cptr, cptr, &me,
+ "zip_init() failed");
+ }
+ cptr->flags |= FLAGS_ZIP|FLAGS_ZIPSTART;
+ }
+#endif
+
+ det_confs_butmask(cptr, CONF_LEAF|CONF_HUB|CONF_NOCONNECT_SERVER);
+ /*
+ ** *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);
+ istat.is_unknown--;
+ istat.is_serv++;
+ istat.is_myserv++;
+ nextping = timeofday;
+ sendto_flag(SCH_NOTICE, "Link with %s established. (%X%s)", inpath,
+ cptr->hopcount, (cptr->flags & FLAGS_ZIP) ? "z" : "");
+ (void)add_to_client_hash_table(cptr->name, cptr);
+ /* doesnt duplicate cptr->serv if allocted this struct already */
+ (void)make_server(cptr);
+ cptr->serv->up = me.name;
+ cptr->serv->nline = aconf;
+ cptr->serv->version = cptr->hopcount; /* temporary location */
+ cptr->hopcount = 1; /* local server connection */
+ cptr->serv->snum = find_server_num(cptr->name);
+ cptr->serv->stok = 1;
+ cptr->flags |= FLAGS_CBURST;
+ (void) add_to_server_hash_table(cptr->serv, cptr);
+ Debug((DEBUG_NOTICE, "Server link established with %s V%X %d",
+ cptr->name, cptr->serv->version, cptr->serv->stok));
+ add_fd(cptr->fd, &fdas);
+#ifdef USE_SERVICES
+ check_services_butone(SERVICE_WANT_SERVER, cptr->name, cptr,
+ ":%s SERVER %s %d %s :%s", ME, cptr->name,
+ cptr->hopcount+1, cptr->serv->tok, cptr->info);
+#endif
+ sendto_flag(SCH_SERVER, "Sending SERVER %s (%d %s)", cptr->name,
+ 1, cptr->info);
+ /*
+ ** 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 = fdas.highest; i >= 0; i--)
+ {
+ if (!(acptr = local[fdas.fd[i]]) || !IsServer(acptr) ||
+ acptr == cptr || IsMe(acptr))
+ continue;
+ if ((aconf = acptr->serv->nline) &&
+ !match(my_name_for_link(ME, aconf->port), cptr->name))
+ continue;
+ stok = cptr->serv->tok;
+ if (split)
+ sendto_one(acptr,":%s SERVER %s 2 %s :[%s] %s",
+ ME, cptr->name, stok,
+ cptr->sockhost, cptr->info);
+ else
+ sendto_one(acptr,":%s SERVER %s 2 %s :%s",
+ ME, cptr->name, stok, 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) || !IsServer(acptr))
+ continue;
+ if (*mlname == '*' && match(mlname, acptr->name) == 0)
+ continue;
+ split = (MyConnect(acptr) &&
+ mycmp(acptr->name, acptr->sockhost));
+ stok = acptr->serv->tok;
+ if (split)
+ sendto_one(cptr, ":%s SERVER %s %d %s :[%s] %s",
+ acptr->serv->up,
+ acptr->name, acptr->hopcount+1, stok,
+ acptr->sockhost, acptr->info);
+ else
+ sendto_one(cptr, ":%s SERVER %s %d %s :%s",
+ acptr->serv->up, acptr->name,
+ acptr->hopcount+1, stok, acptr->info);
+ }
+
+ for (acptr = &me; acptr; acptr = acptr->prev)
+ {
+ /* acptr->from == acptr for acptr == cptr */
+ if (acptr->from == cptr)
+ continue;
+ if (IsPerson(acptr))
+ {
+ /*
+ ** IsPerson(x) is true only when IsClient(x) is true.
+ ** These are only true when *BOTH* NICK and USER have
+ ** been received. -avalon
+ */
+ if (*mlname == '*' &&
+ match(mlname, acptr->user->server) == 0)
+ stok = me.serv->tok;
+ else
+ stok = acptr->user->servp->tok;
+ send_umode(NULL, acptr, 0, SEND_UMODES, buf);
+ sendto_one(cptr,"NICK %s %d %s %s %s %s :%s",
+ acptr->name, acptr->hopcount + 1,
+ acptr->user->username,
+ acptr->user->host, stok,
+ (*buf) ? buf : "+", acptr->info);
+ if ((cptr->serv->version & SV_NJOIN) == 0)
+ send_user_joins(cptr, acptr);
+ }
+ else if (IsService(acptr) &&
+ match(acptr->service->dist, cptr->name) == 0)
+ {
+ if (*mlname == '*' &&
+ match(mlname, acptr->service->server) == 0)
+ stok = me.serv->tok;
+ else
+ stok = acptr->service->servp->tok;
+ sendto_one(cptr, "SERVICE %s %s %s %d %d :%s",
+ acptr->name, stok, acptr->service->dist,
+ acptr->service->type, acptr->hopcount + 1,
+ acptr->info);
+ }
+ /* the previous if does NOT catch all services.. ! */
+ }
+
+ flush_connections(cptr->fd);
+
+ /*
+ ** Last, pass all channels modes
+ ** only sending modes for LIVE channels.
+ */
+ {
+ Reg aChannel *chptr;
+ for (chptr = channel; chptr; chptr = chptr->nextch)
+ if (chptr->users)
+ {
+ if (cptr->serv->version & SV_NJOIN)
+ send_channel_members(cptr, chptr);
+ send_channel_modes(cptr, chptr);
+ }
+ }
+
+ cptr->flags &= ~FLAGS_CBURST;
+#ifdef ZIP_LINKS
+ /*
+ ** some stats about the connect burst,
+ ** they are slightly incorrect because of cptr->zip->outbuf.
+ */
+ if ((cptr->flags & FLAGS_ZIP) && cptr->zip->out->total_in)
+ sendto_flag(SCH_NOTICE,
+ "Connect burst to %s: %lu, compressed: %lu (%3.1f%%)",
+ get_client_name(cptr, TRUE),
+ cptr->zip->out->total_in,cptr->zip->out->total_out,
+ (float) 100*cptr->zip->out->total_out/cptr->zip->out->total_in);
+#endif
+ return 0;
+}
+
+int m_reconnect(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+ aConfItem *aconf;
+ aClient *acptr = NULL;
+ char *name;
+ int i;
+
+ if (IsRegistered(sptr))
+ return exit_client(cptr, sptr, &me, "Already registered");
+
+ if (parc < 3)
+ return 1;
+
+ name = parv[1];
+
+ for (i = highest_fd; i >= 0; i--)
+ {
+ if (!(acptr = local[i]) || !IsHeld(acptr) ||
+ bcmp((char *)&acptr->ip, (char *)&cptr->ip,
+ sizeof(acptr->ip)) || mycmp(acptr->name, name))
+ continue;
+ if (!(aconf = find_conf_name(name, CONF_CONNECT_SERVER|
+ CONF_ZCONNECT_SERVER)) ||
+ atoi(parv[2]) != acptr->receiveM)
+ break;
+ attach_confs(acptr, name, CONF_SERVER_MASK);
+ acptr->flags &= ~FLAGS_HELD;
+ acptr->fd = cptr->fd;
+ cptr->fd = -2;
+ SetUnknown(acptr);
+ if (check_server(acptr, NULL, NULL, NULL, TRUE) < 0)
+ break;
+ sendto_flag(SCH_NOTICE, "%s has reconnected",
+ get_client_name(acptr, TRUE));
+ return exit_client(cptr, sptr, &me, "Reconnected");
+ }
+ sendto_flag(SCH_NOTICE, "Reconnect from %s failed",
+ get_client_name(cptr, TRUE));
+ if (acptr)
+ (void) exit_client(cptr, acptr, &me, "Reconnect failed");
+ return exit_client(cptr, sptr, &me, "Reconnect failed");
+}
+
+/*
+** 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;
+
+ if (IsServer(cptr) && check_link(cptr))
+ {
+ sendto_one(sptr, rpl_str(RPL_TRYAGAIN, parv[0]),
+ "INFO");
+ return 5;
+ }
+ if (hunt_server(cptr,sptr,":%s INFO :%s",1,parc,parv) == HUNTED_ISME)
+ {
+ while (*text)
+ sendto_one(sptr, rpl_str(RPL_INFO, parv[0]), *text++);
+
+ sendto_one(sptr, rpl_str(RPL_INFO, parv[0]), "");
+ sendto_one(sptr,
+ ":%s %d %s :Birth Date: %s, compile # %s",
+ ME, RPL_INFO, parv[0], creation, generation);
+ sendto_one(sptr, ":%s %d %s :On-line since %s",
+ ME, RPL_INFO, parv[0],
+ myctime(me.firsttime));
+ sendto_one(sptr, rpl_str(RPL_ENDOFINFO, parv[0]));
+ return 5;
+ }
+ else
+ return 10;
+}
+
+/*
+** 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[];
+{
+ Reg aServer *asptr;
+ char *mask;
+ aClient *acptr;
+
+ if (parc > 2)
+ {
+ if (IsServer(cptr) && check_link(cptr) && !IsOper(sptr))
+ {
+ sendto_one(sptr, rpl_str(RPL_TRYAGAIN, parv[0]),
+ "LINKS");
+ return 5;
+ }
+ if (hunt_server(cptr, sptr, ":%s LINKS %s :%s", 1, parc, parv)
+ != HUNTED_ISME)
+ return 5;
+ mask = parv[2];
+ }
+ else
+ mask = parc < 2 ? NULL : parv[1];
+
+ for (asptr = svrtop, (void)collapse(mask); asptr; asptr = asptr->nexts)
+ {
+ acptr = asptr->bcptr;
+ if (!BadPtr(mask) && match(mask, acptr->name))
+ continue;
+ sendto_one(sptr, rpl_str(RPL_LINKS, parv[0]),
+ acptr->name, acptr->serv->up,
+ acptr->hopcount, (acptr->info[0] ? acptr->info :
+ "(Unknown Location)"));
+ }
+
+ sendto_one(sptr, rpl_str(RPL_ENDOFLINKS, parv[0]),
+ BadPtr(mask) ? "*" : mask);
+ return 2;
+}
+
+/*
+** m_summon should be redefined to ":prefix SUMMON host user" so
+** that "hunt_server"-function could be used for this too!!! --msa
+** As of 2.7.1e, this was the case. -avalon
+**
+** parv[0] = sender prefix
+** parv[1] = user
+** parv[2] = server
+** parv[3] = channel (optional)
+*/
+int m_summon(cptr, sptr, parc, parv)
+aClient *sptr, *cptr;
+int parc;
+char *parv[];
+{
+ char *host, *user, *chname;
+#ifdef ENABLE_SUMMON
+ char hostbuf[17], namebuf[10], linebuf[10];
+# ifdef LEAST_IDLE
+ char linetmp[10], ttyname[15]; /* Ack */
+ struct stat stb;
+ time_t ltime = (time_t)0;
+# endif
+ int fd, flag = 0;
+#endif
+
+ if (parc < 2 || *parv[1] == '\0')
+ {
+ sendto_one(sptr, err_str(ERR_NORECIPIENT, parv[0]), "SUMMON");
+ return 1;
+ }
+ user = parv[1];
+ host = (parc < 3 || BadPtr(parv[2])) ? ME : parv[2];
+ chname = (parc > 3) ? parv[3] : "*";
+ /*
+ ** Summoning someone on remote server, find out which link to
+ ** use and pass the message there...
+ */
+ parv[1] = user;
+ parv[2] = host;
+ parv[3] = chname;
+ parv[4] = NULL;
+ if (hunt_server(cptr, sptr, ":%s SUMMON %s %s %s", 2, parc, parv) ==
+ HUNTED_ISME)
+ {
+#ifdef ENABLE_SUMMON
+ if ((fd = utmp_open()) == -1)
+ {
+ sendto_one(sptr, err_str(ERR_FILEERROR, parv[0]),
+ "open", UTMP);
+ return 1;
+ }
+# ifndef LEAST_IDLE
+ while ((flag = utmp_read(fd, namebuf, linebuf, hostbuf,
+ sizeof(hostbuf))) == 0)
+ if (StrEq(namebuf,user))
+ break;
+# else
+ /* use least-idle tty, not the first
+ * one we find in utmp. 10/9/90 Spike@world.std.com
+ * (loosely based on Jim Frost jimf@saber.com code)
+ */
+
+ while ((flag = utmp_read(fd, namebuf, linetmp, hostbuf,
+ sizeof(hostbuf))) == 0)
+ {
+ if (StrEq(namebuf,user))
+ {
+ SPRINTF(ttyname,"/dev/%s",linetmp);
+ if (stat(ttyname,&stb) == -1)
+ {
+ sendto_one(sptr,
+ err_str(ERR_FILEERROR,
+ sptr->name),
+ "stat", ttyname);
+ return 1;
+ }
+ if (!ltime)
+ {
+ ltime= stb.st_mtime;
+ (void)strcpy(linebuf,linetmp);
+ }
+ else if (stb.st_mtime > ltime) /* less idle */
+ {
+ ltime= stb.st_mtime;
+ (void)strcpy(linebuf,linetmp);
+ }
+ }
+ }
+# endif
+ (void)utmp_close(fd);
+# ifdef LEAST_IDLE
+ if (ltime == 0)
+# else
+ if (flag == -1)
+# endif
+ sendto_one(sptr, err_str(ERR_NOLOGIN, parv[0]), user);
+ else
+ summon(sptr, user, linebuf, chname);
+#else
+ sendto_one(sptr, err_str(ERR_SUMMONDISABLED, parv[0]));
+#endif /* ENABLE_SUMMON */
+ }
+ else
+ return 3;
+ return 2;
+}
+
+
+/*
+** 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[17][3] = {
+ { CONF_ZCONNECT_SERVER, RPL_STATSCLINE, 'c'},
+ { CONF_CONNECT_SERVER, RPL_STATSCLINE, 'C'},
+ { CONF_NOCONNECT_SERVER, RPL_STATSNLINE, 'N'},
+ { CONF_CLIENT, RPL_STATSILINE, 'I'},
+ { CONF_RCLIENT, RPL_STATSILINE, 'i'},
+ { CONF_OTHERKILL, RPL_STATSKLINE, 'k'},
+ { CONF_KILL, RPL_STATSKLINE, 'K'},
+ { CONF_QUARANTINED_SERVER,RPL_STATSQLINE, 'Q'},
+ { CONF_LEAF, RPL_STATSLLINE, 'L'},
+ { CONF_OPERATOR, RPL_STATSOLINE, 'O'},
+ { CONF_HUB, RPL_STATSHLINE, 'H'},
+ { CONF_LOCOP, RPL_STATSOLINE, 'o'},
+ { CONF_SERVICE, RPL_STATSSLINE, 'S'},
+ { CONF_VER, RPL_STATSVLINE, 'V'},
+ { CONF_BOUNCE, RPL_STATSBLINE, 'B'},
+ { CONF_DENY, RPL_STATSDLINE, 'D'},
+ { 0, 0, 0}
+ };
+
+static void report_configured_links(sptr, to, mask)
+aClient *sptr;
+char *to;
+int mask;
+{
+ static char null[] = "<NULL>";
+ aConfItem *tmp;
+ int *p, port;
+ char c, *host, *pass, *name;
+
+ for (tmp = (mask & (CONF_KILL|CONF_OTHERKILL)) ? kconf : conf;
+ tmp; tmp = tmp->next)
+ if (tmp->status & mask)
+ {
+ 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/V lines the passwd contents can be
+ * displayed on STATS reply. -Vesa
+ */
+ if (tmp->status == CONF_KILL
+ || tmp->status == CONF_OTHERKILL
+ || tmp->status == CONF_VER)
+ sendto_one(sptr, rpl_str(p[1], to), c, host,
+ (pass) ? pass : null,
+ name, port, get_conf_class(tmp));
+ else
+ sendto_one(sptr, rpl_str(p[1], to), c, host,
+ (pass) ? "*" : null,
+ name, port, get_conf_class(tmp));
+ }
+ return;
+}
+
+static void report_ping(sptr, to)
+aClient *sptr;
+char *to;
+{
+ aConfItem *tmp;
+ aCPing *cp;
+
+ for (tmp = conf; tmp; tmp = tmp->next)
+ if ((cp = tmp->ping) && cp->lseq)
+ {
+ if (mycmp(tmp->name, tmp->host))
+ SPRINTF(buf,"%s[%s]",tmp->name, tmp->host);
+ else
+ (void)strcpy(buf, tmp->name);
+ sendto_one(sptr, rpl_str(RPL_STATSPING, to),
+ buf, cp->lseq, cp->lrecvd,
+ cp->ping / (cp->recvd ? cp->recvd : 1),
+ tmp->pref);
+ sendto_flag(SCH_DEBUG, "%s: %d", buf, cp->seq);
+ }
+ return;
+}
+
+int m_stats(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+ {
+ static char Lformat[] = ":%s %d %s %s %u %u %u %u %u :%u";
+ struct Message *mptr;
+ aClient *acptr;
+ char stat = parc > 1 ? parv[1][0] : '\0';
+ Reg int i;
+ int doall = 0, wilds = 0;
+ char *name = NULL, *cm = NULL;
+
+ if (IsServer(cptr) &&
+ (stat != 'd' && stat != 'p' && stat != 'q' && stat != 's' &&
+ stat != 'u' && stat != 'v') &&
+ !(stat == 'o' && IsOper(sptr)))
+ {
+ if (check_link(cptr))
+ {
+ sendto_one(sptr, rpl_str(RPL_TRYAGAIN, parv[0]),
+ "STATS");
+ return 5;
+ }
+ }
+ if (parc == 3)
+ {
+ if (hunt_server(cptr, sptr, ":%s STATS %s %s",
+ 2, parc, parv) != HUNTED_ISME)
+ return 5;
+ }
+ else if (parc == 4)
+ {
+ if (hunt_server(cptr, sptr, ":%s STATS %s %s %s",
+ 2, parc, parv) != HUNTED_ISME)
+ return 5;
+ }
+
+ if (parc > 2)
+ {
+ name = parv[2];
+ if (!mycmp(name, ME))
+ doall = 2;
+ else if (match(name, ME) == 0)
+ doall = 1;
+ if (index(name, '*') || index(name, '?'))
+ wilds = 1;
+ if (parc > 3)
+ {
+ cm = parv[3];
+ if (!index(cm, '*') && !index(cm, '?'))
+ wilds = 0, doall = 0;
+ }
+ }
+ else
+ name = ME;
+
+ switch (stat)
+ {
+ case 'L' : case 'l' :
+ /*
+ * send info about connections which match, or all if the
+ * mask matches ME. Only restrictions are on those who
+ * are invisible not being visible to 'foreigners' who use
+ * a wild card based search to list it.
+ */
+ for (i = 0; i <= highest_fd; i++)
+ {
+ if (!(acptr = local[i]))
+ continue;
+#if 0
+ if (IsPerson(acptr) && IsInvisible(acptr) &&
+ (doall || wilds) && !(MyConnect(sptr) &&
+ IsLocal(sptr) && IsOper(sptr)) &&
+ !IsAnOper(acptr) && acptr != sptr)
+#endif
+ if (IsPerson(acptr) &&
+ (doall || wilds) &&
+ !(MyConnect(sptr) && IsAnOper(sptr)) &&
+ acptr != sptr)
+ continue;
+ if (!doall && wilds && match(name, acptr->name))
+ continue;
+ if (!(doall || wilds) &&
+ ((!cm && mycmp(name, acptr->name)) ||
+ (cm && match(cm, acptr->name))))
+ continue;
+ sendto_one(cptr, Lformat, ME,
+ RPL_STATSLINKINFO, parv[0],
+ get_client_name(acptr, isupper(stat)),
+ (int)DBufLength(&acptr->sendQ),
+ (int)acptr->sendM, (int)acptr->sendK,
+ (int)acptr->receiveM, (int)acptr->receiveK,
+ timeofday - acptr->firsttime);
+ }
+ break;
+#if defined(USE_IAUTH)
+ case 'a' : case 'A' : /* iauth configuration */
+ report_iauth_conf(sptr, parv[0]);
+ break;
+#endif
+ case 'B' : case 'b' : /* B conf lines */
+ report_configured_links(cptr, parv[0], CONF_BOUNCE);
+ break;
+ case 'c' : case 'C' : /* C and N conf lines */
+ report_configured_links(cptr, parv[0], CONF_CONNECT_SERVER|
+ CONF_ZCONNECT_SERVER|
+ CONF_NOCONNECT_SERVER);
+ break;
+ case 'd' : case 'D' : /* defines */
+ send_defines(cptr, parv[0]);
+ break;
+ case 'H' : case 'h' : /* H, L and D conf lines */
+ report_configured_links(cptr, parv[0],
+ CONF_HUB|CONF_LEAF|CONF_DENY);
+ break;
+ case 'I' : case 'i' : /* I (and i) conf lines */
+ report_configured_links(cptr, parv[0],
+ CONF_CLIENT|CONF_RCLIENT);
+ break;
+ case 'K' : case 'k' : /* K lines */
+ report_configured_links(cptr, parv[0],
+ (CONF_KILL|CONF_OTHERKILL));
+ break;
+ case 'M' : case 'm' : /* commands use/stats */
+ for (mptr = msgtab; mptr->cmd; mptr++)
+ if (mptr->count)
+ sendto_one(cptr, rpl_str(RPL_STATSCOMMANDS,
+ parv[0]), mptr->cmd,
+ mptr->count, mptr->bytes,
+ mptr->rcount);
+ break;
+ case 'o' : case 'O' : /* O (and o) lines */
+ report_configured_links(cptr, parv[0], CONF_OPS);
+ break;
+ case 'p' : case 'P' : /* ircd ping stats */
+ report_ping(sptr, parv[0]);
+ break;
+ case 'Q' : case 'q' : /* Q lines */
+ report_configured_links(cptr,parv[0],CONF_QUARANTINED_SERVER);
+ break;
+ case 'R' : case 'r' : /* usage */
+ send_usage(cptr, parv[0]);
+ break;
+ case 'S' : case 's' : /* S lines */
+ report_configured_links(cptr, parv[0], CONF_SERVICE);
+ break;
+ case 'T' : case 't' : /* various statistics */
+ tstats(cptr, parv[0]);
+ break;
+ case 'U' : case 'u' : /* uptime */
+ {
+ register time_t now;
+
+ now = timeofday - me.since;
+ sendto_one(sptr, rpl_str(RPL_STATSUPTIME, parv[0]),
+ now/86400, (now/3600)%24, (now/60)%60, now%60);
+ break;
+ }
+ case 'V' : case 'v' : /* V conf lines */
+ report_configured_links(cptr, parv[0], CONF_VER);
+ break;
+ case 'X' : case 'x' : /* lists */
+#ifdef DEBUGMODE
+ send_listinfo(cptr, parv[0]);
+#endif
+ break;
+ case 'Y' : case 'y' : /* Y lines */
+ report_classes(cptr, parv[0]);
+ break;
+ case 'Z' : /* memory use (OPER only) */
+ if (MyOper(sptr))
+ count_memory(cptr, parv[0], 1);
+ else
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES, parv[0]));
+ break;
+ case 'z' : /* memory use */
+ count_memory(cptr, parv[0], 0);
+ break;
+ default :
+ stat = '*';
+ break;
+ }
+ sendto_one(cptr, rpl_str(RPL_ENDOFSTATS, parv[0]), stat);
+ return 2;
+ }
+
+/*
+** m_users
+** parv[0] = sender prefix
+** parv[1] = servername
+*/
+int m_users(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+#ifdef ENABLE_USERS
+ char namebuf[10],linebuf[10],hostbuf[17];
+ int fd, flag = 0;
+#endif
+
+ if (hunt_server(cptr,sptr,":%s USERS :%s",1,parc,parv) == HUNTED_ISME)
+ {
+#ifdef ENABLE_USERS
+ if ((fd = utmp_open()) == -1)
+ {
+ sendto_one(sptr, err_str(ERR_FILEERROR, parv[0]),
+ "open", UTMP);
+ return 1;
+ }
+
+ sendto_one(sptr, rpl_str(RPL_USERSSTART, parv[0]));
+ while (utmp_read(fd, namebuf, linebuf,
+ hostbuf, sizeof(hostbuf)) == 0)
+ {
+ flag = 1;
+ sendto_one(sptr, rpl_str(RPL_USERS, parv[0]),
+ namebuf, linebuf, hostbuf);
+ }
+ if (flag == 0)
+ sendto_one(sptr, rpl_str(RPL_NOUSERS, parv[0]));
+
+ sendto_one(sptr, rpl_str(RPL_ENDOFUSERS, parv[0]));
+ (void)utmp_close(fd);
+#else
+ sendto_one(sptr, err_str(ERR_USERSDISABLED, parv[0]));
+#endif
+ }
+ else
+ return 3;
+ return 2;
+}
+
+/*
+** 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[];
+ {
+ Reg 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 2;
+ if (cptr == sptr)
+ sendto_flag(SCH_ERROR, "from %s -- %s",
+ get_client_name(cptr, FALSE), para);
+ else
+ sendto_flag(SCH_ERROR, "from %s via %s -- %s",
+ sptr->name, get_client_name(cptr,FALSE), para);
+ return 2;
+ }
+
+/*
+** m_help
+** parv[0] = sender prefix
+*/
+int m_help(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+ {
+ int i;
+
+ for (i = 0; msgtab[i].cmd; i++)
+ sendto_one(sptr,":%s NOTICE %s :%s",
+ ME, parv[0], msgtab[i].cmd);
+ return 2;
+ }
+
+/*
+ * 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 = 0, /* server */
+ c_count = 0, /* client (visible) */
+ u_count = 0, /* unknown */
+ i_count = 0, /* invisible client */
+ o_count = 0, /* oparator */
+ v_count = 0; /* service */
+ int m_client = 0, /* my clients */
+ m_server = 0, /* my server links */
+ m_service = 0; /* my services */
+ aClient *acptr;
+
+ if (parc > 2)
+ if (hunt_server(cptr, sptr, ":%s LUSERS %s :%s", 2, parc, parv)
+ != HUNTED_ISME)
+ return 3;
+
+ if (parc == 1 || !MyConnect(sptr))
+ {
+ sendto_one(sptr, rpl_str(RPL_LUSERCLIENT, parv[0]),
+ istat.is_user[0] + istat.is_user[1],
+ istat.is_service, istat.is_serv);
+ if (istat.is_oper)
+ sendto_one(sptr, rpl_str(RPL_LUSEROP, parv[0]),
+ istat.is_oper);
+ if (istat.is_unknown > 0)
+ sendto_one(sptr, rpl_str(RPL_LUSERUNKNOWN, parv[0]),
+ istat.is_unknown);
+ if (istat.is_chan)
+ sendto_one(sptr, rpl_str(RPL_LUSERCHANNELS, parv[0]),
+ istat.is_chan);
+ sendto_one(sptr, rpl_str(RPL_LUSERME, parv[0]),
+ istat.is_myclnt, istat.is_myservice,
+ istat.is_myserv);
+ return 2;
+ }
+ (void)collapse(parv[1]);
+ for (acptr = client; acptr; acptr = acptr->next)
+ {
+ 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++;
+ /* flow thru */
+ case STAT_ME:
+ s_count++;
+ break;
+ case STAT_SERVICE:
+ if (MyConnect(acptr))
+ m_service++;
+ v_count++;
+ break;
+ case STAT_CLIENT:
+ if (IsOper(acptr))
+ o_count++;
+#ifdef SHOW_INVISIBLE_LUSERS
+ if (MyConnect(acptr))
+ m_client++;
+ if (!IsInvisible(acptr))
+ c_count++;
+ else
+ i_count++;
+#else
+ if (MyConnect(acptr))
+ {
+ if (IsInvisible(acptr))
+ {
+ if (IsAnOper(sptr))
+ m_client++;
+ }
+ else
+ m_client++;
+ }
+ if (!IsInvisible(acptr))
+ c_count++;
+ else
+ i_count++;
+#endif
+ break;
+ default:
+ u_count++;
+ break;
+ }
+ }
+#ifndef SHOW_INVISIBLE_LUSERS
+ if (IsAnOper(sptr) && i_count)
+#endif
+ sendto_one(sptr, rpl_str(RPL_LUSERCLIENT, parv[0]),
+ c_count + i_count, v_count, s_count);
+#ifndef SHOW_INVISIBLE_LUSERS
+ else
+ sendto_one(sptr, rpl_str(RPL_LUSERCLIENT, parv[0]),
+ c_count, v_count, s_count);
+#endif
+ if (o_count)
+ sendto_one(sptr, rpl_str(RPL_LUSEROP, parv[0]), o_count);
+ if (u_count > 0)
+ sendto_one(sptr, rpl_str(RPL_LUSERUNKNOWN, parv[0]), u_count);
+ if ((c_count = count_channels(sptr))>0)
+ sendto_one(sptr, rpl_str(RPL_LUSERCHANNELS, parv[0]),
+ count_channels(sptr));
+ sendto_one(sptr, rpl_str(RPL_LUSERME, parv[0]), m_client, m_service,
+ m_server);
+ return 2;
+ }
+
+
+/***********************************************************************
+ * 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;
+ aClient *acptr;
+
+ if (parc > 3 && IsLocOp(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES, parv[0]));
+ return 1;
+ }
+
+ if (hunt_server(cptr,sptr,":%s CONNECT %s %s :%s",
+ 3,parc,parv) != HUNTED_ISME)
+ return 1;
+
+ if (parc < 3 || *parv[1] == '\0')
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]),
+ "CONNECT");
+ return 0;
+ }
+
+ if ((acptr = find_name(parv[1], NULL))
+ || (acptr = find_mask(parv[1], NULL)))
+ {
+ sendto_one(sptr, ":%s NOTICE %s :Connect: Server %s %s %s.",
+ ME, 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_ZCONNECT_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 ||
+ aconf->status == CONF_ZCONNECT_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 irc.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 ((port = atoi(parv[2])) <= 0)
+ {
+ sendto_one(sptr, "NOTICE %s :Connect: Illegal port number",
+ parv[0]);
+ return 0;
+ }
+ else if (port <= 0)
+ {
+ sendto_one(sptr, ":%s NOTICE %s :Connect: missing port number",
+ ME, parv[0]);
+ return 0;
+ }
+ /*
+ ** Notify all operators about remote connect requests
+ */
+ if (!IsAnOper(cptr))
+ {
+ sendto_ops_butone(NULL, &me,
+ ":%s WALLOPS :Remote CONNECT %s %s from %s",
+ ME, 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, parv[0], aconf->host, aconf->name);
+ sendto_flag(SCH_NOTICE, "Connecting to %s[%s] by %s",
+ aconf->host, aconf->name,
+ get_client_name(sptr, FALSE));
+ break;
+ case -1:
+ sendto_one(sptr, ":%s NOTICE %s :*** Couldn't connect to %s.",
+ ME, parv[0], aconf->host);
+ sendto_flag(SCH_NOTICE, "Couldn't connect to %s by %s",
+ aconf->host, get_client_name(sptr, FALSE));
+ break;
+ case -2:
+ sendto_one(sptr, ":%s NOTICE %s :*** Host %s is unknown.",
+ ME, parv[0], aconf->host);
+ sendto_flag(SCH_NOTICE, "Connect by %s to unknown host %s",
+ get_client_name(sptr, FALSE), aconf->host);
+ break;
+ default:
+ sendto_one(sptr,
+ ":%s NOTICE %s :*** Connection to %s failed: %s",
+ ME, parv[0], aconf->host, strerror(retval));
+ sendto_flag(SCH_NOTICE, "Connection to %s by %s failed: %s",
+ aconf->host, get_client_name(sptr, FALSE),
+ strerror(retval));
+ }
+ aconf->port = tmpport;
+ return 0;
+ }
+
+/*
+** m_wallops (write to *all* opers currently online)
+** parv[0] = sender prefix
+** parv[1] = message text
+*/
+int m_wallops(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+ {
+ char *message, *pv[4];
+
+ message = parc > 1 ? parv[1] : NULL;
+
+ if (BadPtr(message))
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]),
+ "WALLOPS");
+ return 1;
+ }
+
+ if (!IsServer(sptr))
+ {
+ pv[0] = parv[0];
+ pv[1] = "+wallops";
+ pv[2] = message;
+ pv[3] = NULL;
+ return m_private(cptr, sptr, 3, pv);
+ }
+ sendto_ops_butone(IsServer(cptr) ? cptr : NULL, sptr,
+ ":%s WALLOPS :%s", parv[0], message);
+#ifdef USE_SERVICES
+ check_services_butone(SERVICE_WANT_WALLOP, NULL, sptr,
+ ":%s WALLOP :%s", parv[0], message);
+#endif
+ return 2;
+ }
+
+/*
+** m_time
+** parv[0] = sender prefix
+** parv[1] = servername
+*/
+int m_time(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+ if (hunt_server(cptr,sptr,":%s TIME :%s",1,parc,parv) == HUNTED_ISME)
+ sendto_one(sptr, rpl_str(RPL_TIME, parv[0]), ME, date((long)0));
+ return 2;
+}
+
+
+/*
+** 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;
+
+ if (IsRegistered(cptr) && /* only local query for unregistered */
+ hunt_server(cptr,sptr,":%s ADMIN :%s",1,parc,parv) != HUNTED_ISME)
+ return 3;
+ if ((aconf = find_admin()) && aconf->host && aconf->passwd
+ && aconf->name)
+ {
+ sendto_one(sptr, rpl_str(RPL_ADMINME, parv[0]), ME);
+ sendto_one(sptr, rpl_str(RPL_ADMINLOC1, parv[0]), aconf->host);
+ sendto_one(sptr, rpl_str(RPL_ADMINLOC2, parv[0]),
+ aconf->passwd);
+ sendto_one(sptr, rpl_str(RPL_ADMINEMAIL, parv[0]),
+ aconf->name);
+ }
+ else
+ sendto_one(sptr, err_str(ERR_NOADMININFO, parv[0]), ME);
+ return 2;
+ }
+
+#if defined(OPER_REHASH) || defined(LOCOP_REHASH)
+/*
+** m_rehash
+**
+*/
+int m_rehash(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+ sendto_one(sptr, rpl_str(RPL_REHASHING, parv[0]),
+ mybasename(configfile));
+ sendto_flag(SCH_NOTICE,
+ "%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);
+}
+#endif
+
+#if defined(OPER_RESTART) || defined(LOCOP_RESTART)
+/*
+** m_restart
+**
+*/
+int m_restart(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+ Reg aClient *acptr;
+ Reg int i;
+ char killer[HOSTLEN * 2 + USERLEN + 5];
+
+ strcpy(killer, get_client_name(sptr, TRUE));
+ for (i = 0; i <= highest_fd; i++)
+ {
+ if (!(acptr = local[i]))
+ continue;
+ if (IsClient(acptr) || IsService(acptr))
+ {
+ sendto_one(acptr,
+ ":%s NOTICE %s :Server Restarting. %s",
+ ME, acptr->name, killer);
+ acptr->exitc = EXITC_DIE;
+ if (IsClient(acptr))
+ exit_client(acptr, acptr, &me,
+ "Server Restarting");
+ /* services are kept for logging purposes */
+ }
+ else if (IsServer(acptr))
+ sendto_one(acptr, ":%s ERROR :Restarted by %s",
+ ME, killer);
+ }
+ flush_connections(me.fd);
+
+ SPRINTF(buf, "RESTART by %s", get_client_name(sptr, TRUE));
+ restart(buf);
+ /*NOT REACHED*/
+ return 0;
+}
+#endif
+
+/*
+** m_trace
+** parv[0] = sender prefix
+** parv[1] = servername
+*/
+int m_trace(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+ Reg int i;
+ Reg aClient *acptr;
+ aClass *cltmp;
+ char *tname;
+ int doall, link_s[MAXCONNECTIONS], link_u[MAXCONNECTIONS];
+ int wilds, dow;
+
+ if (parc > 1)
+ tname = parv[1];
+ else
+ tname = ME;
+
+ 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, parv[1]);
+ sendto_one(sptr, rpl_str(RPL_TRACELINK, parv[0]),
+ version, debugmode, tname, ac2ptr->from->name,
+ ac2ptr->from->serv->version,
+ (ac2ptr->from->flags & FLAGS_ZIP) ? "z" : "",
+ timeofday - ac2ptr->from->firsttime,
+ (int)DBufLength(&ac2ptr->from->sendQ),
+ (int)DBufLength(&sptr->from->sendQ));
+ return 5;
+ }
+ case HUNTED_ISME:
+ break;
+ default:
+ return 1;
+ }
+
+ doall = (parv[1] && (parc > 1)) ? !match(tname, ME): TRUE;
+ wilds = !parv[1] || index(tname, '*') || index(tname, '?');
+ dow = wilds || doall;
+
+ if (doall) {
+ for (i = 0; i < MAXCONNECTIONS; i++)
+ link_s[i] = 0, link_u[i] = 0;
+ for (acptr = client; acptr; acptr = acptr->next)
+#ifdef SHOW_INVISIBLE_LUSERS
+ if (IsPerson(acptr))
+ link_u[acptr->from->fd]++;
+#else
+ if (IsPerson(acptr) &&
+ (!IsInvisible(acptr) || IsOper(sptr)))
+ link_u[acptr->from->fd]++;
+#endif
+ else if (IsServer(acptr))
+ link_s[acptr->from->fd]++;
+ }
+
+ /* report all direct connections */
+
+ for (i = 0; i <= highest_fd; i++)
+ {
+ char *name;
+ int class;
+
+ if (!(acptr = local[i])) /* Local Connection? */
+ continue;
+ if (IsPerson(acptr) && IsInvisible(acptr) && dow &&
+ !(MyConnect(sptr) && IsAnOper(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,
+ parv[0]), class, name);
+ break;
+ case STAT_HANDSHAKE:
+ sendto_one(sptr, rpl_str(RPL_TRACEHANDSHAKE, parv[0]),
+ class, name);
+ break;
+ case STAT_ME:
+ break;
+ case STAT_UNKNOWN:
+ if (IsAnOper(sptr) || MyClient(sptr))
+ sendto_one(sptr,
+ rpl_str(RPL_TRACEUNKNOWN, parv[0]),
+ class, name);
+ break;
+ case STAT_CLIENT:
+ /* Only opers see users if there is a wildcard
+ * but anyone can see all the opers.
+ */
+/*
+ if (IsOper(sptr) &&
+ (MyClient(sptr) || !(dow && IsInvisible(acptr)))
+ || !dow || IsAnOper(acptr))
+ {
+ if (IsOper(sptr) && !(dow || IsInvisible(acptr)) ||
+ (IsOper(sptr) && IsLocal(sptr)) ||
+ !dow || IsAnOper(acptr))
+*/
+ if (IsAnOper(acptr))
+ sendto_one(sptr,
+ rpl_str(RPL_TRACEOPERATOR, parv[0]),
+ class, name);
+ else if (!dow || (MyConnect(sptr) && IsAnOper(sptr)))
+ sendto_one(sptr,
+ rpl_str(RPL_TRACEUSER, parv[0]),
+ class, name);
+/*
+ {
+ if (IsAnOper(acptr))
+ sendto_one(sptr,
+ rpl_str(RPL_TRACEOPERATOR,
+ parv[0]), class, name);
+ else
+ sendto_one(sptr, rpl_str(RPL_TRACEUSER,
+ parv[0]), class, name);
+ }
+*/
+ break;
+ case STAT_SERVER:
+ if (acptr->serv->user)
+ sendto_one(sptr, rpl_str(RPL_TRACESERVER,
+ parv[0]), class, link_s[i],
+ link_u[i], name, acptr->serv->by,
+ acptr->serv->user->username,
+ acptr->serv->user->host,
+ acptr->serv->version,
+ (acptr->flags & FLAGS_ZIP) ?"z":"");
+ else
+ sendto_one(sptr, rpl_str(RPL_TRACESERVER,
+ parv[0]), class, link_s[i],
+ link_u[i], name,
+ *(acptr->serv->by) ?
+ acptr->serv->by : "*", "*", ME,
+ acptr->serv->version,
+ (acptr->flags & FLAGS_ZIP) ?"z":""); break;
+ case STAT_RECONNECT:
+ sendto_one(sptr, rpl_str(RPL_TRACERECONNECT, parv[0]),
+ class, name);
+ break;
+ case STAT_SERVICE:
+ sendto_one(sptr, rpl_str(RPL_TRACESERVICE, parv[0]),
+ class, name, acptr->service->type,
+ acptr->service->wants);
+ break;
+ case STAT_LOG:
+ sendto_one(sptr, rpl_str(RPL_TRACELOG, parv[0]),
+ ME, acptr->port);
+ break;
+ default: /* ...we actually shouldn't come here... --msa */
+ sendto_one(sptr, rpl_str(RPL_TRACENEWTYPE, parv[0]),
+ name);
+ break;
+ }
+ }
+
+ /*
+ * Add these lines to summarize the above which can get rather long
+ * and messy when done remotely - Avalon
+ */
+ if (IsPerson(sptr) && SendWallops(sptr))
+ for (cltmp = FirstClass(); doall && cltmp; cltmp = NextClass(cltmp))
+ if (Links(cltmp) > 0)
+ sendto_one(sptr, rpl_str(RPL_TRACECLASS, parv[0]),
+ Class(cltmp), Links(cltmp));
+ sendto_one(sptr, rpl_str(RPL_TRACEEND, parv[0]), tname, version,
+ debugmode);
+ return 2;
+ }
+
+/*
+** m_motd
+** parv[0] = sender prefix
+** parv[1] = servername
+*/
+int m_motd(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+#ifdef CACHED_MOTD
+ register aMotd *temp;
+ struct tm *tm;
+#else
+ int fd;
+ char line[80];
+ Reg char *tmp;
+ struct stat sb;
+ struct tm *tm;
+#endif
+
+ if (check_link(cptr))
+ {
+ sendto_one(sptr, rpl_str(RPL_TRYAGAIN, parv[0]), "MOTD");
+ return 5;
+ }
+ if (hunt_server(cptr, sptr, ":%s MOTD :%s", 1,parc,parv)!=HUNTED_ISME)
+ return 5;
+#ifdef CACHED_MOTD
+ tm = &motd_tm;
+ if (motd == NULL)
+ {
+ sendto_one(sptr, err_str(ERR_NOMOTD, parv[0]));
+ return 1;
+ }
+ sendto_one(sptr, rpl_str(RPL_MOTDSTART, parv[0]), ME);
+ sendto_one(sptr, ":%s %d %s :- %d/%d/%d %d:%02d", ME, RPL_MOTD,
+ parv[0], tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year,
+ tm->tm_hour, tm->tm_min);
+ temp = motd;
+ for(temp=motd;temp != NULL;temp = temp->next)
+ sendto_one(sptr, rpl_str(RPL_MOTD, parv[0]), temp->line);
+ sendto_one(sptr, rpl_str(RPL_ENDOFMOTD, parv[0]));
+ return 2;
+#else
+ /*
+ * stop NFS hangs...most systems should be able to open a file in
+ * 3 seconds. -avalon (curtesy of wumpus)
+ */
+ (void)alarm(3);
+ fd = open(IRCDMOTD_PATH, O_RDONLY);
+ (void)alarm(0);
+ if (fd == -1)
+ {
+ sendto_one(sptr, err_str(ERR_NOMOTD, parv[0]));
+ return 1;
+ }
+ (void)fstat(fd, &sb);
+ sendto_one(sptr, rpl_str(RPL_MOTDSTART, parv[0]), ME);
+ tm = localtime(&sb.st_mtime);
+ sendto_one(sptr, ":%s %d %s :- %d/%d/%d %d:%02d", ME, 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 (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, rpl_str(RPL_MOTD, parv[0]), line);
+ }
+ (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
+ sendto_one(sptr, rpl_str(RPL_ENDOFMOTD, parv[0]));
+ (void)close(fd);
+ return 2;
+#endif /* CACHED_MOTD */
+}
+
+/*
+** m_close - added by Darren Reed Jul 13 1992.
+*/
+int m_close(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+ Reg aClient *acptr;
+ Reg int i;
+ int closed = 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, parv[0]),
+ get_client_name(acptr, TRUE), acptr->status);
+ (void)exit_client(acptr, acptr, &me, "Oper Closing");
+ closed++;
+ }
+ sendto_one(sptr, rpl_str(RPL_CLOSEEND, parv[0]), closed);
+ return 1;
+}
+
+#if defined(OPER_DIE) || defined(LOCOP_DIE)
+int m_die(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+ Reg aClient *acptr;
+ Reg int i;
+ char killer[HOSTLEN * 2 + USERLEN + 5];
+
+ strcpy(killer, get_client_name(sptr, TRUE));
+ for (i = 0; i <= highest_fd; i++)
+ {
+ if (!(acptr = local[i]))
+ continue;
+ if (IsClient(acptr) || IsService(acptr))
+ {
+ sendto_one(acptr,
+ ":%s NOTICE %s :Server Terminating. %s",
+ ME, acptr->name, killer);
+ acptr->exitc = EXITC_DIE;
+ if (IsClient(acptr))
+ exit_client(acptr, acptr, &me, "Server died");
+ /* services are kept for logging purposes */
+ }
+ else if (IsServer(acptr))
+ sendto_one(acptr, ":%s ERROR :Terminated by %s",
+ ME, killer);
+ }
+ flush_connections(me.fd);
+ (void)s_die(0);
+ return 0;
+}
+#endif
+
+/*
+** storing server names in User structures is a real waste,
+** the following functions change it to only store a pointer.
+** A better way might be to store in Server structure and use servp. -krys
+*/
+
+static char **server_name = NULL;
+static int server_max = 0, server_num = 0;
+
+/*
+** find_server_string
+**
+** Given an index, this will return a pointer to the corresponding
+** (already allocated) string
+*/
+char *
+find_server_string(snum)
+int snum;
+{
+ if (snum < server_num && snum >= 0)
+ return server_name[snum];
+ /* request for a bogus snum value, something is wrong */
+ sendto_flag(SCH_ERROR, "invalid index for server_name[] : %d (%d,%d)",
+ snum, server_num, server_max);
+ return NULL;
+}
+
+/*
+** find_server_num
+**
+** Given a server name, this will return the index of the corresponding
+** string. This index can be used with find_server_name_from_num().
+** If the string doesn't exist already, it will be allocated.
+*/
+int
+find_server_num(sname)
+char *sname;
+{
+ Reg int i = 0;
+
+ while (i < server_num)
+ {
+ if (!strcasecmp(server_name[i], sname))
+ break;
+ i++;
+ }
+ if (i < server_num)
+ return i;
+ if (i == server_max)
+ {
+ /* server_name[] array is full, let's make it bigger! */
+ if (server_name)
+ server_name = (char **) MyRealloc((char *)server_name,
+ sizeof(char *)*(server_max+=50));
+ else
+ server_name = (char **) MyMalloc(sizeof(char *)*(server_max=50));
+ }
+ server_name[server_num] = mystrdup(sname);
+ return server_num++;
+}
+
+/*
+** check_link (added 97/12 to prevent abuse)
+** routine which tries to find out how healthy a link is.
+** useful to know if more strain may be imposed on the link or not.
+**
+** returns 0 if link load is light, -1 otherwise.
+*/
+static int
+check_link(cptr)
+aClient *cptr;
+{
+ if (!IsServer(cptr))
+ return 0;
+ if (!(bootopt & BOOT_PROT))
+ return 0;
+
+ ircstp->is_ckl++;
+ if ((int)DBufLength(&cptr->sendQ) > 65536) /* SendQ is already (too) high*/
+ {
+ cptr->serv->lastload = timeofday;
+ ircstp->is_cklQ++;
+ return -1;
+ }
+ if (timeofday - cptr->firsttime < 60) /* link is too young */
+ {
+ ircstp->is_ckly++;
+ return -1;
+ }
+ if (timeofday - cptr->serv->lastload > 30)
+ /* last request more than 30 seconds ago => OK */
+ {
+ cptr->serv->lastload = timeofday;
+ ircstp->is_cklok++;
+ return 0;
+ }
+ if (timeofday - cptr->serv->lastload > 15
+ && (int)DBufLength(&cptr->sendQ) < CHREPLLEN)
+ /* last request between 15 and 30 seconds ago, but little SendQ */
+ {
+ cptr->serv->lastload = timeofday;
+ ircstp->is_cklq++;
+ return 0;
+ }
+ ircstp->is_cklno++;
+ return -1;
+}
diff --git a/ircd/s_serv_ext.h b/ircd/s_serv_ext.h
new file mode 100644
index 0000000..4beb828
--- /dev/null
+++ b/ircd/s_serv_ext.h
@@ -0,0 +1,72 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/s_serv_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in ircd/s_serv.c.
+ */
+
+/* External definitions for global functions.
+ */
+#ifndef S_SERV_C
+#define EXTERN extern
+#else /* S_SERV_C */
+#define EXTERN
+#endif /* S_SERV_C */
+EXTERN int m_version __P((aClient *cptr, aClient *sptr, int parc,
+ char *parv[]));
+EXTERN int m_squit __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN int check_version __P((aClient *cptr));
+EXTERN int m_server __P((aClient *cptr, aClient *sptr, int parc,
+ char *parv[]));
+EXTERN int m_server_estab __P((Reg aClient *cptr));
+EXTERN int m_reconnect __P((aClient *cptr, aClient *sptr, int parc,
+ char *parv[]));
+EXTERN int m_info __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN int m_links __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN int m_summon __P((aClient *cptr, aClient *sptr, int parc,
+ char *parv[]));
+EXTERN int m_stats __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN int m_users __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN int m_error __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN int m_help __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN int m_lusers __P((aClient *cptr, aClient *sptr, int parc,
+ char *parv[]));
+EXTERN int m_connect __P((aClient *cptr, aClient *sptr, int parc,
+ char *parv[]));
+EXTERN int m_wallops __P((aClient *cptr, aClient *sptr, int parc,
+ char *parv[]));
+EXTERN int m_time __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN int m_admin __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN int m_trace __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN int m_motd __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN int m_close __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN char *find_server_string __P((int snum));
+EXTERN int find_server_num __P((char *sname));
+#if defined(OPER_REHASH) || defined(LOCOP_REHASH)
+EXTERN int m_rehash __P((aClient *cptr, aClient *sptr, int parc,
+ char *parv[]));
+#endif /* OPER_REHASH || LOCOP_REHASH */
+#if defined(OPER_RESTART) || defined(LOCOP_RESTART)
+EXTERN int m_restart __P((aClient *cptr, aClient *sptr, int parc,
+ char *parv[]));
+#endif /* OPER_RESTART || LOCOP_RESTART */
+#if defined(OPER_DIE) || defined(LOCOP_DIE)
+EXTERN int m_die __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+#endif /* OPER_DIE || LOCOP_DIE */
+#undef EXTERN
diff --git a/ircd/s_service.c b/ircd/s_service.c
new file mode 100644
index 0000000..a86bd02
--- /dev/null
+++ b/ircd/s_service.c
@@ -0,0 +1,708 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/s_service.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: s_service.c,v 1.30 1999/07/02 16:49:37 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "s_defines.h"
+#define S_SERVICE_C
+#include "s_externs.h"
+#undef S_SERVICE_C
+
+aService *svctop = NULL;
+
+aService *make_service(cptr)
+aClient *cptr;
+{
+ Reg aService *svc = cptr->service;
+
+ if (svc)
+ return svc;
+
+ cptr->service = svc = (aService *)MyMalloc(sizeof(*svc));
+ bzero((char *)svc, sizeof(*svc));
+ svc->bcptr = cptr;
+ if (svctop)
+ svctop->prevs = svc;
+ svc->nexts = svctop;
+ svc->prevs = NULL; /* useless */
+ svctop = svc;
+ return svc;
+}
+
+
+void free_service(cptr)
+aClient *cptr;
+{
+ Reg aService *serv;
+
+ if ((serv = cptr->service))
+ {
+ if (serv->nexts)
+ serv->nexts->prevs = serv->prevs;
+ if (serv->prevs)
+ serv->prevs->nexts = serv->nexts;
+ if (svctop == serv)
+ svctop = serv->nexts;
+ if (serv->servp)
+ free_server(serv->servp, cptr);
+ if (serv->server)
+ MyFree(serv->server);
+ MyFree((char *)serv);
+ cptr->service = NULL;
+ }
+}
+
+
+static aClient *best_service(name, cptr)
+char *name;
+aClient *cptr;
+{
+ Reg aClient *acptr = NULL;
+ Reg aClient *bcptr;
+ Reg aService *sp;
+ int len = strlen(name);
+
+ if (!index(name, '@') || !(acptr = find_service(name, cptr)))
+ for (sp = svctop; sp; sp = sp->nexts)
+ if ((bcptr = sp->bcptr) &&
+ !myncmp(name, bcptr->name, len))
+ {
+ acptr = bcptr;
+ break;
+ }
+ return (acptr ? acptr : cptr);
+}
+
+
+#ifdef USE_SERVICES
+/*
+** check_services_butone
+** check all local services except `cptr', and send `fmt' according to:
+** action type on notice
+** server origin
+*/
+#if ! USE_STDARG
+void check_services_butone(action, server, cptr, fmt, p1, p2, p3, p4,
+ p5, p6, p7, p8)
+long action;
+aClient *cptr; /* shouldn't this be named sptr? */
+char *fmt, *server;
+void *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
+#else
+void check_services_butone(long action, char *server, aClient *cptr, char *fmt, ...)
+#endif
+{
+ char nbuf[NICKLEN + USERLEN + HOSTLEN + 3];
+ Reg aClient *acptr;
+ Reg int i;
+
+ *nbuf = '\0';
+ for (i = 0; i <= highest_fd; i++)
+ {
+ if (!(acptr = local[i]) || !IsService(acptr) ||
+ (cptr && acptr == cptr->from))
+ continue;
+ /*
+ ** found a (local) service, check if action matches what's
+ ** wanted AND if it comes from a server matching the dist
+ */
+ if ((acptr->service->wants & action)
+ && (!server || !match(acptr->service->dist, server)))
+ if ((acptr->service->wants & SERVICE_WANT_PREFIX) &&
+ cptr && IsRegisteredUser(cptr) &&
+ (action & SERVICE_MASK_PREFIX))
+ {
+#if USE_STDARG
+ char buf[2048];
+ va_list va;
+ va_start(va, fmt);
+ va_arg(va, char *);
+ vsprintf(buf, fmt+3, va);
+ va_end(va);
+#endif
+ sprintf(nbuf, "%s!%s@%s", cptr->name,
+ cptr->user->username,cptr->user->host);
+
+#if ! USE_STDARG
+ sendto_one(acptr, fmt, nbuf, p2, p3, p4, p5,
+ p6, p7, p8);
+#else
+ sendto_one(acptr, ":%s%s", nbuf, buf);
+#endif
+ }
+ else
+ {
+#if ! USE_STDARG
+ sendto_one(acptr, fmt, p1, p2, p3, p4, p5,
+ p6, p7, p8);
+#else
+ va_list va;
+ va_start(va, fmt);
+ vsendto_one(acptr, fmt, va);
+ va_end(va);
+#endif
+ }
+ }
+ return;
+}
+
+/*
+** sendnum_toone
+** send the NICK + USER + UMODE for sptr to cptr according to wants
+*/
+static void sendnum_toone (cptr, wants, sptr, umode)
+aClient *cptr, *sptr;
+char *umode;
+int wants;
+{
+
+ if (!*umode)
+ umode = "+";
+
+ if (wants & SERVICE_WANT_EXTNICK)
+ /* extended NICK syntax */
+ sendto_one(cptr, "NICK %s %d %s %s %s %s :%s",
+ (wants & SERVICE_WANT_NICK) ? sptr->name : ".",
+ sptr->hopcount + 1,
+ (wants & SERVICE_WANT_USER) ? sptr->user->username
+ : ".",
+ (wants & SERVICE_WANT_USER) ? sptr->user->host :".",
+ (wants & SERVICE_WANT_USER) ?
+ ((wants & SERVICE_WANT_TOKEN) ?
+ sptr->user->servp->tok : sptr->user->server) : ".",
+ (wants & SERVICE_WANT_UMODE) ? umode : "+",
+ (wants & SERVICE_WANT_USER) ? sptr->info : "");
+ else
+ /* old style NICK + USER + UMODE */
+ {
+ char nbuf[NICKLEN + USERLEN + HOSTLEN + 3];
+ char *prefix;
+
+ if (wants & SERVICE_WANT_PREFIX)
+ {
+ sprintf(nbuf, "%s!%s@%s", sptr->name,
+ sptr->user->username, sptr->user->host);
+ prefix = nbuf;
+ }
+ else
+ prefix = sptr->name;
+
+ if (wants & SERVICE_WANT_NICK)
+ sendto_one(cptr, "NICK %s :%d", sptr->name,
+ sptr->hopcount+1);
+ if (wants & SERVICE_WANT_USER)
+ sendto_one(cptr, ":%s USER %s %s %s :%s", prefix,
+ sptr->user->username, sptr->user->host,
+ (wants & SERVICE_WANT_TOKEN)?
+ sptr->user->servp->tok : sptr->user->server,
+ sptr->info);
+ if (wants & SERVICE_WANT_UMODE|SERVICE_WANT_OPER)
+ sendto_one(cptr, ":%s MODE %s %s", prefix, sptr->name,
+ umode);
+ }
+}
+
+/*
+** check_services_num
+** check all local services to eventually send NICK + USER + UMODE
+** for new client sptr
+*/
+void check_services_num(sptr, umode)
+aClient *sptr;
+char *umode;
+{
+ Reg aClient *acptr;
+ Reg int i;
+
+ for (i = 0; i <= highest_fd; i++)
+ {
+ if (!(acptr = local[i]) || !IsService(acptr))
+ continue;
+ /*
+ ** found a (local) service, check if action matches what's
+ ** wanted AND if it comes from a server matching the dist
+ */
+ if ((acptr->service->wants & SERVICE_MASK_NUM)
+ && !match(acptr->service->dist, sptr->user->server))
+ sendnum_toone(acptr, acptr->service->wants, sptr,
+ umode);
+ }
+}
+
+
+aConfItem *find_conf_service(cptr, type, aconf)
+aClient *cptr;
+aConfItem *aconf;
+int type;
+{
+ static char uhost[HOSTLEN+USERLEN+3];
+ Reg aConfItem *tmp;
+ char *s;
+ struct hostent *hp;
+ int i;
+
+ for (tmp = conf; tmp; tmp = tmp->next)
+ {
+ /*
+ ** Accept if the *real* hostname (usually sockethost)
+ ** matches host field of the configuration, the name field
+ ** is the same, the type match is correct and nobody else
+ ** is using this S-line.
+ */
+ if (!(tmp->status & CONF_SERVICE))
+ continue;
+ Debug((DEBUG_INFO,"service: cl=%d host (%s) name (%s) port=%d",
+ tmp->clients, tmp->host, tmp->name, tmp->port));
+ Debug((DEBUG_INFO,"service: host (%s) name (%s) type=%d",
+ cptr->sockhost, cptr->name, type));
+ if (tmp->clients || (type && tmp->port != type) ||
+ mycmp(tmp->name, cptr->name))
+ continue;
+ if ((hp = cptr->hostp))
+ for (s = hp->h_name, i = 0; s; s = hp->h_aliases[i++])
+ {
+ SPRINTF(uhost, "%s@%s", cptr->username, s);
+ if (match(tmp->host, uhost) == 0)
+ return tmp;
+ }
+ SPRINTF(uhost, "%s@%s", cptr->username, cptr->sockhost);
+ if (match(tmp->host, uhost) == 0)
+ return tmp;
+ }
+ return aconf;
+}
+#endif
+
+
+/*
+** m_service
+**
+** parv[0] = sender prefix
+** parv[1] = service name
+** parv[2] = server token
+** parv[3] = distribution code
+** parv[4] = service type
+** parv[5] = hopcount
+** parv[6] = info
+*/
+int m_service(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+ Reg aClient *acptr = NULL;
+ Reg aService *svc;
+#ifdef USE_SERVICES
+ Reg aConfItem *aconf;
+#endif
+ aServer *sp = NULL;
+ char *dist, *server = NULL, *info, *stok;
+ int type, metric = 0, i;
+ char *mlname;
+
+ if (sptr->user)
+ {
+ sendto_one(sptr, err_str(ERR_ALREADYREGISTRED, parv[0]));
+ return 1;
+ }
+
+ if (parc < 7 || *parv[1] == '\0' || *parv[2] == '\0' ||
+ *parv[3] == '\0' || *parv[6] == '\0')
+ {
+ sendto_one(cptr, err_str(ERR_NEEDMOREPARAMS,
+ BadPtr(parv[0]) ? "*" : parv[0]), "SERVICE");
+ return 1;
+ }
+
+ /* Copy parameters into better documenting variables */
+
+ /*
+ * Change the sender's origin.
+ */
+ if (IsServer(cptr))
+ {
+ sptr = make_client(cptr);
+ add_client_to_list(sptr);
+ strncpyzt(sptr->name, parv[1], sizeof(sptr->name));
+ server = parv[2];
+ metric = atoi(parv[5]);
+ sp = find_tokserver(atoi(server), cptr, NULL);
+ if (!sp)
+ {
+ sendto_flag(SCH_ERROR,
+ "ERROR: SERVICE:%s without SERVER:%s from %s",
+ sptr->name, server,
+ get_client_name(cptr, FALSE));
+ return exit_client(NULL, sptr, &me, "No Such Server");
+ }
+ if (match(parv[3], ME))
+ {
+ sendto_flag(SCH_ERROR,
+ "ERROR: SERVICE:%s DIST:%s from %s", sptr->name,
+ parv[3], get_client_name(cptr, FALSE));
+ return exit_client(NULL, sptr, &me,
+ "Distribution code mismatch");
+ }
+ }
+#ifndef USE_SERVICES
+ else
+ {
+ sendto_one(cptr, "ERROR :Server doesn't support services");
+ return 1;
+ }
+#endif
+
+ dist = parv[3];
+ type = atoi(parv[4]);
+ info = parv[6];
+
+#ifdef USE_SERVICES
+ if (!IsServer(cptr))
+ {
+ metric = 0;
+ server = ME;
+ sp = me.serv;
+ if (!do_nick_name(parv[1], 0))
+ {
+ sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME,
+ parv[0]), parv[1]);
+ return 1;
+ }
+ if (strlen(parv[1]) + strlen(server) + 2 >= (size_t) HOSTLEN)
+ {
+ sendto_one(acptr, "ERROR :Servicename is too long.");
+ sendto_flag(SCH_ERROR,
+ "Access for service %d (%s) denied (%s)",
+ type, parv[1], "servicename too long");
+ return exit_client(cptr, sptr, &me, "Name too long");
+ }
+
+ strncpyzt(sptr->name, parv[1], sizeof(sptr->name));
+ if (!(aconf = find_conf_service(sptr, type, NULL)))
+ {
+ sendto_one(sptr,
+ "ERROR :Access denied (service %d) %s",
+ type, get_client_name(sptr, TRUE));
+ sendto_flag(SCH_ERROR,
+ "Access denied (service %d) %s", type,
+ get_client_name(sptr, TRUE));
+ return exit_client(cptr, sptr, &me, "Not enabled");
+ }
+
+ if (!BadPtr(aconf->passwd) &&
+ !StrEq(aconf->passwd, sptr->passwd))
+ {
+ sendto_flag(SCH_ERROR,
+ "Access denied: (passwd mismatch) %s",
+ get_client_name(sptr, TRUE));
+ return exit_client(cptr, sptr, &me, "Bad Password");
+ }
+
+ (void)strcat(sptr->name, "@"), strcat(sptr->name, server);
+ if (find_service(sptr->name, NULL))
+ {
+ sendto_flag(SCH_ERROR, "Service %s already exists",
+ get_client_name(sptr, TRUE));
+ return exit_client(cptr, sptr, &me, "Service Exists");
+ }
+ attach_conf(sptr, aconf);
+ sendto_one(sptr, rpl_str(RPL_YOURESERVICE, sptr->name),
+ sptr->name);
+ sendto_one(sptr, rpl_str(RPL_YOURHOST, sptr->name),
+ get_client_name(&me, FALSE), version);
+ sendto_one(sptr, rpl_str(RPL_MYINFO, sptr->name), ME, version);
+ sendto_flag(SCH_NOTICE, "Service %s connected",
+ get_client_name(sptr, TRUE));
+ istat.is_unknown--;
+ istat.is_myservice++;
+ }
+#endif
+
+ istat.is_service++;
+ svc = make_service(sptr);
+ SetService(sptr);
+ svc->servp = sp;
+ sp->refcnt++;
+ svc->server = mystrdup(sp->bcptr->name);
+ strncpyzt(svc->dist, dist, HOSTLEN);
+ if (sptr->info != DefInfo)
+ MyFree(sptr->info);
+ if (strlen(info) > REALLEN) info[REALLEN] = '\0';
+ sptr->info = mystrdup(info);
+ svc->wants = 0;
+ svc->type = type;
+ sptr->hopcount = metric;
+ reorder_client_in_list(sptr);
+ (void)add_to_client_hash_table(sptr->name, sptr);
+
+#ifdef USE_SERVICES
+ check_services_butone(SERVICE_WANT_SERVICE, NULL, sptr,
+ "SERVICE %s %s %s %d %d :%s", sptr->name,
+ server, dist, type, metric, info);
+#endif
+ sendto_flag(SCH_SERVICE, "Received SERVICE %s from %s (%s %d %s)",
+ sptr->name, get_client_name(cptr, TRUE), dist, metric,
+ info);
+
+ for (i = fdas.highest; i >= 0; i--)
+ {
+ if (!(acptr = local[fdas.fd[i]]) || !IsServer(acptr) ||
+ acptr == cptr)
+ continue;
+ if (match(dist, acptr->name))
+ continue;
+ mlname = my_name_for_link(ME, acptr->serv->nline->port);
+ if (*mlname == '*' && match(mlname, sptr->service->server)== 0)
+ stok = me.serv->tok;
+ else
+ stok = sp->tok;
+ sendto_one(acptr, "SERVICE %s %s %s %d %d :%s", sptr->name,
+ stok, dist, type, metric+1, info);
+ }
+ return 0;
+}
+
+
+/*
+** Returns list of all matching services.
+** parv[1] - string to match names against
+** parv[2] - type of service
+*/
+int m_servlist(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+ Reg aService *sp;
+ Reg aClient *acptr;
+ char *mask = BadPtr(parv[1]) ? "*" : parv[1];
+ int type = 0;
+
+ if (parc > 2)
+ type = BadPtr(parv[2]) ? 0 : atoi(parv[2]);
+ for (sp = svctop; sp; sp = sp->nexts)
+ if ((acptr = sp->bcptr) && (!type || type == sp->type) &&
+ (match(mask, acptr->name) == 0))
+ sendto_one(sptr, rpl_str(RPL_SERVLIST, parv[0]),
+ acptr->name, sp->server, sp->dist,
+ sp->type, acptr->hopcount, acptr->info);
+ sendto_one(sptr, rpl_str(RPL_SERVLISTEND, parv[0]), mask, type);
+ return 2;
+}
+
+
+#ifdef USE_SERVICES
+/*
+** m_servset
+**
+** parv[0] = sender prefix
+** parv[1] = data requested
+** parv[2] = burst requested (optional)
+*/
+int m_servset(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+ aClient *acptr;
+ int burst = 0;
+
+ if (!MyConnect(sptr))
+ {
+ sendto_flag(SCH_ERROR, "%s issued a SERVSET (from %s)",
+ sptr->name, get_client_name(cptr, TRUE));
+ return 1;
+ }
+ if (!IsService(sptr) || (IsService(sptr) && sptr->service->wants))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES, parv[0]));
+ return 1;
+ }
+ if (parc < 2)
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]),
+ "SERVSET");
+ return 1;
+ }
+ if (sptr->service->wants)
+ return 1;
+
+ /* check against configuration */
+ sptr->service->wants = atoi(parv[1]) & sptr->service->type;
+ /* check that service is global for some requests */
+ if (strcmp(sptr->service->dist, "*"))
+ sptr->service->wants &= ~SERVICE_MASK_GLOBAL;
+ /* allow options */
+ sptr->service->wants |= (atoi(parv[1]) & ~SERVICE_MASK_ALL);
+ /* send accepted SERVSET */
+ sendto_one(sptr, ":%s SERVSET %s :%d", sptr->name, sptr->name,
+ sptr->service->wants);
+
+ if (parc < 3 ||
+ ((burst = sptr->service->wants & atoi(parv[2])) == 0))
+ return 0;
+
+ /*
+ ** services can request a connect burst.
+ ** it is optional, because most services should not need it,
+ ** so let's save some bandwidth.
+ **
+ ** tokens are NOT used. (2.8.x like burst)
+ ** distribution code is respected.
+ ** service type also respected.
+ */
+ /* cptr->flags |= FLAGS_CBURST; doesn't work.. */
+ if (burst & SERVICE_WANT_SERVER)
+ {
+ int split;
+
+ for (acptr = &me; acptr; acptr = acptr->prev)
+ {
+ if (!IsServer(acptr) && !IsMe(acptr))
+ continue;
+ if (match(sptr->service->dist, acptr->name))
+ continue;
+ split = (MyConnect(acptr) &&
+ mycmp(acptr->name, acptr->sockhost));
+ if (split)
+ sendto_one(sptr,":%s SERVER %s %d %s :[%s] %s",
+ acptr->serv->up, acptr->name,
+ acptr->hopcount+1,
+ acptr->serv->tok,
+ acptr->sockhost, acptr->info);
+ else
+ sendto_one(sptr, ":%s SERVER %s %d %s :%s",
+ acptr->serv->up, acptr->name,
+ acptr->hopcount+1,
+ acptr->serv->tok,
+ acptr->info);
+ }
+ }
+
+ if (burst & (SERVICE_WANT_NICK|SERVICE_WANT_USER|SERVICE_WANT_SERVICE))
+ {
+ char buf[BUFSIZE] = "+";
+
+ for (acptr = &me; acptr; acptr = acptr->prev)
+ {
+ /* acptr->from == acptr for acptr == cptr */
+ if (acptr->from == cptr)
+ continue;
+ if (IsPerson(acptr))
+ {
+ if (match(sptr->service->dist,
+ acptr->user->server))
+ continue;
+ if (burst & SERVICE_WANT_UMODE)
+ send_umode(NULL, acptr, 0, SEND_UMODES,
+ buf);
+ else if (burst & SERVICE_WANT_OPER)
+ send_umode(NULL, acptr, 0, FLAGS_OPER,
+ buf);
+ sendnum_toone(sptr, burst, acptr, buf);
+ }
+ else if (IsService(acptr))
+ {
+ if (!(burst & SERVICE_WANT_SERVICE))
+ continue;
+ if (match(sptr->service->dist,
+ acptr->service->server))
+ continue;
+ sendto_one(sptr, "SERVICE %s %s %s %d %d :%s",
+ acptr->name, acptr->service->server,
+ acptr->service->dist,
+ acptr->service->type,
+ acptr->hopcount + 1, acptr->info);
+ }
+ }
+ }
+
+ if (burst & (SERVICE_WANT_CHANNEL|SERVICE_WANT_VCHANNEL|SERVICE_WANT_MODE|SERVICE_WANT_TOPIC))
+ {
+ char modebuf[MODEBUFLEN], parabuf[MODEBUFLEN];
+ aChannel *chptr;
+
+ for (chptr = channel; chptr; chptr = chptr->nextch)
+ {
+ if (chptr->users == 0)
+ continue;
+ if (burst&(SERVICE_WANT_CHANNEL|SERVICE_WANT_VCHANNEL))
+ sendto_one(sptr, "CHANNEL %s %d",
+ chptr->chname, chptr->users);
+ if (burst & SERVICE_WANT_MODE)
+ {
+ *modebuf = *parabuf = '\0';
+ modebuf[1] = '\0';
+ channel_modes(&me, modebuf, parabuf, chptr);
+ sendto_one(sptr, "MODE %s %s", chptr->chname,
+ modebuf);
+ }
+ if ((burst & SERVICE_WANT_TOPIC) && *chptr->topic)
+ sendto_one(sptr, "TOPIC %s :%s",
+ chptr->chname, chptr->topic);
+ }
+ }
+ /* cptr->flags ^= FLAGS_CBURST; */
+ return 0;
+}
+#endif
+
+
+/*
+** Send query to service.
+** parv[1] - string to match name against
+** parv[2] - string to send to service
+*/
+int m_squery(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+ aClient *acptr;
+
+ if (parc <= 2)
+ {
+ if (parc == 1)
+ sendto_one(sptr, err_str(ERR_NORECIPIENT, parv[0]),
+ "SQUERY");
+ else if (parc == 2 || BadPtr(parv[1]))
+ sendto_one(sptr, err_str(ERR_NOTEXTTOSEND, parv[0]));
+ return 1;
+ }
+
+ if ((acptr = best_service(parv[1], NULL)))
+ if (MyConnect(acptr) &&
+ (acptr->service->wants & SERVICE_WANT_PREFIX))
+ sendto_one(acptr, ":%s!%s@%s SQUERY %s :%s", parv[0],
+ sptr->user->username, sptr->user->host,
+ acptr->name, parv[2]);
+ else
+ sendto_one(acptr, ":%s SQUERY %s :%s",
+ parv[0], acptr->name, parv[2]);
+ else
+ sendto_one(sptr, err_str(ERR_NOSUCHSERVICE, parv[0]), parv[1]);
+ return 2;
+}
diff --git a/ircd/s_service_ext.h b/ircd/s_service_ext.h
new file mode 100644
index 0000000..a809ff5
--- /dev/null
+++ b/ircd/s_service_ext.h
@@ -0,0 +1,58 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/s_service_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in ircd/s_service.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef S_SERVICE_C
+extern aService *svctop;
+#endif
+
+/* External definitions for global functions.
+ */
+#ifndef S_SERVICE_C
+#define EXTERN extern
+#else /* S_SERVICE_C */
+#define EXTERN
+#endif /* S_SERVICE_C */
+EXTERN aService *make_service __P((aClient *cptr));
+EXTERN void free_service __P((aClient *cptr));
+#ifdef USE_SERVICES
+#ifndef USE_STDARG
+EXTERN void check_services_butone();
+#else /* USE_STDARG */
+EXTERN void check_services_butone __P((long action, char *server,
+ aClient *cptr, char *fmt, ...));
+#endif /* USE_STDARG */
+EXTERN void check_services_num __P((aClient *sptr, char *umode));
+EXTERN aConfItem *find_conf_service __P((aClient *cptr, int type,
+ aConfItem *aconf));
+EXTERN int m_servset __P((aClient *cptr, aClient *sptr, int parc,
+ char *parv[]));
+#endif /* USE_SERVICES */
+EXTERN int m_service __P((aClient *cptr, aClient *sptr, int parc,
+ char *parv[]));
+EXTERN int m_servlist __P((aClient *cptr, aClient *sptr, int parc,
+ char *parv[]));
+EXTERN int m_squery __P((aClient *cptr, aClient *sptr, int parc,
+ char *parv[]));
+#undef EXTERN
diff --git a/ircd/s_user.c b/ircd/s_user.c
new file mode 100644
index 0000000..1ba4c32
--- /dev/null
+++ b/ircd/s_user.c
@@ -0,0 +1,2869 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/s_user.c (formerly ircd/s_msg.c)
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ * University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: s_user.c,v 1.86 1999/07/17 11:47:49 q Exp $";
+#endif
+
+#include "os.h"
+#include "s_defines.h"
+#define S_USER_C
+#include "s_externs.h"
+#undef S_USER_C
+
+static char buf[BUFSIZE], buf2[BUFSIZE];
+
+static int user_modes[] = { FLAGS_OPER, 'o',
+ FLAGS_LOCOP, 'O',
+ FLAGS_INVISIBLE, 'i',
+ FLAGS_WALLOP, 'w',
+ FLAGS_RESTRICTED, 'r',
+ FLAGS_AWAY, 'a',
+ 0, 0 };
+
+/*
+** 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)
+Reg aClient *next; /* First client to check */
+Reg char *ch; /* search string (may include wilds) */
+{
+ Reg 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 (!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, parv[server]) == 0 ||
+ match(parv[server], ME) == 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;
+ /* Match *.masked.servers */
+ if (!acptr && (acptr = find_server(parv[server], NULL)))
+ if (acptr->from == sptr->from && !MyConnect(acptr))
+ acptr = NULL;
+ /* Remote services@servers */
+ if (!acptr && (acptr = find_service(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 (!IsRegistered(acptr))
+ return HUNTED_ISME;
+ if (IsMe(acptr) || MyClient(acptr) || MyService(acptr))
+ return HUNTED_ISME;
+ if (match(acptr->name, parv[server]))
+ parv[server] = acptr->name;
+ if (IsService(sptr)
+ && (IsServer(acptr->from)
+ && match(sptr->service->dist,acptr->name) != 0))
+ {
+ sendto_one(sptr, err_str(ERR_NOSUCHSERVER, parv[0]),
+ parv[server]);
+ return(HUNTED_NOSUCH);
+ }
+ 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, parv[0]), parv[server]);
+ return(HUNTED_NOSUCH);
+ }
+
+/*
+** '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.
+** Finally forbid the use of "anonymous" because of possible
+** abuses related to anonymous channnels. -kalt
+**
+** 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, server)
+char *nick;
+int server;
+{
+ Reg char *ch;
+
+ if (*nick == '-') /* first character '-' */
+ return 0;
+
+ if (isdigit(*nick) && !server) /* first character in [0..9] */
+ return 0;
+
+ if (!strcasecmp(nick, "anonymous"))
+ 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];
+ Reg char *s, *t, *cp = cbuf;
+ Reg 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;
+}
+
+/*
+** ereject_user
+** extracted from register_user for clarity
+** early rejection of a user connection, with logging.
+*/
+int
+ereject_user(cptr, shortm, longm)
+aClient *cptr;
+char *shortm, *longm;
+{
+#if defined(USE_SYSLOG) && defined(SYSLOG_CONN)
+ syslog(LOG_NOTICE, "%s ( %s ): <none>@%s [%s] %c\n",
+ myctime(cptr->firsttime), shortm, longm,
+ (IsUnixSocket(cptr)) ? me.sockhost :
+ ((cptr->hostp) ? cptr->hostp->h_name : cptr->sockhost),
+ cptr->auth, cptr->exitc);
+#endif
+#if defined(FNAME_CONNLOG) || defined(USE_SERVICES)
+ sendto_flog(cptr, shortm, 0, "<none>",
+ (IsUnixSocket(cptr)) ? me.sockhost :
+ ((cptr->hostp) ? cptr->hostp->h_name : cptr->sockhost));
+#endif
+ return exit_client(cptr, cptr, &me, longm);
+}
+
+/*
+** 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...
+*/
+
+int register_user(cptr, sptr, nick, username)
+aClient *cptr;
+aClient *sptr;
+char *nick, *username;
+{
+ Reg aConfItem *aconf;
+ aClient *acptr;
+ aServer *sp = NULL;
+ anUser *user = sptr->user;
+ short oldstatus = sptr->status;
+ char *parv[3];
+#ifndef NO_PREFIX
+ char prefix;
+#endif
+ int i;
+
+ user->last = timeofday;
+ parv[0] = sptr->name;
+ parv[1] = parv[2] = NULL;
+
+ if (MyConnect(sptr))
+ {
+ char *reason = NULL;
+
+#if defined(USE_IAUTH)
+ static time_t last = 0;
+ static u_int count = 0;
+
+ if (iauth_options & XOPT_EARLYPARSE && DoingXAuth(cptr))
+ {
+ cptr->flags |= FLAGS_WXAUTH;
+ /* fool check_pings() and give iauth more time! */
+ cptr->firsttime = timeofday;
+ cptr->lasttime = timeofday;
+ strncpyzt(sptr->user->username, username, USERLEN+1);
+ if (sptr->passwd[0])
+ sendto_iauth("%d P %s", sptr->fd,sptr->passwd);
+ sendto_iauth("%d U %s", sptr->fd, username);
+ return 1;
+ }
+ if (!DoneXAuth(sptr) && (iauth_options & XOPT_REQUIRED))
+ {
+ char *reason;
+
+ if (iauth_options & XOPT_NOTIMEOUT)
+ {
+ count += 1;
+ if (timeofday - last > 300)
+ {
+ sendto_flag(SCH_AUTH,
+ "iauth may not be running! (refusing new user connections)");
+ last = timeofday;
+ }
+ reason = "No iauth!";
+ }
+ else
+ reason = "iauth t/o";
+ sptr->exitc = EXITC_AUTHFAIL;
+ return ereject_user(cptr, reason,
+ "Authentication failure!");
+ }
+ if (timeofday - last > 300 && count)
+ {
+ sendto_flag(SCH_AUTH, "%d users rejected.", count);
+ count = 0;
+ }
+
+ /* this should not be needed, but there's a bug.. -kalt */
+ /* haven't seen any notice like this, ever.. no bug no more? */
+ if (*cptr->username == '\0')
+ {
+ sendto_flag(SCH_AUTH,
+ "Ouch! Null username for %s (%d %X)",
+ get_client_name(cptr, TRUE), cptr->fd,
+ cptr->flags);
+ sendto_iauth("%d E Null username [%s] %X", cptr->fd,
+ get_client_name(cptr, TRUE), cptr->flags);
+ return exit_client(cptr, sptr, &me,
+ "Fatal Bug - Try Again");
+ }
+#endif
+ /*
+ ** the following insanity used to be after check_client()
+ ** but check_client()->attach_Iline() now needs to know the
+ ** username for global u@h limits.
+ ** moving this shit here shouldn't be a problem. -krys
+ ** what a piece of $#@!.. restricted can only be known
+ ** *after* attach_Iline(), so it matters and I have to move
+ ** come of it back below. so global u@h limits really suck.
+ */
+#ifndef NO_PREFIX
+ /*
+ ** ident is fun.. ahem
+ ** prefixes used:
+ ** none I line with ident
+ ** ^ I line with OTHER type ident
+ ** ~ I line, no ident
+ ** + i line with ident
+ ** = i line with OTHER type ident
+ ** - i line, no ident
+ */
+ if (!(sptr->flags & FLAGS_GOTID))
+ prefix = '~';
+ else
+ if (*sptr->username == '-' ||
+ index(sptr->username, '@'))
+ prefix = '^';
+ else
+ prefix = '\0';
+
+ /* OTHER type idents have '-' prefix (from s_auth.c), */
+ /* and they are not supposed to be used as userid (rfc1413) */
+ /* @ isn't valid in usernames (m_user()) */
+ if (sptr->flags & FLAGS_GOTID && *sptr->username != '-' &&
+ index(sptr->username, '@') == NULL)
+ strncpyzt(buf2, sptr->username, USERLEN+1);
+ else /* No ident, or unusable ident string */
+ /* because username may point to user->username */
+ strncpyzt(buf2, username, USERLEN+1);
+
+ if (prefix)
+ {
+ *user->username = prefix;
+ strncpy(&user->username[1], buf2, USERLEN);
+ }
+ else
+ strncpy(user->username, buf2, USERLEN+1);
+ user->username[USERLEN] = '\0';
+ /* eos */
+#else
+ strncpyzt(user->username, username, USERLEN+1);
+#endif
+
+ if (sptr->exitc == EXITC_AREF || sptr->exitc == EXITC_AREFQ)
+ {
+ if (sptr->exitc == EXITC_AREF)
+ sendto_flag(SCH_LOCAL,
+ "Denied connection from %s.",
+ get_client_host(sptr));
+ return ereject_user(cptr, " Denied ","Denied access");
+ }
+ if ((i = check_client(sptr)))
+ {
+ struct msg_set { char *shortm; char *longm; };
+
+ static struct msg_set exit_msg[7] = {
+ { "G u@h max", "Too many user connections (global)" },
+ { "G IP max", "Too many host connections (global)" },
+ { "L u@h max", "Too many user connections (local)" },
+ { "L IP max", "Too many host connections (local)" },
+ { " max ", "Too many connections" },
+ { " No Auth ", "Unauthorized connection" },
+ { " Failure ", "Connect failure" } };
+
+ i += 7;
+ if (i < 0 || i > 6) /* in case.. */
+ i = 6;
+
+ ircstp->is_ref++;
+ sptr->exitc = EXITC_REF;
+ sendto_flag(SCH_LOCAL, "%s from %s.",
+ exit_msg[i].longm, get_client_host(sptr));
+ return ereject_user(cptr, exit_msg[i].shortm,
+ exit_msg[i].longm);
+ }
+
+#ifndef NO_PREFIX
+ if (IsRestricted(sptr))
+ {
+ if (!(sptr->flags & FLAGS_GOTID))
+ prefix = '-';
+ else
+ if (*sptr->username == '-' ||
+ index(sptr->username, '@'))
+ prefix = '=';
+ else
+ prefix = '+';
+ *user->username = prefix;
+ strncpy(&user->username[1], buf2, USERLEN);
+ user->username[USERLEN] = '\0';
+ }
+#endif
+
+ aconf = sptr->confs->value.aconf;
+ if (IsUnixSocket(sptr))
+ strncpyzt(user->host, me.sockhost, HOSTLEN+1);
+ else
+ strncpyzt(user->host, sptr->sockhost, HOSTLEN+1);
+
+ if (!BadPtr(aconf->passwd) &&
+ !StrEq(sptr->passwd, aconf->passwd))
+ {
+ ircstp->is_ref++;
+ sendto_one(sptr, err_str(ERR_PASSWDMISMATCH, parv[0]));
+ return exit_client(cptr, sptr, &me, "Bad Password");
+ }
+ bzero(sptr->passwd, sizeof(sptr->passwd));
+ /*
+ * following block for the benefit of time-dependent K:-lines
+ */
+ if (find_kill(sptr, 1, &reason))
+ {
+ /*char buf[100];*/
+
+ sendto_flag(SCH_LOCAL, "K-lined %s@%s.",
+ user->username, sptr->sockhost);
+ ircstp->is_ref++;
+ sptr->exitc = EXITC_REF;
+#if defined(USE_SYSLOG) && defined(SYSLOG_CONN)
+ syslog(LOG_NOTICE, "%s ( K lined ): %s@%s [%s] %c\n",
+ myctime(sptr->firsttime), user->username,
+ user->host, sptr->auth, '-');
+#endif
+#if defined(FNAME_CONNLOG) || defined(USE_SERVICES)
+ sendto_flog(sptr, " K lined ", 0, user->username,
+ user->host);
+#endif
+ if (reason)
+ sprintf(buf, "K-lined: %.80s", reason);
+ return exit_client(cptr, sptr, &me, (reason) ? buf :
+ "K-lined");
+ }
+#ifdef R_LINES
+ if (find_restrict(sptr))
+ {
+ sendto_flag(SCH_LOCAL, "R-lined %s@%s.",
+ user->username, sptr->sockhost);
+ ircstp->is_ref++;
+ sptr->exitc = EXITC_REF;
+# if defined(USE_SYSLOG) && defined(SYSLOG_CONN)
+ syslog(LOG_NOTICE, "%s ( R lined ): %s@%s [%s] %c\n",
+ myctime(sptr->firsttime), user->username,
+ user->host, sptr->username, '-');
+# endif
+# if defined(FNAME_CONNLOG) || defined(USE_SERVICES)
+ sendto_flog(sptr, " R lined ", 0, user->username,
+ user->host);
+# endif
+ return exit_client(cptr, sptr, &me , "R-lined");
+ }
+#endif
+ if (oldstatus == STAT_MASTER && MyConnect(sptr))
+ (void)m_oper(&me, sptr, 1, parv);
+/* *user->tok = '1';
+ user->tok[1] = '\0';*/
+ sp = user->servp;
+ }
+ else
+ strncpyzt(user->username, username, USERLEN+1);
+ SetClient(sptr);
+ if (MyConnect(sptr))
+ {
+ sprintf(buf, "%s!%s@%s", nick, user->username, user->host);
+ sptr->exitc = EXITC_REG;
+ sendto_one(sptr, rpl_str(RPL_WELCOME, nick), buf);
+ /* This is a duplicate of the NOTICE but see below...*/
+ sendto_one(sptr, rpl_str(RPL_YOURHOST, nick),
+ get_client_name(&me, FALSE), version);
+ sendto_one(sptr, rpl_str(RPL_CREATED, nick), creation);
+ sendto_one(sptr, rpl_str(RPL_MYINFO, parv[0]),
+ ME, version);
+ (void)m_lusers(sptr, sptr, 1, parv);
+ (void)m_motd(sptr, sptr, 1, parv);
+ nextping = timeofday;
+ }
+ else if (IsServer(cptr))
+ {
+ acptr = find_server(user->server, NULL);
+ if (acptr && acptr->from != cptr)
+ {
+ sendto_one(cptr, ":%s KILL %s :%s (%s != %s[%s])",
+ ME, sptr->name, ME, user->server,
+ acptr->from->name, acptr->from->sockhost);
+ sptr->flags |= FLAGS_KILLED;
+ return exit_client(cptr, sptr, &me,
+ "USER server wrong direction");
+ }
+ }
+
+ send_umode(NULL, sptr, 0, SEND_UMODES, buf);
+ for (i = fdas.highest; i >= 0; i--)
+ { /* Find my leaf servers and feed the new client to them */
+ if ((acptr = local[fdas.fd[i]]) == cptr || IsMe(acptr))
+ continue;
+ if ((aconf = acptr->serv->nline) &&
+ !match(my_name_for_link(ME, aconf->port),
+ user->server))
+ sendto_one(acptr, "NICK %s %d %s %s %s %s :%s",
+ nick, sptr->hopcount+1,
+ user->username, user->host,
+ me.serv->tok, (*buf) ? buf : "+",
+ sptr->info);
+ else
+ sendto_one(acptr, "NICK %s %d %s %s %s %s :%s",
+ nick, sptr->hopcount+1,
+ user->username, user->host,
+ user->servp->tok,
+ (*buf) ? buf : "+", sptr->info);
+ } /* for(my-leaf-servers) */
+ if (MyConnect(sptr))
+ {
+ if (IsRestricted(sptr))
+ sendto_one(sptr, err_str(ERR_RESTRICTED, nick));
+ send_umode(sptr, sptr, 0, ALL_UMODES, buf);
+ }
+
+ if (IsInvisible(sptr)) /* Can be initialized in m_user() */
+ istat.is_user[1]++; /* Local and server defaults +i */
+ else
+ istat.is_user[0]++;
+ if (MyConnect(sptr))
+ {
+ istat.is_unknown--;
+ istat.is_myclnt++;
+ }
+#ifdef USE_SERVICES
+#if 0
+ check_services_butone(SERVICE_WANT_NICK, user->server, NULL,
+ "NICK %s :%d", nick, sptr->hopcount+1);
+ check_services_butone(SERVICE_WANT_USER, user->server, sptr,
+ ":%s USER %s %s %s :%s", nick, user->username,
+ user->host, user->server, sptr->info);
+ if (MyConnect(sptr)) /* all modes about local users */
+ send_umode(NULL, sptr, 0, ALL_UMODES, buf);
+ check_services_butone(SERVICE_WANT_UMODE, user->server, sptr,
+ ":%s MODE %s :%s", nick, nick, buf);
+#endif
+ if (MyConnect(sptr)) /* all modes about local users */
+ send_umode(NULL, sptr, 0, ALL_UMODES, buf);
+ check_services_num(sptr, buf);
+#endif
+ return 1;
+ }
+
+/*
+** m_nick
+** parv[0] = sender prefix
+** parv[1] = nickname
+** the following are only used between servers since version 2.9
+** parv[2] = hopcount
+** parv[3] = username (login name, account)
+** parv[4] = client host name
+** parv[5] = server token
+** parv[6] = users mode
+** parv[7] = users real name info
+*/
+int m_nick(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+ aClient *acptr;
+ int delayed = 0;
+ char nick[NICKLEN+2], *s, *user, *host;
+ Link *lp = NULL;
+
+ if (IsService(sptr))
+ {
+ sendto_one(sptr, err_str(ERR_ALREADYREGISTRED, parv[0]));
+ return 1;
+ }
+
+ if (parc < 2)
+ {
+ sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN, parv[0]));
+ return 1;
+ }
+ if (MyConnect(sptr) && (s = (char *)index(parv[1], '~')))
+ *s = '\0';
+ strncpyzt(nick, parv[1], NICKLEN+1);
+
+ if (parc == 8 && cptr->serv)
+ {
+ user = parv[3];
+ host = parv[4];
+ }
+ else
+ {
+ if (sptr->user)
+ {
+ user = sptr->username;
+ host = sptr->user->host;
+ }
+ else
+ user = host = "";
+ }
+ /*
+ * 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, IsServer(cptr)) == 0 ||
+ (IsServer(cptr) && strcmp(nick, parv[1])))
+ {
+ sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME, parv[0]),
+ parv[1]);
+
+ if (IsServer(cptr))
+ {
+ ircstp->is_kill++;
+ sendto_flag(SCH_KILL, "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, parv[1], ME, parv[1],
+ nick, cptr->name);
+ if (sptr != cptr) /* bad nick change */
+ {
+ sendto_serv_butone(cptr,
+ ":%s KILL %s :%s (%s <- %s!%s@%s)",
+ ME, parv[0], ME,
+ get_client_name(cptr, FALSE),
+ parv[0], user, host);
+ sptr->flags |= FLAGS_KILLED;
+ return exit_client(cptr,sptr,&me,"BadNick");
+ }
+ }
+ return 2;
+ }
+
+ /*
+ ** 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, parv[0]),
+ nick);
+ return 2; /* NICK message ignored */
+ }
+ /*
+ ** acptr already has result from previous find_server()
+ */
+ if (acptr)
+ {
+ /*
+ ** We have a nickname trying to use the same name as
+ ** a server. Send out a nick collision KILL to remove
+ ** the nickname. As long as only a KILL is sent out,
+ ** there is no danger of the server being disconnected.
+ ** Ultimate way to jupiter a nick ? >;-). -avalon
+ */
+ sendto_flag(SCH_KILL,
+ "Nick collision on %s (%s@%s)%s <- (%s@%s)%s",
+ sptr->name,
+ (acptr->user) ? acptr->user->username : "???",
+ (acptr->user) ? acptr->user->host : "???",
+ acptr->from->name, user, host,
+ get_client_name(cptr, FALSE));
+ ircstp->is_kill++;
+ sendto_one(cptr, ":%s KILL %s :%s (%s <- %s)",
+ ME, sptr->name, ME, 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 (!(acptr = find_client(nick, NULL)))
+ {
+ aClient *acptr2;
+
+ if (IsServer(cptr) || !(bootopt & BOOT_PROT))
+ goto nickkilldone;
+ if ((acptr2 = get_history(nick, (long)(KILLCHASETIMELIMIT))) &&
+ !MyConnect(acptr2))
+ /*
+ ** Lock nick for KCTL so one cannot nick collide
+ ** (due to kill chase) people who recently changed
+ ** their nicks. --Beeth
+ */
+ delayed = 1;
+ else
+ /*
+ ** Let ND work
+ */
+ delayed = find_history(nick, (long)(DELAYCHASETIMELIMIT));
+ if (!delayed)
+ goto nickkilldone; /* No collisions, all clear... */
+ }
+ /*
+ ** If acptr == sptr, then we have a client doing a nick
+ ** change between *equivalent* nicknames as far as server
+ ** is concerned (user is changing the case of his/her
+ ** nickname or somesuch)
+ */
+ if (acptr == sptr)
+ if (strcmp(acptr->name, nick) != 0)
+ /*
+ ** Allows change of case in his/her nick
+ */
+ goto nickkilldone; /* -- go and process change */
+ else
+ /*
+ ** 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 2; /* NICK Message ignored */
+ /*
+ ** Note: From this point forward it can be assumed that
+ ** acptr != sptr (point to different client structures).
+ */
+ /*
+ ** If the older one is "non-person", the new entry is just
+ ** allowed to overwrite it. Just silently drop non-person,
+ ** and proceed with the nick. This should take care of the
+ ** "dormant nick" way of generating collisions...
+ */
+ if (acptr && IsUnknown(acptr) && MyConnect(acptr))
+ {
+ (void) exit_client(acptr, acptr, &me, "Overridden");
+ goto nickkilldone;
+ }
+ /*
+ ** 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((delayed) ? ERR_UNAVAILRESOURCE
+ : ERR_NICKNAMEINUSE,
+ parv[0]), nick);
+ return 2; /* NICK message ignored */
+ }
+ /*
+ ** NICK was coming from a server connection. Means that the same
+ ** nick is registered for different users by different server.
+ ** This is either a race condition (two users coming online about
+ ** same time, or net reconnecting) or just two net fragments becoming
+ ** joined and having same nicks in use. We cannot have TWO users with
+ ** same nick--purge this NICK from the system with a KILL... >;)
+ **
+ ** The client indicated by 'acptr' is dead meat, give at least some
+ ** indication of the reason why we are just dropping it cold.
+ */
+ sendto_one(acptr, err_str(ERR_NICKCOLLISION, acptr->name),
+ acptr->name, user, host);
+ /*
+ ** This seemingly obscure test (sptr == cptr) differentiates
+ ** between "NICK new" (TRUE) and ":old NICK new" (FALSE) forms.
+ */
+ if (sptr == cptr)
+ {
+ sendto_flag(SCH_KILL,
+ "Nick collision on %s (%s@%s)%s <- (%s@%s)%s",
+ acptr->name,
+ (acptr->user) ? acptr->user->username : "???",
+ (acptr->user) ? acptr->user->host : "???",
+ acptr->from->name,
+ user, host, get_client_name(cptr, FALSE));
+ /*
+ ** A new NICK being introduced by a neighbouring
+ ** server (e.g. message type "NICK new" received)
+ */
+ ircstp->is_kill++;
+ sendto_serv_butone(NULL,
+ ":%s KILL %s :%s ((%s@%s)%s <- (%s@%s)%s)",
+ ME, acptr->name, ME,
+ (acptr->user) ? acptr->user->username:"???",
+ (acptr->user) ? acptr->user->host : "???",
+ acptr->from->name, user, host,
+ /* NOTE: Cannot use get_client_name twice
+ ** here, it returns static string pointer:
+ ** the other info would be lost
+ */
+ get_client_name(cptr, FALSE));
+ acptr->flags |= FLAGS_KILLED;
+ return exit_client(NULL, acptr, &me, "Nick collision");
+ }
+ /*
+ ** A NICK change has collided (e.g. message type
+ ** ":old NICK new". This requires more complex cleanout.
+ ** Both clients must be purged from this server, the "new"
+ ** must be killed from the incoming connection, and "old" must
+ ** be purged from all outgoing connections.
+ */
+ sendto_flag(SCH_KILL, "Nick change collision %s!%s@%s to %s %s <- %s",
+ sptr->name, user, host, acptr->name, acptr->from->name,
+ get_client_name(cptr, FALSE));
+ ircstp->is_kill++;
+ sendto_serv_butone(NULL, /* KILL old from outgoing servers */
+ ":%s KILL %s :%s (%s(%s) <- %s)",
+ ME, sptr->name, ME, acptr->from->name,
+ acptr->name, get_client_name(cptr, FALSE));
+ ircstp->is_kill++;
+ sendto_serv_butone(NULL, /* Kill new from incoming link */
+ ":%s KILL %s :%s (%s <- %s(%s))",
+ ME, acptr->name, ME, acptr->from->name,
+ get_client_name(cptr, FALSE), sptr->name);
+ acptr->flags |= FLAGS_KILLED;
+ (void)exit_client(NULL, acptr, &me, "Nick collision(new)");
+ sptr->flags |= FLAGS_KILLED;
+ return exit_client(cptr, sptr, &me, "Nick collision(old)");
+
+nickkilldone:
+ if (IsServer(sptr))
+ {
+ char *pv[7];
+
+ if (parc != 8)
+ {
+ sendto_flag(SCH_NOTICE,
+ "Bad NICK param count (%d) for %s from %s via %s",
+ parc, parv[1], sptr->name,
+ get_client_name(cptr, FALSE));
+ sendto_one(cptr, ":%s KILL %s :%s (Bad NICK %d)",
+ ME, nick, ME, parc);
+ return 0;
+ }
+ /* A server introducing a new client, change source */
+ sptr = make_client(cptr);
+ add_client_to_list(sptr);
+ if (parc > 2)
+ sptr->hopcount = atoi(parv[2]);
+ (void)strcpy(sptr->name, nick);
+
+ pv[0] = sptr->name;
+ pv[1] = parv[3];
+ pv[2] = parv[4];
+ pv[3] = parv[5];
+ pv[4] = parv[7];
+ pv[5] = parv[6];
+ pv[6] = NULL;
+ (void)add_to_client_hash_table(nick, sptr);
+ return m_user(cptr, sptr, 6, pv);
+ }
+ else if (sptr->name[0]) /* NICK received before, changing */
+ {
+ if (MyConnect(sptr))
+ {
+ if (!IsPerson(sptr)) /* Unregistered client */
+ return 2; /* Ignore new NICKs */
+ if (IsRestricted(sptr))
+ {
+ sendto_one(sptr,
+ err_str(ERR_RESTRICTED, nick));
+ return 2;
+ }
+ /* is the user banned on any channel ? */
+ for (lp = sptr->user->channel; lp; lp = lp->next)
+ if (can_send(sptr, lp->value.chptr) ==MODE_BAN)
+ break;
+ }
+ /*
+ ** 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.
+ */
+ sendto_common_channels(sptr, ":%s NICK :%s", parv[0], nick);
+ if (sptr->user) /* should always be true.. */
+ {
+ add_history(sptr, sptr);
+#ifdef USE_SERVICES
+ check_services_butone(SERVICE_WANT_NICK,
+ sptr->user->server, sptr,
+ ":%s NICK :%s", parv[0], nick);
+#endif
+ }
+ else
+ sendto_flag(SCH_NOTICE,
+ "Illegal NICK change: %s -> %s from %s",
+ parv[0], nick, get_client_name(cptr,TRUE));
+ sendto_serv_butone(cptr, ":%s NICK :%s", parv[0], nick);
+ if (sptr->name[0])
+ (void)del_from_client_hash_table(sptr->name, sptr);
+ (void)strcpy(sptr->name, nick);
+ }
+ else
+ {
+ /* Client setting NICK the first time */
+
+ /* This had to be copied here to avoid problems.. */
+ (void)strcpy(sptr->name, nick);
+ if (sptr->user)
+ /*
+ ** 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!!!
+ */
+ if (register_user(cptr, sptr, nick,
+ sptr->user->username)
+ == FLUSH_BUFFER)
+ return FLUSH_BUFFER;
+ }
+ /*
+ ** Finally set new nick name.
+ */
+ (void)add_to_client_hash_table(nick, sptr);
+ if (lp)
+ return 15;
+ else
+ return 3;
+}
+
+/*
+** 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;
+char *parv[];
+int parc, notice;
+{
+ Reg aClient *acptr;
+ Reg char *s;
+ aChannel *chptr;
+ char *nick, *server, *p, *cmd, *user, *host;
+ int count = 0, penalty = 0;
+
+ cmd = notice ? MSG_NOTICE : MSG_PRIVATE;
+
+ if (parc < 2 || *parv[1] == '\0')
+ {
+ sendto_one(sptr, err_str(ERR_NORECIPIENT, parv[0]), cmd);
+ return 1;
+ }
+
+ if (parc < 3 || *parv[2] == '\0')
+ {
+ sendto_one(sptr, err_str(ERR_NOTEXTTOSEND, parv[0]));
+ return 1;
+ }
+
+ if (MyConnect(sptr))
+ parv[1] = canonize(parv[1]);
+ for (p = NULL, nick = strtoken(&p, parv[1], ","); nick;
+ nick = strtoken(&p, NULL, ","), penalty++)
+ {
+ /*
+ ** restrict destination list to MAXPENALTY/2 recipients to
+ ** solve SPAM problem --Yegg
+ */
+ if (2*penalty >= MAXPENALTY) {
+ if (!notice)
+ sendto_one(sptr, err_str(ERR_TOOMANYTARGETS,
+ parv[0]),
+ "Too many",nick,"No Message Delivered");
+ continue;
+ }
+ /*
+ ** nickname addressed?
+ */
+ if ((acptr = find_person(nick, NULL)))
+ {
+ if (!notice && MyConnect(sptr) &&
+ acptr->user && (acptr->user->flags & FLAGS_AWAY))
+ sendto_one(sptr, rpl_str(RPL_AWAY, parv[0]),
+ acptr->name,
+ (acptr->user->away) ?
+ acptr->user->away : "Gone");
+ sendto_prefix_one(acptr, sptr, ":%s %s %s :%s",
+ parv[0], cmd, nick, parv[2]);
+ continue;
+ }
+ /*
+ ** channel msg?
+ */
+ if ((IsPerson(sptr) || IsService(sptr) || IsServer(sptr)) &&
+ (chptr = find_channel(nick, NullChn)))
+ {
+ if (can_send(sptr, chptr) == 0 || IsServer(sptr))
+ 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,
+ parv[0]), nick);
+ 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,
+ parv[0]), nick);
+ continue;
+ }
+ while (*++s)
+ if (*s == '.' || *s == '*' || *s == '?')
+ break;
+ if (*s == '*' || *s == '?')
+ {
+ sendto_one(sptr, err_str(ERR_WILDTOPLEVEL,
+ 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;
+ }
+
+ /*
+ ** nick!user@host addressed?
+ */
+ if ((user = (char *)index(nick, '!')) &&
+ (host = (char *)index(nick, '@')))
+ {
+ *user = '\0';
+ *host = '\0';
+ if ((acptr = find_person(nick, NULL)) &&
+ !mycmp(user+1, acptr->user->username) &&
+ !mycmp(host+1, acptr->user->host))
+ {
+ sendto_prefix_one(acptr, sptr, ":%s %s %s :%s",
+ parv[0], cmd, nick, parv[2]);
+ *user = '!';
+ *host = '@';
+ continue;
+ }
+ *user = '!';
+ *host = '@';
+ }
+
+ /*
+ ** 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;
+ }
+ *server = '\0';
+
+ if ((host = (char *)index(nick, '%')))
+ *host++ = '\0';
+
+ /*
+ ** Look for users which match the destination host
+ ** (no host == wildcard) and if one and one only is
+ ** found connected to me, deliver message!
+ */
+ acptr = find_userhost(nick, host, NULL, &count);
+ if (server)
+ *server = '@';
+ if (host)
+ *--host = '%';
+ if (acptr)
+ {
+ if (count == 1)
+ sendto_prefix_one(acptr, sptr,
+ ":%s %s %s :%s",
+ parv[0], cmd,
+ nick, parv[2]);
+ else if (!notice)
+ sendto_one(sptr, err_str(
+ ERR_TOOMANYTARGETS,
+ parv[0]), "Duplicate", nick,
+ "No Message Delivered");
+ continue;
+ }
+ }
+ else if ((host = (char *)index(nick, '%')))
+ {
+ /*
+ ** user%host addressed?
+ */
+ *host++ = '\0';
+ acptr = find_userhost(nick, host, NULL, &count);
+ *--host = '%';
+ if (acptr)
+ {
+ if (count == 1)
+ sendto_prefix_one(acptr, sptr,
+ ":%s %s %s :%s",
+ parv[0], cmd,
+ nick, parv[2]);
+ else if (!notice)
+ sendto_one(sptr, err_str(
+ ERR_TOOMANYTARGETS,
+ parv[0]), "Duplicate", nick,
+ "No Message Delivered");
+ continue;
+ }
+ }
+ if (!notice)
+ sendto_one(sptr, err_str(ERR_NOSUCHNICK, parv[0]),
+ nick);
+ }
+ return penalty;
+}
+
+/*
+** 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);
+}
+
+/*
+** 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[];
+{
+ return m_message(cptr, sptr, parc, parv, 1);
+}
+
+/*
+** who_one
+** sends one RPL_WHOREPLY to sptr concerning acptr & repchan
+*/
+static void who_one(sptr, acptr, repchan, lp)
+aClient *sptr, *acptr;
+aChannel *repchan;
+Link *lp;
+{
+ char status[5];
+ int i = 0;
+
+ if (acptr->user->flags & FLAGS_AWAY)
+ status[i++] = 'G';
+ else
+ status[i++] = 'H';
+ if (IsAnOper(acptr))
+ status[i++] = '*';
+ if ((repchan != NULL) && (lp == NULL))
+ lp = find_user_link(repchan->members, acptr);
+ if (lp != NULL)
+ {
+ if (lp->flags & CHFL_CHANOP)
+ status[i++] = '@';
+ else if (lp->flags & CHFL_VOICE)
+ status[i++] = '+';
+ }
+ status[i] = '\0';
+ sendto_one(sptr, rpl_str(RPL_WHOREPLY, sptr->name),
+ (repchan) ? (repchan->chname) : "*", acptr->user->username,
+ acptr->user->host, acptr->user->server, acptr->name,
+ status, acptr->hopcount, acptr->info);
+}
+
+
+/*
+** who_channel
+** lists all users on a given channel
+*/
+static void who_channel(sptr, chptr, oper)
+aClient *sptr;
+aChannel *chptr;
+int oper;
+{
+ Reg Link *lp;
+ int member;
+
+ if (!IsAnonymous(chptr))
+ {
+ member = IsMember(sptr, chptr);
+ if (member || !SecretChannel(chptr))
+ for (lp = chptr->members; lp; lp = lp->next)
+ {
+ if (oper && !IsAnOper(lp->value.cptr))
+ continue;
+ if (IsInvisible(lp->value.cptr) && !member)
+ continue;
+ who_one(sptr, lp->value.cptr, chptr, lp);
+ }
+ }
+ else if (lp = find_user_link(chptr->members, sptr))
+ who_one(sptr, lp->value.cptr, chptr, lp);
+}
+
+/*
+** who_find
+** lists all (matching) users.
+** CPU intensive, but what can be done?
+*/
+static void who_find(sptr, mask, oper)
+aClient *sptr;
+char *mask;
+int oper;
+{
+ aChannel *chptr, *ch2ptr;
+ Link *lp;
+ int member;
+ int showperson, isinvis;
+ aClient *acptr;
+
+ for (acptr = client; acptr; acptr = acptr->next)
+ {
+ ch2ptr = NULL;
+
+ 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 = IsInvisible(acptr);
+ for (lp = acptr->user->channel; lp; lp = lp->next)
+ {
+ chptr = lp->value.chptr;
+ if (IsAnonymous(chptr))
+ continue;
+ member = IsMember(sptr, chptr);
+ if (isinvis && !member)
+ continue;
+ if (member || (!isinvis && PubChannel(chptr)))
+ {
+ showperson = 1;
+ if (!IsAnonymous(chptr) ||
+ acptr != sptr)
+ {
+ ch2ptr = chptr;
+ break;
+ }
+ }
+ if (HiddenChannel(chptr) &&
+ !SecretChannel(chptr) && !isinvis)
+ showperson = 1;
+ }
+ if (!acptr->user->channel && !isinvis)
+ showperson = 1;
+ /*
+ ** This is brute force solution, not efficient...? ;(
+ ** Show entry, if no mask or any of the fields match
+ ** the mask. --msa
+ */
+ if (showperson &&
+ (!mask ||
+ match(mask, acptr->name) == 0 ||
+ match(mask, acptr->user->username) == 0 ||
+ match(mask, acptr->user->host) == 0 ||
+ match(mask, acptr->user->server) == 0 ||
+ match(mask, acptr->info) == 0))
+ who_one(sptr, acptr, ch2ptr, NULL);
+ }
+}
+
+/*
+** 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[];
+{
+ Link *lp;
+ aChannel *chptr, *mychannel;
+ char *channame = NULL;
+ int oper = parc > 2 ? (*parv[2] == 'o' ): 0; /* Show OPERS only */
+ int penalty = 0;
+ char *p, *mask;
+
+ if (parc < 2)
+ {
+ who_find(sptr, NULL, oper);
+ sendto_one(sptr, rpl_str(RPL_ENDOFWHO, parv[0]), "*");
+ return 5;
+ }
+
+ for (p = NULL, mask = strtoken(&p, parv[1], ",");
+ mask && penalty < MAXPENALTY;
+ mask = strtoken(&p, NULL, ","))
+ {
+ channame = NULL;
+ mychannel = NullChn;
+ clean_channelname(mask);
+ if (sptr->user && (lp = sptr->user->channel))
+ mychannel = lp->value.chptr;
+ /*
+ ** 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 always false? */
+ 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))
+ {
+ chptr = find_channel(channame, NULL);
+ if (chptr)
+ who_channel(sptr, chptr, oper);
+ penalty += 1;
+ }
+ else
+ {
+ who_find(sptr, mask, oper);
+ if (mask && (int)strlen(mask) > 4)
+ penalty += 3;
+ else
+ penalty += 5;
+ }
+ sendto_one(sptr, rpl_str(RPL_ENDOFWHO, parv[0]),
+ BadPtr(mask) ? "*" : mask);
+ }
+ return penalty;
+}
+
+/* send_whois() is used by m_whois() to send whois reply to sptr, for acptr */
+static void
+send_whois(sptr, acptr)
+aClient *sptr, *acptr;
+{
+ static anUser UnknownUser =
+ {
+ NULL, /* channel */
+ NULL, /* invited */
+ NULL, /* uwas */
+ NULL, /* away */
+ 0, /* last */
+ 1, /* refcount */
+ 0, /* joined */
+ 0, /* flags */
+ NULL, /* servp */
+ NULL, /* next, prev, bcptr */
+ "<Unknown>", /* user */
+ "<Unknown>", /* host */
+ "<Unknown>", /* server */
+ };
+ Link *lp;
+ anUser *user;
+ aChannel *chptr;
+ aClient *a2cptr;
+ int len, mlen;
+ char *name;
+
+ user = acptr->user ? acptr->user : &UnknownUser;
+ name = (!*acptr->name) ? "?" : acptr->name;
+
+ a2cptr = find_server(user->server, NULL);
+
+ sendto_one(sptr, rpl_str(RPL_WHOISUSER, sptr->name),
+ name, user->username, user->host, acptr->info);
+
+ mlen = strlen(ME) + strlen(sptr->name) + 6 + strlen(name);
+
+ for (len = 0, *buf = '\0', lp = user->channel; lp; lp = lp->next)
+ {
+ chptr = lp->value.chptr;
+ if ((!IsAnonymous(chptr) || acptr == sptr) &&
+ ShowChannel(sptr, chptr))
+ {
+ if (len + strlen(chptr->chname)
+ > (size_t) BUFSIZE - 4 - mlen)
+ {
+ sendto_one(sptr, ":%s %d %s %s :%s", ME,
+ RPL_WHOISCHANNELS, sptr->name, name,
+ buf);
+ *buf = '\0';
+ len = 0;
+ }
+ if (is_chan_op(acptr, chptr))
+ *(buf + len++) = '@';
+ else if (has_voice(acptr, chptr))
+ *(buf + len++) = '+';
+ if (len)
+ *(buf + len) = '\0';
+ (void)strcpy(buf + len, chptr->chname);
+ len += strlen(chptr->chname);
+ (void)strcat(buf + len, " ");
+ len++;
+ }
+ }
+ if (buf[0] != '\0')
+ sendto_one(sptr, rpl_str(RPL_WHOISCHANNELS, sptr->name), name,
+ buf);
+
+ sendto_one(sptr, rpl_str(RPL_WHOISSERVER, sptr->name),
+ name, user->server,
+ a2cptr ? a2cptr->info:"*Not On This Net*");
+
+ if (user->flags & FLAGS_AWAY)
+ sendto_one(sptr, rpl_str(RPL_AWAY, sptr->name), name,
+ (user->away) ? user->away : "Gone");
+
+ if (IsAnOper(acptr))
+ sendto_one(sptr, rpl_str(RPL_WHOISOPERATOR, sptr->name), name);
+
+ if (acptr->user && MyConnect(acptr))
+ sendto_one(sptr, rpl_str(RPL_WHOISIDLE, sptr->name),
+ name, timeofday - user->last);
+}
+
+/*
+** m_whois
+** parv[0] = sender prefix
+** parv[1] = nickname masklist
+*/
+int m_whois(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+ Link *lp;
+ aClient *acptr;
+ aChannel *chptr;
+ char *nick, *tmp;
+ char *p = NULL;
+ int found = 0;
+
+ if (parc < 2)
+ {
+ sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN, parv[0]));
+ return 1;
+ }
+
+ if (parc > 2)
+ {
+ if (hunt_server(cptr,sptr,":%s WHOIS %s :%s", 1,parc,parv) !=
+ HUNTED_ISME)
+ return 3;
+ parv[1] = parv[2];
+ }
+
+ parv[1] = canonize(parv[1]);
+
+ for (tmp = parv[1]; (nick = strtoken(&p, tmp, ",")); tmp = NULL)
+ {
+ int invis, showperson, member, wilds;
+
+ found &= 0x0f; /* high/boolean, low/counter */
+ (void)collapse(nick);
+ wilds = (index(nick, '?') || index(nick, '*'));
+ /*
+ * We're no longer allowing remote users to generate
+ * requests with wildcard, nor local users with more
+ * than one wildcard target per command.
+ * Max 3 targets per command allowed.
+ */
+ if ((wilds && (!MyConnect(sptr) || p)) || found++ > 3)
+ break;
+
+ if (!wilds)
+ {
+ acptr = hash_find_client(nick, (aClient *)NULL);
+ if (!acptr || !IsPerson(acptr))
+ sendto_one(sptr,
+ err_str(ERR_NOSUCHNICK, parv[0]),
+ nick);
+ else
+ send_whois(sptr, acptr);
+ continue;
+ }
+
+ for (acptr = client; (acptr = next_client(acptr, nick));
+ acptr = acptr->next)
+ {
+ if (IsServer(acptr) || IsService(acptr))
+ continue;
+ /*
+ * I'm always last :-) and acptr->next == NULL!!
+ */
+ if (IsMe(acptr))
+ break;
+ /*
+ * 'Rules' established for sending a WHOIS reply:
+ * - if wildcards are being used don't 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;
+ */
+ invis = (acptr->user) ?
+ (acptr->user->flags & FLAGS_INVISIBLE) : 0;
+ member = (acptr->user && acptr->user->channel) ? 1 : 0;
+ showperson = (wilds && !invis && !member) || !wilds;
+ for (lp = (acptr->user) ? acptr->user->channel : NULL;
+ lp; lp = lp->next)
+ {
+ chptr = lp->value.chptr;
+ if (IsAnonymous(chptr))
+ continue;
+ member = IsMember(sptr, chptr);
+ if (invis && !member)
+ continue;
+ if (member || (!invis && PubChannel(chptr)))
+ {
+ showperson = 1;
+ break;
+ }
+ if (!invis && HiddenChannel(chptr) &&
+ !SecretChannel(chptr))
+ showperson = 1;
+ }
+ if (!showperson)
+ continue;
+
+ found |= 0x10;
+
+ send_whois(sptr, acptr);
+ }
+ if (!(found & 0x10))
+ {
+ if (strlen(nick) > (size_t) NICKLEN)
+ nick[NICKLEN] = '\0';
+ sendto_one(sptr, err_str(ERR_NOSUCHNICK, parv[0]),
+ nick);
+ }
+ if (p)
+ p[-1] = ',';
+ }
+ sendto_one(sptr, rpl_str(RPL_ENDOFWHOIS, parv[0]), parv[1]);
+
+ return 2;
+}
+
+/*
+** 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
+** parv[5] = users mode (is only used internally by the server,
+** NULL otherwise)
+*/
+int m_user(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+#define UFLAGS (FLAGS_INVISIBLE|FLAGS_WALLOP)
+ char *username, *host, *server, *realname;
+ anUser *user;
+
+ /* Reject new USER */
+ if (IsServer(sptr) || IsService(sptr) || sptr->user)
+ {
+ sendto_one(sptr, err_str(ERR_ALREADYREGISTRED, parv[0]));
+ return 1;
+ }
+ 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, parv[0]), "USER");
+ if (IsServer(cptr))
+ {
+ /* send error */
+ sendto_flag(SCH_NOTICE,
+ "bad USER param count for %s from %s",
+ parv[0], get_client_name(cptr, FALSE));
+ /*
+ ** and kill it, as there's no reason to expect more
+ ** USER messages about it, or we'll create a ghost.
+ */
+ sendto_one(cptr,
+ ":%s KILL %s :%s (bad USER param count)",
+ ME, parv[0], ME);
+ sptr->flags |= FLAGS_KILLED;
+ exit_client(NULL, sptr, &me, "bad USER param count");
+ }
+ return 1;
+ }
+
+ /* Copy parameters into better documenting variables */
+
+ username = (parc < 2 || BadPtr(parv[1])) ? "<bad-boy>" : parv[1];
+ host = (parc < 3 || BadPtr(parv[2])) ? "<nohost>" : parv[2];
+ server = (parc < 4 || BadPtr(parv[3])) ? "<noserver>" : parv[3];
+ realname = (parc < 5 || BadPtr(parv[4])) ? "<bad-realname>" : parv[4];
+
+ user = make_user(sptr);
+
+ if (!MyConnect(sptr))
+ {
+ aClient *acptr = NULL;
+ aServer *sp = NULL;
+
+ if (!(sp = find_tokserver(atoi(server), cptr, NULL)))
+ {
+ /*
+ ** Why? Why do we keep doing this?
+ ** s_service.c had the same kind of kludge.
+ ** Can't we get rid of this? - krys
+ */
+ acptr = find_server(server, NULL);
+ if (acptr)
+ sendto_flag(SCH_ERROR,
+ "ERROR: SERVER:%s uses wrong syntax for NICK (%s)",
+ get_client_name(cptr, FALSE),
+ parv[0]);
+ }
+ if (acptr)
+ sp = acptr->serv;
+ else if (!sp)
+ {
+ sendto_flag(SCH_ERROR,
+ "ERROR: USER:%s without SERVER:%s from %s",
+ parv[0], server,
+ get_client_name(cptr, FALSE));
+ ircstp->is_nosrv++;
+ return exit_client(NULL, sptr, &me, "No Such Server");
+ }
+ user->servp = sp;
+ user->servp->refcnt++;
+
+ Debug((DEBUG_DEBUG, "from %s user %s server %s -> %#x %s",
+ parv[0], username, server, sp, sp->bcptr->name));
+ strncpyzt(user->host, host, sizeof(user->host));
+ user->server = find_server_string(sp->snum);
+ goto user_finish;
+ }
+
+ user->servp = me.serv;
+ me.serv->refcnt++;
+#ifndef NO_DEFAULT_INVISIBLE
+ SetInvisible(sptr);
+#endif
+ if (sptr->flags & FLAGS_RILINE)
+ sptr->user->flags |= FLAGS_RESTRICTED;
+ sptr->user->flags |= (UFLAGS & atoi(host));
+ strncpyzt(user->host, host, sizeof(user->host));
+ user->server = find_server_string(me.serv->snum);
+
+user_finish:
+ reorder_client_in_list(sptr);
+ if (sptr->info != DefInfo)
+ MyFree(sptr->info);
+ if (strlen(realname) > REALLEN)
+ realname[REALLEN] = '\0';
+ sptr->info = mystrdup(realname);
+ if (sptr->name[0]) /* NICK already received, now we have USER... */
+ {
+ if ((parc == 6) && IsServer(cptr)) /* internal m_user() */
+ {
+ char *pv[4];
+
+ pv[0] = ME;
+ pv[1] = sptr->name;
+ pv[2] = parv[5];
+ pv[3] = NULL;
+ m_umode(NULL, sptr, 3, pv);/*internal fake call again*/
+ /* The internal m_umode does NOT propagate to 2.8
+ ** servers. (it can NOT since NICK/USER hasn't been
+ ** sent yet). See register_user()
+ */
+ }
+ return register_user(cptr, sptr, sptr->name, username);
+ }
+ else
+ strncpyzt(sptr->user->username, username, USERLEN+1);
+ return 2;
+}
+
+/*
+** m_quit
+** parv[0] = sender prefix
+** parv[1] = comment
+*/
+int m_quit(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+ {
+ static char quitc[] = "I Quit";
+ register char *comment = (parc > 1 && parv[1]) ? parv[1] : quitc;
+
+ if (MyClient(sptr) || MyService(sptr))
+ if (!strncmp("Local Kill", comment, 10) ||
+ !strncmp(comment, "Killed", 6))
+ comment = quitc;
+ if (strlen(comment) > (size_t) TOPICLEN)
+ comment[TOPICLEN] = '\0';
+ return IsServer(sptr) ? 0 : exit_client(cptr, sptr, sptr, comment);
+ }
+
+/*
+** m_kill
+** parv[0] = sender prefix
+** parv[1] = kill victim
+** parv[2] = kill path
+*/
+int m_kill(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+ aClient *acptr;
+ char *inpath = get_client_name(cptr,FALSE);
+ char *user, *path, *killer;
+ int chasing = 0;
+
+ if (parc < 2 || *parv[1] == '\0')
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]), "KILL");
+ return 1;
+ }
+
+ user = parv[1];
+ path = parv[2]; /* Either defined or NULL (parc >= 2!!) */
+
+ if (IsAnOper(cptr))
+ {
+ if (BadPtr(path))
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]),
+ "KILL");
+ return 1;
+ }
+ if (strlen(path) > (size_t) TOPICLEN)
+ path[TOPICLEN] = '\0';
+ }
+
+ if (!(acptr = find_client(user, 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(user, (long)KILLCHASETIMELIMIT)))
+ {
+ if (!IsServer(sptr))
+ sendto_one(sptr, err_str(ERR_NOSUCHNICK,
+ parv[0]), user);
+ return 1;
+ }
+ sendto_one(sptr,":%s NOTICE %s :KILL changed from %s to %s",
+ ME, parv[0], user, acptr->name);
+ chasing = 1;
+ }
+ if (!MyConnect(acptr) && IsLocOp(cptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES, parv[0]));
+ return 1;
+ }
+ if (IsServer(acptr) || IsMe(acptr))
+ {
+ sendto_flag(SCH_ERROR, "%s tried to KILL server %s: %s %s %s",
+ sptr->name, acptr->name, parv[0], parv[1], parv[2]);
+ sendto_one(sptr, err_str(ERR_CANTKILLSERVER, parv[0]),
+ acptr->name);
+ return 1;
+ }
+
+#ifdef LOCAL_KILL_ONLY
+ if (MyOper(sptr) && !MyConnect(acptr))
+ {
+ sendto_one(sptr, ":%s NOTICE %s :Nick %s isnt on your server",
+ ME, parv[0], acptr->name);
+ return 1;
+ }
+#endif
+ if (!IsServer(cptr))
+ {
+ /*
+ ** The kill originates from this server, initialize path.
+ ** (In which case the 'path' may contain user suplied
+ ** explanation ...or some nasty comment, sigh... >;-)
+ **
+ ** ...!operhost!oper
+ ** ...!operhost!oper (comment)
+ */
+ if (IsUnixSocket(cptr)) /* Don't use get_client_name syntax */
+ inpath = me.sockhost;
+ else
+ inpath = cptr->sockhost;
+ if (!BadPtr(path))
+ {
+ 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.
+ */
+ if (IsLocOp(sptr) && !MyConnect(acptr))
+ {
+ sendto_one(sptr, err_str(ERR_NOPRIVILEGES, parv[0]));
+ return 1;
+ }
+ sendto_flag(SCH_KILL,
+ "Received KILL message for %s. From %s Path: %s!%s",
+ acptr->name, 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 && !IsClient(cptr))
+ sendto_one(cptr, ":%s KILL %s :%s!%s",
+ ME, acptr->name, inpath, path);
+ acptr->flags |= FLAGS_KILLED;
+ }
+#ifdef USE_SERVICES
+ check_services_butone(SERVICE_WANT_KILL, NULL, 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))
+ sendto_prefix_one(acptr, sptr,":%s KILL %s :%s!%s",
+ parv[0], acptr->name, inpath, path);
+ /*
+ ** Set FLAGS_KILLED. This prevents exit_one_client from sending
+ ** the unnecessary QUIT for this. (This flag should never be
+ ** set in any other place)
+ */
+ if (MyConnect(acptr) && MyConnect(sptr) && IsAnOper(sptr))
+ {
+ acptr->exitc = EXITC_KILL;
+ SPRINTF(buf2, "Local Kill by %s (%s)", sptr->name,
+ BadPtr(parv[2]) ? sptr->name : parv[2]);
+ }
+ else
+ {
+ if ((killer = index(path, ' ')))
+ {
+ while (killer > path && *killer != '!')
+ killer--;
+ if (killer != path)
+ killer++;
+ }
+ else
+ killer = path;
+ SPRINTF(buf2, "Killed (%s)", killer);
+ }
+ return exit_client(cptr, acptr, sptr, buf2);
+}
+
+/***********************************************************************
+ * 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[];
+{
+ Reg char *away, *awy2 = parv[1];
+ int len;
+
+ away = sptr->user->away;
+
+ if (parc < 2 || !*awy2) /* Marking as not away */
+ {
+ if (away)
+ {
+ istat.is_away--;
+ istat.is_awaymem -= (strlen(away) + 1);
+ MyFree(away);
+ sptr->user->away = NULL;
+ }
+ if (sptr->user->flags & FLAGS_AWAY)
+ sendto_serv_butone(cptr, ":%s MODE %s :-a", parv[0],
+ parv[0]);
+ /* sendto_serv_butone(cptr, ":%s AWAY", parv[0]); */
+ if (MyConnect(sptr))
+ sendto_one(sptr, rpl_str(RPL_UNAWAY, parv[0]));
+#ifdef USE_SERVICES
+ check_services_butone(SERVICE_WANT_AWAY, NULL, sptr,
+ ":%s AWAY", parv[0]);
+#endif
+ sptr->user->flags &= ~FLAGS_AWAY;
+ return 1;
+ }
+
+ /* Marking as away */
+
+ if ((len = strlen(awy2)) > (size_t) TOPICLEN)
+ {
+ len = TOPICLEN;
+ awy2[TOPICLEN] = '\0';
+ }
+ len++;
+ /* sendto_serv_butone(cptr, ":%s AWAY :%s", parv[0], awy2); */
+#ifdef USE_SERVICES
+ check_services_butone(SERVICE_WANT_AWAY, NULL, sptr,
+ ":%s AWAY :%s", parv[0], awy2);
+#endif
+
+ if (away)
+ {
+ istat.is_awaymem -= (strlen(away) + 1);
+ away = (char *)MyRealloc(away, len);
+ istat.is_awaymem += len;
+ }
+ else
+ {
+ istat.is_away++;
+ istat.is_awaymem += len;
+ away = (char *)MyMalloc(len);
+ sendto_serv_butone(cptr, ":%s MODE %s :+a", parv[0], parv[0]);
+ }
+
+ sptr->user->flags |= FLAGS_AWAY;
+ if (MyConnect(sptr))
+ {
+ sptr->user->away = away;
+ (void)strcpy(away, awy2);
+ sendto_one(sptr, rpl_str(RPL_NOWAWAY, parv[0]));
+ }
+ return 2;
+}
+
+/*
+** m_ping
+** parv[0] = sender prefix
+** parv[1] = origin
+** parv[2] = destination
+*/
+int m_ping(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+ aClient *acptr;
+ char *origin, *destination;
+
+ if (parc < 2 || *parv[1] == '\0')
+ {
+ sendto_one(sptr, err_str(ERR_NOORIGIN, parv[0]));
+ return 1;
+ }
+ 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) != 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, parv[0]),
+ destination);
+ return 1;
+ }
+ }
+ else
+ sendto_one(sptr, ":%s PONG %s :%s", ME,
+ (destination) ? destination : ME, origin);
+ return 1;
+ }
+
+/*
+** 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;
+
+ if (parc < 2 || *parv[1] == '\0')
+ {
+ sendto_one(sptr, err_str(ERR_NOORIGIN, parv[0]));
+ return 1;
+ }
+
+ origin = parv[1];
+ destination = parv[2];
+ cptr->flags &= ~FLAGS_PINGSENT;
+ sptr->flags &= ~FLAGS_PINGSENT;
+
+ if (!BadPtr(destination) && mycmp(destination, ME) != 0)
+ {
+ if ((acptr = find_client(destination, NULL)) ||
+ (acptr = find_server(destination, NULL))) {
+ if (!(MyClient(sptr) && mycmp(origin, sptr->name)))
+ sendto_one(acptr,":%s PONG %s %s",
+ parv[0], origin, destination);
+ } else
+ sendto_one(sptr, err_str(ERR_NOSUCHSERVER, parv[0]),
+ destination);
+ return 2;
+ }
+#ifdef DEBUGMODE
+ else
+ Debug((DEBUG_NOTICE, "PONG: %s %s", origin,
+ destination ? destination : "*"));
+#endif
+ return 1;
+ }
+
+
+/*
+** 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 */
+
+ 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, parv[0]), "OPER");
+ return 1;
+ }
+
+ /* if message arrived from server, trust it, and set to oper */
+
+ if ((IsServer(cptr) || IsMe(cptr)) && !IsOper(sptr))
+ {
+ /* we never get here, do we?? (counters!) -krys */
+ sptr->user->flags |= FLAGS_OPER;
+ sendto_serv_butone(cptr, ":%s MODE %s :+o", parv[0], parv[0]);
+ if (IsMe(cptr))
+ sendto_one(sptr, rpl_str(RPL_YOUREOPER, parv[0]));
+#ifdef USE_SERVICES
+ check_services_butone(SERVICE_WANT_OPER, sptr->user->server,
+ sptr, ":%s MODE %s :+o", parv[0],
+ parv[0]);
+#endif
+ return 1;
+ }
+ else if (IsAnOper(sptr))
+ {
+ if (MyConnect(sptr))
+ sendto_one(sptr, rpl_str(RPL_YOUREOPER, parv[0]));
+ return 1;
+ }
+ if (!(aconf = find_conf_exact(name, sptr->username, sptr->sockhost,
+ CONF_OPS)) &&
+ !(aconf = find_conf_exact(name, sptr->username,
+#ifdef INET6
+ (char *)inetntop(AF_INET6,
+ (char *)&cptr->ip,
+ mydummy, MYDUMMY_SIZE),
+#else
+ (char *)inetntoa((char *)&cptr->ip),
+#endif
+ CONF_OPS)))
+ {
+ sendto_one(sptr, err_str(ERR_NOOPERHOST, parv[0]));
+ return 1;
+ }
+#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)
+ {
+ /* Determine if MD5 or DES */
+ if (strncmp(aconf->passwd, "$1$", 3))
+ {
+ salt[0] = aconf->passwd[0];
+ salt[1] = aconf->passwd[1];
+ }
+ else
+ {
+ salt[0] = aconf->passwd[3];
+ salt[1] = aconf->passwd[4];
+ }
+ 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->user->flags & ALL_UMODES);
+ char *s;
+
+ s = index(aconf->host, '@');
+ *s++ = '\0';
+#ifdef OPER_REMOTE
+ if (aconf->status == CONF_LOCOP)
+#else
+ if ((match(s,me.sockhost) && !IsLocal(sptr)) ||
+ aconf->status == CONF_LOCOP)
+#endif
+ SetLocOp(sptr);
+ else
+ SetOper(sptr);
+ *--s = '@';
+ sendto_flag(SCH_NOTICE, "%s (%s@%s) is now operator (%c)",
+ parv[0], sptr->user->username, sptr->user->host,
+ IsOper(sptr) ? 'o' : 'O');
+ send_umode_out(cptr, sptr, old);
+ sendto_one(sptr, rpl_str(RPL_YOUREOPER, parv[0]));
+#if !defined(CRYPT_OPER_PASSWORD) && (defined(FNAME_OPERLOG) ||\
+ (defined(USE_SYSLOG) && defined(SYSLOG_OPER)))
+ encr = "";
+#endif
+#if defined(USE_SYSLOG) && defined(SYSLOG_OPER)
+ syslog(LOG_INFO, "OPER (%s) (%s) by (%s!%s@%s) [%s@%s]",
+ name, encr,
+ parv[0], sptr->user->username, sptr->user->host,
+ sptr->auth, IsUnixSocket(sptr) ? sptr->sockhost :
+#ifdef INET6
+ inet_ntop(AF_INET6, (char *)&sptr->ip), mydummy, MYDUMMY_SIZE);
+#else
+ inetntoa((char *)&sptr->ip));
+#endif
+#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)
+ */
+ (void)alarm(3);
+ if (IsPerson(sptr) &&
+ (logfile = open(FNAME_OPERLOG, O_WRONLY|O_APPEND)) != -1)
+ {
+ (void)alarm(0);
+ SPRINTF(buf, "%s OPER (%s) (%s) by (%s!%s@%s) [%s@%s]\n",
+ myctime(timeofday), name, encr,
+ parv[0], sptr->user->username, sptr->user->host,
+ sptr->auth, IsUnixSocket(sptr) ? sptr->sockhost :
+#ifdef INET6
+ inetntop(AF_INET6, (char *)&sptr->ip, mydummy,
+ MYDUMMY_SIZE));
+#else
+ inetntoa((char *)&sptr->ip));
+#endif
+ (void)alarm(3);
+ (void)write(logfile, buf, strlen(buf));
+ (void)alarm(0);
+ (void)close(logfile);
+ }
+ (void)alarm(0);
+ /* Modification by pjg */
+ }
+#endif
+#ifdef USE_SERVICES
+ check_services_butone(SERVICE_WANT_OPER, sptr->user->server,
+ sptr, ":%s MODE %s :+%c", parv[0],
+ parv[0], IsOper(sptr) ? 'O' : 'o');
+#endif
+ if (IsAnOper(sptr))
+ istat.is_oper++;
+ }
+ else
+ {
+ (void)detach_conf(sptr, aconf);
+ sendto_one(sptr,err_str(ERR_PASSWDMISMATCH, parv[0]));
+ }
+ return 3;
+ }
+
+/***************************************************************************
+ * m_pass() - Added Sat, 4 March 1989
+ ***************************************************************************/
+
+/*
+** m_pass
+** parv[0] = sender prefix
+** parv[1] = password
+** parv[2] = protocol & server versions (server only)
+** parv[3] = server id & options (server only)
+** parv[4] = (optional) link options (server only)
+*/
+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, parv[0]), "PASS");
+ return 1;
+ }
+ /* Temporarily store PASS pwd *parameters* into info field */
+ if (parc > 2 && parv[2])
+ {
+ strncpyzt(buf, parv[2], 15);
+ if (parc > 3 && parv[3])
+ {
+ strcat(buf, " ");
+ strncat(buf, parv[3], 100);
+ if (parc > 4 && parv[4])
+ {
+ strcat(buf, " ");
+ strncat(buf, parv[4], 5);
+ }
+ }
+ if (cptr->info != DefInfo)
+ MyFree(cptr->info);
+ cptr->info = mystrdup(buf);
+ }
+ strncpyzt(cptr->passwd, password, sizeof(cptr->passwd));
+ return 1;
+ }
+
+/*
+ * 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[];
+{
+ char *p = NULL;
+ aClient *acptr;
+ Reg char *s;
+ Reg int i, len;
+ int idx = 1;
+
+ if (parc < 2)
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]),
+ "USERHOST");
+ return 1;
+ }
+
+ (void)strcpy(buf, rpl_str(RPL_USERHOST, parv[0]));
+ len = strlen(buf);
+ *buf2 = '\0';
+
+ for (i = 5, s = strtoken(&p, parv[idx], " "); i && s; i--)
+ {
+ if ((acptr = find_person(s, NULL)))
+ {
+ if (*buf2)
+ (void)strcat(buf, " ");
+ SPRINTF(buf2, "%s%s=%c%s@%s", acptr->name,
+ IsAnOper(acptr) ? "*" : "",
+ (acptr->user->flags & FLAGS_AWAY) ? '-' : '+',
+ acptr->user->username, acptr->user->host);
+ (void)strncat(buf, buf2, sizeof(buf) - len);
+ len += strlen(buf2);
+ if (len > BUFSIZE - (NICKLEN + 5 + HOSTLEN + USERLEN))
+ {
+ sendto_one(sptr, "%s", buf);
+ (void)strcpy(buf, rpl_str(RPL_USERHOST,
+ parv[0]));
+ len = strlen(buf);
+ *buf2 = '\0';
+ }
+ }
+ s = strtoken(&p, (char *)NULL, " ");
+ if (!s && parv[++idx])
+ {
+ p = NULL;
+ s = strtoken(&p, parv[idx], " ");
+ }
+ }
+ sendto_one(sptr, "%s", buf);
+ return 1;
+}
+
+/*
+ * 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[];
+{
+ Reg aClient *acptr;
+ Reg char *s, **pav = parv;
+ Reg int len = 0;
+ char *p = NULL;
+
+ if (parc < 2)
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]), "ISON");
+ return 1;
+ }
+
+ (void)strcpy(buf, rpl_str(RPL_ISON, *parv));
+ len = strlen(buf);
+
+ for (s = strtoken(&p, *++pav, " "); s; s = strtoken(&p, NULL, " "))
+ if ((acptr = find_person(s, NULL)))
+ {
+ (void) strcpy(buf + len, acptr->name);
+ len += strlen(acptr->name);
+ (void) strcpy(buf + len++, " ");
+ }
+ sendto_one(sptr, "%s", buf);
+ return 1;
+}
+
+/*
+ * m_umode() added 15/10/91 By Darren Reed.
+ * parv[0] - sender (can be NULL, see below..)
+ * 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[];
+{
+ Reg int flag;
+ Reg int *s;
+ Reg char **p, *m;
+ aClient *acptr = NULL;
+ int what, setflags, penalty = 0;
+
+ what = MODE_ADD;
+
+ if (parc < 2)
+ {
+ sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]), "MODE");
+ return 1;
+ }
+
+ if (cptr && !(acptr = find_person(parv[1], NULL)))
+ {
+ if (MyConnect(sptr))
+ sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL, parv[0]),
+ parv[1]);
+ return 1;
+ }
+ if (cptr == NULL)
+ /* internal call which has to be handled in a special way */
+ acptr = sptr;
+
+ if ((cptr != NULL) &&
+ ((IsServer(sptr) || sptr != acptr || acptr->from != sptr->from)))
+ {
+ if (IsServer(cptr))
+ sendto_ops_butone(NULL, &me,
+ ":%s WALLOPS :MODE for User %s From %s!%s",
+ ME, parv[1],
+ get_client_name(cptr, FALSE), sptr->name);
+ else
+ sendto_one(sptr, err_str(ERR_USERSDONTMATCH, parv[0]));
+ return 1;
+ }
+
+ if (parc < 3)
+ {
+ m = buf;
+ *m++ = '+';
+ for (s = user_modes; (flag = *s) && (m - buf < BUFSIZE - 4);
+ s += 2)
+ if (sptr->user->flags & flag)
+ *m++ = (char)(*(s+1));
+ *m = '\0';
+ sendto_one(sptr, rpl_str(RPL_UMODEIS, parv[0]), buf);
+ return 1;
+ }
+
+ /* find flags already set for user */
+ setflags = 0;
+ for (s = user_modes; (flag = *s); s += 2)
+ if (sptr->user->flags & 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 'a' : /* fall through case */
+ /* users should use the AWAY message */
+ if (cptr && !IsServer(cptr))
+ break;
+ if (what == MODE_DEL && sptr->user->away)
+ {
+ istat.is_away--;
+ istat.is_awaymem -= (strlen(sptr->user->away) + 1);
+ MyFree(sptr->user->away);
+ sptr->user->away = NULL;
+#ifdef USE_SERVICES
+ check_services_butone(SERVICE_WANT_AWAY,
+ sptr->user->server, sptr,
+ ":%s AWAY", parv[0]);
+#endif
+ }
+#ifdef USE_SERVICES
+ if (what == MODE_ADD)
+ check_services_butone(SERVICE_WANT_AWAY,
+ sptr->user->server, sptr,
+ ":%s AWAY :", parv[0]);
+#endif
+ default :
+ for (s = user_modes; (flag = *s); s += 2)
+ if (*m == (char)(*(s+1)))
+ {
+ if (what == MODE_ADD)
+ sptr->user->flags |= flag;
+ else
+ sptr->user->flags &= ~flag;
+ penalty += 1;
+ break;
+ }
+ if (flag == 0 && MyConnect(sptr))
+ sendto_one(sptr, err_str(
+ ERR_UMODEUNKNOWNFLAG, parv[0]),
+ *m);
+ break;
+ }
+ /*
+ * stop users making themselves operators too easily
+ */
+ if (cptr)
+ {
+ if (!(setflags & FLAGS_OPER) && IsOper(sptr) &&
+ !IsServer(cptr))
+ ClearOper(sptr);
+ if (!(setflags & FLAGS_LOCOP) && IsLocOp(sptr) &&
+ !IsServer(cptr))
+ sptr->user->flags &= ~FLAGS_LOCOP;
+ if ((setflags & FLAGS_RESTRICTED) &&
+ !(sptr->user->flags & FLAGS_RESTRICTED))
+ {
+ sendto_one(sptr, err_str(ERR_RESTRICTED, parv[0]));
+ SetRestricted(sptr);
+ /* Can't return; here since it could mess counters */
+ }
+ if ((setflags & (FLAGS_OPER|FLAGS_LOCOP)) && !IsAnOper(sptr) &&
+ MyConnect(sptr))
+ det_confs_butmask(sptr, CONF_CLIENT);
+
+ /*
+ * compare new flags with old flags and send string which
+ * will cause servers to update correctly.
+ */
+ if (!IsInvisible(sptr) && (setflags & FLAGS_INVISIBLE))
+ {
+ istat.is_user[1]--;
+ istat.is_user[0]++;
+ }
+ if (IsInvisible(sptr) && !(setflags & FLAGS_INVISIBLE))
+ {
+ istat.is_user[1]++;
+ istat.is_user[0]--;
+ }
+ send_umode_out(cptr, sptr, setflags);
+ }
+
+ /* update counters */
+ if (IsOper(sptr) && !(setflags & FLAGS_OPER))
+ {
+ istat.is_oper++;
+#ifdef USE_SERVICES
+ check_services_butone(SERVICE_WANT_OPER, sptr->user->server,
+ sptr, ":%s MODE %s :+o", parv[0],
+ parv[0]);
+#endif
+ }
+ else if (!IsOper(sptr) && (setflags & FLAGS_OPER))
+ {
+ istat.is_oper--;
+#ifdef USE_SERVICES
+ check_services_butone(SERVICE_WANT_OPER, sptr->user->server,
+ sptr, ":%s MODE %s :-o", parv[0],
+ parv[0]);
+#endif
+ }
+ else if (MyConnect(sptr) && !IsLocOp(sptr) && (setflags & FLAGS_LOCOP))
+ {
+ istat.is_oper--;
+#ifdef USE_SERVICES
+ check_services_butone(SERVICE_WANT_OPER, sptr->user->server,
+ sptr, ":%s MODE %s :-O", parv[0],
+ parv[0]);
+#endif
+ }
+
+ return penalty;
+}
+
+/*
+ * 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;
+{
+ Reg int *s, flag;
+ Reg char *m;
+ int what = MODE_NULL;
+
+ if (!sptr->user)
+ return;
+ /*
+ * 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->user->flags & flag))
+ {
+ if (what == MODE_DEL)
+ *m++ = *(s+1);
+ else
+ {
+ what = MODE_DEL;
+ *m++ = '-';
+ *m++ = *(s+1);
+ }
+ }
+ else if (!(flag & old) && (sptr->user->flags & 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 MODE %s :%s",
+ sptr->name, 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;
+{
+ Reg int i;
+ Reg aClient *acptr;
+
+ send_umode(NULL, sptr, old, SEND_UMODES, buf);
+
+ if (*buf)
+ for (i = fdas.highest; i >= 0; i--)
+ {
+ if (!(acptr = local[fdas.fd[i]]) || !IsServer(acptr))
+ continue;
+ if (acptr == cptr || acptr == sptr)
+ continue;
+ sendto_one(acptr, ":%s MODE %s :%s",
+ sptr->name, sptr->name, buf);
+ }
+
+ if (cptr && MyClient(cptr))
+ send_umode(cptr, sptr, old, ALL_UMODES, buf);
+#ifdef USE_SERVICES
+ /* buf contains all modes for local users, and iow only for remotes */
+ if (*buf)
+ check_services_butone(SERVICE_WANT_UMODE, NULL, sptr,
+ ":%s MODE %s :%s", sptr->name,
+ sptr->name, buf);
+#endif
+}
diff --git a/ircd/s_user_ext.h b/ircd/s_user_ext.h
new file mode 100644
index 0000000..2feec20
--- /dev/null
+++ b/ircd/s_user_ext.h
@@ -0,0 +1,60 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/s_user_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in ircd/s_user.c.
+ */
+
+/* External definitions for global functions.
+ */
+#ifndef S_USER_C
+#define EXTERN extern
+#else /* S_USER_C */
+#define EXTERN
+#endif /* S_USER_C */
+EXTERN aClient *next_client __P((Reg aClient *next, Reg char *ch));
+EXTERN int hunt_server __P((aClient *cptr, aClient *sptr, char *command,
+ int server, int parc, char *parv[]));
+EXTERN int do_nick_name __P((char *nick, int server));
+EXTERN int ereject_user __P((aClient *, char *, char *));
+EXTERN int register_user __P((aClient *, aClient *, char *, char *));
+EXTERN char *canonize __P((char *buffer));
+EXTERN int m_nick __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN int m_private __P((aClient *cptr, aClient *sptr, int parc,
+ char *parv[]));
+EXTERN int m_notice __P((aClient *cptr, aClient *sptr, int parc,
+ char *parv[]));
+EXTERN int m_who __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN int m_whois __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN int m_user __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN int m_quit __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN int m_kill __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN int m_away __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN int m_ping __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN int m_pong __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN int m_oper __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN int m_pass __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN int m_userhost __P((aClient *cptr, aClient *sptr, int parc,
+ char *parv[]));
+EXTERN int m_ison __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN int m_umode __P((aClient *cptr, aClient *sptr, int parc, char *parv[]));
+EXTERN void send_umode __P((aClient *cptr, aClient *sptr, int old,
+ int sendmask, char *umode_buf));
+EXTERN void send_umode_out __P((aClient *cptr, aClient *sptr, int old));
+#undef EXTERN
diff --git a/ircd/s_zip.c b/ircd/s_zip.c
new file mode 100644
index 0000000..819c9a9
--- /dev/null
+++ b/ircd/s_zip.c
@@ -0,0 +1,261 @@
+/************************************************************************
+ * 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: s_zip.c,v 1.7 1998/12/24 16:29:17 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "s_defines.h"
+#define S_ZIP_C
+#include "s_externs.h"
+#undef S_ZIP_C
+
+#ifdef ZIP_LINKS
+
+/*
+** Important note:
+** The provided buffers for 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 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 (MAX(ZIP_MAXIMUM, READBUF_SIZE))
+
+/*
+** size of the buffer where zlib puts compressed data
+** should be enough to hold uncompressed data resulting of the
+** uncompression of zipbuffer
+**
+** tests show that an average ratio is around 40%,
+** in some very particular cases, ratio can be VERY low, BUT:
+**
+** s_bsd.c/read_packet() is now smart enough to detect when uncompression
+** stopped because the buffer is too small, and calls dopacket() again
+** to finish the work (as many times as needed).
+*/
+#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(cptr)
+aClient *cptr;
+{
+ cptr->zip = (aZdata *) MyMalloc(sizeof(aZdata));
+ cptr->zip->outcount = 0;
+
+ cptr->zip->in = (z_stream *) MyMalloc(sizeof(z_stream));
+ cptr->zip->in->avail_in = 0;
+ 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(cptr)
+aClient *cptr;
+{
+ cptr->flags &= ~FLAGS_ZIP;
+ if (cptr->zip)
+ {
+ if (cptr->zip->in)
+ inflateEnd(cptr->zip->in);
+ MyFree((char *)cptr->zip->in);
+ if (cptr->zip->out)
+ deflateEnd(cptr->zip->out);
+ MyFree((char *)cptr->zip->out);
+ MyFree((char *)cptr->zip);
+ cptr->zip = NULL;
+ }
+}
+
+/*
+** unzip_packet
+** Unzip the content of the buffer, don't worry about any leftover.
+**
+** will return the uncompressed buffer, length will be updated.
+** if a fatal error occurs, length will be set to -1
+*/
+char * unzip_packet(cptr, buffer, length)
+aClient *cptr;
+char *buffer;
+int *length;
+{
+ Reg z_stream *zin = cptr->zip->in;
+ int r;
+
+ if (*length != 0 && zin->avail_in != 0)
+ {
+ sendto_flag(SCH_ERROR,
+ "assertion failed in unzip_packet(): %d %d",
+ *length, zin->avail_in);
+ sendto_flag(SCH_ERROR, "Please report to ircd-bugs@irc.org");
+ *length = -1;
+ return NULL;
+ }
+ if (*length)
+ {
+ zin->next_in = buffer;
+ zin->avail_in = *length;
+ }
+ zin->next_out = unzipbuf;
+ zin->avail_out = UNZIP_BUFFER_SIZE;
+ switch (r = inflate(zin, Z_PARTIAL_FLUSH))
+ {
+ case Z_OK:
+ cptr->flags &= ~FLAGS_ZIPRQ;
+ *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_flag(SCH_ERROR,
+ "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->flags & FLAGS_ZIPRQ) &&
+ !strncmp("ERROR ", buffer, 6))
+ {
+ cptr->flags &= ~(FLAGS_ZIP | FLAGS_ZIPRQ);
+ /*
+ * 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_flag(SCH_ERROR, "inflate() error(%d): %s", r,
+ (zin->msg) ? zin->msg : "?");
+ *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(cptr, buffer, length, flush)
+aClient *cptr;
+char *buffer;
+int *length, flush;
+{
+ Reg 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)) &&
+ CBurst(cptr))))
+ 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_flag(SCH_ERROR,
+ "deflate() didn't process all available data!");
+ }
+ cptr->zip->outcount = 0;
+ *length = ZIP_BUFFER_SIZE - zout->avail_out;
+ return zipbuf;
+
+ default: /* error ! */
+ sendto_flag(SCH_ERROR, "deflate() error(%d): %s", r,
+ (zout->msg) ? zout->msg : "?");
+ *length = -1;
+ break;
+ }
+ return NULL;
+}
+
+#endif /* ZIP_LINKS */
diff --git a/ircd/s_zip_ext.h b/ircd/s_zip_ext.h
new file mode 100644
index 0000000..6ab86d1
--- /dev/null
+++ b/ircd/s_zip_ext.h
@@ -0,0 +1,38 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/s_zip_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in ircd/s_zip.c.
+ */
+
+/* External definitions for global functions.
+ */
+#ifndef S_ZIP_C
+#define EXTERN extern
+#else /* S_ZIP_C */
+#define EXTERN
+#endif /* S_ZIP_C */
+#ifdef ZIP_LINKS
+EXTERN int zip_init __P((aClient *cptr));
+EXTERN void zip_free __P((aClient *cptr));
+EXTERN char *unzip_packet __P((aClient *cptr, char *buffer, int *length));
+EXTERN char *zip_buffer __P((aClient *cptr, char *buffer, int *length,
+ int flush));
+#endif /* ZIP_LINKS */
+#undef EXTERN
diff --git a/ircd/service_def.h b/ircd/service_def.h
new file mode 100644
index 0000000..02a1d9d
--- /dev/null
+++ b/ircd/service_def.h
@@ -0,0 +1,54 @@
+
+/* The different things a service can `sniff' */
+
+#define SERVICE_WANT_SERVICE 0x00000001 /* other services signing on/off */
+#define SERVICE_WANT_OPER 0x00000002 /* operators, included in _UMODE */
+#define SERVICE_WANT_UMODE 0x00000004 /* user modes, iow + local modes */
+#define SERVICE_WANT_AWAY 0x00000008 /* away isn't propaged anymore.. */
+#define SERVICE_WANT_KILL 0x00000010 /* KILLs */
+#define SERVICE_WANT_NICK 0x00000020 /* all NICKs (new user, change) */
+#define SERVICE_WANT_USER 0x00000040 /* USER signing on */
+#define SERVICE_WANT_QUIT 0x00000080 /* all QUITs (users signing off) */
+#define SERVICE_WANT_SERVER 0x00000100 /* servers signing on */
+#define SERVICE_WANT_WALLOP 0x00000200 /* wallops */
+#define SERVICE_WANT_SQUIT 0x00000400 /* servers signing off */
+#define SERVICE_WANT_RQUIT 0x00000800 /* regular user QUITs (these which
+ are also sent between servers) */
+#define SERVICE_WANT_MODE 0x00001000 /* channel modes (not +ov) */
+#define SERVICE_WANT_CHANNEL 0x00002000 /* channel creations/destructions */
+#define SERVICE_WANT_VCHANNEL 0x00004000 /* channel joins/parts */
+#define SERVICE_WANT_TOPIC 0x00008000 /* channel topics */
+
+#define SERVICE_WANT_ERRORS 0x01000000 /* &ERRORS */
+#define SERVICE_WANT_NOTICES 0x02000000 /* &NOTICES */
+#define SERVICE_WANT_LOCAL 0x04000000 /* &LOCAL */
+#define SERVICE_WANT_NUMERICS 0x08000000 /* &NUMERICS */
+
+#define SERVICE_WANT_USERLOG 0x10000000 /* FNAME_USERLOG */
+#define SERVICE_WANT_CONNLOG 0x20000000 /* FNAME_CONNLOG */
+
+/* masks */
+#define SERVICE_MASK_GLOBAL 0x00007000 /*for these,service must be global*/
+#define SERVICE_MASK_PREFIX 0x00000FFF /* these actions have a prefix */
+#define SERVICE_MASK_ALL 0x3F00FFFF /* all possible actions */
+#define SERVICE_MASK_NUM (SERVICE_WANT_NICK|SERVICE_WANT_USER|\
+ SERVICE_WANT_UMODE)
+
+/* options */
+#define SERVICE_WANT_PREFIX 0x00010000 /* to receive n!u@h instead of n */
+#define SERVICE_WANT_TOKEN 0x00020000 /* use serv token instead of name */
+#define SERVICE_WANT_EXTNICK 0x00040000 /* user extended NICK syntax */
+
+/* A couple example types of services */
+#define SERVICE_ALL SERVICE_MASK_ALL /* 4095 */
+#define SERVICE_NICK SERVICE_WANT_NICK | \
+ SERVICE_WANT_QUIT | \
+ SERVICE_WANT_AWAY /* 168 */
+#define SERVICE_USERS SERVICE_WANT_NICK | \
+ SERVICE_WANT_USER | \
+ SERVICE_WANT_QUIT | \
+ SERVICE_WANT_AWAY | \
+ SERVICE_WANT_UMODE /* 236 */
+#define SERVICE_LINKS SERVICE_WANT_SERVER | \
+ SERVICE_WANT_SQUIT | \
+ SERVICE_WANT_WALLOP /* 1792 */
diff --git a/ircd/sys_def.h b/ircd/sys_def.h
new file mode 100644
index 0000000..72cd68e
--- /dev/null
+++ b/ircd/sys_def.h
@@ -0,0 +1,31 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/sys_def.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.
+ */
+
+#if defined(DEBUGMODE) && !defined(CLIENT_COMPILE) && \
+ !defined(CHKCONF_COMPILE) && defined(DO_DEBUG_MALLOC)
+# define free(x) MyFree(x)
+#else
+# define MyFree(x) if ((x) != NULL) free(x)
+#endif
+
+#define SETSOCKOPT(fd, o1, o2, p1, o3) setsockopt(fd, o1, o2, (char *)p1,\
+ (SOCK_LEN_TYPE) sizeof(o3))
+
+#define GETSOCKOPT(fd, o1, o2, p1, p2) getsockopt(fd, o1, o2, (char *)p1,\
+ (SOCK_LEN_TYPE *)p2)
diff --git a/ircd/version.c.SH.in b/ircd/version.c.SH.in
new file mode 100644
index 0000000..9bdb9c4
--- /dev/null
+++ b/ircd/version.c.SH.in
@@ -0,0 +1,113 @@
+#! /bin/sh
+
+echo "Building 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`
+
+sumsserv="`(cd ../ircd; @SUM@ s_serv.c)`"
+sumsuser="`(cd ../ircd; @SUM@ s_user.c)`"
+sumchan="`(cd ../ircd; @SUM@ channel.c)`"
+sumsbsd="`(cd ../ircd; @SUM@ s_bsd.c)`"
+sumhash="`(cd ../ircd; @SUM@ hash.c)`"
+sumsmisc="`(cd ../ircd; @SUM@ s_misc.c)`"
+sumircd="`(cd ../ircd; @SUM@ ircd.c)`"
+
+creation=`date | \
+awk '{if (NF == 6) \
+ { print $1 " " $2 " " $3 " " $6 " at " $4 " " $5 } \
+else \
+ { print $1 " " $2 " " $3 " " $7 " at " $4 " " $5 " " $6 }}'`
+
+cat >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.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)\$Id: version.c.SH.in,v 1.9 1999/07/21 22:59:54 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "s_defines.h"
+#define VERSION_C
+#include "s_externs.h"
+#undef VERSION_C
+
+char *generation = "$generation";
+char *creation = "$creation";
+char *version; /* Filled by make_version() */
+char *pass_version = PATCHLEVEL;
+
+char *infotext[] =
+ {
+ "IRC --",
+ "Based on the original code written by Jarkko Oikarinen",
+ "Copyright 1988, 1989, 1990, 1991 University of Oulu, Computing Center",
+ "",
+ "This program is free software; you can redistribute it and/or",
+ "modify it under the terms of the GNU General Public License as",
+ "published by the Free Software Foundation; either version 1, or",
+ "(at your option) any later version.",
+ "",
+ "The following persons have made many changes and enhancements to the",
+ "code and still know how IRC really works if you have questions about it:",
+ "",
+ "syrk Christophe Kalt kalt@stealth.net",
+ "",
+ "Thanks to the following people for help with preparing 2.10",
+ "",
+ "Beeth Piotr Kucharski chopin@sgh.waw.pl",
+ "Q Kurt Roeckx Q@ping.be",
+ "Core Magnus Tjernstrom d92-mtm@ludd.luth.se",
+ "",
+ "Those who helped in prior versions and continue to be helpful:",
+ "",
+ "Jarkko Oikarinen",
+ "Darren Reed Vesa Ruokonen",
+ "Matthew Green Chuck Kane Matt Lyle",
+ "Markku Savela Greg Lindahl Armin Gruner",
+ "Stellan Klebom Dan Goodwin Mike Bolotski",
+ "Ian Frechette Markku Jarvinen Kimmo Suominen",
+ "Jeff Trim Vijay Subramaniam Karl Kleinpaste",
+ "Bill Wisner Tom Davis Hugo Calendar",
+ "Tom Hopkins Stephen van den Berg",
+ "Bo Adler Michael Sandrof Jon Solomon",
+ "Jan Peterson Helen Rose Paul Graham",
+ "",
+ "Thanks also goes to those persons not mentioned here who have added",
+ "their advice, opinions, and code to IRC.",
+ "Thanks also to those who provide the kind sys admins who let me and",
+ "others continue to develop IRC.",
+ "",
+ "[$sumsserv] [$sumchan] [$sumsbsd] [$sumsuser]",
+ "[$sumhash] [$sumsmisc] [$sumircd]",
+ 0,
+ };
+!SUB!THIS!
diff --git a/ircd/version_ext.h b/ircd/version_ext.h
new file mode 100644
index 0000000..5729c6f
--- /dev/null
+++ b/ircd/version_ext.h
@@ -0,0 +1,32 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/version_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in ircd/version.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef VERSION_C
+extern char *generation;
+extern char *creation;
+extern char *version;
+extern char *pass_version;
+extern char *infotext[];
+#endif /* VERSION_C */
diff --git a/ircd/whowas.c b/ircd/whowas.c
new file mode 100644
index 0000000..0dec472
--- /dev/null
+++ b/ircd/whowas.c
@@ -0,0 +1,464 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/whowas.c
+ * Copyright (C) 1990 Markku Savela
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * --- avalon --- 6th April 1992
+ * rewritten to scrap linked lists and use a table of structures which
+ * is referenced like a circular loop. Should be faster and more efficient.
+ */
+
+#ifndef lint
+static char rcsid[] = "@(#)$Id: whowas.c,v 1.6 1999/06/27 19:08:46 kalt Exp $";
+#endif
+
+#include "os.h"
+#include "s_defines.h"
+#define WHOWAS_C
+#include "s_externs.h"
+#undef WHOWAS_C
+
+static aName *was;
+int ww_index = 0, ww_size = MAXCONNECTIONS*2;
+static aLock *locked;
+int lk_index = 0, lk_size = MAXCONNECTIONS*2;
+
+static void grow_history()
+{
+ int osize = ww_size;
+
+ Debug((DEBUG_ERROR, "Whowas/grow_history ww:%d, lk:%d, #%d, %#x/%#x",
+ ww_size, lk_size, numclients, was, locked));
+ ww_size = (int)((float)numclients * 1.1);
+ was = (aName *)MyRealloc((char *)was, sizeof(*was) * ww_size);
+ bzero((char *)(was + osize), sizeof(*was) * (ww_size - osize));
+ lk_size = (int)((float)numclients * 1.1);
+ locked = (aLock *)MyRealloc((char *)locked, sizeof(*locked) * lk_size);
+ bzero((char *)(locked + osize), sizeof(*locked) * (lk_size - osize));
+ Debug((DEBUG_ERROR, "Whowas/grow_history %#x/%#x", was, locked));
+ ircd_writetune(tunefile);
+}
+
+
+/*
+** 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).
+** if nodelay is NULL, then the nickname will be subject to NickDelay
+*/
+void add_history(cptr, nodelay)
+Reg aClient *cptr, *nodelay;
+{
+ Reg aName *np;
+ Reg Link *uwas;
+
+ cptr->user->refcnt++;
+
+ np = &was[ww_index];
+
+ if ((np->ww_online && (np->ww_online != &me))
+ && !(np->ww_user && np->ww_user->uwas))
+#ifdef DEBUGMODE
+ dumpcore("whowas[%d] %#x %#x %#x", ww_index, np->ww_online,
+ np->ww_user, np->ww_user->uwas);
+#else
+ sendto_flag(SCH_ERROR, "whowas[%d] %#x %#x %#x", ww_index,
+ np->ww_online, np->ww_user, np->ww_user->uwas);
+#endif
+ /*
+ ** The entry to be overwritten in was[] is still online.
+ ** its uwas has to be updated
+ */
+ if (np->ww_online && (np->ww_online != &me))
+ {
+ Reg Link **old_uwas;
+
+ old_uwas = &(np->ww_user->uwas);
+ /* (*old_uwas) should NEVER happen to be NULL. -krys */
+ while ((*old_uwas)->value.i != ww_index)
+ old_uwas = &((*old_uwas)->next);
+ uwas = *old_uwas;
+ *old_uwas = uwas->next;
+ free_link(uwas);
+ free_user(np->ww_user, np->ww_online);
+ istat.is_wwuwas--;
+ }
+ else if (np->ww_user)
+ {
+ /*
+ ** Testing refcnt here is quite ugly, and unexact.
+ ** Nonetheless, the result is almost correct, and another
+ ** ugly thing in free_server() shoud make it exact.
+ ** The problem is that 1 anUser structure might be
+ ** referenced several times from whowas[] but is only counted
+ ** once. One knows when to add, not when to substract - krys
+ */
+ if (np->ww_user->refcnt == 1)
+ {
+ istat.is_wwusers--;
+ if (np->ww_user->away)
+ {
+ istat.is_wwaways--;
+ istat.is_wwawaysmem -=strlen(np->ww_user->away)
+ + 1;
+ }
+ }
+ free_user(np->ww_user, NULL);
+ }
+
+ if (np->ww_logout != 0)
+ {
+ int elapsed = timeofday - np->ww_logout;
+
+ /* some stats */
+ ircstp->is_wwcnt++;
+ ircstp->is_wwt += elapsed;
+ if (elapsed < ircstp->is_wwmt)
+ ircstp->is_wwmt = elapsed;
+ if (elapsed > ircstp->is_wwMt)
+ ircstp->is_wwMt = elapsed;
+
+ if (np->ww_online == NULL)
+ {
+ if (locked[lk_index].logout)
+ {
+ elapsed = timeofday - locked[lk_index].logout;
+ /* some stats first */
+ ircstp->is_lkcnt++;
+ ircstp->is_lkt += elapsed;
+ if (elapsed < ircstp->is_lkmt)
+ ircstp->is_lkmt = elapsed;
+ if (elapsed > ircstp->is_lkMt)
+ ircstp->is_lkMt = elapsed;
+ }
+
+ /*
+ ** This nickname has to be locked, thus copy it to the
+ ** lock[] array.
+ */
+ strncpyzt(locked[lk_index].nick, np->ww_nick, NICKLEN);
+ locked[lk_index++].logout = np->ww_logout;
+ if (lk_index >= lk_size)
+ lk_index = 0;
+ }
+ }
+
+ if (nodelay == cptr) /* &me is NOT a valid value, see off_history() */
+ {
+ /*
+ ** The client is online, np->ww_online is going to point to
+ ** it. The client user struct has to point to this entry
+ ** as well for faster off_history()
+ ** this uwas, and the ww_online form a pair.
+ */
+ uwas = make_link();
+ istat.is_wwuwas++;
+ /*
+ ** because of reallocs, one can not store a pointer inside
+ ** the array. store the index instead.
+ */
+ uwas->value.i = ww_index;
+ uwas->flags = timeofday;
+ uwas->next = cptr->user->uwas;
+ cptr->user->uwas = uwas;
+ }
+
+ np->ww_logout = timeofday;
+ np->ww_user = cptr->user;
+ np->ww_online = (nodelay != NULL) ? nodelay : NULL;
+
+ strncpyzt(np->ww_nick, cptr->name, NICKLEN+1);
+ strncpyzt(np->ww_info, cptr->info, REALLEN+1);
+
+ ww_index++;
+ if ((ww_index == ww_size) && (numclients > ww_size))
+ grow_history();
+ if (ww_index >= ww_size)
+ 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;
+{
+ Reg aName *wp, *wp2;
+ Reg int i = 0;
+
+ wp = wp2 = &was[ww_index];
+ timelimit = timeofday - timelimit;
+
+ do {
+ if (!mycmp(nick, wp->ww_nick) && wp->ww_logout >= timelimit)
+ break;
+ wp++;
+ if (wp == &was[ww_size])
+ i = 1, wp = was;
+ } while (wp != wp2);
+
+ if (wp != wp2 || !i)
+ if (wp->ww_online == &me)
+ return (NULL);
+ else
+ return (wp->ww_online);
+ return (NULL);
+}
+
+/*
+** find_history
+** Returns 1 if a user was using the given nickname within
+** the timelimit. Returns 0, if none found...
+*/
+int find_history(nick, timelimit)
+char *nick;
+time_t timelimit;
+{
+ Reg aName *wp, *wp2;
+ Reg aLock *lp, *lp2;
+ Reg int i = 0;
+
+ wp = wp2 = &was[ww_index];
+#ifdef RANDOM_NDELAY
+ timelimit = timeofday - timelimit - (lk_index % 60);
+#else
+ timelimit = timeofday - timelimit;
+#endif
+
+ do {
+ if (!mycmp(nick, wp->ww_nick) &&
+ (wp->ww_logout >= timelimit) && (wp->ww_online == NULL))
+ break;
+ wp++;
+ if (wp == &was[ww_size])
+ i = 1, wp = was;
+ } while (wp != wp2);
+ if ((wp != wp2 || !i) && (wp->ww_online == NULL))
+ return (1);
+
+ lp = lp2 = &locked[lk_index];
+ i = 0;
+ do {
+ if (!myncmp(nick, lp->nick, NICKLEN) &&
+ (lp->logout >= timelimit))
+ break;
+ lp++;
+ if (lp == &locked[lk_size])
+ i = 1, lp = locked;
+ } while (lp != lp2);
+ if (lp != lp2 || !i)
+ return (1);
+
+ return (0);
+}
+
+/*
+** 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(cptr)
+Reg aClient *cptr;
+{
+ Reg Link *uwas;
+
+ /*
+ ** If the client has uwas entry/ies, there are also entries in
+ ** the whowas array which point back to it.
+ ** They have to be removed, by pairs
+ */
+ while ((uwas = cptr->user->uwas))
+ {
+ if (was[uwas->value.i].ww_online != cptr)
+#ifdef DEBUGMODE
+ dumpcore("was[%d]: %#x != %#x", uwas->value.i,
+ was[uwas->value.i].ww_online, cptr);
+#else
+ sendto_flag(SCH_ERROR, "was[%d]: %#x != %#x",
+ uwas->value.i,
+ was[uwas->value.i].ww_online, cptr);
+#endif
+ /*
+ ** using &me to make ww_online non NULL (nicknames to be
+ ** locked). &me can safely be used, it is constant.
+ */
+ was[uwas->value.i].ww_online = &me;
+ cptr->user->uwas = uwas->next;
+ free_link(uwas);
+ istat.is_wwuwas--;
+ }
+
+ istat.is_wwusers++;
+ if (cptr->user->away)
+ {
+ istat.is_wwaways++;
+ istat.is_wwawaysmem += strlen(cptr->user->away) + 1;
+ }
+
+ return;
+}
+
+void initwhowas()
+{
+ Reg int i;
+
+ was = (aName *)MyMalloc(sizeof(*was) * ww_size);
+
+ for (i = 0; i < ww_size; i++)
+ bzero((char *)&was[i], sizeof(aName));
+ locked = (aLock *)MyMalloc(sizeof(*locked) * lk_size);
+ for (i = 0; i < lk_size; i++)
+ bzero((char *)&locked[i], sizeof(aLock));
+
+ ircstp->is_wwmt = ircstp->is_lkmt = DELAYCHASETIMELIMIT
+ * DELAYCHASETIMELIMIT;
+ 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[];
+{
+ Reg aName *wp, *wp2 = NULL;
+ Reg int j = 0;
+ Reg anUser *up = NULL;
+ int max = -1;
+ char *p, *nick, *s;
+
+ if (parc < 2)
+ {
+ sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN, parv[0]));
+ return 1;
+ }
+ if (parc > 2)
+ max = atoi(parv[2]);
+ if (parc > 3)
+ if (hunt_server(cptr,sptr,":%s WHOWAS %s %s :%s", 3,parc,parv))
+ return 3;
+
+ parv[1] = canonize(parv[1]);
+ if (!MyConnect(sptr))
+ max = MIN(max, 20);
+
+ for (s = parv[1]; (nick = strtoken(&p, s, ",")); s = NULL)
+ {
+ wp = wp2 = &was[ww_index - 1];
+
+ do {
+ if (wp < was)
+ wp = &was[ww_size - 1];
+ if (mycmp(nick, wp->ww_nick) == 0)
+ {
+ up = wp->ww_user;
+ sendto_one(sptr, rpl_str(RPL_WHOWASUSER,
+ parv[0]), wp->ww_nick, up->username,
+ up->host, wp->ww_info);
+ sendto_one(sptr, rpl_str(RPL_WHOISSERVER,
+ parv[0]), wp->ww_nick, up->server,
+ myctime(wp->ww_logout));
+ if (up->away)
+ sendto_one(sptr, rpl_str(RPL_AWAY,
+ parv[0]),
+ wp->ww_nick, up->away);
+ j++;
+ }
+ if (max > 0 && j >= max)
+ break;
+ wp--;
+ } while (wp != wp2);
+
+ if (up == NULL)
+ {
+ if (strlen(parv[1]) > (size_t) NICKLEN)
+ parv[1][NICKLEN] = '\0';
+ sendto_one(sptr, err_str(ERR_WASNOSUCHNICK, parv[0]),
+ parv[1]);
+ }
+
+ if (p)
+ p[-1] = ',';
+ }
+ sendto_one(sptr, rpl_str(RPL_ENDOFWHOWAS, parv[0]), parv[1]);
+ return 2;
+ }
+
+
+/*
+** for debugging...counts related structures stored in whowas array.
+*/
+void count_whowas_memory(wwu, wwa, wwam, wwuw)
+int *wwu, *wwa, *wwuw;
+u_long *wwam;
+{
+ Reg anUser *tmp;
+ Reg Link *tmpl;
+ Reg int i, j;
+ int u = 0, a = 0, w = 0;
+ u_long am = 0;
+
+ for (i = 0; i < ww_size; i++)
+ if ((tmp = was[i].ww_user))
+ {
+ for (j = 0; j < i; j++)
+ if (was[j].ww_user == tmp)
+ break;
+ if (j < i)
+ continue;
+ if (was[i].ww_online == NULL ||
+ was[i].ww_online == &me)
+ {
+ u++;
+ if (tmp->away)
+ {
+ a++;
+ am += (strlen(tmp->away)+1);
+ }
+ }
+ else
+ {
+ tmpl = tmp->uwas;
+ while (tmpl)
+ {
+ w++;
+ tmpl = tmpl->next;
+ }
+ }
+ }
+ *wwu = u;
+ *wwa = a;
+ *wwam = am;
+ *wwuw = w;
+
+ return;
+}
diff --git a/ircd/whowas_def.h b/ircd/whowas_def.h
new file mode 100644
index 0000000..d1ba12f
--- /dev/null
+++ b/ircd/whowas_def.h
@@ -0,0 +1,34 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/whowas_def.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.
+ */
+
+/*
+** 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];
+} aName;
+
+typedef struct alock {
+ time_t logout;
+ char nick[NICKLEN];
+} aLock;
diff --git a/ircd/whowas_ext.h b/ircd/whowas_ext.h
new file mode 100644
index 0000000..f65d437
--- /dev/null
+++ b/ircd/whowas_ext.h
@@ -0,0 +1,47 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/whowas_ext.h
+ * Copyright (C) 1997 Alain Nissen
+ *
+ * This program is free software; you can 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 contains external definitions for global variables and functions
+ defined in ircd/whowas.c.
+ */
+
+/* External definitions for global variables.
+ */
+#ifndef WHOWAS_C
+extern int ww_index, ww_size;
+extern int lk_index, lk_size;
+#endif /* WHOWAS_C */
+
+/* External definitions for global functions.
+ */
+#ifndef WHOWAS_C
+#define EXTERN extern
+#else /* WHOWAS_C */
+#define EXTERN
+#endif /* WHOWAS_C */
+EXTERN void add_history __P((Reg aClient *cptr, Reg aClient *nodelay));
+EXTERN aClient *get_history __P((char *nick, time_t timelimit));
+EXTERN int find_history __P((char *nick, time_t timelimit));
+EXTERN void off_history __P((Reg aClient *cptr));
+EXTERN void initwhowas();
+EXTERN int m_whowas __P((aClient *cptr, aClient *sptr, int parc,
+ char *parv[]));
+EXTERN void count_whowas_memory __P((int *wwu, int *wwa, u_long *wwam,
+ int *wwuw));
+#undef EXTERN
diff --git a/support/Makefile.in b/support/Makefile.in
new file mode 100644
index 0000000..1cebf69
--- /dev/null
+++ b/support/Makefile.in
@@ -0,0 +1,488 @@
+#************************************************************************
+#* IRC - Internet Relay Chat, Makefile
+#* Copyright (C) 1990, Jarkko Oikarinen
+#*
+#* This program is free software; you can redistribute it and/or modify
+#* it under the terms of the GNU General Public License as published by
+#* the Free Software Foundation; either version 1, or (at your option)
+#* any later version.
+#*
+#* This program is distributed in the hope that it will be useful,
+#* but WITHOUT ANY WARRANTY; without even the implied warranty of
+#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+#* GNU General Public License for more details.
+#*
+#* You should have received a copy of the GNU General Public License
+#* along with this program; if not, write to the Free Software
+#* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#*
+#* $Id: Makefile.in,v 1.45 1999/07/22 12:17:15 kalt Exp $
+#*
+#*/
+
+# -------------------------------------------------------------------------
+# Start of system configuration section.
+#
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+# compiler program
+CC = @CC@
+# compiler flags used for the server
+S_CFLAGS = @CFLAGS@ -I. -I../ircd -I../common @IRC_ZLIB_INCLUDE@
+# compiler flags used for the authentication slave
+A_CFLAGS = @CFLAGS@ -I. -I../iauth -I../common @IRC_ZLIB_INCLUDE@
+# compiler flags used for chkconfig
+CC_CFLAGS = @CFLAGS@ -I. -I../ircd -I../common
+# compiler flags used for the client
+C_CFLAGS = @CFLAGS@ -I. -I../irc -I../common
+# compiler flags used for other things (in contrib/)
+O_CFLAGS = @CFLAGS@ -I. -I../common -DCONTRIB_COMPILE
+# linker flags
+LDFLAGS = @LDFLAGS@
+# required libraries, except zlib and curses/termcap
+LIBS = @LIBS@
+MATHLIBS = -lm
+# zlib, eventually
+ZLIBS = @IRC_ZLIB_LIBRARY@
+# for DSM support (dlopen(), dlsym(), dlclose())
+DLIBS = @IRC_DLIB@
+# curses library
+CURSESLIBS = @IRC_CURSES_TERMCAP_LIBRARY@
+# install and related programs
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+MKDIRHIER = ../support/mkdirhier
+
+#
+# Binary names
+#
+CLIENT = irc
+SERVER = ircd
+IAUTH = iauth
+IRCDWATCH = ircdwatch
+
+#
+# Directories definitions
+#
+# Directory in which to install irc.
+client_bin_dir = @bindir@
+# Directory in which to install ircd, iauth, ircdwatch, mkpasswd and chkconf.
+server_bin_dir = @sbindir@
+# Directory in which to install the client manual page.
+client_man_dir = @mandir@/man1
+# Directory in which to install the configuration manual page.
+conf_man_dir = @mandir@/man5
+# Directory in which to install the server manual page.
+server_man_dir = @mandir@/man8
+# Directory where config files (ircd.conf, ircd.motd and iauth.conf) live.
+ircd_conf_dir = @sysconfdir@
+# Directory where state files (ircd.pid, ircd.tune) live.
+ircd_var_dir = @localstatedir@
+# Directory where log files (users, opers, rejects and auth) live.
+ircd_log_dir = @logdir@
+
+#
+# Most of these PATHs are hardcoded in the binaries.
+# They should all be absolute.
+#
+# Path to server binary
+IRCD_PATH = $(server_bin_dir)/$(SERVER)
+# Path to authentification slave binary
+IAUTH_PATH = $(server_bin_dir)/$(IAUTH)
+# Path to the m4 configuration file
+IRCDM4_PATH = $(ircd_conf_dir)/ircd.m4
+
+# server configuration file
+IRCDCONF_PATH = $(ircd_conf_dir)/ircd.conf
+# server Message Of The Day
+IRCDMOTD_PATH = $(ircd_conf_dir)/ircd.motd
+# authentication slave configuration file
+IAUTHCONF_PATH = $(ircd_conf_dir)/iauth.conf
+# server PID file
+IRCDPID_PATH = $(ircd_var_dir)/ircd.pid
+# server state file
+IRCDTUNE_PATH = $(ircd_var_dir)/ircd.tune
+# ircdwatch PID file
+IRCDWATCHPID_PATH = $(ircd_var_dir)/ircdwatch.pid
+
+# Define these filenames to maintain a list of persons who log
+# into this server. Logging will stop when the file does not exist.
+# Logging will be disabled also if you do not define this.
+FNAME_USERLOG = $(ircd_log_dir)/users
+FNAME_OPERLOG = $(ircd_log_dir)/opers
+FNAME_CONNLOG = $(ircd_log_dir)/rejects
+FNAME_AUTHLOG = $(ircd_log_dir)/auth
+
+# files used for debugging purposes
+IRCDDBG_PATH = $(ircd_log_dir)/ircd.log
+IAUTHDBG_PATH = $(ircd_log_dir)/iauth.log
+
+# Access mode for irc.
+irc_mode = 755
+
+# Access mode for ircd.
+ircd_mode = 711
+
+#
+# TK line service configuration
+#
+# TK line service binary
+TKSERV = tkserv
+# TK line service logfile
+TKSERV_LOGFILE = $(ircd_log_dir)/tkserv.log
+# TK line service access file
+TKSERV_ACCESSFILE = $(ircd_conf_dir)/tkserv.access
+# IRCD config file without path (from CPATH)
+TKSERV_IRCD_CONF = ircd.conf
+
+# End of system configuration section.
+# ------------------------------------------------------------------------
+# Please don't change anything below this point - no need really - I hope.
+
+RM = rm -f
+
+CLIENT_COMMON_OBJS = clbsd.o cldbuf.o clpacket.o clsend.o clmatch.o \
+ clparse.o clsupport.o
+CLIENT_OBJS = c_bsd.o c_msg.o c_numeric.o c_version.o edit.o help.o \
+ ignore.o irc.o screen.o str.o swear.o c_debug.o ctcp.o
+
+SERVER_COMMON_OBJS = bsd.o dbuf.o packet.o send.o match.o parse.o \
+ support.o
+SERVER_OBJS = channel.o class.o hash.o ircd.o list.o res.o s_auth.o \
+ s_bsd.o s_conf.o s_debug.o s_err.o s_id.o s_misc.o s_numeric.o \
+ s_serv.o s_service.o s_user.o s_zip.o whowas.o \
+ res_init.o res_comp.o res_mkquery.o
+
+IAUTH_COMMON_OBJS = clsupport.o clmatch.o # This is a little evil
+IAUTH_OBJS = iauth.o a_conf.o a_io.o a_log.o \
+ mod_lhex.o mod_pipe.o mod_rfc931.o mod_socks.o
+IAUTH = iauth
+
+CHKCONF_COMMON_OBJS = match.o
+CHKCONF_OBJS = chkconf.o
+CHKCONF = chkconf
+
+help:
+ @echo "Choose one of the following:"
+ @echo " all : build everything"
+ @echo " server : build server programs"
+ @echo " ircd : build the irc daemon"
+ @echo " iauth : build the authentication slave"
+ @echo " chkconf : build the configuration file checker"
+ @echo " ircd-mkpasswd : build ircd-mkpasswd"
+ @echo " ircdwatch : build ircdwatch"
+ @echo " client : build the client"
+ @echo " $(TKSERV) : build tkserv"
+ @echo
+ @echo " install : build and install server and client programs"
+ @echo " install-server : build and install server programs"
+ @echo " install-client : build and install client program"
+ @echo " install-tkserv : build and install tkserv"
+
+all: server client
+
+server: $(SERVER) $(IAUTH) $(CHKCONF) ircd-mkpasswd $(IRCDWATCH)
+
+client: $(CLIENT)
+
+$(SERVER): $(SERVER_COMMON_OBJS) $(SERVER_OBJS)
+ $(RM) $@
+ ./version.c.SH
+ $(CC) $(S_CFLAGS) -c -o version.o version.c
+ $(CC) $(LDFLAGS) -o $@ $(SERVER_COMMON_OBJS) version.o $(SERVER_OBJS) $(ZLIBS) $(MATHLIBS) $(LIBS)
+
+$(IAUTH): $(IAUTH_COMMON_OBJS) $(IAUTH_OBJS)
+ $(RM) $@
+ $(CC) $(LDFLAGS) -o $@ $(IAUTH_COMMON_OBJS) $(IAUTH_OBJS) $(LIBS) $(DLIBS)
+
+$(CLIENT): $(CLIENT_COMMON_OBJS) $(CLIENT_OBJS)
+ $(RM) $@
+ $(CC) $(LDFLAGS) -o $@ $(CLIENT_COMMON_OBJS) $(CLIENT_OBJS) $(CURSESLIBS) $(LIBS)
+
+$(CHKCONF): $(CHKCONF_COMMON_OBJS) $(CHKCONF_OBJS)
+ $(RM) $@
+ $(CC) $(LDFLAGS) -o $@ $(CHKCONF_COMMON_OBJS) $(CHKCONF_OBJS) $(LIBS)
+
+# stuff in contrib/
+
+$(IRCDWATCH): ircdwatch.o clsupport.o clmatch.o
+ $(RM) $(IRCDWATCH)
+ $(CC) -o $(IRCDWATCH) clsupport.o clmatch.o ircdwatch.o
+
+ircd-mkpasswd: mkpasswd.o
+ $(RM) ircd-mkpasswd
+ $(CC) $(LDFLAGS) -o ircd-mkpasswd mkpasswd.o $(LIBS)
+
+$(TKSERV): tkserv.o
+ $(RM) $(TKSERV)
+ $(CC) $(LDFLAGS) -o $(TKSERV) tkserv.o $(LIBS)
+
+install: install-server install-client
+
+install-client: client
+ -@if [ ! -d $(client_bin_dir) ]; then \
+ $(MKDIRHIER) $(client_bin_dir); \
+ fi
+ -@if [ ! -d $(client_man_dir) ]; then \
+ $(MKDIRHIER) $(client_man_dir); \
+ fi
+ $(INSTALL_PROGRAM) -m $(irc_mode) $(CLIENT) $(client_bin_dir)
+ (cd ../doc; $(INSTALL_DATA) irc.1 $(client_man_dir))
+ @echo "installation of client done."
+
+install-server: server
+ -@if [ ! -d $(server_bin_dir) ]; then \
+ $(MKDIRHIER) $(server_bin_dir); \
+ fi
+ -@if [ ! -d $(server_man_dir) ]; then \
+ $(MKDIRHIER) $(server_man_dir); \
+ fi
+ -@if [ ! -d $(conf_man_dir) ]; then \
+ $(MKDIRHIER) $(conf_man_dir); \
+ fi
+ -@if [ ! -d $(ircd_conf_dir) ]; then \
+ $(MKDIRHIER) $(ircd_conf_dir); \
+ fi
+ -@if [ ! -d $(ircd_var_dir) ]; then \
+ $(MKDIRHIER) $(ircd_var_dir); \
+ fi
+ -@if [ ! -d $(ircd_log_dir) ]; then \
+ $(MKDIRHIER) $(ircd_log_dir); \
+ fi
+ $(INSTALL_PROGRAM) -m $(ircd_mode) $(SERVER) $(server_bin_dir)
+ $(INSTALL_PROGRAM) -m $(ircd_mode) $(IAUTH) $(server_bin_dir)
+ $(INSTALL_PROGRAM) -m $(ircd_mode) $(CHKCONF) $(server_bin_dir)
+ $(INSTALL_PROGRAM) -m $(ircd_mode) ircd-mkpasswd $(server_bin_dir)
+ $(INSTALL_PROGRAM) -m $(ircd_mode) $(IRCDWATCH) $(server_bin_dir)
+ $(RM) $(IRCDM4_PATH)
+ ../ircd/buildm4 $(IRCDM4_PATH)
+ $(INSTALL_DATA) ../doc/ircd.8 $(server_man_dir)
+ $(INSTALL_DATA) ../doc/iauth.8 $(server_man_dir)
+ $(INSTALL_DATA) ../doc/iauth.conf.5 $(conf_man_dir)
+ $(INSTALL_DATA) ../contrib/ircdwatch/ircdwatch.8 $(server_man_dir)
+ $(INSTALL_DATA) ../doc/example.conf $(ircd_conf_dir)
+ -@if [ ! -f $(IAUTHCONF_PATH) ]; then \
+ $(INSTALL_DATA) ../support/iauth.conf $(IAUTHCONF_PATH); \
+ fi
+ @echo "installation of server done."
+
+install-tkserv: $(TKSERV)
+ -@if [ ! -d $(server_bin_dir) ]; then \
+ $(MKDIRHIER) $(server_bin_dir); \
+ fi
+ -@if [ ! -d $(ircd_conf_dir) ]; then \
+ $(MKDIRHIER) $(ircd_conf_dir); \
+ fi
+ $(INSTALL_PROGRAM) -m $(ircd_mode) $(TKSERV) $(server_bin_dir)
+ @echo "installation of client done."
+
+clbsd.o: ../common/bsd.c setup.h config.h
+ $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../common/bsd.c
+
+cldbuf.o: ../common/dbuf.c setup.h config.h
+ $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../common/dbuf.c
+
+clpacket.o: ../common/packet.c setup.h config.h
+ $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../common/packet.c
+
+clsend.o: ../common/send.c setup.h config.h
+ $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../common/send.c
+
+clmatch.o: ../common/match.c setup.h config.h
+ $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../common/match.c
+
+clparse.o: ../common/parse.c setup.h config.h
+ $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../common/parse.c
+
+clsupport.o: ../common/support.c setup.h config.h ../common/patchlevel.h
+ $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../common/support.c
+
+c_bsd.o: ../irc/c_bsd.c setup.h config.h
+ $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../irc/c_bsd.c
+
+c_msg.o: ../irc/c_msg.c setup.h config.h
+ $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../irc/c_msg.c
+
+c_numeric.o: ../irc/c_numeric.c setup.h config.h
+ $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../irc/c_numeric.c
+
+c_version.o: ../irc/c_version.c setup.h config.h
+ $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../irc/c_version.c
+
+edit.o: ../irc/edit.c setup.h config.h
+ $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../irc/edit.c
+
+help.o: ../irc/help.c setup.h config.h
+ $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../irc/help.c
+
+ignore.o: ../irc/ignore.c setup.h config.h
+ $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../irc/ignore.c
+
+irc.o: ../irc/irc.c setup.h config.h
+ $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../irc/irc.c
+
+screen.o: ../irc/screen.c setup.h config.h
+ $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../irc/screen.c
+
+str.o: ../irc/str.c setup.h config.h
+ $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../irc/str.c
+
+swear.o: ../irc/swear.c setup.h config.h
+ $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../irc/swear.c
+
+c_debug.o: ../irc/c_debug.c setup.h config.h
+ $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../irc/c_debug.c
+
+ctcp.o: ../irc/ctcp.c setup.h config.h
+ $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../irc/ctcp.c
+
+bsd.o: ../common/bsd.c setup.h config.h
+ $(CC) $(S_CFLAGS) -c -o $@ ../common/bsd.c
+
+dbuf.o: ../common/dbuf.c setup.h config.h
+ $(CC) $(S_CFLAGS) -c -o $@ ../common/dbuf.c
+
+packet.o: ../common/packet.c setup.h config.h
+ $(CC) $(S_CFLAGS) -c -o $@ ../common/packet.c
+
+send.o: ../common/send.c setup.h config.h
+ $(CC) $(S_CFLAGS) -DFNAME_USERLOG="\"$(FNAME_USERLOG)\"" -DFNAME_CONNLOG="\"$(FNAME_CONNLOG)\"" -c -o $@ ../common/send.c
+
+match.o: ../common/match.c setup.h config.h
+ $(CC) $(S_CFLAGS) -c -o $@ ../common/match.c
+
+parse.o: ../common/parse.c setup.h config.h
+ $(CC) $(S_CFLAGS) -c -o $@ ../common/parse.c
+
+support.o: ../common/support.c setup.h config.h ../common/patchlevel.h
+ $(CC) $(S_CFLAGS) -c -o $@ ../common/support.c
+
+channel.o: ../ircd/channel.c setup.h config.h
+ $(CC) $(S_CFLAGS) -c -o $@ ../ircd/channel.c
+
+class.o: ../ircd/class.c setup.h config.h
+ $(CC) $(S_CFLAGS) -c -o $@ ../ircd/class.c
+
+hash.o: ../common/struct_def.h ../common/os.h ../ircd/hash_def.h \
+ ../ircd/hash_ext.h ../common/common_def.h ../ircd/s_bsd.c \
+ ../ircd/s_serv.c ../ircd/s_user.c ../ircd/channel.c ../ircd/s_misc.c \
+ ../ircd/hash.c ../ircd/ircd.c Makefile setup.h config.h
+ @cp ../ircd/hash.c .
+ @/bin/sh ./sums
+ $(CC) $(S_CFLAGS) -c -o $@ hash.c
+ @$(RM) hash.c hash.c.old
+ @touch hash.o
+
+ircd.o: ../ircd/ircd.c setup.h config.h
+ $(CC) $(S_CFLAGS) -DIRCDCONF_PATH="\"$(IRCDCONF_PATH)\"" \
+ -DIRCDTUNE_PATH="\"$(IRCDTUNE_PATH)\"" \
+ -DIRCDMOTD_PATH="\"$(IRCDMOTD_PATH)\"" \
+ -DIRCD_PATH="\"$(IRCD_PATH)\"" -DIAUTH_PATH="\"$(IAUTH_PATH)\"" \
+ -DIAUTH="\"$(IAUTH)\"" -DIRCDDBG_PATH="\"$(IRCDDBG_PATH)\"" \
+ -c -o $@ ../ircd/ircd.c
+
+list.o: ../ircd/list.c setup.h config.h
+ $(CC) $(S_CFLAGS) -c -o $@ ../ircd/list.c
+
+res.o: ../ircd/res.c setup.h config.h
+ $(CC) $(S_CFLAGS) -c -o $@ ../ircd/res.c
+
+s_auth.o: ../ircd/s_auth.c setup.h config.h
+ $(CC) $(S_CFLAGS) -c -o $@ ../ircd/s_auth.c
+
+s_bsd.o: ../ircd/s_bsd.c setup.h config.h
+ $(CC) $(S_CFLAGS) -DIRCDPID_PATH="\"$(IRCDPID_PATH)\"" -DIAUTH_PATH="\"$(IAUTH_PATH)\"" -DIAUTH="\"$(IAUTH)\"" -c -o $@ ../ircd/s_bsd.c
+
+s_conf.o: ../ircd/s_conf.c setup.h config.h
+ $(CC) $(S_CFLAGS) -DIRCDMOTD_PATH="\"$(IRCDMOTD_PATH)\"" -DIRCDM4_PATH="\"$(IRCDM4_PATH)\"" -c -o $@ ../ircd/s_conf.c
+
+s_debug.o: ../ircd/s_debug.c setup.h config.h
+ $(CC) $(S_CFLAGS) -c -o $@ ../ircd/s_debug.c
+
+s_err.o: ../ircd/s_err.c setup.h config.h
+ $(CC) $(S_CFLAGS) -c -o $@ ../ircd/s_err.c
+
+s_id.o: ../ircd/s_id.c setup.h config.h
+ $(CC) $(S_CFLAGS) -c -o $@ ../ircd/s_id.c
+
+s_misc.o: ../ircd/s_misc.c setup.h config.h
+ $(CC) $(S_CFLAGS) -DFNAME_USERLOG="\"$(FNAME_USERLOG)\"" -DFNAME_CONNLOG="\"$(FNAME_CONNLOG)\"" -c -o $@ ../ircd/s_misc.c
+
+s_numeric.o: ../ircd/s_numeric.c setup.h config.h
+ $(CC) $(S_CFLAGS) -c -o $@ ../ircd/s_numeric.c
+
+s_serv.o: ../ircd/s_serv.c setup.h config.h
+ $(CC) $(S_CFLAGS) -DIRCDMOTD_PATH="\"$(IRCDMOTD_PATH)\"" -c -o $@ ../ircd/s_serv.c
+
+s_service.o: ../ircd/s_service.c setup.h config.h
+ $(CC) $(S_CFLAGS) -c -o $@ ../ircd/s_service.c
+
+s_user.o: ../ircd/s_user.c setup.h config.h
+ $(CC) $(S_CFLAGS) -DFNAME_USERLOG="\"$(FNAME_USERLOG)\"" -DFNAME_CONNLOG="\"$(FNAME_CONNLOG)\"" -DFNAME_OPERLOG="\"$(FNAME_OPERLOG)\"" -c -o $@ ../ircd/s_user.c
+
+s_zip.o: ../ircd/s_zip.c setup.h config.h
+ $(CC) $(S_CFLAGS) -c -o $@ ../ircd/s_zip.c
+
+whowas.o: ../ircd/whowas.c setup.h config.h
+ $(CC) $(S_CFLAGS) -c -o $@ ../ircd/whowas.c
+
+res_init.o: ../ircd/res_init.c setup.h config.h
+ $(CC) $(S_CFLAGS) -c -o $@ ../ircd/res_init.c
+
+res_comp.o: ../ircd/res_comp.c setup.h config.h
+ $(CC) $(S_CFLAGS) -c -o $@ ../ircd/res_comp.c
+
+res_mkquery.o: ../ircd/res_mkquery.c setup.h config.h
+ $(CC) $(S_CFLAGS) -c -o $@ ../ircd/res_mkquery.c
+
+iauth.o: ../iauth/iauth.c config.h setup.h
+ $(CC) $(A_CFLAGS) -c -o $@ ../iauth/iauth.c
+
+a_conf.o: ../iauth/a_conf.c config.h setup.h
+ $(CC) $(A_CFLAGS) -DIAUTHCONF_PATH="\"$(IAUTHCONF_PATH)\"" -c -o $@ ../iauth/a_conf.c
+
+a_dyn.o: ../iauth/a_dyn.c config.h setup.h
+ $(CC) $(A_CFLAGS) -c -o $@ ../iauth/a_dyn.c
+
+a_io.o: ../iauth/a_io.c config.h setup.h
+ $(CC) $(A_CFLAGS) -c -o $@ ../iauth/a_io.c
+
+a_log.o: ../iauth/a_log.c config.h setup.h
+ $(CC) $(A_CFLAGS) -DIAUTHDBG_PATH="\"$(IAUTHDBG_PATH)\"" -DFNAME_AUTHLOG="\"$(FNAME_AUTHLOG)\"" -c -o $@ ../iauth/a_log.c
+
+mod_lhex.o: ../iauth/mod_lhex.c config.h setup.h
+ $(CC) $(A_CFLAGS) -c -o $@ ../iauth/mod_lhex.c
+
+mod_pipe.o: ../iauth/mod_pipe.c config.h setup.h
+ $(CC) $(A_CFLAGS) -c -o $@ ../iauth/mod_pipe.c
+
+mod_rfc931.o: ../iauth/mod_rfc931.c config.h setup.h
+ $(CC) $(A_CFLAGS) -c -o $@ ../iauth/mod_rfc931.c
+
+mod_socks.o: ../iauth/mod_socks.c config.h setup.h
+ $(CC) $(A_CFLAGS) -c -o $@ ../iauth/mod_socks.c
+
+chkconf.o: ../ircd/chkconf.c setup.h config.h
+ $(CC) $(CC_CFLAGS) -DCHKCONF_COMPILE -DIRCDCONF_PATH="\"$(IRCDCONF_PATH)\"" -DIRCDM4_PATH="\"$(IRCDM4_PATH)\"" -c -o $@ ../ircd/chkconf.c
+
+# stuff in contrib/
+
+ircdwatch.o: ../contrib/ircdwatch/ircdwatch.c
+ $(CC) $(O_CFLAGS) -DIRCDWATCH_PID_FILENAME="\"$(IRCDWATCHPID_PATH)\"" -DIRCD_PATH="\"$(IRCD_PATH)\"" -DIRCDCONF_PATH="\"$(IRCDCONF_PATH)\"" -DIRCDPID_PATH="\"$(IRCDPID_PATH)\"" -c -o $@ ../contrib/ircdwatch/ircdwatch.c
+
+mkpasswd.o: ../contrib/mkpasswd/mkpasswd.c
+ $(CC) $(O_CFLAGS) -c -o $@ ../contrib/mkpasswd/mkpasswd.c
+
+tkserv.o: ../contrib/tkserv/tkserv.c tkconf.h
+ $(CC) $(O_CFLAGS) -DTKSERV_LOGFILE="\"$(TKSERV_LOGFILE)\"" -DTKSERV_ACCESSFILE="\"$(TKSERV_ACCESSFILE)\"" -DTKSERV_IRCD_CONF="\"$(TKSERV_IRCD_CONF)\"" -DCPATH="\"$(IRCDCONF_PATH)\"" -DPPATH="\"$(IRCDPID_PATH)\"" -c -o $@ ../contrib/tkserv/tkserv.c
+
+clean:
+ $(RM) $(CLIENT) $(SERVER) $(IAUTH) $(CHKCONF) ircd-mkpasswd $(IRCDWATCH) $(TKSERV) *.CKP *.ln *.BAK *.bak *.o core errs ,* *~ *.a .emacs_* tags TAGS make.log MakeOut "#"* version.c
+
+distclean:
+ @echo "To make distclean, just delete the current directory."
+
+rcs:
+ (cd ..; cii -H -R configure common doc include irc ircd support)
diff --git a/support/acconfig.h b/support/acconfig.h
new file mode 100644
index 0000000..6372a57
--- /dev/null
+++ b/support/acconfig.h
@@ -0,0 +1,101 @@
+/* $Id: acconfig.h,v 1.9 1999/03/10 00:30:17 kalt Exp $ */
+
+/* Define if zlib package must be used for compilation/linking. */
+#undef USE_ZLIB
+
+/* Define if ncurses library must be used for compilation/linking. */
+#undef USE_NCURSES
+
+/* Define if cursesX library must be used for compilation/linking. */
+#undef USE_CURSESX
+
+/* Define if curses library must be used for compilation/linking. */
+#undef USE_CURSES
+
+/* Define if termcap library must be used for compilation/linking. */
+#undef USE_TERMCAP
+
+/* Define if the second argument of waitpid must be an "union wait *" instead
+ of an "int *". */
+#undef USE_UNION_WAIT
+
+/* Define if int8_t, u_int8_t, int16_t, u_int16_t, int32_t, u_int32_t, u_char,
+ * u_short, u_int, u_long are not known types. */
+#undef int8_t
+#undef u_int8_t
+#undef int16_t
+#undef u_int16_t
+#undef int32_t
+#undef u_int32_t
+#undef u_char
+#undef u_short
+#undef u_int
+#undef u_long
+
+/* Define if memcmp is not 8-bit clean. */
+#undef MEMCMP_BROKEN
+
+/* Define if the operating system is AIX 3.2. */
+#undef AIX_3_2
+
+/* Define if the operating system is Solaris 2.x (SunOS 5.x). */
+#undef SOLARIS_2
+
+/* Define if the operating system is Solaris 2.3 (SunOS 5.3). */
+#undef SOLARIS_2_3
+
+/* Define if the operating system is Solaris 2.[0-2] (SunOS 5.[0-2]). */
+#undef SOLARIS_2_0_2_1_2_2
+
+/* Define if <netdb.h> contains bad __const usages (Linux). */
+#undef BAD___CONST_NETDB_H
+
+/* Define if sys_errlist is declared in stdio.h or errno.h. */
+#undef SYS_ERRLIST_DECLARED
+
+/* Define if sys_nerr is declared in stdio.h or errno.h. */
+#undef SYS_NERR_DECLARED
+
+/* Define if errno is declared in errno.h. */
+#undef ERRNO_DECLARED
+
+/* Define if h_errno is declared in errno.h or netdb.h. */
+#undef H_ERRNO_DECLARED
+
+/* Define if poll(2) must be used instead of select(2). */
+/* Note: some systems (e.g. linux 2.0.x) have a non-working poll() */
+#undef USE_POLL
+
+/* Define if the system provides POSIX sigaction. */
+#undef POSIX_SIGNALS
+
+/* Define if the system provides reliable BSD signals through sigset instead
+ of signal. */
+/* #define signal sigset */
+
+/* Define if the system provides reliable BSD signals. */
+#undef BSD_RELIABLE_SIGNALS
+
+/* Define if the system provides unreliable SystemV signals. */
+#undef SYSV_UNRELIABLE_SIGNALS
+
+/* Define if the system provides POSIX non-blocking system. */
+#undef NBLOCK_POSIX
+
+/* Define if the system provides BSD non-blocking system. */
+#undef NBLOCK_BSD
+
+/* Define if the system provides SystemV non-blocking system. */
+#undef NBLOCK_SYSV
+
+/* Define is the system can use variable arguments. */
+#undef USE_STDARG
+
+/* Define as the resolver configuration file. */
+#undef IRC_RESCONF
+
+/* Define to enable IPv6 support */
+#undef INET6
+
+/* Define to enable dynamically shared iauth module support */
+#undef USE_DSM
diff --git a/support/config.guess b/support/config.guess
new file mode 100755
index 0000000..b8bc3ba
--- /dev/null
+++ b/support/config.guess
@@ -0,0 +1,954 @@
+#! /bin/sh
+#
+# $Id: config.guess,v 1.4 1999/01/18 00:24:17 kalt Exp $
+#
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
+#
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Written by Per Bothner <bothner@cygnus.com>.
+# The master version of this file is at the FSF in /home/gd/gnu/lib.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit system type (host/target name).
+#
+# Only a few systems have been added to this list; please add others
+# (but try to keep the structure clean).
+#
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 8/24/94.)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+trap 'rm -f dummy.c dummy.o dummy; exit 1' 1 2 15
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ alpha:OSF1:*:*)
+ if test $UNAME_RELEASE = "V4.0"; then
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ fi
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ cat <<EOF >dummy.s
+ .globl main
+ .ent main
+main:
+ .frame \$30,0,\$26,0
+ .prologue 0
+ .long 0x47e03d80 # implver $0
+ lda \$2,259
+ .long 0x47e20c21 # amask $2,$1
+ srl \$1,8,\$2
+ sll \$2,2,\$2
+ sll \$0,3,\$0
+ addl \$1,\$0,\$0
+ addl \$2,\$0,\$0
+ ret \$31,(\$26),1
+ .end main
+EOF
+ ${CC-cc} dummy.s -o dummy 2>/dev/null
+ if test "$?" = 0 ; then
+ ./dummy
+ case "$?" in
+ 7)
+ UNAME_MACHINE="alpha"
+ ;;
+ 15)
+ UNAME_MACHINE="alphaev5"
+ ;;
+ 14)
+ UNAME_MACHINE="alphaev56"
+ ;;
+ 10)
+ UNAME_MACHINE="alphapca56"
+ ;;
+ 16)
+ UNAME_MACHINE="alphaev6"
+ ;;
+ esac
+ fi
+ rm -f dummy.s dummy
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr [[A-Z]] [[a-z]]`
+ exit 0 ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit 0 ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-cbm-sysv4
+ exit 0;;
+ amiga:NetBSD:*:*)
+ echo m68k-cbm-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ amiga:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit 0 ;;
+ arc64:OpenBSD:*:*)
+ echo mips64el-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ arc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ hkmips:OpenBSD:*:*)
+ echo mips-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ pmax:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sgi:OpenBSD:*:*)
+ echo mips-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ wgrisc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit 0;;
+ arm32:NetBSD:*:*)
+ echo arm-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ exit 0 ;;
+ SR2?01:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit 0;;
+ Pyramid*:OSx*:*:*|MIS*:OSx*:*:*|MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit 0 ;;
+ NILE:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit 0 ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ i86pc:SunOS:5.*:*)
+ echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit 0 ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit 0 ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ atari*:NetBSD:*:*)
+ echo m68k-atari-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ atari*:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sun3*:NetBSD:*:*)
+ echo m68k-sun-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sun3*:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mac68k:NetBSD:*:*)
+ echo m68k-apple-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mac68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme88k:OpenBSD:*:*)
+ echo m88k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit 0 ;;
+ macppc:NetBSD:*:*)
+ echo powerpc-apple-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit 0 ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ 2020:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit 0 ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ sed 's/^ //' << EOF >dummy.c
+ int main (argc, argv) int argc; char **argv; {
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ ${CC-cc} dummy.c -o dummy \
+ && ./dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+ && rm dummy.c dummy && exit 0
+ rm -f dummy.c dummy
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit 0 ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit 0 ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit 0 ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit 0 ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88110 ] ; then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \
+ -o ${TARGET_BINARY_INTERFACE}x = x ] ; then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit 0 ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit 0 ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit 0 ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit 0 ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i?86:AIX:*:*)
+ echo i386-ibm-aix
+ exit 0 ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ sed 's/^ //' << EOF >dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
+ rm -f dummy.c dummy
+ echo rs6000-ibm-aix3.2.5
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit 0 ;;
+ *:AIX:*:4)
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -EHl ${IBM_CPU_ID} | grep POWER >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=4.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit 0 ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit 0 ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit 0 ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC NetBSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit 0 ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit 0 ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit 0 ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit 0 ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit 0 ;;
+ 9000/[34678]??:HP-UX:*:*)
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/6?? | 9000/7?? | 9000/80[24] | 9000/8?[13679] | 9000/892 )
+ sed 's/^ //' << EOF >dummy.c
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (${CC-cc} dummy.c -o dummy 2>/dev/null ) && HP_ARCH=`./dummy`
+ rm -f dummy.c dummy
+ esac
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit 0 ;;
+ 3050*:HI-UX:*:*)
+ sed 's/^ //' << EOF >dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
+ rm -f dummy.c dummy
+ echo unknown-hitachi-hiuxwe2
+ exit 0 ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit 0 ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit 0 ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit 0 ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit 0 ;;
+ i?86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit 0 ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit 0 ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ CRAY*X-MP:*:*:*)
+ echo xmp-cray-unicos
+ exit 0 ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE}
+ exit 0 ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
+ exit 0 ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE}
+ exit 0 ;;
+ CRAY-2:*:*:*)
+ echo cray2-cray-unicos
+ exit 0 ;;
+ F300:UNIX_System_V:*:*)
+ FUJITSU_SYS=`uname -p | tr [A-Z] [a-z] | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit 0 ;;
+ F301:UNIX_System_V:*:*)
+ echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'`
+ exit 0 ;;
+ hp3[0-9][05]:NetBSD:*:*)
+ echo m68k-hp-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ hp300:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ i?86:BSD/386:*:* | *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:FreeBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit 0 ;;
+ *:NetBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ exit 0 ;;
+ *:OpenBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ exit 0 ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit 0 ;;
+ i*:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit 0 ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit 0 ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ *:GNU:*:*)
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit 0 ;;
+ *:Linux:*:*)
+ # uname on the ARM produces all sorts of strangeness, and we need to
+ # filter it out.
+ case "$UNAME_MACHINE" in
+ arm* | sa110*) UNAME_MACHINE="arm" ;;
+ esac
+
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us.
+ ld_help_string=`ld --help 2>&1`
+ ld_supported_emulations=`echo $ld_help_string \
+ | sed -ne '/supported emulations:/!d
+ s/[ ][ ]*/ /g
+ s/.*supported emulations: *//
+ s/ .*//
+ p'`
+ case "$ld_supported_emulations" in
+ i?86linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" ; exit 0 ;;
+ i?86coff) echo "${UNAME_MACHINE}-pc-linux-gnucoff" ; exit 0 ;;
+ sparclinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
+ armlinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
+ m68klinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
+ elf32ppc) echo "powerpc-unknown-linux-gnu" ; exit 0 ;;
+ esac
+
+ if test "${UNAME_MACHINE}" = "alpha" ; then
+ sed 's/^ //' <<EOF >dummy.s
+ .globl main
+ .ent main
+ main:
+ .frame \$30,0,\$26,0
+ .prologue 0
+ .long 0x47e03d80 # implver $0
+ lda \$2,259
+ .long 0x47e20c21 # amask $2,$1
+ srl \$1,8,\$2
+ sll \$2,2,\$2
+ sll \$0,3,\$0
+ addl \$1,\$0,\$0
+ addl \$2,\$0,\$0
+ ret \$31,(\$26),1
+ .end main
+EOF
+ LIBC=""
+ ${CC-cc} dummy.s -o dummy 2>/dev/null
+ if test "$?" = 0 ; then
+ ./dummy
+ case "$?" in
+ 7)
+ UNAME_MACHINE="alpha"
+ ;;
+ 15)
+ UNAME_MACHINE="alphaev5"
+ ;;
+ 14)
+ UNAME_MACHINE="alphaev56"
+ ;;
+ 10)
+ UNAME_MACHINE="alphapca56"
+ ;;
+ 16)
+ UNAME_MACHINE="alphaev6"
+ ;;
+ esac
+
+ objdump --private-headers dummy | \
+ grep ld.so.1 > /dev/null
+ if test "$?" = 0 ; then
+ LIBC="libc1"
+ fi
+ fi
+ rm -f dummy.s dummy
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0
+ elif test "${UNAME_MACHINE}" = "mips" ; then
+ cat >dummy.c <<EOF
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+#ifdef __MIPSEB__
+ printf ("%s-unknown-linux-gnu\n", argv[1]);
+#endif
+#ifdef __MIPSEL__
+ printf ("%sel-unknown-linux-gnu\n", argv[1]);
+#endif
+ return 0;
+}
+EOF
+ ${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0
+ rm -f dummy.c dummy
+ else
+ # Either a pre-BFD a.out linker (linux-gnuoldld)
+ # or one that does not give us useful --help.
+ # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout.
+ # If ld does not provide *any* "supported emulations:"
+ # that means it is gnuoldld.
+ echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:"
+ test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0
+
+ case "${UNAME_MACHINE}" in
+ i?86)
+ VENDOR=pc;
+ ;;
+ *)
+ VENDOR=unknown;
+ ;;
+ esac
+ # Determine whether the default compiler is a.out or elf
+ cat >dummy.c <<EOF
+#include <features.h>
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+#ifdef __ELF__
+# ifdef __GLIBC__
+# if __GLIBC__ >= 2
+ printf ("%s-${VENDOR}-linux-gnu\n", argv[1]);
+# else
+ printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
+# endif
+# else
+ printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
+# endif
+#else
+ printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]);
+#endif
+ return 0;
+}
+EOF
+ ${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0
+ rm -f dummy.c dummy
+ fi ;;
+# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions
+# are messed up and put the nodename in both sysname and nodename.
+ i?86:DYNIX/ptx:4*:*)
+ echo i386-sequent-sysv4
+ exit 0 ;;
+ i?86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit 0 ;;
+ i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*)
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ i?86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit 0 ;;
+ i?86:UnixWare:*:*)
+ if /bin/uname -X 2>/dev/null >/dev/null ; then
+ (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ fi
+ echo ${UNAME_MACHINE}-unixware-${UNAME_RELEASE}-${UNAME_VERSION}
+ exit 0 ;;
+ pc:*:*:*)
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i386.
+ echo i386-pc-msdosdjgpp
+ exit 0 ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit 0 ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit 0 ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit 0 ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit 0 ;;
+ M68*:*:R3V[567]*:*)
+ test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+ 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4 && exit 0 ;;
+ m68*:LynxOS:2.*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit 0 ;;
+ i?86:LynxOS:2.*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit 0 ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit 0 ;;
+ PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit 0 ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit 0 ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit 0 ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit 0 ;;
+ news*:NEWS-OS:*:6*)
+ echo mips-sony-newsos6
+ exit 0 ;;
+ R3000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R4000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit 0 ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit 0 ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+cat >dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+#if !defined (ultrix)
+ printf ("vax-dec-bsd\n"); exit (0);
+#else
+ printf ("vax-dec-ultrix\n"); exit (0);
+#endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy && exit 0
+rm -f dummy.c dummy
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ c34*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ c38*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ c4*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ esac
+fi
+
+#echo '(Unable to guess system type)' 1>&2
+
+exit 1
diff --git a/support/config.h.dist b/support/config.h.dist
new file mode 100644
index 0000000..4d742c3
--- /dev/null
+++ b/support/config.h.dist
@@ -0,0 +1,555 @@
+/************************************************************************
+ * IRC - Internet Relay Chat, support/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.
+ */
+
+/*
+ * ircdwatch configuration options.
+ */
+
+/* how often (in seconds) should we check that ircd runs? */
+#define IRCDWATCH_POLLING_INTERVAL 30
+
+/*
+ * should we check for config file changes and HUP the server
+ * if a change is detected?
+ */
+#undef IRCDWATCH_HUP_ON_CONFIG_CHANGE
+
+/*
+ * although you may not want to log ircd-messages to syslog you
+ * may want to log when ircdwatch reloads the config or when
+ * ircd croaks and ircdwatch has to restart it
+ */
+#define IRCDWATCH_USE_SYSLOG
+#ifdef IRCDWATCH_USE_SYSLOG
+# define IRCDWATCH_SYSLOG_IDENT "ircdwatch"
+# define IRCDWATCH_SYSLOG_OPTIONS (LOG_PID)
+# define IRCDWATCH_SYSLOG_FACILITY LOG_DAEMON
+#endif
+
+
+/*
+ * irc[d] configuration options.
+ *
+ * Most of the following defines are related to the server,
+ * some apply to the client.
+ *
+ */
+
+/*
+ * If you don't want the server to keep reading the MOTD file from the disk,
+ * define CACHED_MOTD. The server will store the MOTD in memory, and only
+ * read it again from the disk when rehashing if the file has changed.
+ */
+#define CACHED_MOTD
+
+/* CHROOTDIR
+ *
+ * Define for value added security if you are a rooter.
+ *
+ * CPATH, MPATH, LPATH, PPATH, TPATH, QPATH, OPATH,
+ * FNAME_USERLOG, FNAME_OPERLOG, FNAME_CONNLOG, FNAME_AUTHLOG
+ * must have RPATH as root directory! Set them in Makefile
+ *
+ * You may want to define IRC_UID and IRC_GID
+ */
+#undef CHROOTDIR
+
+#if defined(CHROOTDIR)
+ #define ROOT_PATH "/where/to/change/root/dir"
+#endif
+
+/* ENABLE_SUMMON
+ *
+ * The SUMMON command requires the ircd to be run as group tty in order
+ * to work properly in many cases. If you are on a machine where it
+ * won't work, or simply don't want local users to be summoned, undefine
+ * this.
+ */
+#undef ENABLE_SUMMON /* local summon */
+#undef ENABLE_USERS /* enables local /users (same as who/finger output) */
+
+/* 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.
+ */
+#define SHOW_INVISIBLE_LUSERS
+
+/* NO_DEFAULT_INVISIBLE
+ *
+ * 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.
+ */
+#undef NO_DEFAULT_INVISIBLE
+
+/* OPER_KILL
+ *
+ * If you dont believe operators should be allowed to use the /KILL command
+ * or believe it is uncessary for them to use it, then leave OPER_KILL
+ * undefined. This will not affect other operators or servers issuing KILL
+ * commands however. OPER_REHASH and OPER_RESTART allow operators to
+ * issue the REHASH and RESTART commands when connected to your server.
+ * Left undefined they increase the security of your server from wayward
+ * operators and accidents. Defining OPER_REMOTE removes the restriction
+ * that O-lines only become fully effective for people on the 'same network'
+ * as the server. Undefined, it increases the security of the server by
+ * placing restrictions on where people can use operator powers from.
+ * The 'LOCOP_' #defines are for making the respective commands available
+ * to 'local' operators. Note that the 'OPER_' #defines affect both global
+ * (big O) and local (little o) operators. Defining 'LOCOP_x' has no effect
+ * if 'OPER_x' is undefined so you can't give local operators more rights
+ * than global ones.
+ */
+#undef OPER_KILL
+#define OPER_REHASH
+#undef OPER_RESTART
+#define OPER_DIE
+#undef OPER_REMOTE
+#undef LOCOP_REHASH
+#undef LOCOP_RESTART
+#undef LOCOP_DIE
+
+/*
+ * 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 50 or so
+ * connections.
+ * 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* 4: 2 listen ports (1 tcp, 1 udp)
+ * 1 dns port, 1 client
+ */
+#define MAXCONNECTIONS 50
+
+/* 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
+
+/*
+ * A pure non-routing leaf server can undefine HUB for best performance.
+ * 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 HUB */
+
+#ifdef HUB
+/*
+ * MAXSERVERS is the maximum number of servers that will be linked
+ * to your server at the same time. This number is not a limit,
+ * it is used to allocate memory when ircd is started.
+ */
+# define MAXSERVERS 3
+#else
+# define MAXSERVERS 1
+#endif
+
+/* R_LINES: The conf file now allows the existence of R lines, or
+ * restrict lines. These allow more freedom in the ability to restrict
+ * who is to sign on and when. What the R line does is call an outside
+ * program which returns a reply indicating whether to let the person on.
+ * Because there is another program involved, Delays and overhead could
+ * result. It is for this reason that there is a line in config.h to
+ * decide whether it is something you want or need. -Hoppie
+ *
+ * The default is no R_LINES as most people probably don't need it. --Jto
+ */
+#undef R_LINES
+
+#ifdef R_LINES
+/* Also, even if you have R lines defined, you might not want them to be
+ checked everywhere, since it could cost lots of time and delay. Therefore,
+ The following two options are also offered: R_LINES_REHASH rechecks for
+ R lines after a rehash, and R_LINES_OFTEN, which rechecks it as often
+ as it does K lines. Note that R_LINES_OFTEN is *very* likely to cause
+ a resource drain, use at your own risk. R_LINES_REHASH shouldn't be too
+ bad, assuming the programs are fairly short. */
+#define R_LINES_REHASH
+#define R_LINES_OFTEN
+#endif
+
+/*
+ * 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 */
+#undef SYSLOG_CONN /* log all uncomplete/rejected connections */
+
+/*
+ * If you want to log to a different facility than DAEMON, change
+ * this define.
+ */
+#define LOG_FACILITY LOG_DAEMON
+#endif /* USE_SYSLOG */
+
+/*
+ * define this if you want to use crypted passwords for operators in your
+ * ircd.conf file. See contrib/mkpasswd/README for more details on this.
+ */
+#undef CRYPT_OPER_PASSWORD
+
+/*
+ * If you want to store encrypted passwords in N-lines for server links,
+ * define this. For a C/N pair in your ircd.conf file, the password
+ * need not be the same for both, as long as hte opposite end has the
+ * right password in the opposite line. See INSTALL doc for more details.
+ */
+#undef CRYPT_LINK_PASSWORD
+
+/*
+ * define this if you enable summon and if you want summon to look for the
+ * least idle tty a user is logged in on.
+ */
+#undef LEAST_IDLE
+
+/*
+ * 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
+
+/*
+ * use these to setup a Unix domain socket to connect clients/servers to.
+ */
+#undef UNIXPORT
+
+/*
+ * 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
+
+#ifdef notdef
+#define IRC_UID 65534 /* eg for what to do to enable this feature */
+#define IRC_GID 65534
+#endif
+
+/*
+ * 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 1000
+
+/* Remote query flood protection. */
+#define CHREPLLEN 8192
+
+/* Default server for standard client */
+#define UPHOST "irc"
+
+/*
+ * If you wish to run services, define USE_SERVICES.
+ * This can make the server noticeably bigger and slower.
+ * services are not fully implemented yet, so don't use it unless you really
+ * know what you are doing.
+ */
+#undef USE_SERVICES
+
+/*
+ * Define the following to make the delay for nicks random.
+ * Some people believe a bot can exactly time the delay and don't like it,
+ * I think this is a useless concern. -krys
+ */
+#undef RANDOM_NDELAY
+
+/*
+ * You've read the BOFH saga and you liked it, then define the following.
+ *
+ * The two following will change the nick delay and channel delay features
+ * making them totally user unfriendly but more efficient.
+ */
+#undef BETTER_NDELAY
+#undef BETTER_CDELAY
+
+/*
+ * Defining this will enable the use of compressed server-server links.
+ * In order to have it work, you must have the zlib version 1.0 or higher.
+ * The library and the include files must have been found by configure,
+ * if you have installed the zlib after running configure, run it again.
+ */
+#undef ZIP_LINKS
+
+/*
+ * Defining this will add an artificial 2 seconds delay for accepting
+ * connections. This is the OLD behaviour of the server.
+ *
+ * NOTE: Undefining this leads to a significant increase in CPU usage if
+ * you reject client which keeps connecting.
+ */
+#define SLOW_ACCEPT
+
+/*
+ * Defining this will make the server check for rapid connections from a single
+ * host and reject new connections from this host if the limit is reached.
+ *
+ * NOTE: Enabling this feature will significantly increase the CPU usage
+ * for servers carrying several hundred clients and getting many connections.
+ *
+ * IMPORTANT: This **MUST** defined if SLOW_ACCEPT is NOT defined
+ */
+#undef CLONE_CHECK
+
+/* STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP */
+/* STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP */
+/* 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. */
+
+#ifdef OPER_KILL
+/* LOCAL_KILL_ONLY
+ *
+ * To be used, OPER_KILL must be defined.
+ * LOCAL_KILL_ONLY restricts KILLs to clients which are connected to the
+ * server the Operator is connected to (ie lets them deal with local
+ * problem users or 'ghost' clients
+ */
+#define LOCAL_KILL_ONLY
+#endif
+
+/* Default server port, used by client. */
+#define PORTNUM 6667
+
+/* Maximum length the queue of pending connections to one port may grow to. */
+#define LISTENQUEUE 128
+
+/* define DEBUGMODE to enable debugging mode.*/
+#undef DEBUGMODE
+
+/*
+ * 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 30 /* Recommended value: 30 seconds */
+#define HANGONGOODLINK 900 /* Recommended value: 15 minutes */
+
+/*
+ * Number of seconds to wait for write to complete if stuck.
+ */
+#define WRITEWAITDELAY 15 /* Recommended value: 15 */
+
+/*
+ * Number of seconds to wait for DNS/authentication to complete.
+ * Note that iauth's default timeout per module is 30 seconds, so this value
+ * should be at least 30 * number of modules. Extra time should really be
+ * given to be safe.
+ */
+#define ACCEPTTIMEOUT 90 /* Recommended value: 90 */
+
+/*
+ * Max time from the nickname change that still causes KILL
+ * automaticly to switch for the current nick of that user. (seconds)
+ */
+#define KILLCHASETIMELIMIT 90 /* Recommended value: 90 */
+
+/*
+ * Max time for the channel history and nick delay to be effective.
+ * It should be the same value on all servers of a same net, and
+ * be greater than the split durations usually seen.
+ * DELAYCHASETIMELIMIT is the default.
+ */
+#define DELAYCHASETIMELIMIT 1800 /* Recommended value: 1800 */
+
+/*
+ * Max time for !channel history, this *MUST* be fairly long (usually
+ * much longer than the value above) to ensure shortname unicity.
+ * It makes very little sense to use a short time limit here.
+ */
+#define LDELAYCHASETIMELIMIT 5400 /* Recommended value: 5400 */
+
+/*
+ * Max number of channels a user is allowed to join.
+ */
+#define MAXCHANNELSPERUSER 10 /* Recommended value: 10 */
+
+/*
+ * USE_IAUTH makes ircd use the iauth program for authentication.
+ * it can always be overriden by using the -s switch
+ */
+#define USE_IAUTH
+
+#ifdef ZIP_LINKS
+/*
+ * the compression level used. (Suggested values: 3, 4, 5)
+ * Above 5 will only give a *very* marginal increase in compression for a
+ * *very* large increase in CPU usage.
+ */
+# define ZIP_LEVEL 5
+#endif
+
+#ifdef CLONE_CHECK
+/*
+ * If CLONE_CHECK has been defined, these control how the checks are performed,
+ * and how the alarm is triggered.
+ */
+# define CLONE_MAX 2
+# define CLONE_PERIOD 10
+#endif
+
+/*
+ * define NO_IDENT if you don't want to support ident (RFC1413).
+ * it is a VERY bad idea to do so, since this will make it impossible to
+ * efficientely track abusers.
+ * NO_PREFIX should always be undefined.
+ */
+/* #undef NO_IDENT */
+/* #undef NO_PREFIX */
+
+/* ------------------------- END CONFIGURATION SECTION -------------------- */
+#ifndef ENABLE_SUMMON
+# undef LEAST_IDLE
+#endif
+
+#define SEQ_NOFILE 128 /* For Dynix (sequent OS) users :
+ * set to your current kernel impl,
+ * max number of socket connections;
+ * ignored on other OS.
+ */
+/*
+ * safety margin so we can always have one spare fd, for motd/authd or
+ * whatever else. -5 allows "safety" margin of 1 and space reserved.
+ */
+#define MAXCLIENTS (MAXCONNECTIONS-5)
+
+#if defined(CLIENT_FLOOD)
+# if (CLIENT_FLOOD > 8000) || (CLIENT_FLOOD < 512)
+error CLIENT_FLOOD needs redefining.
+# endif
+#else
+error CLIENT_FLOOD undefined
+#endif
+
+#if defined(ZIP_LINKS)
+# if (ZIP_MINIMUM > ZIP_MAXIMUM)
+error ZIP_MINIMUM needs redefining.
+# endif
+#endif
+
+#if !defined(SLOW_ACCEPT) && !defined(CLONE_CHECK)
+# define CLONE_CHECK
+# define CLONE_MAX 2
+# define CLONE_PERIOD 10
+#endif
+
+/*
+** you wouldn't want to compress messages one by one.. would you?
+** (it's not implemented anyways)
+*/
+#ifdef ZIP_LINKS
+# define SENDQ_ALWAYS
+#endif
+
+#if ! USE_POLL
+# if (MAXCONNECTIONS > FD_SETSIZE)
+error FD_SETSIZE must be bigger than MAXCONNECTIONS
+# endif
+#endif
diff --git a/support/config.sub b/support/config.sub
new file mode 100644
index 0000000..00bea6e
--- /dev/null
+++ b/support/config.sub
@@ -0,0 +1,955 @@
+#! /bin/sh
+# Configuration validation subroutine script, version 1.1.
+# Copyright (C) 1991, 92-97, 1998 Free Software Foundation, Inc.
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine. It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+if [ x$1 = x ]
+then
+ echo Configuration name missing. 1>&2
+ echo "Usage: $0 CPU-MFR-OPSYS" 1>&2
+ echo "or $0 ALIAS" 1>&2
+ echo where ALIAS is a recognized configuration type. 1>&2
+ exit 1
+fi
+
+# First pass through any local machine types.
+case $1 in
+ *local*)
+ echo $1
+ exit 0
+ ;;
+ *)
+ ;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ linux-gnu*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple)
+ os=
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco5)
+ os=sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ tahoe | i860 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \
+ | arme[lb] | pyramid | mn10200 | mn10300 | tron | a29k \
+ | 580 | i960 | h8300 | hppa | hppa1.0 | hppa1.1 | hppa2.0 \
+ | alpha | alphaev5 | alphaev56 | we32k | ns16k | clipper \
+ | i370 | sh | powerpc | powerpcle | 1750a | dsp16xx | pdp11 \
+ | mips64 | mipsel | mips64el | mips64orion | mips64orionel \
+ | mipstx39 | mipstx39el \
+ | sparc | sparclet | sparclite | sparc64 | v850)
+ basic_machine=$basic_machine-unknown
+ ;;
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i[34567]86)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ vax-* | tahoe-* | i[34567]86-* | i860-* | m32r-* | m68k-* | m68000-* \
+ | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \
+ | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
+ | power-* | none-* | 580-* | cray2-* | h8300-* | i960-* \
+ | xmp-* | ymp-* | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* \
+ | alpha-* | alphaev5-* | alphaev56-* | we32k-* | cydra-* \
+ | ns16k-* | pn-* | np1-* | xps100-* | clipper-* | orion-* \
+ | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \
+ | sparc64-* | mips64-* | mipsel-* \
+ | mips64el-* | mips64orion-* | mips64orionel-* \
+ | mipstx39-* | mipstx39el-* \
+ | f301-*)
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-cbm
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-cbm
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-cbm
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ cray2)
+ basic_machine=cray2-cray
+ os=-unicos
+ ;;
+ [ctj]90-cray)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k7[0-9][0-9] | hp7[0-9][0-9] | hp9k8[0-9]7 | hp8[0-9]7)
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i[34567]86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i[34567]86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i[34567]86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i[34567]86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ mipsel*-linux*)
+ basic_machine=mipsel-unknown
+ os=-linux-gnu
+ ;;
+ mips*-linux*)
+ basic_machine=mips-unknown
+ os=-linux-gnu
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pentium | p5 | k5 | nexen)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | k6 | 6x86)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | nexen-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | k6-* | 6x86-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=rs6000-ibm
+ ;;
+ ppc) basic_machine=powerpc-unknown
+ ;;
+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ xmp)
+ basic_machine=xmp-cray
+ os=-unicos
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ mips)
+ if [ x$os = x-linux-gnu ]; then
+ basic_machine=mips-unknown
+ else
+ basic_machine=mips-mips
+ fi
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sparc)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
+ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -uxpv* | -beos*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f301-fujitsu)
+ os=-uxpv
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -aix*)
+ vendor=ibm
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -vxsim* | -vxworks*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
diff --git a/support/configure b/support/configure
new file mode 100755
index 0000000..6af37fe
--- /dev/null
+++ b/support/configure
@@ -0,0 +1,4671 @@
+#! /bin/sh
+
+# From configure.in Id: configure.in,v 1.45 1999/07/17 21:12:43 kalt Exp
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+ --with-zlib checks for zlib; if found, enables compressed links"
+ac_help="$ac_help
+ --without-zlib does not check for zlib; disables compressed links"
+ac_help="$ac_help
+ --without-ncurses does not look for ncurses library, will not use it"
+ac_help="$ac_help
+ --without-cursesX does not look for cursesX library, will not use it"
+ac_help="$ac_help
+ --without-curses does not look for curses library, will not use it"
+ac_help="$ac_help
+ --without-termcap does not look for termcap library, will not use it"
+ac_help="$ac_help
+ --enable-ip6 enables IPv6"
+ac_help="$ac_help
+ --enable-dsm enables dynamically shared modules for iauth"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+zlib_include=NONE
+zlib_library=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+logdir='${prefix}/var/log/ircd'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ case "$ac_option" in
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir="$ac_optarg" ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg" ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he)
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --version print the version of autoconf that created configure
+Directory and file names:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [same as prefix]
+ --bindir=DIR user executables in DIR [EPREFIX/bin]
+ --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
+ --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data in DIR
+ [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data in DIR
+ [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data in DIR[PREFIX/var/run]
+ --includedir=DIR C header files in DIR [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
+ --logdir=DIR log files in DIR [PREFIX/var/log/ircd]
+ --infodir=DIR info documentation in DIR [PREFIX/info]
+ --mandir=DIR man documentation in DIR [PREFIX/man]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM
+ run sed PROGRAM on installed program names
+EOF
+ cat << EOF
+Host type:
+ --build=BUILD configure for building on BUILD [BUILD=HOST]
+ --host=HOST configure for HOST [guessed]
+ --target=TARGET configure for TARGET [TARGET=HOST]
+Features and packages:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --resconf=FILE use FILE as resolver config file [/etc/resolv.conf]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --zlib-prefix=ZDIR zlib installation prefix is ZDIR
+ --zlib-include=ZIDIR zlib include files are in ZIDIR [ZDIR/include]
+ --zlib-library=ZLDIR zlib library files are in ZLDIR [ZDIR/lib]
+EOF
+ if test -n "$ac_help"; then
+ echo "--enable and --with options recognized:$ac_help"
+ fi
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir="$ac_optarg" ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir="$ac_optarg" ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir="$ac_optarg" ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir="$ac_optarg" ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir="$ac_optarg" ;;
+
+ -logdir | --logdir | --logdi | --logd)
+ ac_prev=logdir ;;
+ -logdir=* | --logdir=* | --logdi=* | --logd=*)
+ logdir="$ac_optarg/" ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir="$ac_optarg" ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir="$ac_optarg" ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg" ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix="$ac_optarg" ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix="$ac_optarg" ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name="$ac_optarg" ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -resconf | --resconf | --rescon | --resco | --resc | --res \
+ | --re | --r)
+ ac_prev=irc_resconf ;;
+ -resconf=* | --resconf=* | --rescon=* | --resco=* | --resc=* \
+ | --res=* | --re=* | --r=*)
+ irc_resconf="$ac_optarg" ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir="$ac_optarg" ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir="$ac_optarg" ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir="$ac_optarg" ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version 2.13"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+ -zlib-prefix | --zlib-prefix | --zlib-prefi | --zlib-pref \
+ | --zlib-pre | --zlib-pr | --zlib-p)
+ ac_prev=irc_zlib_prefix ;;
+ -zlib-prefix=* | --zlib-prefix=* | --zlib-prefi=* | --zlib-pref=* \
+ | --zlib-pre=* | --zlib-pr=* | --zlib-p=*)
+ irc_zlib_prefix="$ac_optarg" ;;
+
+ -zlib-include | --zlib-include | --zlib-includ | --zlib-inclu \
+ | --zlib-incl | --zlib-inc | --zlib-in | --zlib-i)
+ ac_prev=irc_zlib_include ;;
+ -zlib-include=* | --zlib-include=* | --zlib-includ=* | --zlib-inclu=* \
+ | --zlib-incl=* | --zlib-inc=* | --zlib-in=* | --zlib-i=*)
+ irc_zlib_include="$ac_optarg" ;;
+
+ -zlib-library | --zlib-library | --zlib-librar | --zlib-libra | --zlib-libr \
+ | --zlib-lib | --zlib-li | --zlib-l)
+ ac_prev=irc_zlib_library ;;
+ -zlib-library=* | --zlib-library=* | --zlib-librar=* | --zlib-libra=* \
+ | --zlib-libr=* | --zlib-lib=* | --zlib-li=* | --zlib-l=*)
+ irc_zlib_library="$ac_optarg" ;;
+
+ -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+ ;;
+
+ *)
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+ echo "configure: warning: $ac_option: invalid host type" 1>&2
+ fi
+ if test "x$nonopt" != xNONE; then
+ { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+ exec 6>/dev/null
+else
+ exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+ case "$ac_arg" in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+ esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set. These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=../ircd/ircd.c
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+ else
+ { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+ fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ echo "loading site script $ac_site_file"
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ echo "loading cache $cache_file"
+ . $cache_file
+else
+ echo "creating cache $cache_file"
+ > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+ ac_n= ac_c='
+' ac_t=' '
+ else
+ ac_n=-n ac_c= ac_t=
+ fi
+else
+ ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+ac_aux_dir=
+for ac_dir in ../support $srcdir/../support; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { echo "configure: error: can not find install-sh or install.sh in ../support $srcdir/../support" 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+
+# Do some error checking and defaulting for the host and target type.
+# The inputs are:
+# configure --host=HOST --target=TARGET --build=BUILD NONOPT
+#
+# The rules are:
+# 1. You are not allowed to specify --host, --target, and nonopt at the
+# same time.
+# 2. Host defaults to nonopt.
+# 3. If nonopt is not specified, then host defaults to the current host,
+# as determined by config.guess.
+# 4. Target and build default to nonopt.
+# 5. If nonopt is not specified, then target and build default to host.
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+case $host---$target---$nonopt in
+NONE---*---* | *---NONE---* | *---*---NONE) ;;
+*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;;
+esac
+
+
+# Make sure we can run config.sub.
+if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then :
+else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking host system type""... $ac_c" 1>&6
+echo "configure:609: checking host system type" >&5
+
+host_alias=$host
+case "$host_alias" in
+NONE)
+ case $nonopt in
+ NONE)
+ if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then :
+ else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; }
+ fi ;;
+ *) host_alias=$nonopt ;;
+ esac ;;
+esac
+
+host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias`
+host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$host" 1>&6
+
+echo $ac_n "checking target system type""... $ac_c" 1>&6
+echo "configure:630: checking target system type" >&5
+
+target_alias=$target
+case "$target_alias" in
+NONE)
+ case $nonopt in
+ NONE) target_alias=$host_alias ;;
+ *) target_alias=$nonopt ;;
+ esac ;;
+esac
+
+target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias`
+target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$target" 1>&6
+
+echo $ac_n "checking build system type""... $ac_c" 1>&6
+echo "configure:648: checking build system type" >&5
+
+build_alias=$build
+case "$build_alias" in
+NONE)
+ case $nonopt in
+ NONE) build_alias=$host_alias ;;
+ *) build_alias=$nonopt ;;
+ esac ;;
+esac
+
+build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias`
+build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$build" 1>&6
+
+test "$host_alias" != "$target_alias" &&
+ test "$program_prefix$program_suffix$program_transform_name" = \
+ NONENONEs,x,x, &&
+ program_prefix=${target_alias}-
+
+
+
+ echo $ac_n "checking cached system tuple""... $ac_c" 1>&6
+echo "configure:673: checking cached system tuple" >&5
+ if { test x"${ac_cv_host_system_type+set}" = x"set" &&
+ test x"$ac_cv_host_system_type" != x"$host"; } ||
+ { test x"${ac_cv_build_system_type+set}" = x"set" &&
+ test x"$ac_cv_build_system_type" != x"$build"; } ||
+ { test x"${ac_cv_target_system_type+set}" = x"set" &&
+ test x"$ac_cv_target_system_type" != x"$target"; }; then
+ echo "$ac_t""different" 1>&6
+
+ else
+ echo "$ac_t""ok" 1>&6
+ fi
+ ac_cv_host_system_type="$host"
+ ac_cv_build_system_type="$build"
+ ac_cv_target_system_type="$target"
+
+
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:694: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="gcc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:724: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_prog_rejected=no
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# -gt 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ set dummy "$ac_dir/$ac_word" "$@"
+ shift
+ ac_cv_prog_CC="$@"
+ fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:772: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 783 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:788: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ ac_cv_prog_cc_works=yes
+ # If we can't run a trivial program, we are probably using a cross compiler.
+ if (./conftest; exit) 2>/dev/null; then
+ ac_cv_prog_cc_cross=no
+ else
+ ac_cv_prog_cc_cross=yes
+ fi
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+ { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:814: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:819: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:828: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gcc=yes
+else
+ ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+ac_test_CFLAGS="${CFLAGS+set}"
+if test $ac_cv_prog_gcc = yes; then
+ GCC=yes
+ ac_save_CFLAGS="$CFLAGS"
+ CFLAGS=
+ echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:842: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_g=yes
+else
+ ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+ if test "$ac_test_CFLAGS" = set; then
+ CFLAGS="$ac_save_CFLAGS"
+ else
+ CFLAGS="-O2"
+ fi
+else
+ GCC=
+fi
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:867: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and "${CC-cc}" will confuse make.
+ CPP="${CC-cc} -E"
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp.
+ cat > conftest.$ac_ext <<EOF
+#line 882 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:888: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -E -traditional-cpp"
+ cat > conftest.$ac_ext <<EOF
+#line 899 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:905: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -nologo -E"
+ cat > conftest.$ac_ext <<EOF
+#line 916 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:922: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+ ac_cv_prog_CPP="$CPP"
+fi
+ CPP="$ac_cv_prog_CPP"
+else
+ ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+for ac_prog in mawk gawk nawk awk
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:951: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$AWK"; then
+ ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_AWK="$ac_prog"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+AWK="$ac_cv_prog_AWK"
+if test -n "$AWK"; then
+ echo "$ac_t""$AWK" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+test -n "$AWK" && break
+done
+
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX v4 /usr/bin/installbsd, which does not work if the user is not root
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:993: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ # Account for people who put trailing slashes in PATH elements.
+ case "$ac_dir/" in
+ /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ for ac_prog in ginstall installbsd scoinst install; do
+ if test -f $ac_dir/$ac_prog; then
+ if test $ac_prog = install &&
+ grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ # OSF/1 installbsd also uses dspmsg, but is usable.
+ :
+ elif test $ac_prog = installbsd -a "x`(uname -sv) 2>/dev/null`" = "xAIX 4"; then
+ # AIX v4 installbsd. Does not work if the user is not root.
+ :
+ else
+ ac_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+ IFS="$ac_save_IFS"
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL="$ac_cv_path_install"
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL="$ac_install_sh"
+ fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+for ac_prog in md5sum sum cksum
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1050: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_SUM'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$SUM" in
+ /*)
+ ac_cv_path_SUM="$SUM" # Let the user override the test with a path.
+ ;;
+ ?:/*)
+ ac_cv_path_SUM="$SUM" # Let the user override the test with a dos path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_SUM="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ ;;
+esac
+fi
+SUM="$ac_cv_path_SUM"
+if test -n "$SUM"; then
+ echo "$ac_t""$SUM" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+test -n "$SUM" && break
+done
+test -n "$SUM" || SUM="true"
+
+if test $ac_cv_prog_gcc = yes; then
+ echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6
+echo "configure:1088: checking whether ${CC-cc} needs -traditional" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_pattern="Autoconf.*'x'"
+ cat > conftest.$ac_ext <<EOF
+#line 1094 "configure"
+#include "confdefs.h"
+#include <sgtty.h>
+Autoconf TIOCGETP
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "$ac_pattern" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_prog_gcc_traditional=yes
+else
+ rm -rf conftest*
+ ac_cv_prog_gcc_traditional=no
+fi
+rm -f conftest*
+
+
+ if test $ac_cv_prog_gcc_traditional = no; then
+ cat > conftest.$ac_ext <<EOF
+#line 1112 "configure"
+#include "confdefs.h"
+#include <termio.h>
+Autoconf TCGETA
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "$ac_pattern" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_prog_gcc_traditional=yes
+fi
+rm -f conftest*
+
+ fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6
+ if test $ac_cv_prog_gcc_traditional = yes; then
+ CC="$CC -traditional"
+ fi
+fi
+
+
+echo $ac_n "checking for AIX""... $ac_c" 1>&6
+echo "configure:1135: checking for AIX" >&5
+if eval "test \"`echo '$''{'irc_cv_aix'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "x`(uname) 2>/dev/null`" = "xAIX"; then
+ irc_cv_aix="`uname -rv`"
+else
+ irc_cv_aix=no
+fi
+
+fi
+
+if test "$irc_cv_aix" = no; then
+ echo "$ac_t""no" 1>&6
+else
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define _ALL_SOURCE 1
+EOF
+
+ if test "x$irc_cv_aix" = "x2 3"; then
+ cat >> confdefs.h <<\EOF
+#define AIX_3_2 1
+EOF
+
+ fi
+ if test x$CC = xcc; then
+ CFLAGS="$CFLAGS -O3 -qstrict"
+ fi
+fi
+
+echo $ac_n "checking for POSIXized ISC""... $ac_c" 1>&6
+echo "configure:1167: checking for POSIXized ISC" >&5
+if test -d /etc/conf/kconfig.d &&
+ grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1
+then
+ echo "$ac_t""yes" 1>&6
+ ISC=yes # If later tests want to check for ISC.
+ cat >> confdefs.h <<\EOF
+#define _POSIX_SOURCE 1
+EOF
+
+ if test "$GCC" = yes; then
+ CC="$CC -posix"
+ else
+ CC="$CC -Xp"
+ fi
+else
+ echo "$ac_t""no" 1>&6
+ ISC=
+fi
+
+ac_safe=`echo "minix/config.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for minix/config.h""... $ac_c" 1>&6
+echo "configure:1189: checking for minix/config.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1194 "configure"
+#include "confdefs.h"
+#include <minix/config.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1199: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ MINIX=yes
+else
+ echo "$ac_t""no" 1>&6
+MINIX=
+fi
+
+if test "$MINIX" = yes; then
+ cat >> confdefs.h <<\EOF
+#define _POSIX_SOURCE 1
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define _POSIX_1_SOURCE 2
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define _MINIX 1
+EOF
+
+fi
+
+echo $ac_n "checking for SGI's cc""... $ac_c" 1>&6
+echo "configure:1237: checking for SGI's cc" >&5
+cat > conftest.$ac_ext <<EOF
+#line 1239 "configure"
+#include "confdefs.h"
+#ifdef sgi
+yes
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "yes" >/dev/null 2>&1; then
+ rm -rf conftest*
+ if test x$CC = xcc; then
+ echo "$ac_t""yes" 1>&6
+ CC="$CC -cckr"
+else
+ echo "$ac_t""no" 1>&6
+fi
+else
+ rm -rf conftest*
+ echo "$ac_t""no" 1>&6
+fi
+rm -f conftest*
+
+
+echo $ac_n "checking for HPUX's cc""... $ac_c" 1>&6
+echo "configure:1262: checking for HPUX's cc" >&5
+cat > conftest.$ac_ext <<EOF
+#line 1264 "configure"
+#include "confdefs.h"
+#ifdef hpux
+yes
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "yes" >/dev/null 2>&1; then
+ rm -rf conftest*
+ if test x$CC = xcc; then
+ echo "$ac_t""yes" 1>&6
+ CC="$CC -Ae"
+else
+ echo "$ac_t""no" 1>&6
+fi
+else
+ rm -rf conftest*
+ echo "$ac_t""no" 1>&6
+fi
+rm -f conftest*
+
+
+echo $ac_n "checking for SunOS""... $ac_c" 1>&6
+echo "configure:1287: checking for SunOS" >&5
+if eval "test \"`echo '$''{'irc_cv_sun'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "x`(uname) 2>/dev/null`" = "xSunOS"; then
+ irc_cv_sun="`uname -r`"
+else
+ irc_cv_sun=no
+fi
+
+fi
+
+irc_cv_solaris_2=no
+if test "$irc_sun" = no; then
+ echo "$ac_t""no" 1>&6
+else
+ if uname -r 2>/dev/null | grep "^5" >/dev/null; then
+ irc_cv_solaris_2="`uname -r | sed -e \"s/^5/2/g\"`"
+ echo "$ac_t""yes, Solaris $irc_cv_solaris_2" 1>&6
+ cat >> confdefs.h <<\EOF
+#define SOLARIS_2 1
+EOF
+
+ if echo "$irc_cv_solaris_2" | egrep "^2\.(0|1|2)" >/dev/null; then
+ cat >> confdefs.h <<\EOF
+#define SOLARIS_2_0_2_1_2_2 1
+EOF
+
+ elif echo "$irc_cv_solaris_2" | grep "^2\.3" >/dev/null; then
+ cat >> confdefs.h <<\EOF
+#define SOLARIS_2_3 1
+EOF
+
+ fi
+ else
+ echo "$ac_t""yes, SunOS $irc_cv_sun" 1>&6
+ fi
+fi
+
+echo $ac_n "checking for Linux""... $ac_c" 1>&6
+echo "configure:1327: checking for Linux" >&5
+if eval "test \"`echo '$''{'irc_cv_linux'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "x`(uname) 2>/dev/null`" = "xLinux"; then
+ cat > conftest.$ac_ext <<EOF
+#line 1333 "configure"
+#include "confdefs.h"
+#include <netdb.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $AWK "{if (NR > 1) printf(\" \"); printf(\$0)}" |
+ egrep "struct( | )+hostent( | )+\{.*const.*h_name" >/dev/null 2>&1; then
+ rm -rf conftest*
+ irc_cv_linux=bad
+else
+ rm -rf conftest*
+ irc_cv_linux=good
+fi
+rm -f conftest*
+
+else
+ irc_cv_linux=no
+fi
+
+fi
+
+if test "$irc_cv_linux" = no; then
+ echo "$ac_t""no" 1>&6
+elif test "$irc_cv_linux" = good; then
+ echo "$ac_t""yes, with a good <netdb.h> file" 1>&6
+else
+ echo "$ac_t""yes, with a bad <netdb.h> file" 1>&6
+ cat >> confdefs.h <<\EOF
+#define BAD___CONST_NETDB_H 1
+EOF
+
+fi
+
+echo $ac_n "checking for Cygwin environment""... $ac_c" 1>&6
+echo "configure:1367: checking for Cygwin environment" >&5
+if eval "test \"`echo '$''{'ac_cv_cygwin'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1372 "configure"
+#include "confdefs.h"
+
+int main() {
+
+#ifndef __CYGWIN__
+#define __CYGWIN__ __CYGWIN32__
+#endif
+return __CYGWIN__;
+; return 0; }
+EOF
+if { (eval echo configure:1383: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_cygwin=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_cygwin=no
+fi
+rm -f conftest*
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_cygwin" 1>&6
+CYGWIN=
+test "$ac_cv_cygwin" = yes && CYGWIN=yes
+if test ! -z "$CYGWIN"; then
+ if test ! -x /bin/mv || test ! -x /bin/rm || test ! -x /bin/sh; then
+ { echo "configure: error: mv, rm and/or sh is missing from /bin" 1>&2; exit 1; }
+ fi
+ echo "configure: warning: The IRC client and the iauth program do not work under the CYGWIN environment." 1>&2
+fi
+
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1408: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1413 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1421: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ ac_cv_header_stdc=yes
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1438 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "memchr" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1456 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "free" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+ :
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1477 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1488: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ :
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+ cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&6
+echo "configure:1512: checking for sys/wait.h that is POSIX.1 compatible" >&5
+if eval "test \"`echo '$''{'ac_cv_header_sys_wait_h'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1517 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+int main() {
+int s;
+wait (&s);
+s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
+; return 0; }
+EOF
+if { (eval echo configure:1533: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_header_sys_wait_h=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_sys_wait_h=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_sys_wait_h" 1>&6
+if test $ac_cv_header_sys_wait_h = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_SYS_WAIT_H 1
+EOF
+
+fi
+
+for ac_hdr in stdio.h stdlib.h sys/types.h sys/bitypes.h stddef.h stdarg.h unistd.h ctype.h memory.h ncurses.h curses.h cursesX.h term.h sgtty.h errno.h sys/errno.h sys/syscall.h pwd.h math.h utmp.h fcntl.h signal.h sys/ioctl.h sys/file.h sys/filio.h sys/socket.h sys/stat.h sys/resource.h sys/select.h sys/poll.h stropts.h netdb.h netinet/in.h sys/un.h arpa/inet.h sys/param.h syslog.h sys/syslog.h string.h strings.h sys/time.h time.h sys/times.h netinet/in_systm.h netinfo/ni.h resolv.h arpa/nameser.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1557: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1562 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1567: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+echo $ac_n "checking for sys_errlist declaration in stdio.h, errno.h or sys/errno.h""... $ac_c" 1>&6
+echo "configure:1594: checking for sys_errlist declaration in stdio.h, errno.h or sys/errno.h" >&5
+if eval "test \"`echo '$''{'irc_cv_decl_sys_errlist'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1599 "configure"
+#include "confdefs.h"
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#if HAVE_SYS_ERRNO_H
+#include <sys/errno.h>
+#endif
+int main() {
+char *msg = sys_errlist[0];
+; return 0; }
+EOF
+if { (eval echo configure:1618: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ irc_cv_decl_sys_errlist=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ irc_cv_decl_sys_errlist=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$irc_cv_decl_sys_errlist" 1>&6
+if test $irc_cv_decl_sys_errlist = yes; then
+ cat >> confdefs.h <<\EOF
+#define SYS_ERRLIST_DECLARED 1
+EOF
+
+fi
+
+echo $ac_n "checking for sys_nerr declaration in stdio.h, errno.h or sys/errno.h""... $ac_c" 1>&6
+echo "configure:1639: checking for sys_nerr declaration in stdio.h, errno.h or sys/errno.h" >&5
+if eval "test \"`echo '$''{'irc_cv_decl_sys_nerr'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1644 "configure"
+#include "confdefs.h"
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#if HAVE_SYS_ERRNO_H
+#include <sys/errno.h>
+#endif
+int main() {
+int num = sys_nerr;
+; return 0; }
+EOF
+if { (eval echo configure:1663: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ irc_cv_decl_sys_nerr=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ irc_cv_decl_sys_nerr=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$irc_cv_decl_sys_nerr" 1>&6
+if test $irc_cv_decl_sys_nerr = yes; then
+ cat >> confdefs.h <<\EOF
+#define SYS_NERR_DECLARED 1
+EOF
+
+fi
+
+echo $ac_n "checking for errno declaration in errno.h or sys/errno.h""... $ac_c" 1>&6
+echo "configure:1684: checking for errno declaration in errno.h or sys/errno.h" >&5
+if eval "test \"`echo '$''{'irc_cv_decl_errno'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1689 "configure"
+#include "confdefs.h"
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#if HAVE_SYS_ERRNO_H
+#include <sys/errno.h>
+#endif
+int main() {
+int num = errno;
+; return 0; }
+EOF
+if { (eval echo configure:1705: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ irc_cv_decl_errno=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ irc_cv_decl_errno=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$irc_cv_decl_errno" 1>&6
+if test $irc_cv_decl_errno = yes; then
+ cat >> confdefs.h <<\EOF
+#define ERRNO_DECLARED 1
+EOF
+
+fi
+
+echo $ac_n "checking for h_errno declaration in errno.h, sys/errno.h or netdb.h""... $ac_c" 1>&6
+echo "configure:1726: checking for h_errno declaration in errno.h, sys/errno.h or netdb.h" >&5
+if eval "test \"`echo '$''{'irc_cv_decl_h_errno'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1731 "configure"
+#include "confdefs.h"
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#if HAVE_SYS_ERRNO_H
+#include <sys/errno.h>
+#endif
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+int main() {
+int num = h_errno;
+; return 0; }
+EOF
+if { (eval echo configure:1750: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ irc_cv_decl_h_errno=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ irc_cv_decl_h_errno=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$irc_cv_decl_h_errno" 1>&6
+if test $irc_cv_decl_h_errno = yes; then
+ cat >> confdefs.h <<\EOF
+#define H_ERRNO_DECLARED 1
+EOF
+
+fi
+
+echo $ac_n "checking whether stat file-mode macros are broken""... $ac_c" 1>&6
+echo "configure:1771: checking whether stat file-mode macros are broken" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stat_broken'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1776 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if defined(S_ISBLK) && defined(S_IFDIR)
+# if S_ISBLK (S_IFDIR)
+You lose.
+# endif
+#endif
+
+#if defined(S_ISBLK) && defined(S_IFCHR)
+# if S_ISBLK (S_IFCHR)
+You lose.
+# endif
+#endif
+
+#if defined(S_ISLNK) && defined(S_IFREG)
+# if S_ISLNK (S_IFREG)
+You lose.
+# endif
+#endif
+
+#if defined(S_ISSOCK) && defined(S_IFREG)
+# if S_ISSOCK (S_IFREG)
+You lose.
+# endif
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "You lose" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_header_stat_broken=yes
+else
+ rm -rf conftest*
+ ac_cv_header_stat_broken=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_header_stat_broken" 1>&6
+if test $ac_cv_header_stat_broken = yes; then
+ cat >> confdefs.h <<\EOF
+#define STAT_MACROS_BROKEN 1
+EOF
+
+fi
+
+echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
+echo "configure:1827: checking whether time.h and sys/time.h may both be included" >&5
+if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1832 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+int main() {
+struct tm *tp;
+; return 0; }
+EOF
+if { (eval echo configure:1841: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_header_time=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_time=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_time" 1>&6
+if test $ac_cv_header_time = yes; then
+ cat >> confdefs.h <<\EOF
+#define TIME_WITH_SYS_TIME 1
+EOF
+
+fi
+
+echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6
+echo "configure:1862: checking whether struct tm is in sys/time.h or time.h" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1867 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <time.h>
+int main() {
+struct tm *tp; tp->tm_sec;
+; return 0; }
+EOF
+if { (eval echo configure:1875: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_struct_tm=time.h
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_struct_tm=sys/time.h
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_tm" 1>&6
+if test $ac_cv_struct_tm = sys/time.h; then
+ cat >> confdefs.h <<\EOF
+#define TM_IN_SYS_TIME 1
+EOF
+
+fi
+
+echo $ac_n "checking for mode_t""... $ac_c" 1>&6
+echo "configure:1896: checking for mode_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_mode_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1901 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])mode_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_mode_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_mode_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_mode_t" 1>&6
+if test $ac_cv_type_mode_t = no; then
+ cat >> confdefs.h <<\EOF
+#define mode_t int
+EOF
+
+fi
+
+echo $ac_n "checking for off_t""... $ac_c" 1>&6
+echo "configure:1929: checking for off_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1934 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])off_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_off_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_off_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_off_t" 1>&6
+if test $ac_cv_type_off_t = no; then
+ cat >> confdefs.h <<\EOF
+#define off_t long
+EOF
+
+fi
+
+echo $ac_n "checking for pid_t""... $ac_c" 1>&6
+echo "configure:1962: checking for pid_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1967 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])pid_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_pid_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_pid_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_pid_t" 1>&6
+if test $ac_cv_type_pid_t = no; then
+ cat >> confdefs.h <<\EOF
+#define pid_t int
+EOF
+
+fi
+
+echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
+echo "configure:1995: checking return type of signal handlers" >&5
+if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2000 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int main() {
+int i;
+; return 0; }
+EOF
+if { (eval echo configure:2017: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_type_signal=void
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_type_signal=int
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_type_signal" 1>&6
+cat >> confdefs.h <<EOF
+#define RETSIGTYPE $ac_cv_type_signal
+EOF
+
+
+echo $ac_n "checking for size_t""... $ac_c" 1>&6
+echo "configure:2036: checking for size_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2041 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_size_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_size_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_size_t" 1>&6
+if test $ac_cv_type_size_t = no; then
+ cat >> confdefs.h <<\EOF
+#define size_t unsigned
+EOF
+
+fi
+
+echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&6
+echo "configure:2069: checking for uid_t in sys/types.h" >&5
+if eval "test \"`echo '$''{'ac_cv_type_uid_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2074 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "uid_t" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_uid_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_uid_t=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_type_uid_t" 1>&6
+if test $ac_cv_type_uid_t = no; then
+ cat >> confdefs.h <<\EOF
+#define uid_t int
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define gid_t int
+EOF
+
+fi
+
+echo $ac_n "checking whether an union wait * is mandatory in waitpid""... $ac_c" 1>&6
+echo "configure:2103: checking whether an union wait * is mandatory in waitpid" >&5
+if eval "test \"`echo '$''{'irc_cv_type_union_wait'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2108 "configure"
+#include "confdefs.h"
+
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+int main() {
+
+int status;
+waitpid(-1, &status, 0);
+
+; return 0; }
+EOF
+if { (eval echo configure:2121: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ irc_cv_type_union_wait=no
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ cat > conftest.$ac_ext <<EOF
+#line 2129 "configure"
+#include "confdefs.h"
+
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+int main() {
+
+union wait status;
+waitpid(-1, &status, 0);
+
+; return 0; }
+EOF
+if { (eval echo configure:2142: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ irc_cv_type_union_wait=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ irc_cv_type_union_wait=no
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+
+if test $irc_cv_type_union_wait = yes; then
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define USE_UNION_WAIT 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for int8_t""... $ac_c" 1>&6
+echo "configure:2167: checking for int8_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_int8_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2172 "configure"
+#include "confdefs.h"
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#if HAVE_SYS_BITYPES_H
+#include <sys/bitypes.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "int8_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_int8_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_int8_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_int8_t" 1>&6
+if test $ac_cv_type_int8_t = no; then
+ cat >> confdefs.h <<\EOF
+#define int8_t char
+EOF
+
+fi
+
+echo $ac_n "checking for u_int8_t""... $ac_c" 1>&6
+echo "configure:2206: checking for u_int8_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_u_int8_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2211 "configure"
+#include "confdefs.h"
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#if HAVE_SYS_BITYPES_H
+#include <sys/bitypes.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "u_int8_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_u_int8_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_u_int8_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_u_int8_t" 1>&6
+if test $ac_cv_type_u_int8_t = no; then
+ cat >> confdefs.h <<\EOF
+#define u_int8_t unsigned char
+EOF
+
+fi
+
+echo $ac_n "checking for int16_t""... $ac_c" 1>&6
+echo "configure:2245: checking for int16_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_int16_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2250 "configure"
+#include "confdefs.h"
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#if HAVE_SYS_BITYPES_H
+#include <sys/bitypes.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "int16_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_int16_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_int16_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_int16_t" 1>&6
+if test $ac_cv_type_int16_t = no; then
+ cat >> confdefs.h <<\EOF
+#define int16_t short
+EOF
+
+fi
+
+echo $ac_n "checking for u_int16_t""... $ac_c" 1>&6
+echo "configure:2284: checking for u_int16_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_u_int16_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2289 "configure"
+#include "confdefs.h"
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#if HAVE_SYS_BITYPES_H
+#include <sys/bitypes.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "u_int16_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_u_int16_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_u_int16_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_u_int16_t" 1>&6
+if test $ac_cv_type_u_int16_t = no; then
+ cat >> confdefs.h <<\EOF
+#define u_int16_t unsigned short
+EOF
+
+fi
+
+echo $ac_n "checking for int32_t""... $ac_c" 1>&6
+echo "configure:2323: checking for int32_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_int32_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2328 "configure"
+#include "confdefs.h"
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#if HAVE_SYS_BITYPES_H
+#include <sys/bitypes.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "int32_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_int32_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_int32_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_int32_t" 1>&6
+if test $ac_cv_type_int32_t = no; then
+ cat >> confdefs.h <<\EOF
+#define int32_t int
+EOF
+
+fi
+
+echo $ac_n "checking for u_int32_t""... $ac_c" 1>&6
+echo "configure:2362: checking for u_int32_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_u_int32_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2367 "configure"
+#include "confdefs.h"
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#if HAVE_SYS_BITYPES_H
+#include <sys/bitypes.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "u_int32_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_u_int32_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_u_int32_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_u_int32_t" 1>&6
+if test $ac_cv_type_u_int32_t = no; then
+ cat >> confdefs.h <<\EOF
+#define u_int32_t unsigned int
+EOF
+
+fi
+
+echo $ac_n "checking for u_char""... $ac_c" 1>&6
+echo "configure:2401: checking for u_char" >&5
+if eval "test \"`echo '$''{'ac_cv_type_u_char'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2406 "configure"
+#include "confdefs.h"
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#if HAVE_SYS_BITYPES_H
+#include <sys/bitypes.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "u_char[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_u_char=yes
+else
+ rm -rf conftest*
+ ac_cv_type_u_char=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_u_char" 1>&6
+if test $ac_cv_type_u_char = no; then
+ cat >> confdefs.h <<\EOF
+#define u_char unsigned char
+EOF
+
+fi
+
+echo $ac_n "checking for u_short""... $ac_c" 1>&6
+echo "configure:2440: checking for u_short" >&5
+if eval "test \"`echo '$''{'ac_cv_type_u_short'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2445 "configure"
+#include "confdefs.h"
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#if HAVE_SYS_BITYPES_H
+#include <sys/bitypes.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "u_short[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_u_short=yes
+else
+ rm -rf conftest*
+ ac_cv_type_u_short=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_u_short" 1>&6
+if test $ac_cv_type_u_short = no; then
+ cat >> confdefs.h <<\EOF
+#define u_short unsigned short
+EOF
+
+fi
+
+echo $ac_n "checking for u_int""... $ac_c" 1>&6
+echo "configure:2479: checking for u_int" >&5
+if eval "test \"`echo '$''{'ac_cv_type_u_int'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2484 "configure"
+#include "confdefs.h"
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#if HAVE_SYS_BITYPES_H
+#include <sys/bitypes.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "u_int[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_u_int=yes
+else
+ rm -rf conftest*
+ ac_cv_type_u_int=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_u_int" 1>&6
+if test $ac_cv_type_u_int = no; then
+ cat >> confdefs.h <<\EOF
+#define u_int unsigned int
+EOF
+
+fi
+
+echo $ac_n "checking for u_long""... $ac_c" 1>&6
+echo "configure:2518: checking for u_long" >&5
+if eval "test \"`echo '$''{'ac_cv_type_u_long'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2523 "configure"
+#include "confdefs.h"
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#if HAVE_SYS_BITYPES_H
+#include <sys/bitypes.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "u_long[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_u_long=yes
+else
+ rm -rf conftest*
+ ac_cv_type_u_long=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_u_long" 1>&6
+if test $ac_cv_type_u_long = no; then
+ cat >> confdefs.h <<\EOF
+#define u_long unsigned long
+EOF
+
+fi
+
+
+echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6
+echo "configure:2558: checking whether byte ordering is bigendian" >&5
+if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_cv_c_bigendian=unknown
+# See if sys/param.h defines the BYTE_ORDER macro.
+cat > conftest.$ac_ext <<EOF
+#line 2565 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/param.h>
+int main() {
+
+#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
+ bogus endian macros
+#endif
+; return 0; }
+EOF
+if { (eval echo configure:2576: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ # It does; now see whether it defined to BIG_ENDIAN or not.
+cat > conftest.$ac_ext <<EOF
+#line 2580 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/param.h>
+int main() {
+
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+#endif
+; return 0; }
+EOF
+if { (eval echo configure:2591: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_c_bigendian=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_c_bigendian=no
+fi
+rm -f conftest*
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+if test $ac_cv_c_bigendian = unknown; then
+if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2611 "configure"
+#include "confdefs.h"
+main () {
+ /* Are we little or big endian? From Harbison&Steele. */
+ union
+ {
+ long l;
+ char c[sizeof (long)];
+ } u;
+ u.l = 1;
+ exit (u.c[sizeof (long) - 1] == 1);
+}
+EOF
+if { (eval echo configure:2624: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_c_bigendian=no
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_c_bigendian=yes
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_c_bigendian" 1>&6
+if test $ac_cv_c_bigendian = yes; then
+ cat >> confdefs.h <<\EOF
+#define WORDS_BIGENDIAN 1
+EOF
+
+fi
+
+echo $ac_n "checking for working const""... $ac_c" 1>&6
+echo "configure:2648: checking for working const" >&5
+if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2653 "configure"
+#include "confdefs.h"
+
+int main() {
+
+/* Ultrix mips cc rejects this. */
+typedef int charset[2]; const charset x;
+/* SunOS 4.1.1 cc rejects this. */
+char const *const *ccp;
+char **p;
+/* NEC SVR4.0.2 mips cc rejects this. */
+struct point {int x, y;};
+static struct point const zero = {0,0};
+/* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in an arm
+ of an if-expression whose if-part is not a constant expression */
+const char *g = "string";
+ccp = &g + (g ? g-g : 0);
+/* HPUX 7.0 cc rejects these. */
+++ccp;
+p = (char**) ccp;
+ccp = (char const *const *) p;
+{ /* SCO 3.2v4 cc rejects this. */
+ char *t;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+}
+{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+}
+{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+}
+{ /* AIX XL C 1.02.0.0 rejects this saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; };
+ struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+}
+
+; return 0; }
+EOF
+if { (eval echo configure:2702: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_c_const=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_c_const=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_const" 1>&6
+if test $ac_cv_c_const = no; then
+ cat >> confdefs.h <<\EOF
+#define const
+EOF
+
+fi
+
+
+echo $ac_n "checking for crypt in -lcrypt""... $ac_c" 1>&6
+echo "configure:2724: checking for crypt in -lcrypt" >&5
+ac_lib_var=`echo crypt'_'crypt | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lcrypt $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2732 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char crypt();
+
+int main() {
+crypt()
+; return 0; }
+EOF
+if { (eval echo configure:2743: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo crypt | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lcrypt $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for socket in -lsocket""... $ac_c" 1>&6
+echo "configure:2771: checking for socket in -lsocket" >&5
+ac_lib_var=`echo socket'_'socket | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsocket $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2779 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char socket();
+
+int main() {
+socket()
+; return 0; }
+EOF
+if { (eval echo configure:2790: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo socket | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lsocket $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for socket in -lnsl""... $ac_c" 1>&6
+echo "configure:2818: checking for socket in -lnsl" >&5
+ac_lib_var=`echo nsl'_'socket | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lnsl $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2826 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char socket();
+
+int main() {
+socket()
+; return 0; }
+EOF
+if { (eval echo configure:2837: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo nsl | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lnsl $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+echo $ac_n "checking for zlib package""... $ac_c" 1>&6
+echo "configure:2866: checking for zlib package" >&5
+# Check whether --with-zlib or --without-zlib was given.
+if test "${with_zlib+set}" = set; then
+ withval="$with_zlib"
+ :
+fi
+
+# Check whether --with-zlib or --without-zlib was given.
+if test "${with_zlib+set}" = set; then
+ withval="$with_zlib"
+ :
+fi
+
+if test "x$with_zlib" = xno; then
+ no_zlib=yes
+else
+if eval "test \"`echo '$''{'irc_cv_path_zlib'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ no_zlib=yes
+no_zlib_include=yes
+no_zlib_library=yes
+cat > conftest.$ac_ext <<EOF
+#line 2889 "configure"
+#include "confdefs.h"
+#include <zlib.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2894: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ no_zlib_include=
+irc_zlib_include=
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ for irc_dir in "$irc_zlib_include" \
+ `test -z "$irc_zlib_prefix" || echo "$irc_zlib_prefix/include"` \
+ `echo "$irc_zlib_library" | sed s/lib/include/` \
+ /usr/include /usr/local/include /usr/unsupported/include \
+ /usr/share/include /usr/local/share/include /include \
+ /usr/zlib/include /usr/local/zlib/include \
+ /usr/include/zlib /usr/local/include/zlib \
+ /usr/unsupported/include/zlib /usr/share/include/zlib \
+ /usr/local/share/include/zlib /include/zlib \
+ /usr/zlib/include/zlib /usr/local/zlib/include/zlib; \
+ do
+ if test -r "$irc_dir/zlib.h"; then
+ no_zlib_include=
+ irc_zlib_include=$irc_dir
+ break
+ fi
+ done
+
+fi
+rm -f conftest*
+irc_save_LIBS="$LIBS"
+LIBS="-lz $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2928 "configure"
+#include "confdefs.h"
+
+int main() {
+inflate()
+; return 0; }
+EOF
+if { (eval echo configure:2935: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ no_zlib_library=
+irc_zlib_library=
+LIBS="$irc_save_LIBS"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ LIBS="$irc_save_LIBS"
+for irc_dir in "$irc_zlib_library" \
+ `test -z "$irc_zlib_prefix" || echo "$irc_zlib_prefix/lib"` \
+ `echo "$irc_zlib_include" | sed s/include/lib/` \
+ /usr/lib /usr/local/lib /usr/unsupported/lib \
+ /usr/share/lib /usr/local/share/lib /lib /usr/zlib/lib \
+ /usr/local/zlib/lib /usr/lib/zlib /usr/local/lib/zlib \
+ /usr/unsupported/lib/zlib /usr/share/lib/zlib \
+ /usr/local/share/lib/zlib /lib/zlib \
+ /usr/zlib/lib/zlib /usr/local/zlib/lib/zlib; \
+do
+ for irc_extension in a so sl; do
+ if test -r $irc_dir/libz.$irc_extension; then
+ no_zlib_library=
+ irc_zlib_library=$irc_dir
+ break 2
+ fi
+ done
+done
+
+fi
+rm -f conftest*
+if test "x$no_zlib_include" = x && test "x$no_zlib_library" = x; then
+ no_zlib=
+fi
+if test "$no_zlib" = yes; then
+ irc_cv_path_zlib="no_zlib=yes"
+else
+ irc_cv_path_zlib="no_zlib= irc_zlib_include=$irc_zlib_include irc_zlib_library=$irc_zlib_library"
+fi
+fi
+
+ eval "$irc_cv_path_zlib"
+fi
+if test "$no_zlib" = yes; then
+ IRC_ZLIB_LIBRARY=
+ IRC_ZLIB_INCLUDE=
+ echo "$ac_t""no" 1>&6
+else
+ cat >> confdefs.h <<\EOF
+#define USE_ZLIB 1
+EOF
+
+ if test "x$irc_zlib_library" = x; then
+ irc_zlib_library_message="found by the linker"
+ IRC_ZLIB_LIBRARY=-lz
+ else
+ irc_zlib_library_message="in $irc_zlib_library"
+ IRC_ZLIB_LIBRARY=-L$irc_zlib_library
+ if test ! "$irc_cv_solaris_2" = no; then
+ IRC_ZLIB_LIBRARY="$IRC_ZLIB_LIBRARY -R$irc_zlib_library"
+ fi
+ IRC_ZLIB_LIBRARY="$IRC_ZLIB_LIBRARY -lz"
+ fi
+ if test "x$irc_zlib_include" = x; then
+ irc_zlib_include_message="found by the compiler"
+ IRC_ZLIB_INCLUDE=
+ else
+ irc_zlib_include_message="in $irc_zlib_include"
+ IRC_ZLIB_INCLUDE=-I$irc_zlib_include
+ fi
+ echo "$ac_t""" 1>&6
+ echo "$ac_t"" library $irc_zlib_library_message" 1>&6
+ echo "$ac_t"" header $irc_zlib_include_message" 1>&6
+fi
+
+
+
+echo $ac_n "checking which curses or termcap library will be used""... $ac_c" 1>&6
+echo "configure:3013: checking which curses or termcap library will be used" >&5
+# Check whether --with-ncurses or --without-ncurses was given.
+if test "${with_ncurses+set}" = set; then
+ withval="$with_ncurses"
+ :
+fi
+
+# Check whether --with-cursesX or --without-cursesX was given.
+if test "${with_cursesX+set}" = set; then
+ withval="$with_cursesX"
+ :
+fi
+
+# Check whether --with-curses or --without-curses was given.
+if test "${with_curses+set}" = set; then
+ withval="$with_curses"
+ :
+fi
+
+# Check whether --with-termcap or --without-termcap was given.
+if test "${with_termcap+set}" = set; then
+ withval="$with_termcap"
+ :
+fi
+
+if eval "test \"`echo '$''{'irc_cv_curses_termcap'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ irc_save_LIBS="$LIBS"
+LIBS="-lncurses $irc_save_LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 3044 "configure"
+#include "confdefs.h"
+
+int main() {
+initscr()
+; return 0; }
+EOF
+if { (eval echo configure:3051: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ irc_ncurses=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ irc_ncurses=no
+fi
+rm -f conftest*
+LIBS="-lcursesX $irc_save_LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 3063 "configure"
+#include "confdefs.h"
+
+int main() {
+initscr()
+; return 0; }
+EOF
+if { (eval echo configure:3070: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ irc_cursesX=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ irc_cursesX=no
+fi
+rm -f conftest*
+LIBS="-lcurses $irc_save_LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 3082 "configure"
+#include "confdefs.h"
+
+int main() {
+initscr()
+; return 0; }
+EOF
+if { (eval echo configure:3089: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ irc_curses=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ irc_curses=no
+fi
+rm -f conftest*
+LIBS="-lcurses -ltermcap $irc_save_LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 3101 "configure"
+#include "confdefs.h"
+
+int main() {
+initscr()
+; return 0; }
+EOF
+if { (eval echo configure:3108: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ irc_curses_termcap=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ irc_curses_termcap=no
+fi
+rm -f conftest*
+LIBS="-ltermcap $irc_save_LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 3120 "configure"
+#include "confdefs.h"
+
+int main() {
+tgetent()
+; return 0; }
+EOF
+if { (eval echo configure:3127: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ irc_termcap=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ irc_termcap=no
+fi
+rm -f conftest*
+LIBS="$irc_save_LIBS"
+irc_cv_curses_termcap="irc_ncurses=$irc_ncurses irc_curses=$irc_curses irc_cursesX=$irc_cursesX irc_curses_termcap=$irc_curses_termcap irc_termcap=$irc_termcap"
+
+fi
+
+eval $irc_cv_curses_termcap
+if test "x$with_ncurses" = xno; then
+ irc_ncurses=no
+fi
+if test "x$with_cursesX" = xno; then
+ irc_cursesX=no
+fi
+if test "x$with_curses" = xno; then
+ irc_curses=no
+ irc_curses_termcap=no
+fi
+if test "x$with_termcap" = xno; then
+ irc_termcap=no
+fi
+if test $irc_ncurses = yes; then
+ echo "$ac_t""ncurses" 1>&6
+ cat >> confdefs.h <<\EOF
+#define USE_NCURSES 1
+EOF
+
+ IRC_CURSES_TERMCAP_LIBRARY="-lncurses"
+elif test $irc_cursesX = yes; then
+ echo "$ac_t""cursesX" 1>&6
+ cat >> confdefs.h <<\EOF
+#define USE_CURSESX 1
+EOF
+
+ IRC_CURSES_TERMCAP_LIBRARY="-lcursesX"
+elif test $irc_curses = yes; then
+ echo "$ac_t""curses" 1>&6
+ cat >> confdefs.h <<\EOF
+#define USE_CURSES 1
+EOF
+
+ IRC_CURSES_TERMCAP_LIBRARY="-lcurses"
+elif test $irc_curses_termcap = yes; then
+ echo "$ac_t""curses over termcap" 1>&6
+ cat >> confdefs.h <<\EOF
+#define USE_CURSES 1
+EOF
+
+ IRC_CURSES_TERMCAP_LIBRARY="-lcurses -ltermcap"
+elif test $irc_termcap = yes; then
+ echo "$ac_t""termcap" 1>&6
+ cat >> confdefs.h <<\EOF
+#define USE_TERMCAP 1
+EOF
+
+ IRC_CURSES_TERMCAP_LIBRARY="-ltermcap"
+else
+ echo "$ac_t""none" 1>&6
+ echo "configure: warning: I can't find either ncurses, cursesX, curses or termcap library." 1>&2
+ IRC_CURSES_TERMCAP_LIBRARY=
+fi
+
+
+
+echo $ac_n "checking whether setpgrp takes no argument""... $ac_c" 1>&6
+echo "configure:3200: checking whether setpgrp takes no argument" >&5
+if eval "test \"`echo '$''{'ac_cv_func_setpgrp_void'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ { echo "configure: error: cannot check setpgrp if cross compiling" 1>&2; exit 1; }
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3208 "configure"
+#include "confdefs.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/*
+ * If this system has a BSD-style setpgrp, which takes arguments, exit
+ * successfully.
+ */
+main()
+{
+ if (setpgrp(1,1) == -1)
+ exit(0);
+ else
+ exit(1);
+}
+
+EOF
+if { (eval echo configure:3228: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_func_setpgrp_void=no
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_func_setpgrp_void=yes
+fi
+rm -fr conftest*
+fi
+
+
+fi
+
+echo "$ac_t""$ac_cv_func_setpgrp_void" 1>&6
+if test $ac_cv_func_setpgrp_void = yes; then
+ cat >> confdefs.h <<\EOF
+#define SETPGRP_VOID 1
+EOF
+
+fi
+
+echo $ac_n "checking whether setvbuf arguments are reversed""... $ac_c" 1>&6
+echo "configure:3252: checking whether setvbuf arguments are reversed" >&5
+if eval "test \"`echo '$''{'ac_cv_func_setvbuf_reversed'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3260 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+/* If setvbuf has the reversed format, exit 0. */
+main () {
+ /* This call has the arguments reversed.
+ A reversed system may check and see that the address of main
+ is not _IOLBF, _IONBF, or _IOFBF, and return nonzero. */
+ if (setvbuf(stdout, _IOLBF, (char *) main, BUFSIZ) != 0)
+ exit(1);
+ putc('\r', stdout);
+ exit(0); /* Non-reversed systems segv here. */
+}
+EOF
+if { (eval echo configure:3274: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_func_setvbuf_reversed=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_func_setvbuf_reversed=no
+fi
+rm -fr conftest*
+fi
+
+rm -f core core.* *.core
+fi
+
+echo "$ac_t""$ac_cv_func_setvbuf_reversed" 1>&6
+if test $ac_cv_func_setvbuf_reversed = yes; then
+ cat >> confdefs.h <<\EOF
+#define SETVBUF_REVERSED 1
+EOF
+
+fi
+
+ac_safe=`echo "vfork.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for vfork.h""... $ac_c" 1>&6
+echo "configure:3299: checking for vfork.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3304 "configure"
+#include "confdefs.h"
+#include <vfork.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:3309: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define HAVE_VFORK_H 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for working vfork""... $ac_c" 1>&6
+echo "configure:3334: checking for working vfork" >&5
+if eval "test \"`echo '$''{'ac_cv_func_vfork_works'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ echo $ac_n "checking for vfork""... $ac_c" 1>&6
+echo "configure:3340: checking for vfork" >&5
+if eval "test \"`echo '$''{'ac_cv_func_vfork'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3345 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char vfork(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char vfork();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_vfork) || defined (__stub___vfork)
+choke me
+#else
+vfork();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3368: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_vfork=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_vfork=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'vfork`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ :
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ac_cv_func_vfork_works=$ac_cv_func_vfork
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3390 "configure"
+#include "confdefs.h"
+/* Thanks to Paul Eggert for this test. */
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_VFORK_H
+#include <vfork.h>
+#endif
+/* On some sparc systems, changes by the child to local and incoming
+ argument registers are propagated back to the parent.
+ The compiler is told about this with #include <vfork.h>,
+ but some compilers (e.g. gcc -O) don't grok <vfork.h>.
+ Test for this by using a static variable whose address
+ is put into a register that is clobbered by the vfork. */
+static
+#ifdef __cplusplus
+sparc_address_test (int arg)
+#else
+sparc_address_test (arg) int arg;
+#endif
+{
+ static pid_t child;
+ if (!child) {
+ child = vfork ();
+ if (child < 0) {
+ perror ("vfork");
+ _exit(2);
+ }
+ if (!child) {
+ arg = getpid();
+ write(-1, "", 0);
+ _exit (arg);
+ }
+ }
+}
+main() {
+ pid_t parent = getpid ();
+ pid_t child;
+
+ sparc_address_test ();
+
+ child = vfork ();
+
+ if (child == 0) {
+ /* Here is another test for sparc vfork register problems.
+ This test uses lots of local variables, at least
+ as many local variables as main has allocated so far
+ including compiler temporaries. 4 locals are enough for
+ gcc 1.40.3 on a Solaris 4.1.3 sparc, but we use 8 to be safe.
+ A buggy compiler should reuse the register of parent
+ for one of the local variables, since it will think that
+ parent can't possibly be used any more in this routine.
+ Assigning to the local variable will thus munge parent
+ in the parent process. */
+ pid_t
+ p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(),
+ p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid();
+ /* Convince the compiler that p..p7 are live; otherwise, it might
+ use the same hardware register for all 8 local variables. */
+ if (p != p1 || p != p2 || p != p3 || p != p4
+ || p != p5 || p != p6 || p != p7)
+ _exit(1);
+
+ /* On some systems (e.g. IRIX 3.3),
+ vfork doesn't separate parent from child file descriptors.
+ If the child closes a descriptor before it execs or exits,
+ this munges the parent's descriptor as well.
+ Test for this by closing stdout in the child. */
+ _exit(close(fileno(stdout)) != 0);
+ } else {
+ int status;
+ struct stat st;
+
+ while (wait(&status) != child)
+ ;
+ exit(
+ /* Was there some problem with vforking? */
+ child < 0
+
+ /* Did the child fail? (This shouldn't happen.) */
+ || status
+
+ /* Did the vfork/compiler bug occur? */
+ || parent != getpid()
+
+ /* Did the file descriptor bug occur? */
+ || fstat(fileno(stdout), &st) != 0
+ );
+ }
+}
+EOF
+if { (eval echo configure:3485: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_func_vfork_works=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_func_vfork_works=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_func_vfork_works" 1>&6
+if test $ac_cv_func_vfork_works = no; then
+ cat >> confdefs.h <<\EOF
+#define vfork fork
+EOF
+
+fi
+
+for ac_func in setpgrp strchr strrchr memcmp memset memmove memcpy index rindex bcmp bcopy bzero select inet_ntoa inet_aton inet_addr inet_netof getrusage times strerror strtoken strtok sigaction sigset truncate poll vsyslog
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:3510: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3515 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:3538: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+echo $ac_n "checking for 8-bit clean memcmp""... $ac_c" 1>&6
+echo "configure:3563: checking for 8-bit clean memcmp" >&5
+if eval "test \"`echo '$''{'irc_cv_func_memcmp_clean'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ irc_cv_func_memcmp_clean=no
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3571 "configure"
+#include "confdefs.h"
+
+main()
+{
+ char c0 = 0x40, c1 = 0x80, c2 = 0x81;
+ exit(memcmp(&c0, &c2, 1) < 0 && memcmp(&c1, &c2, 1) < 0 ? 0 : 1);
+}
+
+EOF
+if { (eval echo configure:3581: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ irc_cv_func_memcmp_clean=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ irc_cv_func_memcmp_clean=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$irc_cv_func_memcmp_clean" 1>&6
+if test $irc_cv_func_memcmp_clean = no; then
+ cat >> confdefs.h <<\EOF
+#define MEMCMP_BROKEN 1
+EOF
+
+fi
+
+echo $ac_n "checking whether select or poll system call will be used""... $ac_c" 1>&6
+echo "configure:3604: checking whether select or poll system call will be used" >&5
+if eval "test \"`echo '$''{'irc_cv_select_poll'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$irc_cv_sun" != "no" && test "x$irc_cv_solaris_2" = "xno"; then
+ # we don't like SunOS' poll() function
+ irc_cv_select_poll=select
+else
+ if test "$ac_cv_func_poll" = "yes"; then
+ irc_cv_select_poll=poll
+ else
+ irc_cv_select_poll=select
+ fi
+fi
+fi
+
+
+if test "$irc_cv_select_poll" = "poll"; then
+ echo "$ac_t""poll" 1>&6
+ cat >> confdefs.h <<\EOF
+#define USE_POLL 1
+EOF
+
+ if test ! "$irc_cv_linux" = "no"; then
+ echo "configure: warning: Aiiie.. This is linux. poll() is known to be broken for some releases (2.0.x with libc6?). You may want to edit setup.h to undefine USE_POLL" 1>&2
+ fi
+else
+ echo "$ac_t""select" 1>&6
+fi
+
+
+echo $ac_n "checking for signal implementation""... $ac_c" 1>&6
+echo "configure:3636: checking for signal implementation" >&5
+if eval "test \"`echo '$''{'irc_cv_signal_implementation'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test x$ac_cv_func_sigaction = xyes; then
+ irc_cv_signal_implementation=posix_sigaction
+elif test x$ac_cv_func_sigset = xyes; then
+ irc_cv_signal_implementation=bsd_sigset
+else
+ if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3649 "configure"
+#include "confdefs.h"
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+#ifndef SIGCHLD
+#define SIGCHLD SIGCLD
+#endif
+
+int got = 0;
+
+RETSIGTYPE hand()
+{
+ got++;
+}
+
+main()
+{
+ (void)signal(SIGCHLD, hand);
+ kill(getpid(), SIGCHLD);
+ kill(getpid(), SIGCHLD);
+ if (got < 2)
+ exit(1);
+ exit(0);
+}
+
+EOF
+if { (eval echo configure:3680: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ irc_cv_signal_implementation=bsd_signal
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ irc_cv_signal_implementation=sysv_signal
+fi
+rm -fr conftest*
+fi
+
+fi
+
+fi
+
+if test $irc_cv_signal_implementation = posix_sigaction; then
+ echo "$ac_t""using POSIX sigaction" 1>&6
+ cat >> confdefs.h <<\EOF
+#define POSIX_SIGNALS 1
+EOF
+
+elif test $irc_cv_signal_implementation = bsd_sigset; then
+ echo "$ac_t""using BSD sigset" 1>&6
+ cat >> confdefs.h <<\EOF
+#define BSD_RELIABLE_SIGNALS 1
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define signal sigset
+EOF
+
+elif test $irc_cv_signal_implementation = bsd_signal; then
+ echo "$ac_t""using reliable BSD signal" 1>&6
+ cat >> confdefs.h <<\EOF
+#define BSD_RELIABLE_SIGNALS 1
+EOF
+
+else
+ echo "$ac_t""using unreliable SystemV signal" 1>&6
+ cat >> confdefs.h <<\EOF
+#define SYSV_UNRELIABLE_SIGNALS 1
+EOF
+
+fi
+
+echo $ac_n "checking for a working non-blocking system""... $ac_c" 1>&6
+echo "configure:3727: checking for a working non-blocking system" >&5
+if eval "test \"`echo '$''{'irc_cv_non_blocking_system'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+irc_precode='#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#if HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#if HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+RETSIGTYPE alarmed()
+{
+ exit(1);
+}
+
+main()
+{
+ char b[12];
+ struct sockaddr_in x;
+ int f, l = sizeof(x);
+ f = socket(AF_INET, SOCK_DGRAM, 0);
+ if (f >= 0 && !(fcntl(f, F_SETFL, '
+irc_postcode=')))
+ {
+ signal(SIGALRM, alarmed);
+ alarm(3);
+ recvfrom(f, b, 12, 0, &x, &l);
+ alarm(0);
+ exit(0);
+ }
+ exit(1);
+}'
+irc_code_posix="${irc_precode}O_NONBLOCK${irc_postcode}"
+irc_code_bsd="${irc_precode}O_NDELAY${irc_postcode}"
+irc_code_sysv="${irc_precode}FIONBIO${irc_postcode}"
+if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3783 "configure"
+#include "confdefs.h"
+$irc_code_posix
+EOF
+if { (eval echo configure:3787: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ irc_cv_non_blocking_system=posix
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3798 "configure"
+#include "confdefs.h"
+$irc_code_bsd
+EOF
+if { (eval echo configure:3802: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ irc_cv_non_blocking_system=bsd
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3813 "configure"
+#include "confdefs.h"
+$irc_code_sysv
+EOF
+if { (eval echo configure:3817: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ irc_cv_non_blocking_system=sysv
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ irc_cv_non_blocking_system=none
+fi
+rm -fr conftest*
+fi
+
+fi
+rm -fr conftest*
+fi
+
+fi
+rm -fr conftest*
+fi
+
+
+fi
+
+if test $irc_cv_non_blocking_system = posix; then
+ echo "$ac_t""using POSIX O_NONBLOCK" 1>&6
+ cat >> confdefs.h <<\EOF
+#define NBLOCK_POSIX 1
+EOF
+
+elif test $irc_cv_non_blocking_system = bsd; then
+ echo "$ac_t""using BSD O_NDELAY" 1>&6
+ cat >> confdefs.h <<\EOF
+#define NBLOCK_BSD 1
+EOF
+
+elif test $irc_cv_non_blocking_system = sysv; then
+ echo "$ac_t""using SystemV FIONBIO" 1>&6
+ cat >> confdefs.h <<\EOF
+#define NBLOCK_SYSV 1
+EOF
+
+else
+ echo "$ac_t""using none" 1>&6
+ echo "configure: warning: I can't find a working non-blocking system." 1>&2
+fi
+
+echo $ac_n "checking for working stdarg""... $ac_c" 1>&6
+echo "configure:3864: checking for working stdarg" >&5
+if eval "test \"`echo '$''{'irc_cv_stdarg'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3872 "configure"
+#include "confdefs.h"
+
+#if HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#if HAVE_STDARG_H
+#include <stdarg.h>
+#endif
+#if HAVE_STRING_H
+#include <string.h>
+#endif
+
+char buf1[256];
+
+int level1(char *data, char *format, va_list ap)
+{
+ return vsprintf(data, format, ap);
+}
+
+int level2(char *data, int rounds, char *format, va_list ap)
+{
+ if(!--rounds)
+ return level1(data, format, ap);
+ else {
+ if(rounds == 2) {
+ va_list ap2 = ap;
+ char *arg = va_arg(ap2, char *);
+ strcpy(buf1, arg);
+ }
+ return level2(data, rounds, format, ap);
+ }
+}
+
+int level3(char *data, char *format, va_list ap)
+{
+ return level2(data, 5, format, ap);
+}
+
+int dotest(int size, char *val, char *data)
+{
+ if(size != strlen(val))
+ return 0;
+ if(strcmp(data, val))
+ return 0;
+ if(strcmp(buf1, "was"))
+ return 0;
+ return 1;
+}
+
+int base(char *val, char *format, ...)
+{
+ int res = 1;
+ char data[256];
+
+ {
+ va_list ap;
+ data[0]=0;
+ va_start(ap, format);
+ res = dotest(level3(data, format, ap), val, data);
+ va_end(ap);
+ }
+
+ {
+ va_list ap;
+ data[0]=0;
+ va_start(ap, format);
+ res = res && dotest(level3(data, format, ap), val, data);
+ va_end(ap);
+ }
+
+ return res;
+}
+
+int main(void)
+{
+ int res = base("toto was here ! 42", "toto %s here ! %d", "was", 42);
+
+ exit(res ? 0 : 1);
+}
+
+EOF
+if { (eval echo configure:3954: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ irc_cv_stdarg=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ irc_cv_stdarg=no
+fi
+rm -fr conftest*
+fi
+
+
+fi
+
+if test $irc_cv_stdarg = yes; then
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define USE_STDARG 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for resolver configuration file""... $ac_c" 1>&6
+echo "configure:3980: checking for resolver configuration file" >&5
+if eval "test \"`echo '$''{'irc_cv_path_resconf'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -z "$irc_resconf"; then
+ irc_cv_path_resconf="/etc/resolv.conf";
+ else
+ irc_cv_path_resconf="$irc_resconf";
+ fi
+
+fi
+
+echo "$ac_t""$irc_cv_path_resconf" 1>&6
+cat >> confdefs.h <<EOF
+#define IRC_RESCONF "$irc_cv_path_resconf"
+EOF
+
+if test ! -r "$irc_cv_path_resconf"; then
+ echo "configure: warning: Unable to read \"$irc_cv_path_resconf\"! Without resolver configuration file, the server won't work." 1>&2
+fi
+
+# Check whether --enable-ip6 or --disable-ip6 was given.
+if test "${enable_ip6+set}" = set; then
+ enableval="$enable_ip6"
+ :
+fi
+
+if test "x$enable_ip6" != x; then
+ cat >> confdefs.h <<\EOF
+#define INET6 1
+EOF
+
+ echo $ac_n "checking IPv6 system type""... $ac_c" 1>&6
+echo "configure:4013: checking IPv6 system type" >&5
+ if eval "test \"`echo '$''{'irc_cv_v6type'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+
+ if test -d /usr/inet6; then
+ irc_cv_v6type=linux
+ else
+ cat > conftest.$ac_ext <<EOF
+#line 4022 "configure"
+#include "confdefs.h"
+dnl
+#include <netinet/in.h>
+#ifdef IPV6_INRIA_VERSION
+yes
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "yes" >/dev/null 2>&1; then
+ rm -rf conftest*
+ irc_cv_v6type=inria
+else
+ rm -rf conftest*
+ cat > conftest.$ac_ext <<EOF
+#line 4037 "configure"
+#include "confdefs.h"
+#include <netinet/in.h>
+#ifdef __KAME__
+yes
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "yes" >/dev/null 2>&1; then
+ rm -rf conftest*
+ irc_cv_v6type=kame
+else
+ rm -rf conftest*
+ cat > conftest.$ac_ext <<EOF
+#line 4051 "configure"
+#include "confdefs.h"
+#include <sys/param.h>
+#ifdef _TOSHIBA_INET6
+yes
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "yes" >/dev/null 2>&1; then
+ rm -rf conftest*
+ irc_cv_v6type=toshiba
+else
+ rm -rf conftest*
+ cat > conftest.$ac_ext <<EOF
+#line 4065 "configure"
+#include "confdefs.h"
+#include </usr/local/v6/include/sys/types.h>
+#ifdef __V6D__
+yes
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "yes" >/dev/null 2>&1; then
+ rm -rf conftest*
+ irc_cv_v6type=v6d
+else
+ rm -rf conftest*
+ cat > conftest.$ac_ext <<EOF
+#line 4079 "configure"
+#include "confdefs.h"
+#include <sys/param.h>
+#ifdef _ZETA_MINAMI_INET6
+yes
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "yes" >/dev/null 2>&1; then
+ rm -rf conftest*
+ irc_cv_v6type=zeta
+fi
+rm -f conftest*
+
+fi
+rm -f conftest*
+
+fi
+rm -f conftest*
+
+fi
+rm -f conftest*
+
+fi
+rm -f conftest*
+
+ fi
+fi
+
+ echo "$ac_t""$irc_cv_v6type" 1>&6
+
+ case $irc_cv_v6type in
+ kame)
+ LIBS="-L/usr/local/v6/lib -linet6 $LIBS"
+ CFLAGS="$CFLAGS -I/usr/local/v6/include"
+ ;;
+ linux)
+ LIBS="-L/usr/inet6/lib -linet6 $LIBS"
+ CFLAGS="$CFLAGS -I/usr/inet6/include"
+ ;;
+ toshiba)
+ LIBS="-L/usr/local/v6/lib -linet6 $LIBS"
+ CFLAGS="$CFLAGS -I/usr/local/v6/include"
+ ;;
+ v6d)
+ LIBS="-L/usr/local/v6/lib -lv6 $LIBS"
+ CFLAGS="$CFLAGS -I/usr/local/v6/include"
+ ;;
+ zeta)
+ LIBS="-L/usr/local/v6/lib -linet6 $LIBS"
+ CFLAGS="$CFLAGS -I/usr/local/v6/include"
+ ;;
+ esac
+
+ echo $ac_n "checking for IPv6 name server addresses in resolv.conf ($irc_cv_path_resconf)""... $ac_c" 1>&6
+echo "configure:4134: checking for IPv6 name server addresses in resolv.conf ($irc_cv_path_resconf)" >&5
+ if grep nameserver $irc_cv_path_resconf | grep ':' >/dev/null 2>&1; then
+ echo "$ac_t""yes" 1>&6
+ echo "configure: warning: $irc_cv_path_resconf is not setup correctly." 1>&2
+ else
+ echo "$ac_t""no" 1>&6
+ fi
+fi
+
+# Check whether --enable-dsm or --disable-dsm was given.
+if test "${enable_dsm+set}" = set; then
+ enableval="$enable_dsm"
+ :
+fi
+
+if test "x$enable_dsm" != x; then
+ cat >> confdefs.h <<\EOF
+#define USE_DSM 1
+EOF
+
+ for ac_hdr in dlfcn.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:4158: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 4163 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:4168: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+ echo $ac_n "checking for dlclose in -ldl""... $ac_c" 1>&6
+echo "configure:4195: checking for dlclose in -ldl" >&5
+ac_lib_var=`echo dl'_'dlclose | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ldl $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 4203 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dlclose();
+
+int main() {
+dlclose()
+; return 0; }
+EOF
+if { (eval echo configure:4214: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ IRC_DLIB="-ldl"
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+fi
+
+echo $ac_n "checking whether this is an alpha/beta release""... $ac_c" 1>&6
+echo "configure:4238: checking whether this is an alpha/beta release" >&5
+if eval "test \"`echo '$''{'irc_cv_alpha_beta'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 4243 "configure"
+#include "confdefs.h"
+#include "../common/patchlevel.h"
+#ifdef PATCHLEVEL
+PATCHLEVEL
+#else
+"0000000000"
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "^\"......00" >/dev/null 2>&1; then
+ rm -rf conftest*
+ irc_cv_alpha_beta=
+else
+ rm -rf conftest*
+ irc_cv_alpha_beta=yes
+fi
+rm -f conftest*
+
+
+fi
+
+if test x$irc_cv_alpha_beta = xyes; then
+ echo "$ac_t""yes" 1>&6
+ echo "configure: warning:
+
+This is a development version of the package,
+it is not intended to be used in a production environment.
+" 1>&2
+# if test ! "$ac_test_CFLAGS" = set; then
+# if test x$ac_cv_prog_cc_g = xyes -o x$GCC = x; then
+# CFLAGS="$CFLAGS -g"
+# fi
+# fi
+else
+ echo "$ac_t""no" 1>&6
+# if test ! "${LDFLAGS+set}" = set; then
+# LDFLAGS="-s"
+# fi
+fi
+
+if test ! "$ac_test_CFLAGS" = set; then
+ if test x$ac_cv_prog_cc_g = xyes -o x$GCC = x; then
+ CFLAGS="$CFLAGS -g"
+ fi
+fi
+
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote substitution
+ # turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ -e "s/'/'\\\\''/g" \
+ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+ ;;
+ esac >> confcache
+if cmp -s $cache_file confcache; then
+ :
+else
+ if test -w $cache_file; then
+ echo "updating cache $cache_file"
+ cat confcache > $cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "\$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+ exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "$CONFIG_STATUS generated by autoconf version 2.13"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "\$ac_cs_usage"; exit 0 ;;
+ *) echo "\$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "Makefile:../support/Makefile.in version.c.SH:../ircd/version.c.SH.in sums:../support/sums.in tkconf.h:../support/tkconf.h.dist setup.h:../support/setup.h.in" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@logdir@%$logdir%g
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@host@%$host%g
+s%@host_alias@%$host_alias%g
+s%@host_cpu@%$host_cpu%g
+s%@host_vendor@%$host_vendor%g
+s%@host_os@%$host_os%g
+s%@target@%$target%g
+s%@target_alias@%$target_alias%g
+s%@target_cpu@%$target_cpu%g
+s%@target_vendor@%$target_vendor%g
+s%@target_os@%$target_os%g
+s%@build@%$build%g
+s%@build_alias@%$build_alias%g
+s%@build_cpu@%$build_cpu%g
+s%@build_vendor@%$build_vendor%g
+s%@build_os@%$build_os%g
+s%@CC@%$CC%g
+s%@CPP@%$CPP%g
+s%@AWK@%$AWK%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@SUM@%$SUM%g
+s%@IRC_ZLIB_INCLUDE@%$IRC_ZLIB_INCLUDE%g
+s%@IRC_ZLIB_LIBRARY@%$IRC_ZLIB_LIBRARY%g
+s%@IRC_CURSES_TERMCAP_LIBRARY@%$IRC_CURSES_TERMCAP_LIBRARY%g
+s%@IRC_DLIB@%$IRC_DLIB%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+ else
+ sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+ fi
+ if test ! -s conftest.s$ac_file; then
+ ac_more_lines=false
+ rm -f conftest.s$ac_file
+ else
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f conftest.s$ac_file"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+ fi
+ ac_file=`expr $ac_file + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_cmds`
+ fi
+done
+if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile:../support/Makefile.in version.c.SH:../ircd/version.c.SH.in sums:../support/sums.in tkconf.h:../support/tkconf.h.dist"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+ case "$ac_given_INSTALL" in
+ [/$]*) INSTALL="$ac_given_INSTALL" ;;
+ *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+ esac
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='\([ ][ ]*\)[^ ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='\([ ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+ CONFIG_HEADERS="setup.h:../support/setup.h.in"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ echo creating $ac_file
+
+ rm -f conftest.frag conftest.in conftest.out
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h. And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+ ac_lines=`grep -c . conftest.vals`
+ # grep -c gives empty output for an empty file on some AIX systems.
+ if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+ # Write a limited-size here document to conftest.frag.
+ echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+ echo 'CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+ rm -f conftest.vals
+ mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+ rm -f conftest.frag conftest.h
+ echo "/* $ac_file. Generated automatically by configure. */" > conftest.h
+ cat conftest.in >> conftest.h
+ rm -f conftest.in
+ if cmp -s $ac_file conftest.h 2>/dev/null; then
+ echo "$ac_file is unchanged"
+ rm -f conftest.h
+ else
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ fi
+ rm -f $ac_file
+ mv conftest.h $ac_file
+ fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
+
+chmod a+x version.c.SH
+
diff --git a/support/configure.in b/support/configure.in
new file mode 100644
index 0000000..3d425e5
--- /dev/null
+++ b/support/configure.in
@@ -0,0 +1,1519 @@
+dnl configure.in for irc-2.10.1
+dnl Matthew Green (mrg@mame.mu.oz.au), Alain Nissen (Alain.Nissen@ulg.ac.be)
+dnl using portions of Avalon's Config and GNU Autoconf 1.12.
+
+dnl ---------
+dnl new tests
+dnl ---------
+
+AC_DEFUN(IRC_PATH_ZLIB,
+[AC_MSG_CHECKING(for zlib package)
+AC_ARG_WITH(zlib, [ --with-zlib checks for zlib; if found, enables compressed links])
+AC_ARG_WITH(zlib, [ --without-zlib does not check for zlib; disables compressed links])
+if test "x$with_zlib" = xno; then
+ no_zlib=yes
+else
+AC_CACHE_VAL(irc_cv_path_zlib,
+[no_zlib=yes
+no_zlib_include=yes
+no_zlib_library=yes
+AC_TRY_CPP([#include <zlib.h>],
+[no_zlib_include=
+irc_zlib_include=],
+[for irc_dir in "$irc_zlib_include" \
+ `test -z "$irc_zlib_prefix" || echo "$irc_zlib_prefix/include"` \
+ `echo "$irc_zlib_library" | sed s/lib/include/` \
+ /usr/include /usr/local/include /usr/unsupported/include \
+ /usr/share/include /usr/local/share/include /include \
+ /usr/zlib/include /usr/local/zlib/include \
+ /usr/include/zlib /usr/local/include/zlib \
+ /usr/unsupported/include/zlib /usr/share/include/zlib \
+ /usr/local/share/include/zlib /include/zlib \
+ /usr/zlib/include/zlib /usr/local/zlib/include/zlib; \
+ do
+ if test -r "$irc_dir/zlib.h"; then
+ no_zlib_include=
+ irc_zlib_include=$irc_dir
+ break
+ fi
+ done
+])
+irc_save_LIBS="$LIBS"
+LIBS="-lz $LIBS"
+AC_TRY_LINK(,
+[inflate()],
+[no_zlib_library=
+irc_zlib_library=
+LIBS="$irc_save_LIBS"],
+[LIBS="$irc_save_LIBS"
+for irc_dir in "$irc_zlib_library" \
+ `test -z "$irc_zlib_prefix" || echo "$irc_zlib_prefix/lib"` \
+ `echo "$irc_zlib_include" | sed s/include/lib/` \
+ /usr/lib /usr/local/lib /usr/unsupported/lib \
+ /usr/share/lib /usr/local/share/lib /lib /usr/zlib/lib \
+ /usr/local/zlib/lib /usr/lib/zlib /usr/local/lib/zlib \
+ /usr/unsupported/lib/zlib /usr/share/lib/zlib \
+ /usr/local/share/lib/zlib /lib/zlib \
+ /usr/zlib/lib/zlib /usr/local/zlib/lib/zlib; \
+do
+ for irc_extension in a so sl; do
+ if test -r $irc_dir/libz.$irc_extension; then
+ no_zlib_library=
+ irc_zlib_library=$irc_dir
+ break 2
+ fi
+ done
+done
+])
+if test "x$no_zlib_include" = x && test "x$no_zlib_library" = x; then
+ no_zlib=
+fi
+if test "$no_zlib" = yes; then
+ irc_cv_path_zlib="no_zlib=yes"
+else
+ irc_cv_path_zlib="no_zlib= irc_zlib_include=$irc_zlib_include irc_zlib_library=$irc_zlib_library"
+fi])
+ eval "$irc_cv_path_zlib"
+fi
+if test "$no_zlib" = yes; then
+ IRC_ZLIB_LIBRARY=
+ IRC_ZLIB_INCLUDE=
+ AC_MSG_RESULT(no)
+else
+ AC_DEFINE(USE_ZLIB)
+ if test "x$irc_zlib_library" = x; then
+ irc_zlib_library_message="found by the linker"
+ IRC_ZLIB_LIBRARY=-lz
+ else
+ irc_zlib_library_message="in $irc_zlib_library"
+ IRC_ZLIB_LIBRARY=-L$irc_zlib_library
+ if test ! "$irc_cv_solaris_2" = no; then
+ IRC_ZLIB_LIBRARY="$IRC_ZLIB_LIBRARY -R$irc_zlib_library"
+ fi
+ IRC_ZLIB_LIBRARY="$IRC_ZLIB_LIBRARY -lz"
+ fi
+ if test "x$irc_zlib_include" = x; then
+ irc_zlib_include_message="found by the compiler"
+ IRC_ZLIB_INCLUDE=
+ else
+ irc_zlib_include_message="in $irc_zlib_include"
+ IRC_ZLIB_INCLUDE=-I$irc_zlib_include
+ fi
+ AC_MSG_RESULT([])
+ AC_MSG_RESULT([ library $irc_zlib_library_message])
+ AC_MSG_RESULT([ header $irc_zlib_include_message])
+fi
+AC_SUBST(IRC_ZLIB_INCLUDE)
+AC_SUBST(IRC_ZLIB_LIBRARY)
+])
+
+
+AC_DEFUN(IRC_CURSES_TERMCAP,
+[AC_MSG_CHECKING([which curses or termcap library will be used])
+AC_ARG_WITH(ncurses, [ --without-ncurses does not look for ncurses library, will not use it])
+AC_ARG_WITH(cursesX, [ --without-cursesX does not look for cursesX library, will not use it])
+AC_ARG_WITH(curses, [ --without-curses does not look for curses library, will not use it])
+AC_ARG_WITH(termcap, [ --without-termcap does not look for termcap library, will not use it])
+AC_CACHE_VAL(irc_cv_curses_termcap,
+[irc_save_LIBS="$LIBS"
+LIBS="-lncurses $irc_save_LIBS"
+AC_TRY_LINK(,
+[initscr()],
+irc_ncurses=yes,
+irc_ncurses=no)
+LIBS="-lcursesX $irc_save_LIBS"
+AC_TRY_LINK(,
+[initscr()],
+irc_cursesX=yes,
+irc_cursesX=no)
+LIBS="-lcurses $irc_save_LIBS"
+AC_TRY_LINK(,
+[initscr()],
+irc_curses=yes,
+irc_curses=no)
+LIBS="-lcurses -ltermcap $irc_save_LIBS"
+AC_TRY_LINK(,
+[initscr()],
+irc_curses_termcap=yes,
+irc_curses_termcap=no)
+LIBS="-ltermcap $irc_save_LIBS"
+AC_TRY_LINK(,
+[tgetent()],
+irc_termcap=yes,
+irc_termcap=no)
+LIBS="$irc_save_LIBS"
+irc_cv_curses_termcap="irc_ncurses=$irc_ncurses irc_curses=$irc_curses irc_cursesX=$irc_cursesX irc_curses_termcap=$irc_curses_termcap irc_termcap=$irc_termcap"
+])
+eval $irc_cv_curses_termcap
+if test "x$with_ncurses" = xno; then
+ irc_ncurses=no
+fi
+if test "x$with_cursesX" = xno; then
+ irc_cursesX=no
+fi
+if test "x$with_curses" = xno; then
+ irc_curses=no
+ irc_curses_termcap=no
+fi
+if test "x$with_termcap" = xno; then
+ irc_termcap=no
+fi
+if test $irc_ncurses = yes; then
+ AC_MSG_RESULT(ncurses)
+ AC_DEFINE(USE_NCURSES)
+ IRC_CURSES_TERMCAP_LIBRARY="-lncurses"
+elif test $irc_cursesX = yes; then
+ AC_MSG_RESULT(cursesX)
+ AC_DEFINE(USE_CURSESX)
+ IRC_CURSES_TERMCAP_LIBRARY="-lcursesX"
+elif test $irc_curses = yes; then
+ AC_MSG_RESULT(curses)
+ AC_DEFINE(USE_CURSES)
+ IRC_CURSES_TERMCAP_LIBRARY="-lcurses"
+elif test $irc_curses_termcap = yes; then
+ AC_MSG_RESULT(curses over termcap)
+ AC_DEFINE(USE_CURSES)
+ IRC_CURSES_TERMCAP_LIBRARY="-lcurses -ltermcap"
+elif test $irc_termcap = yes; then
+ AC_MSG_RESULT(termcap)
+ AC_DEFINE(USE_TERMCAP)
+ IRC_CURSES_TERMCAP_LIBRARY="-ltermcap"
+else
+ AC_MSG_RESULT(none)
+ AC_MSG_WARN([I can't find either ncurses, cursesX, curses or termcap library.])
+ IRC_CURSES_TERMCAP_LIBRARY=
+fi
+AC_SUBST(IRC_CURSES_TERMCAP_LIBRARY)
+])
+
+
+AC_DEFUN(IRC_UNION_WAIT,
+[AC_MSG_CHECKING(whether an union wait * is mandatory in waitpid)
+AC_CACHE_VAL(irc_cv_type_union_wait,
+AC_TRY_COMPILE([
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif],
+[
+int status;
+waitpid(-1, &status, 0);
+],
+irc_cv_type_union_wait=no,
+AC_TRY_COMPILE([
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif],
+[
+union wait status;
+waitpid(-1, &status, 0);
+],
+irc_cv_type_union_wait=yes,
+irc_cv_type_union_wait=no)))
+if test $irc_cv_type_union_wait = yes; then
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(USE_UNION_WAIT)
+else
+ AC_MSG_RESULT(no)
+fi
+])
+
+
+AC_DEFUN(IRC_SUN,
+[AC_MSG_CHECKING([for SunOS])
+AC_CACHE_VAL(irc_cv_sun,
+[if test "x`(uname) 2>/dev/null`" = "xSunOS"; then
+ irc_cv_sun="`uname -r`"
+else
+ irc_cv_sun=no
+fi
+])
+irc_cv_solaris_2=no
+if test "$irc_sun" = no; then
+ AC_MSG_RESULT(no)
+else
+ if uname -r 2>/dev/null | grep "^5" >/dev/null; then
+ irc_cv_solaris_2="`uname -r | sed -e \"s/^5/2/g\"`"
+ AC_MSG_RESULT([yes, Solaris $irc_cv_solaris_2])
+ AC_DEFINE(SOLARIS_2)
+ if echo "$irc_cv_solaris_2" | egrep "^2\.(0|1|2)" >/dev/null; then
+ AC_DEFINE(SOLARIS_2_0_2_1_2_2)
+ elif echo "$irc_cv_solaris_2" | grep "^2\.3" >/dev/null; then
+ AC_DEFINE(SOLARIS_2_3)
+ fi
+ else
+ AC_MSG_RESULT([yes, SunOS $irc_cv_sun])
+ fi
+fi
+])
+
+
+AC_DEFUN(IRC_DECL_SYS_ERRLIST,
+[AC_CACHE_CHECK([for sys_errlist declaration in stdio.h, errno.h or sys/errno.h],
+ irc_cv_decl_sys_errlist,
+[AC_TRY_COMPILE([
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#if HAVE_SYS_ERRNO_H
+#include <sys/errno.h>
+#endif],
+[char *msg = sys_errlist[0];],
+ irc_cv_decl_sys_errlist=yes, irc_cv_decl_sys_errlist=no)])
+if test $irc_cv_decl_sys_errlist = yes; then
+ AC_DEFINE(SYS_ERRLIST_DECLARED)
+fi
+])
+
+
+AC_DEFUN(IRC_DECL_SYS_NERR,
+[AC_CACHE_CHECK([for sys_nerr declaration in stdio.h, errno.h or sys/errno.h],
+ irc_cv_decl_sys_nerr,
+[AC_TRY_COMPILE([
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#if HAVE_SYS_ERRNO_H
+#include <sys/errno.h>
+#endif],
+[int num = sys_nerr;],
+ irc_cv_decl_sys_nerr=yes, irc_cv_decl_sys_nerr=no)])
+if test $irc_cv_decl_sys_nerr = yes; then
+ AC_DEFINE(SYS_NERR_DECLARED)
+fi
+])
+
+
+AC_DEFUN(IRC_DECL_ERRNO,
+[AC_CACHE_CHECK([for errno declaration in errno.h or sys/errno.h],
+ irc_cv_decl_errno,
+[AC_TRY_COMPILE([
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#if HAVE_SYS_ERRNO_H
+#include <sys/errno.h>
+#endif],
+[int num = errno;],
+ irc_cv_decl_errno=yes, irc_cv_decl_errno=no)])
+if test $irc_cv_decl_errno = yes; then
+ AC_DEFINE(ERRNO_DECLARED)
+fi
+])
+
+
+AC_DEFUN(IRC_DECL_H_ERRNO,
+[AC_CACHE_CHECK([for h_errno declaration in errno.h, sys/errno.h or netdb.h],
+ irc_cv_decl_h_errno,
+[AC_TRY_COMPILE([
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#if HAVE_SYS_ERRNO_H
+#include <sys/errno.h>
+#endif
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif],
+[int num = h_errno;],
+ irc_cv_decl_h_errno=yes, irc_cv_decl_h_errno=no)])
+if test $irc_cv_decl_h_errno = yes; then
+ AC_DEFINE(H_ERRNO_DECLARED)
+fi
+])
+
+
+AC_DEFUN(IRC_SGI_CC,
+[AC_MSG_CHECKING([for SGI's cc])
+AC_EGREP_CPP(yes,
+[#ifdef sgi
+yes
+#endif],
+if test x$CC = xcc; then
+ AC_MSG_RESULT(yes)
+ CC="$CC -cckr"
+else
+ AC_MSG_RESULT(no)
+fi,
+AC_MSG_RESULT(no))
+])
+
+
+AC_DEFUN(IRC_HPUX_CC,
+[AC_MSG_CHECKING([for HPUX's cc])
+AC_EGREP_CPP(yes,
+[#ifdef hpux
+yes
+#endif],
+if test x$CC = xcc; then
+ AC_MSG_RESULT(yes)
+ CC="$CC -Ae"
+else
+ AC_MSG_RESULT(no)
+fi,
+AC_MSG_RESULT(no))
+])
+
+
+AC_DEFUN(IRC_ALPHA_BETA,
+[AC_MSG_CHECKING(whether this is an alpha/beta release)
+AC_CACHE_VAL(irc_cv_alpha_beta,
+[AC_EGREP_CPP(^\"......00,
+[#include "../common/patchlevel.h"
+#ifdef PATCHLEVEL
+PATCHLEVEL
+#else
+"0000000000"
+#endif
+],irc_cv_alpha_beta=,
+irc_cv_alpha_beta=yes)
+])
+if test x$irc_cv_alpha_beta = xyes; then
+ AC_MSG_RESULT(yes)
+ AC_MSG_WARN([
+
+This is a development version of the package,
+it is not intended to be used in a production environment.
+])
+# if test ! "$ac_test_CFLAGS" = set; then
+# if test x$ac_cv_prog_cc_g = xyes -o x$GCC = x; then
+# CFLAGS="$CFLAGS -g"
+# fi
+# fi
+else
+ AC_MSG_RESULT(no)
+# if test ! "${LDFLAGS+set}" = set; then
+# LDFLAGS="-s"
+# fi
+fi
+
+if test ! "$ac_test_CFLAGS" = set; then
+ if test x$ac_cv_prog_cc_g = xyes -o x$GCC = x; then
+ CFLAGS="$CFLAGS -g"
+ fi
+fi
+])
+
+
+AC_DEFUN(IRC_SELECT_POLL,
+[AC_MSG_CHECKING([whether select or poll system call will be used])
+AC_CACHE_VAL(irc_cv_select_poll,
+[if test "$irc_cv_sun" != "no" && test "x$irc_cv_solaris_2" = "xno"; then
+ # we don't like SunOS' poll() function
+ irc_cv_select_poll=select
+else
+ if test "$ac_cv_func_poll" = "yes"; then
+ irc_cv_select_poll=poll
+ else
+ irc_cv_select_poll=select
+ fi
+fi])
+
+if test "$irc_cv_select_poll" = "poll"; then
+ AC_MSG_RESULT(poll)
+ AC_DEFINE(USE_POLL)
+ if test ! "$irc_cv_linux" = "no"; then
+ AC_MSG_WARN([Aiiie.. This is linux. poll() is known to be broken for some releases (2.0.x with libc6?). You may want to edit setup.h to undefine USE_POLL])
+ fi
+else
+ AC_MSG_RESULT(select)
+fi
+])
+
+
+AC_DEFUN(IRC_SIGNAL_IMPLEMENTATION,
+[AC_MSG_CHECKING([for signal implementation])
+AC_CACHE_VAL(irc_cv_signal_implementation,
+[if test x$ac_cv_func_sigaction = xyes; then
+ irc_cv_signal_implementation=posix_sigaction
+elif test x$ac_cv_func_sigset = xyes; then
+ irc_cv_signal_implementation=bsd_sigset
+else
+ AC_TRY_RUN([
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+#ifndef SIGCHLD
+#define SIGCHLD SIGCLD
+#endif
+
+int got = 0;
+
+RETSIGTYPE hand()
+{
+ got++;
+}
+
+main()
+{
+ (void)signal(SIGCHLD, hand);
+ kill(getpid(), SIGCHLD);
+ kill(getpid(), SIGCHLD);
+ if (got < 2)
+ exit(1);
+ exit(0);
+}
+],
+ irc_cv_signal_implementation=bsd_signal,
+ irc_cv_signal_implementation=sysv_signal)
+fi
+])
+if test $irc_cv_signal_implementation = posix_sigaction; then
+ AC_MSG_RESULT([using POSIX sigaction])
+ AC_DEFINE(POSIX_SIGNALS)
+elif test $irc_cv_signal_implementation = bsd_sigset; then
+ AC_MSG_RESULT([using BSD sigset])
+ AC_DEFINE(BSD_RELIABLE_SIGNALS)
+ AC_DEFINE(signal, sigset)
+elif test $irc_cv_signal_implementation = bsd_signal; then
+ AC_MSG_RESULT([using reliable BSD signal])
+ AC_DEFINE(BSD_RELIABLE_SIGNALS)
+else
+ AC_MSG_RESULT([using unreliable SystemV signal])
+ AC_DEFINE(SYSV_UNRELIABLE_SIGNALS)
+fi
+])
+
+
+AC_DEFUN(IRC_NON_BLOCKING_SYSTEM,
+[AC_MSG_CHECKING([for a working non-blocking system])
+AC_CACHE_VAL(irc_cv_non_blocking_system,
+[
+changequote(<<, >>)dnl
+irc_precode='#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#if HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#if HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#if HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+RETSIGTYPE alarmed()
+{
+ exit(1);
+}
+
+main()
+{
+ char b[12];
+ struct sockaddr_in x;
+ int f, l = sizeof(x);
+ f = socket(AF_INET, SOCK_DGRAM, 0);
+ if (f >= 0 && !(fcntl(f, F_SETFL, '
+irc_postcode=')))
+ {
+ signal(SIGALRM, alarmed);
+ alarm(3);
+ recvfrom(f, b, 12, 0, &x, &l);
+ alarm(0);
+ exit(0);
+ }
+ exit(1);
+}'
+changequote([, ])dnl
+irc_code_posix="${irc_precode}O_NONBLOCK${irc_postcode}"
+irc_code_bsd="${irc_precode}O_NDELAY${irc_postcode}"
+irc_code_sysv="${irc_precode}FIONBIO${irc_postcode}"
+AC_TRY_RUN($irc_code_posix,
+ irc_cv_non_blocking_system=posix,
+ AC_TRY_RUN($irc_code_bsd,
+ irc_cv_non_blocking_system=bsd,
+ AC_TRY_RUN($irc_code_sysv,
+ irc_cv_non_blocking_system=sysv,
+ irc_cv_non_blocking_system=none)))
+])
+if test $irc_cv_non_blocking_system = posix; then
+ AC_MSG_RESULT([using POSIX O_NONBLOCK])
+ AC_DEFINE(NBLOCK_POSIX)
+elif test $irc_cv_non_blocking_system = bsd; then
+ AC_MSG_RESULT([using BSD O_NDELAY])
+ AC_DEFINE(NBLOCK_BSD)
+elif test $irc_cv_non_blocking_system = sysv; then
+ AC_MSG_RESULT([using SystemV FIONBIO])
+ AC_DEFINE(NBLOCK_SYSV)
+else
+ AC_MSG_RESULT([using none])
+ AC_MSG_WARN([I can't find a working non-blocking system.])
+fi
+])
+
+
+AC_DEFUN(IRC_STDARG,
+[AC_MSG_CHECKING([for working stdarg])
+AC_CACHE_VAL(irc_cv_stdarg,
+AC_TRY_RUN(
+[
+changequote(<<, >>)dnl
+#if HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#if HAVE_STDARG_H
+#include <stdarg.h>
+#endif
+#if HAVE_STRING_H
+#include <string.h>
+#endif
+
+char buf1[256];
+
+int level1(char *data, char *format, va_list ap)
+{
+ return vsprintf(data, format, ap);
+}
+
+int level2(char *data, int rounds, char *format, va_list ap)
+{
+ if(!--rounds)
+ return level1(data, format, ap);
+ else {
+ if(rounds == 2) {
+ va_list ap2 = ap;
+ char *arg = va_arg(ap2, char *);
+ strcpy(buf1, arg);
+ }
+ return level2(data, rounds, format, ap);
+ }
+}
+
+int level3(char *data, char *format, va_list ap)
+{
+ return level2(data, 5, format, ap);
+}
+
+int dotest(int size, char *val, char *data)
+{
+ if(size != strlen(val))
+ return 0;
+ if(strcmp(data, val))
+ return 0;
+ if(strcmp(buf1, "was"))
+ return 0;
+ return 1;
+}
+
+int base(char *val, char *format, ...)
+{
+ int res = 1;
+ char data[256];
+
+ {
+ va_list ap;
+ data[0]=0;
+ va_start(ap, format);
+ res = dotest(level3(data, format, ap), val, data);
+ va_end(ap);
+ }
+
+ {
+ va_list ap;
+ data[0]=0;
+ va_start(ap, format);
+ res = res && dotest(level3(data, format, ap), val, data);
+ va_end(ap);
+ }
+
+ return res;
+}
+
+int main(void)
+{
+ int res = base("toto was here ! 42", "toto %s here ! %d", "was", 42);
+
+ exit(res ? 0 : 1);
+}
+changequote([, ])dnl
+],
+irc_cv_stdarg=yes,
+irc_cv_stdarg=no)
+)
+if test $irc_cv_stdarg = yes; then
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(USE_STDARG)
+else
+ AC_MSG_RESULT(no)
+fi
+])
+
+
+AC_DEFUN(IRC_PATH_RESCONF,
+[AC_MSG_CHECKING([for resolver configuration file])
+AC_CACHE_VAL(irc_cv_path_resconf,
+[if test -z "$irc_resconf"; then
+ irc_cv_path_resconf="/etc/resolv.conf";
+ else
+ irc_cv_path_resconf="$irc_resconf";
+ fi
+])
+AC_MSG_RESULT($irc_cv_path_resconf)
+AC_DEFINE_UNQUOTED(IRC_RESCONF, "$irc_cv_path_resconf")
+if test ! -r "$irc_cv_path_resconf"; then
+ AC_MSG_WARN([Unable to read \"$irc_cv_path_resconf\"! Without resolver configuration file, the server won't work.])
+fi
+])
+
+
+AC_DEFUN(IRC_EGREP_RMLF_CPP,
+[cat > conftest.$ac_ext <<EOF
+[#]line __oline__ "configure"
+#include "confdefs.h"
+[$2]
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&AC_FD_CC |
+ $AWK "{if (NR > 1) printf(\" \"); printf(\[$]0)}" |
+changequote(, )dnl
+ egrep "$1" >/dev/null 2>&1; then
+changequote([, ])dnl
+ ifelse([$3], , :, [rm -rf conftest*
+ $3])
+ifelse([$4], , , [else
+ rm -rf conftest*
+ $4
+])dnl
+fi
+rm -f conftest*
+])
+
+
+AC_DEFUN(IRC_LINUX,
+[AC_MSG_CHECKING(for Linux)
+AC_CACHE_VAL(irc_cv_linux,
+[if test "x`(uname) 2>/dev/null`" = "xLinux"; then
+ IRC_EGREP_RMLF_CPP(
+ [struct( | )+hostent( | )+\{.*const.*h_name],
+ [#include <netdb.h>],
+ irc_cv_linux=bad,
+ irc_cv_linux=good)
+else
+ irc_cv_linux=no
+fi
+])
+if test "$irc_cv_linux" = no; then
+ AC_MSG_RESULT(no)
+elif test "$irc_cv_linux" = good; then
+ AC_MSG_RESULT([yes, with a good <netdb.h> file])
+else
+ AC_MSG_RESULT([yes, with a bad <netdb.h> file])
+ AC_DEFINE(BAD___CONST_NETDB_H)
+fi
+])
+
+
+AC_DEFUN(IRC_IP6,
+[AC_ARG_ENABLE(ip6, [ --enable-ip6 enables IPv6])
+if test "x$enable_ip6" != x; then
+ AC_DEFINE(INET6)
+ dnl be smart about it
+ AC_MSG_CHECKING([IPv6 system type])
+ AC_CACHE_VAL(irc_cv_v6type, [
+ if test -d /usr/inet6; then
+ irc_cv_v6type=linux
+ else
+ AC_EGREP_CPP(yes, [dnl
+#include <netinet/in.h>
+#ifdef IPV6_INRIA_VERSION
+yes
+#endif], irc_cv_v6type=inria,
+ AC_EGREP_CPP(yes, [dnl
+#include <netinet/in.h>
+#ifdef __KAME__
+yes
+#endif], irc_cv_v6type=kame,
+ AC_EGREP_CPP(yes, [dnl
+#include <sys/param.h>
+#ifdef _TOSHIBA_INET6
+yes
+#endif], irc_cv_v6type=toshiba,
+ AC_EGREP_CPP(yes, [dnl
+#include </usr/local/v6/include/sys/types.h>
+#ifdef __V6D__
+yes
+#endif], irc_cv_v6type=v6d,
+ AC_EGREP_CPP(yes, [dnl
+#include <sys/param.h>
+#ifdef _ZETA_MINAMI_INET6
+yes
+#endif], irc_cv_v6type=zeta)))))
+ fi])
+ AC_MSG_RESULT($irc_cv_v6type)
+
+ dnl eventually update LIBS
+ case $irc_cv_v6type in
+ kame)
+ LIBS="-L/usr/local/v6/lib -linet6 $LIBS"
+ CFLAGS="$CFLAGS -I/usr/local/v6/include"
+ ;;
+ linux)
+ LIBS="-L/usr/inet6/lib -linet6 $LIBS"
+ CFLAGS="$CFLAGS -I/usr/inet6/include"
+ ;;
+ toshiba)
+ LIBS="-L/usr/local/v6/lib -linet6 $LIBS"
+ CFLAGS="$CFLAGS -I/usr/local/v6/include"
+ ;;
+ v6d)
+ LIBS="-L/usr/local/v6/lib -lv6 $LIBS"
+ CFLAGS="$CFLAGS -I/usr/local/v6/include"
+ ;;
+ zeta)
+ LIBS="-L/usr/local/v6/lib -linet6 $LIBS"
+ CFLAGS="$CFLAGS -I/usr/local/v6/include"
+ ;;
+ esac
+
+ dnl /etc/resolv.conf check
+ AC_MSG_CHECKING(for IPv6 name server addresses in resolv.conf ($irc_cv_path_resconf))
+ if grep nameserver $irc_cv_path_resconf | grep ':' >/dev/null 2>&1; then
+ AC_MSG_RESULT(yes)
+ AC_MSG_WARN([$irc_cv_path_resconf is not setup correctly.])
+ else
+ AC_MSG_RESULT(no)
+ fi
+fi
+])
+
+
+AC_DEFUN(IRC_SHAREDMODULES,
+[AC_ARG_ENABLE(dsm, [ --enable-dsm enables dynamically shared modules for iauth])
+if test "x$enable_dsm" != x; then
+ AC_DEFINE(USE_DSM)
+dnl AC_CONFIG_HEADER(dl.h)
+ AC_CHECK_HEADERS(dlfcn.h)
+ AC_CHECK_LIB(dl, dlclose, IRC_DLIB="-ldl")
+ AC_SUBST(IRC_DLIB)
+fi
+])
+
+
+dnl -------------------------------------------------------------------
+dnl modified Autoconf tests; their names begin with IRC_ instead of AC_
+dnl -------------------------------------------------------------------
+
+AC_DEFUN(IRC_INIT_PARSE_ARGS,
+[
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+zlib_include=NONE
+zlib_library=NONE
+dnl Installation directory options.
+dnl These are left unexpanded so users can "make install exec_prefix=/foo"
+dnl and all the variables that are supposed to be based on exec_prefix
+dnl by default will actually change.
+dnl Use braces instead of parens because sh, perl, etc. also accept them.
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+logdir='${prefix}/var/log/ircd'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ case "$ac_option" in
+changequote(, )dnl
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+changequote([, ])dnl
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir="$ac_optarg" ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that are not valid shell variable names.
+changequote(, )dnl
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+changequote([, ])dnl
+ AC_MSG_ERROR($ac_feature: invalid feature name)
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+changequote(, )dnl
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+changequote([, ])dnl
+ AC_MSG_ERROR($ac_feature: invalid feature name)
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg" ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he)
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat << EOF
+changequote(, )dnl
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --version print the version of autoconf that created configure
+Directory and file names:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [same as prefix]
+ --bindir=DIR user executables in DIR [EPREFIX/bin]
+ --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
+ --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data in DIR
+ [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data in DIR
+ [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data in DIR[PREFIX/var/run]
+ --includedir=DIR C header files in DIR [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
+ --logdir=DIR log files in DIR [PREFIX/var/log/ircd]
+ --infodir=DIR info documentation in DIR [PREFIX/info]
+ --mandir=DIR man documentation in DIR [PREFIX/man]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM
+ run sed PROGRAM on installed program names
+EOF
+ cat << EOF
+Host type:
+ --build=BUILD configure for building on BUILD [BUILD=HOST]
+ --host=HOST configure for HOST [guessed]
+ --target=TARGET configure for TARGET [TARGET=HOST]
+Features and packages:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --resconf=FILE use FILE as resolver config file [/etc/resolv.conf]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --zlib-prefix=ZDIR zlib installation prefix is ZDIR
+ --zlib-include=ZIDIR zlib include files are in ZIDIR [ZDIR/include]
+ --zlib-library=ZLDIR zlib library files are in ZLDIR [ZDIR/lib]
+changequote([, ])dnl
+EOF
+ if test -n "$ac_help"; then
+ echo "--enable and --with options recognized:$ac_help"
+ fi
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir="$ac_optarg" ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir="$ac_optarg" ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir="$ac_optarg" ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir="$ac_optarg" ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir="$ac_optarg" ;;
+
+ -logdir | --logdir | --logdi | --logd)
+ ac_prev=logdir ;;
+ -logdir=* | --logdir=* | --logdi=* | --logd=*)
+ logdir="$ac_optarg/" ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir="$ac_optarg" ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir="$ac_optarg" ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg" ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix="$ac_optarg" ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix="$ac_optarg" ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name="$ac_optarg" ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -resconf | --resconf | --rescon | --resco | --resc | --res \
+ | --re | --r)
+ ac_prev=irc_resconf ;;
+ -resconf=* | --resconf=* | --rescon=* | --resco=* | --resc=* \
+ | --res=* | --re=* | --r=*)
+ irc_resconf="$ac_optarg" ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir="$ac_optarg" ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir="$ac_optarg" ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir="$ac_optarg" ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version AC_ACVERSION"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+changequote(, )dnl
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+changequote([, ])dnl
+ AC_MSG_ERROR($ac_package: invalid package name)
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that are not valid shell variable names.
+changequote(, )dnl
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+changequote([, ])dnl
+ AC_MSG_ERROR($ac_package: invalid package name)
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+ -zlib-prefix | --zlib-prefix | --zlib-prefi | --zlib-pref \
+ | --zlib-pre | --zlib-pr | --zlib-p)
+ ac_prev=irc_zlib_prefix ;;
+ -zlib-prefix=* | --zlib-prefix=* | --zlib-prefi=* | --zlib-pref=* \
+ | --zlib-pre=* | --zlib-pr=* | --zlib-p=*)
+ irc_zlib_prefix="$ac_optarg" ;;
+
+ -zlib-include | --zlib-include | --zlib-includ | --zlib-inclu \
+ | --zlib-incl | --zlib-inc | --zlib-in | --zlib-i)
+ ac_prev=irc_zlib_include ;;
+ -zlib-include=* | --zlib-include=* | --zlib-includ=* | --zlib-inclu=* \
+ | --zlib-incl=* | --zlib-inc=* | --zlib-in=* | --zlib-i=*)
+ irc_zlib_include="$ac_optarg" ;;
+
+ -zlib-library | --zlib-library | --zlib-librar | --zlib-libra | --zlib-libr \
+ | --zlib-lib | --zlib-li | --zlib-l)
+ ac_prev=irc_zlib_library ;;
+ -zlib-library=* | --zlib-library=* | --zlib-librar=* | --zlib-libra=* \
+ | --zlib-libr=* | --zlib-lib=* | --zlib-li=* | --zlib-l=*)
+ irc_zlib_library="$ac_optarg" ;;
+
+ -*) AC_MSG_ERROR([$ac_option: invalid option; use --help to show usage])
+ ;;
+
+ *)
+changequote(, )dnl
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+changequote([, ])dnl
+ AC_MSG_WARN($ac_option: invalid host type)
+ fi
+ if test "x$nonopt" != xNONE; then
+ AC_MSG_ERROR(can only configure for one host and one target at a time)
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ AC_MSG_ERROR(missing argument to --`echo $ac_prev | sed 's/_/-/g'`)
+fi
+
+AC_SUBST(logdir)
+])
+
+
+AC_DEFUN(IRC_INIT,
+[sinclude(acsite.m4)dnl
+sinclude(./aclocal.m4)dnl
+AC_REQUIRE([AC_INIT_BINSH])dnl
+AC_INIT_NOTICE
+AC_DIVERT_POP()dnl to NORMAL
+AC_DIVERT_PUSH(AC_DIVERSION_INIT)dnl
+IRC_INIT_PARSE_ARGS
+AC_INIT_PREPARE($1)dnl
+AC_DIVERT_POP()dnl to NORMAL
+])
+
+
+AC_DEFUN(IRC_PROG_INSTALL,
+[define(AC_PROVIDE_AC_PROG_INSTALL)
+AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX v4 /usr/bin/installbsd, which does not work if the user is not root
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+AC_MSG_CHECKING(for a BSD compatible install)
+if test -z "$INSTALL"; then
+AC_CACHE_VAL(ac_cv_path_install,
+[ IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ # Account for people who put trailing slashes in PATH elements.
+ case "$ac_dir/" in
+ /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ for ac_prog in ginstall installbsd scoinst install; do
+ if test -f $ac_dir/$ac_prog; then
+ if test $ac_prog = install &&
+ grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ # OSF/1 installbsd also uses dspmsg, but is usable.
+ :
+ elif test $ac_prog = installbsd -a "x`(uname -sv) 2>/dev/null`" = "xAIX 4"; then
+ # AIX v4 installbsd. Does not work if the user is not root.
+ :
+ else
+ ac_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+ IFS="$ac_save_IFS"
+])dnl
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL="$ac_cv_path_install"
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL="$ac_install_sh"
+ fi
+fi
+dnl We do special magic for INSTALL instead of AC_SUBST, to get
+dnl relative paths right.
+AC_MSG_RESULT($INSTALL)
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+AC_SUBST(INSTALL_PROGRAM)dnl
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+AC_SUBST(INSTALL_DATA)dnl
+])
+
+AC_DEFUN(IRC_CYGWIN,
+[AC_CYGWIN
+if test ! -z "$CYGWIN"; then
+ if test ! -x /bin/mv || test ! -x /bin/rm || test ! -x /bin/sh; then
+ AC_MSG_ERROR([mv, rm and/or sh is missing from /bin])
+ fi
+ AC_MSG_WARN([The IRC client and the iauth program do not work under the CYGWIN environment.])
+fi
+])
+
+AC_DEFUN(IRC_PROG_CC,
+[define(AC_PROVIDE_AC_PROG_CC)
+AC_BEFORE([$0], [AC_PROG_CPP])dnl
+AC_CHECK_PROG(CC, gcc, gcc)
+if test -z "$CC"; then
+ AC_CHECK_PROG(CC, cc, cc, , , /usr/ucb/cc)
+ test -z "$CC" && AC_MSG_ERROR([no acceptable cc found in \$PATH])
+fi
+AC_PROG_CC_WORKS
+AC_PROG_CC_GNU
+ac_test_CFLAGS="${CFLAGS+set}"
+if test $ac_cv_prog_gcc = yes; then
+ GCC=yes
+ ac_save_CFLAGS="$CFLAGS"
+ CFLAGS=
+ AC_PROG_CC_G
+ if test "$ac_test_CFLAGS" = set; then
+ CFLAGS="$ac_save_CFLAGS"
+ else
+ CFLAGS="-O2"
+ fi
+else
+ GCC=
+fi
+])
+
+
+AC_DEFUN(IRC_AIX,
+[AC_MSG_CHECKING(for AIX)
+AC_CACHE_VAL(irc_cv_aix,
+[if test "x`(uname) 2>/dev/null`" = "xAIX"; then
+ irc_cv_aix="`uname -rv`"
+else
+ irc_cv_aix=no
+fi
+])
+if test "$irc_cv_aix" = no; then
+ AC_MSG_RESULT(no)
+else
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(_ALL_SOURCE)
+ if test "x$irc_cv_aix" = "x2 3"; then
+ AC_DEFINE(AIX_3_2)
+ fi
+ if test x$CC = xcc; then
+ CFLAGS="$CFLAGS -O3 -qstrict"
+ fi
+fi
+])
+
+
+AC_DEFUN(IRC_CHECK_TYPE,
+[AC_REQUIRE([AC_HEADER_STDC])dnl
+AC_MSG_CHECKING(for $1)
+AC_CACHE_VAL(ac_cv_type_$1,
+[AC_EGREP_CPP(dnl
+changequote(<<,>>)dnl
+<<$1[^a-zA-Z_0-9]>>dnl
+changequote([,]), [
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+#if HAVE_SYS_BITYPES_H
+#include <sys/bitypes.h>
+#endif], ac_cv_type_$1=yes, ac_cv_type_$1=no)])dnl
+AC_MSG_RESULT($ac_cv_type_$1)
+if test $ac_cv_type_$1 = no; then
+ AC_DEFINE($1, $2)
+fi
+])
+
+
+AC_DEFUN(IRC_FUNC_MEMCMP,
+[AC_CACHE_CHECK(for 8-bit clean memcmp, irc_cv_func_memcmp_clean,
+[AC_TRY_RUN([
+main()
+{
+ char c0 = 0x40, c1 = 0x80, c2 = 0x81;
+ exit(memcmp(&c0, &c2, 1) < 0 && memcmp(&c1, &c2, 1) < 0 ? 0 : 1);
+}
+], irc_cv_func_memcmp_clean=yes, irc_cv_func_memcmp_clean=no,
+irc_cv_func_memcmp_clean=no)])
+if test $irc_cv_func_memcmp_clean = no; then
+ AC_DEFINE(MEMCMP_BROKEN)
+fi
+])
+
+
+dnl ----
+dnl main
+dnl ----
+
+AC_REVISION([$Id: configure.in,v 1.46 1999/08/13 17:18:23 kalt Exp $])
+AC_PREREQ(2.13)
+IRC_INIT(../ircd/ircd.c)
+AC_CONFIG_HEADER(setup.h:../support/setup.h.in)
+AC_CONFIG_AUX_DIR(../support)
+AC_VALIDATE_CACHED_SYSTEM_TUPLE()
+
+IRC_PROG_CC
+AC_PROG_CPP
+AC_PROG_AWK
+IRC_PROG_INSTALL
+AC_PATH_PROGS(SUM, md5sum sum cksum, true)
+AC_PROG_GCC_TRADITIONAL
+
+IRC_AIX
+AC_ISC_POSIX
+AC_MINIX
+IRC_SGI_CC
+IRC_HPUX_CC
+IRC_SUN
+IRC_LINUX
+IRC_CYGWIN
+
+AC_HEADER_STDC
+AC_HEADER_SYS_WAIT
+AC_CHECK_HEADERS(stdio.h stdlib.h sys/types.h sys/bitypes.h stddef.h stdarg.h unistd.h ctype.h memory.h ncurses.h curses.h cursesX.h term.h sgtty.h errno.h sys/errno.h sys/syscall.h pwd.h math.h utmp.h fcntl.h signal.h sys/ioctl.h sys/file.h sys/filio.h sys/socket.h sys/stat.h sys/resource.h sys/select.h sys/poll.h stropts.h netdb.h netinet/in.h sys/un.h arpa/inet.h sys/param.h syslog.h sys/syslog.h string.h strings.h sys/time.h time.h sys/times.h netinet/in_systm.h netinfo/ni.h resolv.h arpa/nameser.h)
+IRC_DECL_SYS_ERRLIST
+IRC_DECL_SYS_NERR
+IRC_DECL_ERRNO
+IRC_DECL_H_ERRNO
+AC_HEADER_STAT
+AC_HEADER_TIME
+AC_STRUCT_TM
+AC_TYPE_MODE_T
+AC_TYPE_OFF_T
+AC_TYPE_PID_T
+AC_TYPE_SIGNAL
+AC_TYPE_SIZE_T
+AC_TYPE_UID_T
+IRC_UNION_WAIT
+IRC_CHECK_TYPE(int8_t, char)
+IRC_CHECK_TYPE(u_int8_t, unsigned char)
+IRC_CHECK_TYPE(int16_t, short)
+IRC_CHECK_TYPE(u_int16_t, unsigned short)
+IRC_CHECK_TYPE(int32_t, int)
+IRC_CHECK_TYPE(u_int32_t, unsigned int)
+IRC_CHECK_TYPE(u_char, unsigned char)
+IRC_CHECK_TYPE(u_short, unsigned short)
+IRC_CHECK_TYPE(u_int, unsigned int)
+IRC_CHECK_TYPE(u_long, unsigned long)
+
+AC_C_BIGENDIAN
+AC_C_CONST
+
+AC_CHECK_LIB(crypt, crypt)
+AC_CHECK_LIB(socket, socket)
+AC_CHECK_LIB(nsl, socket)
+
+IRC_PATH_ZLIB
+IRC_CURSES_TERMCAP
+
+AC_FUNC_SETPGRP
+AC_FUNC_SETVBUF_REVERSED
+AC_FUNC_VFORK
+AC_CHECK_FUNCS(setpgrp strchr strrchr memcmp memset memmove memcpy index rindex bcmp bcopy bzero select inet_ntoa inet_aton inet_addr inet_netof getrusage times strerror strtoken strtok sigaction sigset truncate poll vsyslog)
+dnl ---
+dnl Note: additional tests should be performed and used inside the source code
+dnl for the following functions:
+dnl gethostname gettimeofday lrand48 mkdir socket
+dnl ---
+IRC_FUNC_MEMCMP
+IRC_SELECT_POLL
+
+IRC_SIGNAL_IMPLEMENTATION
+IRC_NON_BLOCKING_SYSTEM
+IRC_STDARG
+IRC_PATH_RESCONF
+IRC_IP6
+IRC_SHAREDMODULES
+IRC_ALPHA_BETA
+
+AC_OUTPUT(Makefile:../support/Makefile.in version.c.SH:../ircd/version.c.SH.in sums:../support/sums.in tkconf.h:../support/tkconf.h.dist)
+AC_OUTPUT_COMMANDS(chmod a+x version.c.SH)
diff --git a/support/iauth.conf b/support/iauth.conf
new file mode 100644
index 0000000..c86c379
--- /dev/null
+++ b/support/iauth.conf
@@ -0,0 +1,18 @@
+#
+# Default iauth configuration file
+#
+# $Id: iauth.conf,v 1.2 1999/07/04 22:15:43 kalt Exp $
+#
+
+# If iauth timeouts, then reject user
+notimeout
+# This makes the IRC server require that iauth performs the authentication
+# in order for a new user connection to be accepted
+required
+
+# Perform ident lookups
+module rfc931
+
+# Check and reject open SOCKS proxies
+#module socks
+# option = reject,paranoid
diff --git a/support/install-sh b/support/install-sh
new file mode 100755
index 0000000..5ad826e
--- /dev/null
+++ b/support/install-sh
@@ -0,0 +1,253 @@
+#! /bin/sh
+#
+# $Id: install-sh,v 1.3 1999/01/18 00:24:17 kalt Exp $
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ chmodcmd=""
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
diff --git a/support/mkdirhier b/support/mkdirhier
new file mode 100755
index 0000000..244462a
--- /dev/null
+++ b/support/mkdirhier
@@ -0,0 +1,70 @@
+#!/bin/sh
+# $XConsortium: mkdirhier.sh,v 1.7 94/03/24 15:46:34 gildea Exp $
+# Courtesy of Paul Eggert
+#
+# $Id: mkdirhier,v 1.2 1997/07/22 12:40:10 kalt Exp $
+#
+
+newline='
+'
+IFS=$newline
+
+case ${1--} in
+-*) echo >&2 "mkdirhier: usage: mkdirhier directory ..."; exit 1
+esac
+
+status=
+
+for directory
+do
+ case $directory in
+ '')
+ echo >&2 "mkdirhier: empty directory name"
+ status=1
+ continue;;
+ *"$newline"*)
+ echo >&2 "mkdirhier: directory name contains a newline: \`\`$directory''"
+ status=1
+ continue;;
+ ///*) prefix=/;; # See Posix 2.3 "path".
+ //*) prefix=//;;
+ /*) prefix=/;;
+ -*) prefix=./;;
+ *) prefix=
+ esac
+
+ IFS=/
+ set x $directory
+ case $2 in
+ */*) # IFS parsing is broken
+ IFS=' '
+ set x `echo $directory | tr / ' '`
+ ;;
+ esac
+ IFS=$newline
+ shift
+
+ for filename
+ do
+ path=$prefix$filename
+ prefix=$path/
+ shift
+
+ test -d "$path" || {
+ paths=$path
+ for filename
+ do
+ if [ "$filename" != "." ]; then
+ path=$path/$filename
+ paths=$paths$newline$path
+ fi
+ done
+
+ mkdir $paths || status=$?
+
+ break
+ }
+ done
+ done
+
+exit $status
diff --git a/support/setup.h.in b/support/setup.h.in
new file mode 100644
index 0000000..a01bbc0
--- /dev/null
+++ b/support/setup.h.in
@@ -0,0 +1,413 @@
+/* ../support/setup.h.in. Generated automatically from configure.in by autoheader. */
+
+/* Define if on AIX 3.
+ System headers sometimes define this.
+ We just want to avoid a redefinition error message. */
+#ifndef _ALL_SOURCE
+#undef _ALL_SOURCE
+#endif
+
+/* Define to empty if the keyword does not work. */
+#undef const
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef gid_t
+
+/* Define if system calls automatically restart after interruption
+ by a signal. */
+#undef HAVE_RESTARTABLE_SYSCALLS
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define if you have <vfork.h>. */
+#undef HAVE_VFORK_H
+
+/* Define if on MINIX. */
+#undef _MINIX
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef mode_t
+
+/* Define to `long' if <sys/types.h> doesn't define. */
+#undef off_t
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef pid_t
+
+/* Define if the system does not provide POSIX.1 features except
+ with this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Define if you need to in order for stat and other things to work. */
+#undef _POSIX_SOURCE
+
+/* Define as the return type of signal handlers (int or void). */
+#undef RETSIGTYPE
+
+/* Define if the `setpgrp' function takes no argument. */
+#undef SETPGRP_VOID
+
+/* Define if the setvbuf function takes the buffering type as its second
+ argument and the buffer pointer as the third, as on System V
+ before release 3. */
+#undef SETVBUF_REVERSED
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+#undef size_t
+
+/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly. */
+#undef STAT_MACROS_BROKEN
+
+/* Define if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define if your <sys/time.h> declares struct tm. */
+#undef TM_IN_SYS_TIME
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef uid_t
+
+/* Define vfork as fork if vfork does not work. */
+#undef vfork
+
+/* Define if your processor stores words with the most significant
+ byte first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
+
+/* Define if zlib package must be used for compilation/linking. */
+#undef USE_ZLIB
+
+/* Define if ncurses library must be used for compilation/linking. */
+#undef USE_NCURSES
+
+/* Define if cursesX library must be used for compilation/linking. */
+#undef USE_CURSESX
+
+/* Define if curses library must be used for compilation/linking. */
+#undef USE_CURSES
+
+/* Define if termcap library must be used for compilation/linking. */
+#undef USE_TERMCAP
+
+/* Define if the second argument of waitpid must be an "union wait *" instead
+ of an "int *". */
+#undef USE_UNION_WAIT
+
+/* Define if int8_t, u_int8_t, int16_t, u_int16_t, int32_t, u_int32_t, u_char,
+ * u_short, u_int, u_long are not known types. */
+#undef int8_t
+#undef u_int8_t
+#undef int16_t
+#undef u_int16_t
+#undef int32_t
+#undef u_int32_t
+#undef u_char
+#undef u_short
+#undef u_int
+#undef u_long
+
+/* Define if memcmp is not 8-bit clean. */
+#undef MEMCMP_BROKEN
+
+/* Define if the operating system is AIX 3.2. */
+#undef AIX_3_2
+
+/* Define if the operating system is Solaris 2.x (SunOS 5.x). */
+#undef SOLARIS_2
+
+/* Define if the operating system is Solaris 2.3 (SunOS 5.3). */
+#undef SOLARIS_2_3
+
+/* Define if the operating system is Solaris 2.[0-2] (SunOS 5.[0-2]). */
+#undef SOLARIS_2_0_2_1_2_2
+
+/* Define if <netdb.h> contains bad __const usages (Linux). */
+#undef BAD___CONST_NETDB_H
+
+/* Define if sys_errlist is declared in stdio.h or errno.h. */
+#undef SYS_ERRLIST_DECLARED
+
+/* Define if sys_nerr is declared in stdio.h or errno.h. */
+#undef SYS_NERR_DECLARED
+
+/* Define if errno is declared in errno.h. */
+#undef ERRNO_DECLARED
+
+/* Define if h_errno is declared in errno.h or netdb.h. */
+#undef H_ERRNO_DECLARED
+
+/* Define if poll(2) must be used instead of select(2). */
+/* Note: some systems (e.g. linux 2.0.x) have a non-working poll() */
+#undef USE_POLL
+
+/* Define if the system provides POSIX sigaction. */
+#undef POSIX_SIGNALS
+
+/* Define if the system provides reliable BSD signals through sigset instead
+ of signal. */
+/* #define signal sigset */
+
+/* Define if the system provides reliable BSD signals. */
+#undef BSD_RELIABLE_SIGNALS
+
+/* Define if the system provides unreliable SystemV signals. */
+#undef SYSV_UNRELIABLE_SIGNALS
+
+/* Define if the system provides POSIX non-blocking system. */
+#undef NBLOCK_POSIX
+
+/* Define if the system provides BSD non-blocking system. */
+#undef NBLOCK_BSD
+
+/* Define if the system provides SystemV non-blocking system. */
+#undef NBLOCK_SYSV
+
+/* Define is the system can use variable arguments. */
+#undef USE_STDARG
+
+/* Define as the resolver configuration file. */
+#undef IRC_RESCONF
+
+/* Define to enable IPv6 support */
+#undef INET6
+
+/* Define to enable dynamically shared iauth module support */
+#undef USE_DSM
+
+/* Define if you have the bcmp function. */
+#undef HAVE_BCMP
+
+/* Define if you have the bcopy function. */
+#undef HAVE_BCOPY
+
+/* Define if you have the bzero function. */
+#undef HAVE_BZERO
+
+/* Define if you have the getrusage function. */
+#undef HAVE_GETRUSAGE
+
+/* Define if you have the index function. */
+#undef HAVE_INDEX
+
+/* Define if you have the inet_addr function. */
+#undef HAVE_INET_ADDR
+
+/* Define if you have the inet_aton function. */
+#undef HAVE_INET_ATON
+
+/* Define if you have the inet_netof function. */
+#undef HAVE_INET_NETOF
+
+/* Define if you have the inet_ntoa function. */
+#undef HAVE_INET_NTOA
+
+/* Define if you have the memcmp function. */
+#undef HAVE_MEMCMP
+
+/* Define if you have the memcpy function. */
+#undef HAVE_MEMCPY
+
+/* Define if you have the memmove function. */
+#undef HAVE_MEMMOVE
+
+/* Define if you have the memset function. */
+#undef HAVE_MEMSET
+
+/* Define if you have the poll function. */
+#undef HAVE_POLL
+
+/* Define if you have the rindex function. */
+#undef HAVE_RINDEX
+
+/* Define if you have the select function. */
+#undef HAVE_SELECT
+
+/* Define if you have the setpgrp function. */
+#undef HAVE_SETPGRP
+
+/* Define if you have the sigaction function. */
+#undef HAVE_SIGACTION
+
+/* Define if you have the sigset function. */
+#undef HAVE_SIGSET
+
+/* Define if you have the strchr function. */
+#undef HAVE_STRCHR
+
+/* Define if you have the strerror function. */
+#undef HAVE_STRERROR
+
+/* Define if you have the strrchr function. */
+#undef HAVE_STRRCHR
+
+/* Define if you have the strtok function. */
+#undef HAVE_STRTOK
+
+/* Define if you have the strtoken function. */
+#undef HAVE_STRTOKEN
+
+/* Define if you have the times function. */
+#undef HAVE_TIMES
+
+/* Define if you have the truncate function. */
+#undef HAVE_TRUNCATE
+
+/* Define if you have the vsyslog function. */
+#undef HAVE_VSYSLOG
+
+/* Define if you have the <arpa/inet.h> header file. */
+#undef HAVE_ARPA_INET_H
+
+/* Define if you have the <arpa/nameser.h> header file. */
+#undef HAVE_ARPA_NAMESER_H
+
+/* Define if you have the <ctype.h> header file. */
+#undef HAVE_CTYPE_H
+
+/* Define if you have the <curses.h> header file. */
+#undef HAVE_CURSES_H
+
+/* Define if you have the <cursesX.h> header file. */
+#undef HAVE_CURSESX_H
+
+/* Define if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define if you have the <errno.h> header file. */
+#undef HAVE_ERRNO_H
+
+/* Define if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define if you have the <math.h> header file. */
+#undef HAVE_MATH_H
+
+/* Define if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define if you have the <ncurses.h> header file. */
+#undef HAVE_NCURSES_H
+
+/* Define if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define if you have the <netinet/in_systm.h> header file. */
+#undef HAVE_NETINET_IN_SYSTM_H
+
+/* Define if you have the <netinfo/ni.h> header file. */
+#undef HAVE_NETINFO_NI_H
+
+/* Define if you have the <pwd.h> header file. */
+#undef HAVE_PWD_H
+
+/* Define if you have the <resolv.h> header file. */
+#undef HAVE_RESOLV_H
+
+/* Define if you have the <sgtty.h> header file. */
+#undef HAVE_SGTTY_H
+
+/* Define if you have the <signal.h> header file. */
+#undef HAVE_SIGNAL_H
+
+/* Define if you have the <stdarg.h> header file. */
+#undef HAVE_STDARG_H
+
+/* Define if you have the <stddef.h> header file. */
+#undef HAVE_STDDEF_H
+
+/* Define if you have the <stdio.h> header file. */
+#undef HAVE_STDIO_H
+
+/* Define if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define if you have the <stropts.h> header file. */
+#undef HAVE_STROPTS_H
+
+/* Define if you have the <sys/bitypes.h> header file. */
+#undef HAVE_SYS_BITYPES_H
+
+/* Define if you have the <sys/errno.h> header file. */
+#undef HAVE_SYS_ERRNO_H
+
+/* Define if you have the <sys/file.h> header file. */
+#undef HAVE_SYS_FILE_H
+
+/* Define if you have the <sys/filio.h> header file. */
+#undef HAVE_SYS_FILIO_H
+
+/* Define if you have the <sys/ioctl.h> header file. */
+#undef HAVE_SYS_IOCTL_H
+
+/* Define if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define if you have the <sys/poll.h> header file. */
+#undef HAVE_SYS_POLL_H
+
+/* Define if you have the <sys/resource.h> header file. */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define if you have the <sys/syscall.h> header file. */
+#undef HAVE_SYS_SYSCALL_H
+
+/* Define if you have the <sys/syslog.h> header file. */
+#undef HAVE_SYS_SYSLOG_H
+
+/* Define if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have the <sys/times.h> header file. */
+#undef HAVE_SYS_TIMES_H
+
+/* Define if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define if you have the <sys/un.h> header file. */
+#undef HAVE_SYS_UN_H
+
+/* Define if you have the <syslog.h> header file. */
+#undef HAVE_SYSLOG_H
+
+/* Define if you have the <term.h> header file. */
+#undef HAVE_TERM_H
+
+/* Define if you have the <time.h> header file. */
+#undef HAVE_TIME_H
+
+/* Define if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define if you have the <utmp.h> header file. */
+#undef HAVE_UTMP_H
+
+/* Define if you have the crypt library (-lcrypt). */
+#undef HAVE_LIBCRYPT
+
+/* Define if you have the nsl library (-lnsl). */
+#undef HAVE_LIBNSL
+
+/* Define if you have the socket library (-lsocket). */
+#undef HAVE_LIBSOCKET
diff --git a/support/sums.in b/support/sums.in
new file mode 100644
index 0000000..ff7dffc
--- /dev/null
+++ b/support/sums.in
@@ -0,0 +1,39 @@
+#!/bin/sh
+# trap "" 1 2 3 13 14 15 21 22
+# $Id: sums.in,v 1.1 1998/04/07 20:44:48 kalt Exp $
+trap "" 1 2 3 13 14 15
+/bin/cp hash.c hash.c.old 2>/dev/null
+/bin/mv -f hash.c hash.c.temp 1>/dev/null 2>&1
+csum=`(cd ../ircd; @SUM@ s_bsd.c) 2>/dev/null`
+sed -e "s/SUSER/[${csum}]/g" hash.c.temp > hash.c 2>/dev/null
+/bin/mv -f hash.c hash.c.temp 1>/dev/null 2>&1
+csum=`(cd ../ircd; @SUM@ s_user.c) 2>/dev/null`
+sed -e "s/SSERV/[${csum}]/g" hash.c.temp > hash.c 2>/dev/null
+/bin/mv -f hash.c hash.c.temp 1>/dev/null 2>&1
+csum=`(cd ../ircd; @SUM@ s_serv.c) 2>/dev/null`
+sed -e "s/SBSDC/[${csum}]/g" hash.c.temp > hash.c 2>/dev/null
+/bin/mv -f hash.c hash.c.temp 1>/dev/null 2>&1
+csum=`(cd ../ircd; @SUM@ channel.c) 2>/dev/null`
+sed -e "s/CHANC/[$csum]/g" hash.c.temp > hash.c 2>/dev/null
+/bin/mv -f hash.c hash.c.temp 1>/dev/null 2>&1
+csum=`(cd ../ircd; @SUM@ ircd.c) 2>/dev/null`
+sed -e "s/IRCDC/[$csum]/g" hash.c.temp > hash.c 2>/dev/null
+/bin/mv -f hash.c hash.c.temp 1>/dev/null 2>&1
+csum=`(cd ../ircd; @SUM@ s_misc.c) 2>/dev/null`
+sed -e "s/SMISC/[$csum]/g" hash.c.temp > hash.c 2>/dev/null
+/bin/mv -f hash.c hash.c.temp 1>/dev/null 2>&1
+csum=`@SUM@ hash.c.old 2>/dev/null`
+sed -e "s/HASHC/[$csum]/g" hash.c.temp > hash.c 2>/dev/null
+/bin/mv -f hash.c hash.c.temp 1>/dev/null 2>&1
+csum=`@SUM@ version.c.SH 2>/dev/null`
+sed -e "s/VERSH/[$csum]/g" hash.c.temp > hash.c 2>/dev/null
+/bin/mv -f hash.c hash.c.temp 1>/dev/null 2>&1
+csum=`(cd ../ircd; @SUM@ s_bsd.c) 2>/dev/null`
+sed -e "s/MAKEF/[$csum]/g" hash.c.temp > hash.c 2>/dev/null
+if [ -f /bin/hostid ] ; then
+ /bin/mv -f hash.c hash.c.temp 1>/dev/null 2>&1
+ csum=`hostid 2>/dev/null`
+ sed -e "s/HOSTID/[$csum]/g" hash.c.temp > hash.c 2>/dev/null
+fi
+/bin/rm -f hash.c.temp 1>/dev/null 2>&1
+
diff --git a/support/tkconf.h.dist b/support/tkconf.h.dist
new file mode 100644
index 0000000..3467564
--- /dev/null
+++ b/support/tkconf.h.dist
@@ -0,0 +1,35 @@
+/*
+ * TkServ configuration definitions
+ *
+ * Make sure the ircd conf files are located in the server_bin_dir
+ * (see Makefile) and that USE_SERVICES is #define'd if you intend
+ * to use this service.
+ *
+ */
+
+/* This will be shown on ADMIN requests */
+#define TKSERV_ADMIN_NAME "Admin: Someone Somewhere"
+#define TKSERV_ADMIN_CONTACT "Mail: i.didnt@edit.my.ADMIN.info"
+#define TKSERV_ADMIN_OTHER "SomeAdmin@IRCNet"
+
+/* This is the name of the service which appears on /servlist */
+#define TKSERV_NAME "TkServ"
+
+/* The description of the service (appears on /SERVLIST) */
+#define TKSERV_DESC "Temporary K-line Service"
+
+/* The distribution of the server */
+#define TKSERV_DIST "*"
+
+/* The password for the service (must match the one in the S: line) */
+#define TKSERV_PASSWORD "blah"
+
+/* Debugging (displays service<->server traffic to standard output) */
+#undef TKSERV_DEBUG
+
+/* The name of the ircd config file backup (suffix after CPATH) */
+#define TKSERV_IRCD_CONFIG_BAK CPATH".tkserv"
+
+/* The name of the ircd temp config file (suffix after CPATH) */
+#define TKSERV_IRCD_CONFIG_TMP CPATH".tmp"
+