aboutsummaryrefslogtreecommitdiff
path: root/common/send.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/send.c')
-rw-r--r--common/send.c1555
1 files changed, 1555 insertions, 0 deletions
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 */