/*
 *   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.9 2003/12/09 17:25:09 gvs 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
# endif
		{
			char ebuf[BUFSIZE];

			ebuf[0] = '\0';
			if (IsService(to) || IsServer(to))
			{
				SPRINTF(ebuf,
				"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, ebuf[0] ? ebuf :
				"Max Sendq exceeded");
		}
	}
# 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);

tryagain:
	if (len && (i = dbuf_put(&to->sendQ, msg, len)) < 0)
# else 	/* ZIP_LINKS */
tryagain:
	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", "anonymous.in.IRC", 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) &&
	    !strcasecmp(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,
#ifdef RUSNET_IRCD
						(user->flags & FLAGS_VHOST) ?
#endif
						user->host
#ifdef RUSNET_IRCD
						: from->sockhost
#endif
							);
				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, "@");
#ifdef RUSNET_IRCD
			if (user->flags & FLAGS_VHOST || IsUnixSocket(from))
#else
			if (IsUnixSocket(from))
#endif
				(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 || !strcasecmp(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,
#ifdef RUSNET_IRCD
						(user->flags & FLAGS_VHOST) ?
#endif
							user->host
#ifdef RUSNET_IRCD
							: from->sockhost
#endif
									);
					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, "@");
#ifdef RUSNET_IRCD
				if (user->flags & FLAGS_VHOST || IsUnixSocket(from))
#else
				if (IsUnixSocket(from))
#endif
				    (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

/*
 * sendto_channel_butone
 *
 * Send a message to all members of a channel that are connected to this
 * server except client 'one'.
 */
#ifndef CLIENT_COMPILE
#if ! USE_STDARG
/*VARARGS*/
void	sendto_channel_butone(one, from, chptr, ops, pattern,
			      p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11)
aClient *one, *from;
aChannel *chptr;
int	ops;
char	*pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11;
#else
void	sendto_channel_butone(aClient *one, aClient *from, aChannel *chptr,
						int ops, 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 && !strcasecmp(p1, from->name))
			p1 = anon.name;
#endif
		lfrm = &anon;
	    }

	if (one != from && MyConnect(from) && IsRegisteredUser(from))
	    {
		/* useless junk? */ /* who said that and why? --B. */
#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 */
		/* for ops only: get user flags and check it */
		if (ops && !IsServer(acptr))
		    {
			Reg Link *tmp = find_user_link(chptr->members, acptr);

			if (!tmp)	/* this should NOT happen but... */
				continue;

			if (!(tmp->flags & CHFL_CHANOP))
				continue;
		    }
		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->clist;lp;
			     lp=lp->next)
			    {
				cptr = lp->value.cptr;
				if (user == cptr)
					continue;
				if (!cptr->user || 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 && !strcasecmp(p1, from->name))
			p1 = anon.name;
#endif
		lfrm = &anon;
	    }

	for (lp = chptr->clist; 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:
#ifdef RUSNET_IRCD
		return (match(mask, one->sockhost) == 0);
#else
		return (match(mask, one->user->host) == 0);
#endif
	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;
#ifdef NOWALLOPS_TO_USERS
               if (IsPerson(cptr) && !IsAnOper(cptr))
                       continue;
#endif
		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 },
#ifdef EXTRA_NOTICES
	{ SCH_OPER,	"&OPER",	NULL },
#endif
};


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);
}

#ifdef	LOG_EVENTS
static int killlog;
static int userlog;
static int connlog;
static int locallog;
static int authlog;
static int noticelog;
static int errorlog;	/* last resort */
#endif

/*
 * sendto_log
 *	type		message type/syslog severity
 *	source		message source
 *	channel		message channel (e.g. &ERRORS)
 *	msg		message itself
 */
void	sendto_log(type, source, channel, msg)
int		type;
const char	*source, *channel, *msg;
{
#ifdef LOG_EVENTS
	int	l
#ifdef	USE_SYSLOG
		  , s = LOG_INFO
#endif
				;

	switch (type) {
#ifdef SVLOG_KILL
	case SVLOG_KILL:	l = killlog;
#ifdef	SYSLOG_KILL
				s = SYSLOG_KILL;
#endif
				break;
#endif
#ifdef SVLOG_NOTICES
	case SVLOG_NOTICES:	l = noticelog;
#ifdef	SYSLOG_NOTICES
				s = SYSLOG_NOTICES;
#endif
				break;
#endif
#ifdef SVLOG_LOCAL
	case SVLOG_LOCAL:	l = locallog;
#ifdef	SYSLOG_LOCAL
				s = SYSLOG_LOCAL;
#endif
				break;
#endif
#ifdef SVLOG_AUTH
	case SVLOG_AUTH:	l = userlog;
#ifdef	SYSLOG_AUTH
				s = SYSLOG_AUTH;
#endif
				break;
#endif
#ifdef SVLOG_ERRS
	case SVLOG_ERRS:
#endif
	default:	l = errorlog;
#ifdef	SYSLOG_ERRS
			s = SYSLOG_ERRS;
#endif
	}

#ifdef USE_SYSLOG
	syslog(s, "%s: %s: %s", source, channel, msg);
#endif
	if (l != -1)
	{
		char *buf = MyMalloc(strlen(source) + strlen(channel) +
							strlen(msg) + 26);
		time_t	t = time(NULL);
		int	i = strftime(buf, 20, "%b %e %T ", localtime( &t ) );

		i += sprintf(buf + i, "%s: %s: %s\n", source, channel, msg);

		(void)write(l, buf, i);

		MyFree(buf);
	}
#endif	/* LOG_EVENTS */
}

#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 LOG_EVENTS
		switch (chan) {
#ifdef SVLOG_ERRS
		case SCH_ERROR:
			sendto_log(SVLOG_ERRS, ME, chptr->chname, nbuf);
			break;
#endif
#ifdef SVLOG_NOTICES
		case SCH_NOTICE:
			sendto_log(SVLOG_NOTICES, ME, chptr->chname, nbuf);
			break;
#endif
#ifdef SVLOG_KILL
		case SCH_KILL:
			sendto_log(SVLOG_KILL, ME, chptr->chname, nbuf);
			break;
#endif
#ifdef SVLOG_LOCAL
		case SCH_LOCAL:
			sendto_log(SVLOG_LOCAL, ME, chptr->chname, nbuf);
			break;
#endif
#ifdef SVLOG_AUTH
		case SCH_AUTH:
			sendto_log(SVLOG_AUTH, ME, chptr->chname, nbuf);
			break;
#endif
		}
#endif	/* LOG_EVENTS */

#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;
}

void
logfiles_open()
{
#ifdef	LOG_EVENTS
#ifdef  FNAME_KILLLOG
	killlog = open(LOG_DIR "/" FNAME_KILLLOG, O_WRONLY|O_APPEND|O_NDELAY);
#else
	killlog = -1;
#endif
#ifdef  FNAME_USERLOG
	userlog = open(LOG_DIR "/" FNAME_USERLOG, O_WRONLY|O_APPEND|O_NDELAY);
#else
	userlog = -1;
#endif
#ifdef  FNAME_CONNLOG
	connlog = open(LOG_DIR "/" FNAME_CONNLOG, O_WRONLY|O_APPEND|O_NDELAY);
#else
	connlog = -1;
#endif
#ifdef  FNAME_LOCALLOG
	locallog = open(LOG_DIR "/" FNAME_LOCALLOG, O_WRONLY|O_APPEND|O_NDELAY);
#else
	locallog = -1;
#endif
#ifdef  FNAME_ERRORLOG
	errorlog = open(LOG_DIR "/" FNAME_ERRORLOG, O_WRONLY|O_APPEND|O_NDELAY);
#else
	errorlog = -1;
#endif
#ifdef  FNAME_NOTICELOG
	noticelog = open(LOG_DIR "/" FNAME_NOTICELOG, O_WRONLY|O_APPEND|O_NDELAY);
#else
	noticelog = -1;
#endif
#endif
}

void
logfiles_close()
{
#ifdef	LOG_EVENTS
#ifdef FNAME_KILLLOG
	if (killlog != -1)
		(void)close(killlog);
#endif
#ifdef FNAME_USERLOG
	if (userlog != -1)
		(void)close(userlog);
#endif
#ifdef FNAME_CONNLOG
	if (connlog != -1)
		(void)close(connlog);
#endif
#ifdef FNAME_LOCALLOG
	if (locallog != -1)
		(void)close(locallog);
#endif
#ifdef FNAME_ERRORLOG
	if (errorlog != -1)
		(void)close(errorlog);
#endif
#ifdef FNAME_NOTICELOG
	if (noticelog != -1)
		(void)close(noticelog);
#endif
#endif
}


/*
 * sendto_flog
 *	cptr		used for firsttime, auth, exitc, send/received M/K
 *	msg		if this contains a message, it means rejected client,
 *			hence we will log it in connlog; otherwise it's client
 *			quitting, so it ends up in userlog --Beeth
 *	username	can't get it from cptr
 *	hostname	i.e.
 */
void	sendto_flog(cptr, msg, username, hostname)
aClient	*cptr;
char	*msg, *username, *hostname;
{
#ifdef LOG_EVENTS
	/* 
	** One day we will rewrite linebuf to malloc()s, but for now
	** we are lazy. The longest linebuf I saw during last year
	** was 216. Max auth reply can be 1024, see rfc931_work() and
	** if iauth is disabled, read_authports() makes it max 513.
	** And the rest... just count, I got 154 --Beeth
	*/
	char	linebuf[1500];
	/*
	** This is a potential buffer overflow.
	** I mean, when you manage to keep ircd
	** running for almost 12 years ;-) --B.
	*/
	char	buf[12], *s;
	int	logfile;

	logfile = msg ? connlog : userlog;

#if !defined(USE_SERVICES) && !( defined(USE_SYSLOG) && \
	(defined(SVLOG_USERS) || defined(SVLOG_CONN)) )
	if (logfile == -1)
		return;
#endif
	if (!msg)
	{
		time_t	duration;

		duration = timeofday - cptr->firsttime + 1;
		(void)sprintf(buf, "%3d:%02d:%02d",
			(int) (duration / 3600),
			(int) ((duration % 3600) / 60),
			(int) (duration % 60));
	}

	/*
	** Aha, cptr->firsttime is time when user connected,
	** so we syslog() it anyway. I'm waving big
	** "rewrite log format" flag --Beeth.
	*/
	(void)sprintf(linebuf,
		"%s (%s): %s@%s [%s] %c %lu %luKb %lu %luKb\n",
		myctime(cptr->firsttime), msg ? msg : buf,
		username, hostname, cptr->auth,
		cptr->exitc, cptr->sendM, cptr->sendK,
		cptr->receiveM, cptr->receiveK);

#if defined(USE_SYSLOG) && (defined(SVLOG_USERS) || defined(SVLOG_CONN))
	for (s = linebuf; *s != '('; s++); 
	syslog(LOG_NOTICE, "%s", s);
#endif

#ifdef	USE_SERVICES
	if (!msg)
		check_services_butone(SERVICE_WANT_USERLOG, NULL, &me,
				      "USERLOG :%s", linebuf);
	else
		check_services_butone(SERVICE_WANT_CONNLOG, NULL, &me,
				      "CONNLOG :%s", linebuf);
#endif
	if (logfile != -1)
		(void)write(logfile, linebuf, strlen(linebuf));
#endif /* LOG_EVENTS */
}
#endif /* CLIENT_COMPILE */


syntax highlighted by Code2HTML, v. 0.9.1