aboutsummaryrefslogtreecommitdiff
path: root/common
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 /common
downloadircd-4440a86cfa359b8e40a484a2cd46d33db5455d8a.tar.gz
Initial
Diffstat (limited to 'common')
-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
23 files changed, 7452 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