From 4440a86cfa359b8e40a484a2cd46d33db5455d8a Mon Sep 17 00:00:00 2001 From: Jonas Gunz Date: Mon, 25 May 2020 20:09:04 +0200 Subject: Initial --- common/bsd.c | 192 +++++++ common/bsd_ext.h | 41 ++ common/class_def.h | 58 ++ common/common_def.h | 88 +++ common/dbuf.c | 532 +++++++++++++++++ common/dbuf_def.h | 96 ++++ common/dbuf_ext.h | 49 ++ common/match.c | 314 ++++++++++ common/match_ext.h | 43 ++ common/msg_def.h | 77 +++ common/numeric_def.h | 337 +++++++++++ common/os.h | 765 +++++++++++++++++++++++++ common/packet.c | 197 +++++++ common/packet_ext.h | 32 ++ common/parse.c | 786 +++++++++++++++++++++++++ common/parse_ext.h | 56 ++ common/patchlevel.h | 22 + common/send.c | 1555 ++++++++++++++++++++++++++++++++++++++++++++++++++ common/send_ext.h | 82 +++ common/struct_def.h | 832 +++++++++++++++++++++++++++ common/support.c | 1190 ++++++++++++++++++++++++++++++++++++++ common/support_def.h | 28 + common/support_ext.h | 80 +++ 23 files changed, 7452 insertions(+) create mode 100644 common/bsd.c create mode 100644 common/bsd_ext.h create mode 100644 common/class_def.h create mode 100644 common/common_def.h create mode 100644 common/dbuf.c create mode 100644 common/dbuf_def.h create mode 100644 common/dbuf_ext.h create mode 100644 common/match.c create mode 100644 common/match_ext.h create mode 100644 common/msg_def.h create mode 100644 common/numeric_def.h create mode 100644 common/os.h create mode 100644 common/packet.c create mode 100644 common/packet_ext.h create mode 100644 common/parse.c create mode 100644 common/parse_ext.h create mode 100644 common/patchlevel.h create mode 100644 common/send.c create mode 100644 common/send_ext.h create mode 100644 common/struct_def.h create mode 100644 common/support.c create mode 100644 common/support_def.h create mode 100644 common/support_ext.h (limited to 'common') 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); +** +** 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 +#endif + +#if HAVE_STDLIB_H +# include +#endif + +#if HAVE_SYS_TYPES_H +# include +#endif + +#if HAVE_SYS_BITYPES_H +# include +#endif + +#if HAVE_STDDEF_H +# include +#endif + +#if USE_STDARG +# include +#endif + +#if HAVE_UNISTD_H +# include +#endif + +#if HAVE_CTYPE_H +# include +#endif + +#if HAVE_MEMORY_H +# include +#endif + +#if HAVE_VFORK_H +# include +#endif + +#if HAVE_ERRNO_H +# include +#endif + +#if HAVE_SYS_ERRNO_H +# include +#endif + +#if HAVE_SYS_SYSCALL_H +# include +#endif + +#if HAVE_PWD_H +# include +#endif + +#if HAVE_MATH_H +# include +#endif + +#if HAVE_UTMP_H +# include +#endif + +#if HAVE_FCNTL_H +# include +#endif + +#if HAVE_SIGNAL_H +# include +#endif + +#if HAVE_SYS_WAIT_H +# include +#endif + +#if HAVE_SYS_IOCTL_H +# include +#endif + +#if HAVE_SYS_FILE_H +# include +#endif + +#if HAVE_SYS_FILIO_H +# include +#endif + +#if HAVE_SYS_SOCKET_H +# include +#endif + +#if HAVE_SYS_STAT_H +# include +#endif + +#if HAVE_SYS_SELECT_H +# include +#endif + +#if HAVE_SYS_POLL_H +# if linux +/* Linux is just soooo broken */ +# define _GNU_SOURCE 1 +# endif +# include +# 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 +#endif + +#if HAVE_NETDB_H +# if BAD___CONST_NETDB_H +# ifndef __const +# define __const +# include +# undef __const +# else +# include +# endif +# else +# include +# endif +#endif + +#if HAVE_NETINET_IN_H +# include +#endif + +#if HAVE_SYS_UN_H +# include +#endif + +#if HAVE_ARPA_INET_H +# include +#endif + +#if HAVE_SYS_PARAM_H +# include +#endif + +#if HAVE_SYS_SYSLOG_H +# include +#else +# if HAVE_SYSLOG_H +# include +# endif +#endif + +#if HAVE_STRING_H +# include +#else +# if HAVE_STRINGS_H +# include +# endif +#endif + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#if HAVE_SYS_RESOURCE_H +# include +#endif + +#if HAVE_SYS_TIMES_H +# include +#endif + +#if HAVE_NETINET_IN_SYSTM_H +# include +#endif + +#if HAVE_NETINFO_NI_H +# include +#endif + +#if USE_ZLIB && !defined(CLIENT_COMPILE) && !defined(CHKCONF_COMPILE) && \ + !defined(CONTRIB_COMPILE) +# include +#endif + +#if defined(INET6) && defined(CLIENT_COMPILE) +# if (defined(linux) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__osf__)) && \ + HAVE_RESOLV_H +# include +# endif +# if HAVE_ARPA_NAMESER_H +# include +# endif +#endif + +#if defined(HAVE_DLFCN_H) +# include +#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 +# include +# include +# include +#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 +# endif +# if (USE_NCURSES || USE_CURSES) && HAVE_CURSES_H +# if HAVE_NCURSES_H +# include +# else +# include +# endif +# endif +#else +# undef DOCURSES +#endif /* USE_NCURSES || ... */ + +#if USE_TERMCAP +# define DOTERMCAP +# if HAVE_SGTTY_H +# include +# 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 */ +# define NETDB_INTERNAL -1 /* but not in every vendors' */ +#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 */ + +/* POSIX.1 portability problems - HAVE_SYS_WAIT_H is defined + * only if 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 + +/* 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 . + */ + +#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> * + * <# of users>) * 2 + * pool= * + */ +#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 -- cgit v1.2.3