mirror of
https://github.com/unrealircd/unrealircd.git
synced 2026-06-28 20:46:38 +02:00
1817 lines
42 KiB
C
1817 lines
42 KiB
C
/*
|
|
* Unreal Internet Relay Chat Daemon, src/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.
|
|
*/
|
|
|
|
/* -- Jto -- 16 Jun 1990
|
|
* Added Armin's PRIVMSG patches...
|
|
*/
|
|
|
|
#ifndef lint
|
|
static char sccsid[] =
|
|
"@(#)send.c 2.32 2/28/94 (C) 1988 University of Oulu, Computing Center and Jarkko Oikarinen";
|
|
#endif
|
|
|
|
#include "struct.h"
|
|
#include "common.h"
|
|
#include "sys.h"
|
|
#include "h.h"
|
|
#include "msg.h"
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#ifdef _WIN32
|
|
#include <io.h>
|
|
#endif
|
|
#include <string.h>
|
|
|
|
void vsendto_one(aClient *to, char *pattern, va_list vl);
|
|
void sendbufto_one(aClient *to);
|
|
extern int sendanyways;
|
|
#ifndef NO_FDLIST
|
|
extern fdlist serv_fdlist;
|
|
extern fdlist oper_fdlist;
|
|
#endif
|
|
|
|
#define NEWLINE "\r\n"
|
|
|
|
static char sendbuf[2048];
|
|
static char tcmd[1024];
|
|
static char ccmd[1024];
|
|
|
|
static int send_message PROTO((aClient *, char *, int));
|
|
|
|
static int sentalong[MAXCONNECTIONS];
|
|
|
|
void vsendto_prefix_one(struct Client *to, struct Client *from,
|
|
const char *pattern, va_list vl);
|
|
|
|
int sentalong_marker;
|
|
|
|
/*
|
|
** 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. I 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;
|
|
{
|
|
to->flags |= FLAGS_DEADSOCKET;
|
|
/*
|
|
* If because of BUFFERPOOL problem then clean dbuf's now so that
|
|
* notices don't hurt operators below.
|
|
*/
|
|
DBufClear(&to->recvQ);
|
|
DBufClear(&to->sendQ);
|
|
if (!IsPerson(to) && !IsUnknown(to) && !(to->flags & FLAGS_CLOSING))
|
|
(void)sendto_failops_whoare_opers(notice, get_client_name(to, FALSE),
|
|
#ifndef _WIN32
|
|
strerror(errno));
|
|
#else
|
|
strerror(WSAGetLastError()));
|
|
#endif
|
|
|
|
Debug((DEBUG_ERROR, notice, get_client_name(to, FALSE)));
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
** 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 cant send it, it goes into the sendQ
|
|
** -avalon
|
|
*/
|
|
void flush_connections(aClient* cptr)
|
|
{
|
|
int i;
|
|
aClient *acptr;
|
|
|
|
if (&me == cptr)
|
|
{
|
|
for (i = LastSlot; i >= 0; i--)
|
|
if ((acptr = local[i]) && !(acptr->flags & FLAGS_BLOCKED)
|
|
&& DBufLength(&cptr->sendQ) > 0)
|
|
send_queued(cptr);
|
|
}
|
|
else if (cptr->fd >= 0 && !(cptr->flags & FLAGS_BLOCKED)
|
|
&& DBufLength(&cptr->sendQ) > 0)
|
|
send_queued(cptr);
|
|
|
|
}
|
|
/* flush an fdlist intelligently */
|
|
#ifndef NO_FDLIST
|
|
void flush_fdlist_connections(fdlist * listp)
|
|
{
|
|
int i, fd;
|
|
aClient *cptr;
|
|
|
|
for (fd = listp->entry[i = 1]; i <= listp->last_entry;
|
|
fd = listp->entry[++i])
|
|
if ((cptr = local[fd]) && !(cptr->flags & FLAGS_BLOCKED)
|
|
&& DBufLength(&cptr->sendQ) > 0)
|
|
send_queued(cptr);
|
|
}
|
|
#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;
|
|
|
|
if (IsBlocked(to))
|
|
return; /* Can't write to already blocked socket */
|
|
|
|
/*
|
|
** 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;
|
|
}
|
|
while (DBufLength(&to->sendQ) > 0)
|
|
{
|
|
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 (%s)");
|
|
(void)dbuf_delete(&to->sendQ, rlen);
|
|
to->lastsq = DBufLength(&to->sendQ) / 1024;
|
|
if (rlen < len)
|
|
{
|
|
/* If we can't write full message, mark the socket
|
|
* as "blocking" and stop trying. -Donwulff */
|
|
SetBlocked(to);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (IsDead(to)) ? -1 : 0;
|
|
}
|
|
|
|
/*
|
|
* send message to single client
|
|
*/
|
|
void sendto_one(aClient *to, char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
va_start(vl, pattern);
|
|
vsendto_one(to, pattern, vl);
|
|
va_end(vl);
|
|
}
|
|
|
|
void vsendto_one(aClient *to, char *pattern, va_list vl)
|
|
{
|
|
ircvsprintf(sendbuf, pattern, vl);
|
|
sendbufto_one(to);
|
|
}
|
|
|
|
|
|
void sendbufto_one(aClient *to)
|
|
{
|
|
int len;
|
|
|
|
Debug((DEBUG_ERROR, "Sending [%s] to %s", sendbuf, to->name));
|
|
|
|
if (to->from)
|
|
to = to->from;
|
|
if (IsDead(to))
|
|
return; /* This socket has already
|
|
been marked as dead */
|
|
if (to->fd < 0)
|
|
{
|
|
/* This is normal when 'to' was being closed (via exit_client
|
|
* and close_connection) --Run
|
|
* Print the debug message anyway...
|
|
*/
|
|
Debug((DEBUG_ERROR,
|
|
"Local socket %s with negative fd %d... AARGH!", to->name,
|
|
to->fd));
|
|
return;
|
|
}
|
|
|
|
len = strlen(sendbuf);
|
|
if (sendbuf[len - 1] != '\n')
|
|
{
|
|
if (len > 510)
|
|
len = 510;
|
|
sendbuf[len++] = '\r';
|
|
sendbuf[len++] = '\n';
|
|
sendbuf[len] = '\0';
|
|
}
|
|
|
|
if (IsMe(to))
|
|
{
|
|
char tmp_sendbuf[sizeof(sendbuf)];
|
|
|
|
strcpy(tmp_sendbuf, sendbuf);
|
|
sendto_ops("Trying to send [%s] to myself!", tmp_sendbuf);
|
|
return;
|
|
}
|
|
if (DBufLength(&to->sendQ) > get_sendq(to))
|
|
{
|
|
if (IsServer(to))
|
|
sendto_ops("Max SendQ limit exceeded for %s: "
|
|
"%lu > %lu",
|
|
get_client_name(to, FALSE), DBufLength(&to->sendQ),
|
|
get_sendq(to));
|
|
dead_link(to, "Max SendQ exceeded");
|
|
return;
|
|
}
|
|
|
|
if (!dbuf_put(&to->sendQ, sendbuf, len))
|
|
{
|
|
dead_link(to, "Buffer allocation error");
|
|
return;
|
|
}
|
|
/*
|
|
* 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->listener != &me)
|
|
to->listener->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);
|
|
}
|
|
|
|
void sendto_channel_butone(aClient *one, aClient *from, aChannel *chptr,
|
|
char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
Member *lp;
|
|
aClient *acptr;
|
|
int i;
|
|
|
|
va_start(vl, pattern);
|
|
|
|
++sentalong_marker;
|
|
for (lp = chptr->members; lp; lp = lp->next)
|
|
{
|
|
acptr = lp->cptr;
|
|
/* ...was the one I should skip */
|
|
if (acptr->from == one || (IsDeaf(acptr)
|
|
&& !(sendanyways == 1)))
|
|
continue;
|
|
if (MyConnect(acptr)) /* (It is always a client) */
|
|
vsendto_prefix_one(acptr, from, pattern, vl);
|
|
else if (sentalong[(i = acptr->from->fd)] != sentalong_marker)
|
|
{
|
|
sentalong[i] = sentalong_marker;
|
|
/*
|
|
* Burst messages comes here..
|
|
*/
|
|
vsendto_prefix_one(acptr, from, pattern, vl);
|
|
}
|
|
}
|
|
va_end(vl);
|
|
}
|
|
|
|
void sendto_channelprefix_butone(aClient *one, aClient *from, aChannel *chptr,
|
|
int prefix,
|
|
char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
Member *lp;
|
|
aClient *acptr;
|
|
int i;
|
|
|
|
va_start(vl, pattern);
|
|
for (i = 0; i < MAXCONNECTIONS; i++)
|
|
sentalong[i] = 0;
|
|
for (lp = chptr->members; lp; lp = lp->next)
|
|
{
|
|
acptr = lp->cptr;
|
|
if (acptr->from == one)
|
|
continue; /* ...was the one I should skip
|
|
or user not not a channel op */
|
|
if ((prefix & 0x1) && (lp->flags & CHFL_HALFOP))
|
|
goto good;
|
|
if ((prefix & 0x2) && (lp->flags & CHFL_VOICE))
|
|
goto good;
|
|
if ((prefix & 0x4) && (lp->flags & CHFL_CHANOP))
|
|
goto good;
|
|
bad:
|
|
continue;
|
|
good:
|
|
|
|
i = acptr->from->fd;
|
|
if (MyConnect(acptr) && IsRegisteredUser(acptr))
|
|
{
|
|
vsendto_prefix_one(acptr, from, pattern, vl);
|
|
sentalong[i] = 1;
|
|
}
|
|
else
|
|
{
|
|
/* Now check whether a message has been sent to this
|
|
* remote link already */
|
|
if (sentalong[i] == 0)
|
|
{
|
|
vsendto_prefix_one(acptr, from, pattern, vl);
|
|
sentalong[i] = 1;
|
|
}
|
|
}
|
|
}
|
|
va_end(vl);
|
|
return;
|
|
}
|
|
|
|
void sendto_channelprefix_butone_tok(aClient *one, aClient *from, aChannel *chptr,
|
|
int prefix,
|
|
char *cmd, char *tok, char *nick, char *text)
|
|
{
|
|
Member *lp;
|
|
aClient *acptr;
|
|
int i;
|
|
|
|
sprintf(tcmd, ":%s %s %s :%s", from->name, tok, nick, text);
|
|
sprintf(ccmd, ":%s %s %s :%s", from->name, cmd, nick, text);
|
|
for (i = 0; i < MAXCONNECTIONS; i++)
|
|
sentalong[i] = 0;
|
|
for (lp = chptr->members; lp; lp = lp->next)
|
|
{
|
|
acptr = lp->cptr;
|
|
if (acptr->from == one)
|
|
continue; /* ...was the one I should skip
|
|
or user not not a channel op */
|
|
if (prefix == 0)
|
|
goto good;
|
|
if ((prefix & 0x1) && (lp->flags & CHFL_HALFOP))
|
|
goto good;
|
|
if ((prefix & 0x2) && (lp->flags & CHFL_VOICE))
|
|
goto good;
|
|
if ((prefix & 0x4) && (lp->flags & CHFL_CHANOP))
|
|
goto good;
|
|
bad:
|
|
continue;
|
|
good:
|
|
|
|
i = acptr->from->fd;
|
|
|
|
if (MyConnect(acptr) && IsRegisteredUser(acptr))
|
|
{
|
|
if (IsDeaf(acptr))
|
|
if (!sendanyways)
|
|
continue;
|
|
sendto_prefix_one(acptr, from, ":%s %s %s :%s",
|
|
from->name, cmd, nick, text);
|
|
sentalong[i] = 1;
|
|
}
|
|
else
|
|
{
|
|
if (IsDeaf(acptr))
|
|
if (!sendanyways)
|
|
continue;
|
|
/* Now check whether a message has been sent to this
|
|
* remote link already */
|
|
if (sentalong[i] == 0)
|
|
{
|
|
|
|
if (IsToken(acptr->from))
|
|
sendto_one(acptr, "%s", tcmd);
|
|
else
|
|
sendto_one(acptr, "%s", ccmd);
|
|
sentalong[i] = 1;
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
sendto_chanops_butone -Stskeeps
|
|
*/
|
|
|
|
void sendto_chanops_butone(aClient *one, aChannel *chptr, char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
Member *lp;
|
|
aClient *acptr;
|
|
|
|
va_start(vl, pattern);
|
|
for (lp = chptr->members; lp; lp = lp->next)
|
|
{
|
|
acptr = lp->cptr;
|
|
if (acptr == one || !(lp->flags & (CHFL_CHANOP|CHFL_CHANOWNER|CHFL_CHANPROT)))
|
|
continue; /* ...was the one I should skip
|
|
or user not not a channel op */
|
|
if (MyConnect(acptr) && IsRegisteredUser(acptr))
|
|
{
|
|
vsendto_one(acptr, pattern, vl);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
* sendto_channelops_butone Added 1 Sep 1996 by Cabal95.
|
|
* Send a message to all OPs in channel chptr that
|
|
* are directly on this server and sends the message
|
|
* on to the next server if it has any OPs.
|
|
*
|
|
* All servers must have this functional ability
|
|
* or one without will send back an error message. -- Cabal95
|
|
*/
|
|
void sendto_channelops_butone(aClient *one, aClient *from, aChannel *chptr,
|
|
char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
Member *lp;
|
|
aClient *acptr;
|
|
int i;
|
|
|
|
va_start(vl, pattern);
|
|
for (i = 0; i < MAXCONNECTIONS; i++)
|
|
sentalong[i] = 0;
|
|
for (lp = chptr->members; lp; lp = lp->next)
|
|
{
|
|
acptr = lp->cptr;
|
|
if (acptr->from == one || !(lp->flags & CHFL_CHANOP))
|
|
continue; /* ...was the one I should skip
|
|
or user not not a channel op */
|
|
i = acptr->from->fd;
|
|
if (MyConnect(acptr) && IsRegisteredUser(acptr))
|
|
{
|
|
vsendto_prefix_one(acptr, from, pattern, vl);
|
|
sentalong[i] = 1;
|
|
}
|
|
else
|
|
{
|
|
/* Now check whether a message has been sent to this
|
|
* remote link already */
|
|
if (sentalong[i] == 0)
|
|
{
|
|
vsendto_prefix_one(acptr, from, pattern, vl);
|
|
sentalong[i] = 1;
|
|
}
|
|
}
|
|
}
|
|
va_end(vl);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* sendto_channelvoice_butone
|
|
* direct port of Cabal95's sendto_channelops_butone
|
|
* to allow for /notice @+#channel messages
|
|
* not exactly the most adventurous coding (made heavy use of copy-paste) <G>
|
|
* but it's needed to avoid mass-msg trigger in script vnotices
|
|
* -DuffJ
|
|
*/
|
|
|
|
void sendto_channelvoice_butone(aClient *one, aClient *from, aChannel *chptr,
|
|
char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
Member *lp;
|
|
aClient *acptr;
|
|
int i;
|
|
|
|
va_start(vl, pattern);
|
|
for (i = 0; i < MAXCONNECTIONS; i++)
|
|
sentalong[i] = 0;
|
|
for (lp = chptr->members; lp; lp = lp->next)
|
|
{
|
|
acptr = lp->cptr;
|
|
if (acptr->from == one || !(lp->flags & CHFL_VOICE))
|
|
continue; /* ...was the one I should skip
|
|
or user not (a channel voice or op) */
|
|
i = acptr->from->fd;
|
|
if (MyConnect(acptr) && IsRegisteredUser(acptr))
|
|
{
|
|
vsendto_prefix_one(acptr, from, pattern, vl);
|
|
sentalong[i] = 1;
|
|
}
|
|
else
|
|
{
|
|
/* Now check whether a message has been sent to this
|
|
* remote link already */
|
|
if (sentalong[i] == 0)
|
|
{
|
|
vsendto_prefix_one(acptr, from, pattern, vl);
|
|
sentalong[i] = 1;
|
|
}
|
|
}
|
|
}
|
|
va_end(vl);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* sendto_channelhalfop_butone
|
|
* direct port of Cabal95's sendto_channelops_butone
|
|
* to allow for /notice @+#channel messages
|
|
* not exactly the most adventurous coding (made heavy use of copy-paste) <G>
|
|
* but it's needed to avoid mass-msg trigger in script hnotices
|
|
* -Stskeeps
|
|
*/
|
|
|
|
void sendto_channelhalfop_butone(aClient *one, aClient *from, aChannel *chptr,
|
|
char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
Member *lp;
|
|
aClient *acptr;
|
|
int i;
|
|
|
|
va_start(vl, pattern);
|
|
for (i = 0; i < MAXCONNECTIONS; i++)
|
|
sentalong[i] = 0;
|
|
for (lp = chptr->members; lp; lp = lp->next)
|
|
{
|
|
acptr = lp->cptr;
|
|
if (acptr->from == one || !(lp->flags & CHFL_HALFOP))
|
|
continue; /* ...was the one I should skip
|
|
or user not (a channel halfop or op) */
|
|
i = acptr->from->fd;
|
|
if (MyConnect(acptr) && IsRegisteredUser(acptr))
|
|
{
|
|
vsendto_prefix_one(acptr, from, pattern, vl);
|
|
sentalong[i] = 1;
|
|
}
|
|
else
|
|
{
|
|
/* Now check whether a message has been sent to this
|
|
* remote link already */
|
|
if (sentalong[i] == 0)
|
|
{
|
|
vsendto_prefix_one(acptr, from, pattern, vl);
|
|
sentalong[i] = 1;
|
|
}
|
|
}
|
|
}
|
|
va_end(vl);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* sendto_server_butone
|
|
*
|
|
* Send a message to all connected servers except the client 'one'.
|
|
*/
|
|
void sendto_serv_butone(aClient *one, char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
int i;
|
|
aClient *cptr;
|
|
#ifndef NO_FDLIST
|
|
int j;
|
|
#endif
|
|
|
|
va_start(vl, pattern);
|
|
#ifdef NO_FDLIST
|
|
for (i = 0; i <= LastSlot; i++)
|
|
#else
|
|
for (i = serv_fdlist.entry[j = 1]; j <= serv_fdlist.last_entry; i = serv_fdlist.entry[++j])
|
|
#endif
|
|
{
|
|
if (!(cptr = local[i]) || (one && cptr == one->from))
|
|
continue;
|
|
#ifdef NO_FDLIST
|
|
if (IsServer(cptr))
|
|
#endif
|
|
vsendto_one(cptr, pattern, vl);
|
|
}
|
|
va_end(vl);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* sendto_server_butone_token
|
|
*
|
|
* Send a message to all connected servers except the client 'one'.
|
|
* with capab to tokenize
|
|
*/
|
|
|
|
void sendto_serv_butone_token(aClient *one, char *prefix, char *command,
|
|
char *token, char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
int i;
|
|
aClient *cptr;
|
|
aClient *acptr;
|
|
#ifndef NO_FDLIST
|
|
int j;
|
|
#endif
|
|
static char buff[1024];
|
|
static char pref[100];
|
|
va_start(vl, pattern);
|
|
|
|
pref[0] = '\0';
|
|
if (strchr(prefix, '.'))
|
|
{
|
|
acptr = (aClient *) find_server_quick(prefix);
|
|
if (acptr->serv->numeric)
|
|
{
|
|
strcpy(pref, base64enc(acptr->serv->numeric));
|
|
}
|
|
}
|
|
strcpy(tcmd, token);
|
|
strcpy(ccmd, command);
|
|
strcat(tcmd, " ");
|
|
strcat(ccmd, " ");
|
|
ircvsprintf(buff, pattern, vl);
|
|
strcat(tcmd, buff);
|
|
strcat(ccmd, buff);
|
|
|
|
#ifdef NO_FDLIST
|
|
for (i = 0; i <= LastSlot; i++)
|
|
#else
|
|
for (i = serv_fdlist.entry[j = 1]; j <= serv_fdlist.last_entry; i = serv_fdlist.entry[++j])
|
|
#endif
|
|
{
|
|
if (!(cptr = local[i]) || (one && cptr == one->from))
|
|
continue;
|
|
#ifdef NO_FDLIST
|
|
if (IsServer(cptr))
|
|
#endif
|
|
if (IsToken(cptr))
|
|
{
|
|
if (SupportNS(cptr) && pref[0])
|
|
{
|
|
sendto_one(cptr, "@%s %s",
|
|
pref, tcmd);
|
|
}
|
|
else
|
|
{
|
|
sendto_one(cptr, ":%s %s",
|
|
prefix, tcmd);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (SupportNS(cptr) && pref[0])
|
|
{
|
|
sendto_one(cptr, "@%s %s",
|
|
pref, ccmd);
|
|
}
|
|
else
|
|
{
|
|
sendto_one(cptr, ":%s %s", prefix,
|
|
ccmd);
|
|
}
|
|
}
|
|
}
|
|
va_end(vl);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* sendto_server_butone_token_opt
|
|
*
|
|
* Send a message to all connected servers except the client 'one'.
|
|
* with capab to tokenize, opt
|
|
*/
|
|
|
|
void sendto_serv_butone_token_opt(aClient *one, int opt, char *prefix, char *command,
|
|
char *token, char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
int i;
|
|
aClient *cptr;
|
|
aClient *acptr;
|
|
#ifndef NO_FDLIST
|
|
int j;
|
|
#endif
|
|
static char tcmd[1024];
|
|
static char ccmd[1024];
|
|
static char buff[1024];
|
|
static char pref[100];
|
|
|
|
va_start(vl, pattern);
|
|
|
|
pref[0] = '\0';
|
|
if (strchr(prefix, '.'))
|
|
{
|
|
acptr = (aClient *) find_server_quick(prefix);
|
|
if (acptr->serv->numeric)
|
|
{
|
|
strcpy(pref, base64enc(acptr->serv->numeric));
|
|
}
|
|
}
|
|
|
|
strcpy(tcmd, token);
|
|
strcpy(ccmd, command);
|
|
strcat(tcmd, " ");
|
|
strcat(ccmd, " ");
|
|
ircvsprintf(buff, pattern, vl);
|
|
strcat(tcmd, buff);
|
|
strcat(ccmd, buff);
|
|
|
|
#ifdef NO_FDLIST
|
|
for (i = 0; i <= LastSlot; i++)
|
|
#else
|
|
for (i = serv_fdlist.entry[j = 1]; j <= serv_fdlist.last_entry; i = serv_fdlist.entry[++j])
|
|
#endif
|
|
{
|
|
if (!(cptr = local[i]) || (one && cptr == one->from))
|
|
continue;
|
|
#ifdef NO_FDLIST
|
|
if (IsServer(cptr))
|
|
#endif
|
|
|
|
if ((opt & OPT_NOT_SJOIN) && SupportSJOIN(cptr))
|
|
continue;
|
|
if ((opt & OPT_NOT_NICKv2) && SupportNICKv2(cptr))
|
|
continue;
|
|
if ((opt & OPT_NOT_SJOIN2) && SupportSJOIN2(cptr))
|
|
continue;
|
|
if ((opt & OPT_NOT_UMODE2) && SupportUMODE2(cptr))
|
|
continue;
|
|
if ((opt & OPT_NOT_SJ3) && SupportSJ3(cptr))
|
|
continue;
|
|
if ((opt & OPT_NICKv2) && !SupportNICKv2(cptr))
|
|
continue;
|
|
if ((opt & OPT_SJOIN) && !SupportSJOIN(cptr))
|
|
continue;
|
|
if ((opt & OPT_SJOIN2) && !SupportSJOIN2(cptr))
|
|
continue;
|
|
if ((opt & OPT_UMODE2) && !SupportUMODE2(cptr))
|
|
continue;
|
|
if ((opt & OPT_SJ3) && !SupportSJ3(cptr))
|
|
continue;
|
|
if ((opt & OPT_SJB64) && !(cptr->proto & PROTO_SJB64))
|
|
continue;
|
|
if ((opt & OPT_NOT_SJB64) && (cptr->proto & PROTO_SJB64))
|
|
continue;
|
|
|
|
if (IsToken(cptr))
|
|
{
|
|
if (SupportNS(cptr) && pref[0])
|
|
{
|
|
sendto_one(cptr, "@%s %s",
|
|
pref, tcmd);
|
|
}
|
|
else
|
|
{
|
|
sendto_one(cptr, ":%s %s",
|
|
prefix, tcmd);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (SupportNS(cptr) && pref[0])
|
|
{
|
|
sendto_one(cptr, "@%s %s",
|
|
pref, ccmd);
|
|
}
|
|
else
|
|
{
|
|
sendto_one(cptr, ":%s %s", prefix,
|
|
ccmd);
|
|
}
|
|
}
|
|
}
|
|
va_end(vl);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* sendto_serv_butone_quit
|
|
*
|
|
* Send a message to all connected servers except the client 'one'.
|
|
* BUT, don't send to NOQUIT servers.
|
|
*/
|
|
void sendto_serv_butone_quit(aClient *one, char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
int i;
|
|
aClient *cptr;
|
|
#ifndef NO_FDLIST
|
|
int j;
|
|
#endif
|
|
va_start(vl, pattern);
|
|
|
|
#ifdef NO_FDLIST
|
|
for (i = 0; i <= LastSlot; i++)
|
|
#else
|
|
for (i = serv_fdlist.entry[j = 1]; j <= serv_fdlist.last_entry; i = serv_fdlist.entry[++j])
|
|
#endif
|
|
{
|
|
if (!(cptr = local[i]) || (one && cptr == one->from))
|
|
continue;
|
|
#ifdef NO_FDLIST
|
|
if (IsServer(cptr) && !DontSendQuit(cptr))
|
|
#else
|
|
if (!DontSendQuit(cptr))
|
|
#endif
|
|
vsendto_one(cptr, pattern, vl);
|
|
}
|
|
va_end(vl);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* sendto_serv_butone_sjoin
|
|
*
|
|
* Send a message to all connected servers except the client 'one'.
|
|
* BUT, don't send to SJOIN servers.
|
|
*/
|
|
void sendto_serv_butone_sjoin(aClient *one, char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
int i;
|
|
aClient *cptr;
|
|
#ifndef NO_FDLIST
|
|
int j;
|
|
#endif
|
|
va_start(vl, pattern);
|
|
#ifdef NO_FDLIST
|
|
for (i = 0; i <= LastSlot; i++)
|
|
#else
|
|
for (i = serv_fdlist.entry[j = 1]; j <= serv_fdlist.last_entry; i = serv_fdlist.entry[++j])
|
|
#endif
|
|
{
|
|
if (!(cptr = local[i]) || (one && cptr == one->from))
|
|
continue;
|
|
#ifdef NO_FDLIST
|
|
if (IsServer(cptr) && !SupportSJOIN(cptr))
|
|
#else
|
|
if (!SupportSJOIN(cptr))
|
|
#endif
|
|
vsendto_one(cptr, pattern, vl);
|
|
}
|
|
va_end(vl);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* sendto_serv_sjoin
|
|
*
|
|
* Send a message to all connected servers except the client 'one'.
|
|
* BUT only send to SJOIN servers.
|
|
*/
|
|
void sendto_serv_sjoin(aClient *one, char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
int i;
|
|
aClient *cptr;
|
|
#ifndef NO_FDLIST
|
|
int j;
|
|
#endif
|
|
va_start(vl, pattern);
|
|
|
|
#ifdef NO_FDLIST
|
|
for (i = 0; i <= LastSlot; i++)
|
|
#else
|
|
for (i = serv_fdlist.entry[j = 1]; j <= serv_fdlist.last_entry; i = serv_fdlist.entry[++j])
|
|
#endif
|
|
{
|
|
if (!(cptr = local[i]) || (one && cptr == one->from))
|
|
continue;
|
|
#ifdef NO_FDLIST
|
|
if (IsServer(cptr) && SupportSJOIN(cptr))
|
|
#else
|
|
if (SupportSJOIN(cptr))
|
|
#endif
|
|
vsendto_one(cptr, pattern, vl);
|
|
}
|
|
va_end(vl);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* sendto_serv_butone_nickv2
|
|
*
|
|
* Send a message to all connected servers except the client 'one'.
|
|
* BUT, don't send to NICKv2 servers.
|
|
*/
|
|
void sendto_serv_butone_nickv2(aClient *one, char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
int i;
|
|
aClient *cptr;
|
|
#ifndef NO_FDLIST
|
|
int j;
|
|
#endif
|
|
va_start(vl, pattern);
|
|
|
|
#ifdef NO_FDLIST
|
|
for (i = 0; i <= LastSlot; i++)
|
|
#else
|
|
for (i = serv_fdlist.entry[j = 1]; j <= serv_fdlist.last_entry; i = serv_fdlist.entry[++j])
|
|
#endif
|
|
{
|
|
if (!(cptr = local[i]) || (one && cptr == one->from))
|
|
continue;
|
|
#ifdef NO_FDLIST
|
|
if (IsServer(cptr) && !SupportNICKv2(cptr))
|
|
#else
|
|
if (!SupportNICKv2(cptr))
|
|
#endif
|
|
vsendto_one(cptr, pattern, vl);
|
|
}
|
|
va_end(vl);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* sendto_serv_nickv2
|
|
*
|
|
* Send a message to all connected servers except the client 'one'.
|
|
* BUT only send to NICKv2 servers.
|
|
*/
|
|
void sendto_serv_nickv2(aClient *one, char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
int i;
|
|
aClient *cptr;
|
|
#ifndef NO_FDLIST
|
|
int j;
|
|
#endif
|
|
va_start(vl, pattern);
|
|
|
|
#ifdef NO_FDLIST
|
|
for (i = 0; i <= LastSlot; i++)
|
|
#else
|
|
for (i = serv_fdlist.entry[j = 1]; j <= serv_fdlist.last_entry; i = serv_fdlist.entry[++j])
|
|
#endif
|
|
{
|
|
if (!(cptr = local[i]) || (one && cptr == one->from))
|
|
continue;
|
|
#ifdef NO_FDLIST
|
|
if (IsServer(cptr) && SupportNICKv2(cptr))
|
|
#else
|
|
if (SupportNICKv2(cptr))
|
|
#endif
|
|
vsendto_one(cptr, pattern, vl);
|
|
}
|
|
va_end(vl);
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* sendto_serv_nickv2_token
|
|
*
|
|
* Send a message to all connected servers except the client 'one'.
|
|
* BUT only send to NICKv2 servers. As of Unreal3.1 it uses two patterns now
|
|
* one for non token and one for tokens */
|
|
void sendto_serv_nickv2_token(aClient *one, char *pattern, char *tokpattern,
|
|
...)
|
|
{
|
|
va_list vl;
|
|
int i;
|
|
aClient *cptr;
|
|
#ifndef NO_FDLIST
|
|
int j;
|
|
#endif
|
|
va_start(vl, tokpattern);
|
|
|
|
#ifdef NO_FDLIST
|
|
for (i = 0; i <= LastSlot; i++)
|
|
#else
|
|
for (i = serv_fdlist.entry[j = 1]; j <= serv_fdlist.last_entry; i = serv_fdlist.entry[++j])
|
|
#endif
|
|
{
|
|
if (!(cptr = local[i]) || (one && cptr == one->from))
|
|
continue;
|
|
#ifdef NO_FDLIST
|
|
if (IsServer(cptr) && SupportNICKv2(cptr) && !IsToken(cptr))
|
|
#else
|
|
if (SupportNICKv2(cptr) && !IsToken(cptr))
|
|
#endif
|
|
vsendto_one(cptr, pattern, vl);
|
|
else
|
|
#ifdef NO_FDLIST
|
|
if (IsServer(cptr) && SupportNICKv2(cptr) && IsToken(cptr))
|
|
#else
|
|
if (SupportNICKv2(cptr) && IsToken(cptr))
|
|
#endif
|
|
vsendto_one(cptr, tokpattern, vl);
|
|
}
|
|
va_end(vl);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* sendto_common_channels()
|
|
*
|
|
* Sends a message to all people (inclusing user) on local server who are
|
|
* in same channel with user.
|
|
*/
|
|
void sendto_common_channels(aClient *user, char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
|
|
Membership *channels;
|
|
Member *users;
|
|
aClient *cptr;
|
|
|
|
va_start(vl, pattern);
|
|
memset((char *)sentalong, '\0', sizeof(sentalong));
|
|
if (user->fd >= 0)
|
|
sentalong[user->fd] = 1;
|
|
if (user->user)
|
|
for (channels = user->user->channel; channels;
|
|
channels = channels->next)
|
|
for (users = channels->chptr->members; users;
|
|
users = users->next)
|
|
{
|
|
cptr = users->cptr;
|
|
if (!MyConnect(cptr) || sentalong[cptr->fd])
|
|
continue;
|
|
sentalong[cptr->fd]++;
|
|
vsendto_prefix_one(cptr, user, pattern, vl);
|
|
}
|
|
if (MyConnect(user))
|
|
vsendto_prefix_one(user, user, pattern, vl);
|
|
va_end(vl);
|
|
return;
|
|
}
|
|
/*
|
|
* sendto_channel_butserv
|
|
*
|
|
* Send a message to all members of a channel that are connected to this
|
|
* server.
|
|
*/
|
|
void sendto_channel_butserv(aChannel *chptr, aClient *from, char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
Member *lp;
|
|
aClient *acptr;
|
|
|
|
for (va_start(vl, pattern), lp = chptr->members; lp; lp = lp->next)
|
|
if (MyConnect(acptr = lp->cptr))
|
|
vsendto_prefix_one(acptr, from, pattern, vl);
|
|
va_end(vl);
|
|
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->realhost) == 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.
|
|
*/
|
|
void sendto_match_servs(aChannel *chptr, aClient *from, char *format, ...)
|
|
{
|
|
va_list vl;
|
|
int i;
|
|
aClient *cptr;
|
|
char *mask;
|
|
|
|
va_start(vl, format);
|
|
|
|
if (chptr)
|
|
{
|
|
if (*chptr->chname == '&')
|
|
return;
|
|
if (mask = (char *)rindex(chptr->chname, ':'))
|
|
mask++;
|
|
}
|
|
else
|
|
mask = (char *)NULL;
|
|
|
|
for (i = 0; i <= LastSlot; i++)
|
|
{
|
|
if (!(cptr = local[i]))
|
|
continue;
|
|
if ((cptr == from) || !IsServer(cptr))
|
|
continue;
|
|
if (!BadPtr(mask) && IsServer(cptr) && match(mask, cptr->name))
|
|
continue;
|
|
vsendto_one(cptr, format, vl);
|
|
}
|
|
va_end(vl);
|
|
}
|
|
|
|
/*
|
|
* sendto_match_butone
|
|
*
|
|
* Send to all clients which match the mask in a way defined on 'what';
|
|
* either by user hostname or user servername.
|
|
*/
|
|
void sendto_match_butone(aClient *one, aClient *from, char *mask, int what,
|
|
char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
int i;
|
|
aClient *cptr, *acptr;
|
|
char cansendlocal, cansendglobal;
|
|
|
|
va_start(vl, pattern);
|
|
if (MyConnect(from))
|
|
{
|
|
cansendlocal = (OPCanLNotice(from)) ? 1 : 0;
|
|
cansendglobal = (OPCanGNotice(from)) ? 1 : 0;
|
|
}
|
|
else
|
|
cansendlocal = cansendglobal = 1;
|
|
|
|
for (i = 0; i <= LastSlot; i++)
|
|
{
|
|
if (!(cptr = local[i]))
|
|
continue; /* that clients are not mine */
|
|
if (cptr == one) /* must skip the origin !! */
|
|
continue;
|
|
if (IsServer(cptr))
|
|
{
|
|
if (!cansendglobal)
|
|
continue;
|
|
for (acptr = client; acptr; acptr = acptr->next)
|
|
if (IsRegisteredUser(acptr)
|
|
&& match_it(acptr, mask, what)
|
|
&& acptr->from == cptr)
|
|
break;
|
|
/* a person on that server matches the mask, so we
|
|
** send *one* msg to that server ...
|
|
*/
|
|
if (acptr == NULL)
|
|
continue;
|
|
/* ... but only if there *IS* a matching person */
|
|
}
|
|
/* my client, does he match ? */
|
|
else if (!cansendlocal || (!(IsRegisteredUser(cptr) &&
|
|
match_it(cptr, mask, what))))
|
|
continue;
|
|
vsendto_prefix_one(cptr, from, pattern, vl);
|
|
}
|
|
va_end(vl);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* sendto_all_butone.
|
|
*
|
|
* Send a message to all connections except 'one'. The basic wall type
|
|
* message generator.
|
|
*/
|
|
|
|
void sendto_all_butone(aClient *one, aClient *from, char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
int i;
|
|
aClient *cptr;
|
|
|
|
for (va_start(vl, pattern), i = 0; i <= LastSlot; i++)
|
|
if ((cptr = local[i]) && !IsMe(cptr) && one != cptr)
|
|
vsendto_prefix_one(cptr, from, pattern, vl);
|
|
va_end(vl);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* sendto_ops
|
|
*
|
|
* Send to *local* ops only.
|
|
*/
|
|
void sendto_ops(char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
aClient *cptr;
|
|
int i;
|
|
char nbuf[1024];
|
|
|
|
va_start(vl, pattern);
|
|
for (i = 0; i <= LastSlot; i++)
|
|
if ((cptr = local[i]) && !IsServer(cptr) && !IsMe(cptr) && SendServNotice(cptr))
|
|
{
|
|
(void)ircsprintf(nbuf, ":%s NOTICE %s :*** Notice -- ", me.name, cptr->name);
|
|
(void)strncat(nbuf, pattern, sizeof(nbuf) - strlen(nbuf));
|
|
vsendto_one(cptr, nbuf, vl);
|
|
}
|
|
va_end(vl);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* sendto_failops
|
|
*
|
|
* Send to *local* mode +g ops only.
|
|
*/
|
|
void sendto_failops(char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
aClient *cptr;
|
|
int i;
|
|
char nbuf[1024];
|
|
|
|
va_start(vl, pattern);
|
|
for (i = 0; i <= LastSlot; i++)
|
|
if ((cptr = local[i]) && !IsServer(cptr) && !IsMe(cptr) &&
|
|
SendFailops(cptr))
|
|
{
|
|
(void)ircsprintf(nbuf, ":%s NOTICE %s :*** Global -- ",
|
|
me.name, cptr->name);
|
|
(void)strncat(nbuf, pattern,
|
|
sizeof(nbuf) - strlen(nbuf));
|
|
vsendto_one(cptr, nbuf, vl);
|
|
}
|
|
va_end(vl);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* sendto_umode
|
|
*
|
|
* Send to specified umode
|
|
*/
|
|
void sendto_umode(int umodes, char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
aClient *cptr;
|
|
int i;
|
|
char nbuf[1024];
|
|
int w;
|
|
va_start(vl, pattern);
|
|
w = (umodes == UMODE_OPER | UMODE_CLIENT ? 1 : 0);
|
|
for (i = 0; i <= LastSlot; i++)
|
|
if ((cptr = local[i]) && !IsServer(cptr) && !IsMe(cptr) &&
|
|
(cptr->umodes & umodes) == umodes && ((w == 1)
|
|
&& !IsHybNotice(cptr)))
|
|
{
|
|
(void)ircsprintf(nbuf, ":%s NOTICE %s :",
|
|
me.name, cptr->name);
|
|
(void)strncat(nbuf, pattern,
|
|
sizeof(nbuf) - strlen(nbuf));
|
|
vsendto_one(cptr, nbuf, vl);
|
|
}
|
|
va_end(vl);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* sendto_conn_hcn
|
|
*
|
|
* Send to umode +c && IsHybNotice(cptr)
|
|
*/
|
|
void sendto_conn_hcn(char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
aClient *cptr;
|
|
int i;
|
|
char nbuf[1024];
|
|
|
|
va_start(vl, pattern);
|
|
for (i = 0; i <= LastSlot; i++)
|
|
if ((cptr = local[i]) && !IsServer(cptr) && !IsMe(cptr) &&
|
|
(cptr->umodes & UMODE_CLIENT) && IsHybNotice(cptr))
|
|
{
|
|
(void)ircsprintf(nbuf, ":%s NOTICE %s :",
|
|
me.name, cptr->name);
|
|
(void)strncat(nbuf, pattern,
|
|
sizeof(nbuf) - strlen(nbuf));
|
|
vsendto_one(cptr, nbuf, vl);
|
|
}
|
|
va_end(vl);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* sendto_failops_whoare_opers
|
|
*
|
|
* Send to *local* mode +g ops only who are also +o.
|
|
*/
|
|
void sendto_failops_whoare_opers(char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
aClient *cptr;
|
|
int i;
|
|
char nbuf[1024];
|
|
|
|
va_start(vl, pattern);
|
|
for (i = 0; i <= LastSlot; i++)
|
|
if ((cptr = local[i]) && !IsServer(cptr) && !IsMe(cptr) &&
|
|
SendFailops(cptr) && IsAnOper(cptr))
|
|
{
|
|
(void)ircsprintf(nbuf, ":%s NOTICE %s :*** Global -- ",
|
|
me.name, cptr->name);
|
|
(void)strncat(nbuf, pattern,
|
|
sizeof(nbuf) - strlen(nbuf));
|
|
vsendto_one(cptr, nbuf, vl);
|
|
}
|
|
va_end(vl);
|
|
return;
|
|
}
|
|
/*
|
|
* sendto_locfailops
|
|
*
|
|
* Send to *local* mode +g ops only who are also +o.
|
|
*/
|
|
void sendto_locfailops(char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
aClient *cptr;
|
|
int i;
|
|
char nbuf[1024];
|
|
|
|
va_start(vl, pattern);
|
|
for (i = 0; i <= LastSlot; i++)
|
|
if ((cptr = local[i]) && !IsServer(cptr) && !IsMe(cptr) &&
|
|
SendFailops(cptr) && IsAnOper(cptr))
|
|
{
|
|
(void)ircsprintf(nbuf, ":%s NOTICE %s :*** LocOps -- ",
|
|
me.name, cptr->name);
|
|
(void)strncat(nbuf, pattern,
|
|
sizeof(nbuf) - strlen(nbuf));
|
|
vsendto_one(cptr, nbuf, vl);
|
|
}
|
|
va_end(vl);
|
|
return;
|
|
}
|
|
/*
|
|
* sendto_opers
|
|
*
|
|
* Send to *local* ops only. (all +O or +o people)
|
|
*/
|
|
void sendto_opers(char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
aClient *cptr;
|
|
int i;
|
|
char nbuf[1024];
|
|
|
|
va_start(vl, pattern);
|
|
for (i = 0; i <= LastSlot; i++)
|
|
if ((cptr = local[i]) && !IsServer(cptr) && !IsMe(cptr) &&
|
|
IsAnOper(cptr))
|
|
{
|
|
(void)ircsprintf(nbuf, ":%s NOTICE %s :*** Oper -- ",
|
|
me.name, cptr->name);
|
|
(void)strncat(nbuf, pattern,
|
|
sizeof(nbuf) - strlen(nbuf));
|
|
vsendto_one(cptr, nbuf, vl);
|
|
}
|
|
va_end(vl);
|
|
return;
|
|
}
|
|
|
|
/* ** sendto_ops_butone
|
|
** Send message to all operators.
|
|
** one - client not to send message to
|
|
** from- client which message is from *NEVER* NULL!!
|
|
*/
|
|
void sendto_ops_butone(aClient *one, aClient *from, char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
int i;
|
|
aClient *cptr;
|
|
|
|
va_start(vl, pattern);
|
|
for (i = 0; i <= LastSlot; i++)
|
|
sentalong[i] = 0;
|
|
for (cptr = client; cptr; cptr = cptr->next)
|
|
{
|
|
if (!SendWallops(cptr))
|
|
continue;
|
|
i = cptr->from->slot; /* 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;
|
|
vsendto_prefix_one(cptr->from, from, pattern, vl);
|
|
}
|
|
va_end(vl);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
** sendto_ops_butone
|
|
** Send message to all operators regardless of whether they are +w or
|
|
** not..
|
|
** one - client not to send message to
|
|
** from- client which message is from *NEVER* NULL!!
|
|
*/
|
|
void sendto_opers_butone(aClient *one, aClient *from, char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
int i;
|
|
aClient *cptr;
|
|
|
|
va_start(vl, pattern);
|
|
for (i = 0; i <= LastSlot; i++)
|
|
sentalong[i] = 0;
|
|
for (cptr = client; cptr; cptr = cptr->next)
|
|
{
|
|
if (!IsAnOper(cptr))
|
|
continue;
|
|
i = cptr->from->slot; /* 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;
|
|
vsendto_prefix_one(cptr->from, from, pattern, vl);
|
|
}
|
|
va_end(vl);
|
|
return;
|
|
}
|
|
/*
|
|
** sendto_ops_butme
|
|
** Send message to all operators except local ones
|
|
** from- client which message is from *NEVER* NULL!!
|
|
*/
|
|
void sendto_ops_butme(aClient *from, char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
int i;
|
|
aClient *cptr;
|
|
|
|
va_start(vl, pattern);
|
|
for (i = 0; i <= LastSlot; i++)
|
|
sentalong[i] = 0;
|
|
for (cptr = client; cptr; cptr = cptr->next)
|
|
{
|
|
if (!SendWallops(cptr))
|
|
continue;
|
|
i = cptr->from->slot; /* find connection oper is on */
|
|
if (sentalong[i]) /* sent message along it already ? */
|
|
continue;
|
|
if (!strcmp(cptr->user->server, me.name)) /* a locop */
|
|
continue;
|
|
sentalong[i] = 1;
|
|
vsendto_prefix_one(cptr->from, from, pattern, vl);
|
|
}
|
|
va_end(vl);
|
|
return;
|
|
}
|
|
|
|
void vsendto_prefix_one(struct Client *to, struct Client *from,
|
|
const char *pattern, va_list vl)
|
|
{
|
|
if (to && from && MyClient(to) && from->user)
|
|
{
|
|
static char sender[HOSTLEN + NICKLEN + USERLEN + 5];
|
|
char *par;
|
|
int flag = 0;
|
|
struct User *user = from->user;
|
|
|
|
par = va_arg(vl, char *);
|
|
strcpy(sender, from->name);
|
|
if (user)
|
|
{
|
|
if (*user->username)
|
|
{
|
|
strcat(sender, "!");
|
|
strcat(sender, user->username);
|
|
}
|
|
if ((IsHidden(from) ? *user->virthost : *user->realhost)
|
|
&& !MyConnect(from))
|
|
{
|
|
strcat(sender, "@");
|
|
|
|
(void)strcat(sender,
|
|
(!IsHidden(from) ? user->realhost : user->
|
|
virthost));
|
|
flag = 1;
|
|
}
|
|
}
|
|
/*
|
|
* Flag is used instead of strchr(sender, '@') for speed and
|
|
* also since username/nick may have had a '@' in them. -avalon
|
|
*/
|
|
if (!flag && MyConnect(from)
|
|
&& (IsHidden(from) ? *user->virthost : *user->realhost))
|
|
{
|
|
strcat(sender, "@");
|
|
strcat(sender,
|
|
(!IsHidden(from) ? user->realhost : user->
|
|
virthost));
|
|
}
|
|
*sendbuf = ':';
|
|
strcpy(&sendbuf[1], sender);
|
|
/* Assuming 'pattern' always starts with ":%s ..." */
|
|
ircvsprintf(sendbuf + strlen(sendbuf), &pattern[3], vl);
|
|
}
|
|
else
|
|
ircvsprintf(sendbuf, pattern, vl);
|
|
sendbufto_one(to);
|
|
}
|
|
|
|
/*
|
|
* sendto_prefix_one
|
|
*
|
|
* to - destination client
|
|
* from - client which message is from
|
|
*
|
|
* NOTE: NEITHER OF THESE SHOULD *EVER* BE NULL!!
|
|
* -avalon
|
|
*/
|
|
|
|
void sendto_prefix_one(aClient *to, aClient *from, const char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
va_start(vl, pattern);
|
|
vsendto_prefix_one(to, from, pattern, vl);
|
|
va_end(vl);
|
|
}
|
|
|
|
/*
|
|
* sendto_realops
|
|
*
|
|
* Send to *local* ops only but NOT +s nonopers.
|
|
*/
|
|
void sendto_realops(char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
aClient *cptr;
|
|
int i;
|
|
#ifndef NO_FDLIST
|
|
int j;
|
|
#endif
|
|
char nbuf[1024];
|
|
|
|
va_start(vl, pattern);
|
|
#ifdef NO_FDLIST
|
|
for (i = 0; i <= LastSlot; i++)
|
|
#else
|
|
for (i = oper_fdlist.entry[j = 1]; j <= oper_fdlist.last_entry; i = oper_fdlist.entry[++j])
|
|
#endif
|
|
#ifdef NO_FDLIST
|
|
if ((cptr = local[i]) && !IsServer(cptr) && !IsMe(cptr) &&
|
|
IsOper(cptr))
|
|
#else
|
|
if ((cptr = local[i]))
|
|
#endif
|
|
{
|
|
(void)ircsprintf(nbuf, ":%s NOTICE %s :*** Notice -- ",
|
|
me.name, cptr->name);
|
|
(void)strncat(nbuf, pattern,
|
|
sizeof(nbuf) - strlen(nbuf));
|
|
vsendto_one(cptr, nbuf, vl);
|
|
}
|
|
va_end(vl);
|
|
return;
|
|
}
|
|
|
|
void sendto_connectnotice(nick, user, sptr)
|
|
char *nick;
|
|
anUser *user;
|
|
aClient *sptr;
|
|
{
|
|
aClient *cptr;
|
|
int i;
|
|
char connectd[1024];
|
|
char connecth[1024];
|
|
|
|
RunHook(HOOKTYPE_LOCAL_CONNECT, sptr);
|
|
ircsprintf(connectd,
|
|
"*** Notice -- Client connecting on port %d: %s (%s@%s) [%s] %s%s%s",
|
|
sptr->listener->port, nick, user->username, user->realhost,
|
|
sptr->class ? sptr->class->name : "",
|
|
#ifdef USE_SSL
|
|
IsSecure(sptr) ? "[secure " : "",
|
|
IsSecure(sptr) ? SSL_get_cipher((SSL *)sptr->ssl) : "",
|
|
IsSecure(sptr) ? "]" : "");
|
|
#else
|
|
"", "", "");
|
|
#endif
|
|
ircsprintf(connecth,
|
|
"*** Notice -- Client connecting: %s (%s@%s) [%s] {%s}", nick,
|
|
user->username, user->realhost, sptr->sockhost,
|
|
sptr->class ? sptr->class->name : "0");
|
|
|
|
for (i = 0; i <= LastSlot; i++)
|
|
if ((cptr = local[i]) && !IsServer(cptr) && !IsMe(cptr) &&
|
|
IsOper(cptr) && (cptr->umodes & UMODE_CLIENT))
|
|
{
|
|
if (IsHybNotice(cptr))
|
|
sendto_one(cptr, ":%s NOTICE %s :%s", me.name,
|
|
cptr->name, connecth);
|
|
else
|
|
sendto_one(cptr, ":%s NOTICE %s :%s", me.name,
|
|
cptr->name, connectd);
|
|
|
|
}
|
|
}
|
|
|
|
/*
|
|
* sendto_server_butone_nickcmd
|
|
*
|
|
* Send a message to all connected servers except the client 'one'.
|
|
*/
|
|
void sendto_serv_butone_nickcmd(aClient *one, aClient *sptr,
|
|
char *nick, int hopcount,
|
|
int lastnick, char *username, char *realhost, char *server,
|
|
long servicestamp, char *info, char *umodes, char *virthost)
|
|
{
|
|
int i;
|
|
aClient *cptr;
|
|
#ifndef NO_FDLIST
|
|
int j;
|
|
#endif
|
|
|
|
#ifdef NO_FDLIST
|
|
for (i = 0; i <= LastSlot; i++)
|
|
#else
|
|
for (i = serv_fdlist.entry[j = 1]; j <= serv_fdlist.last_entry; i = serv_fdlist.entry[++j])
|
|
#endif
|
|
{
|
|
if (!(cptr = local[i]) || (one && cptr == one->from))
|
|
continue;
|
|
#ifdef NO_FDLIST
|
|
if (IsServer(cptr))
|
|
#endif
|
|
{
|
|
if (SupportNICKv2(cptr))
|
|
{
|
|
if (sptr->srvptr->serv->numeric && SupportNS(cptr))
|
|
sendto_one(cptr,
|
|
(cptr->proto & PROTO_SJB64) ?
|
|
"%s %s %d %B %s %s %b %lu %s %s :%s"
|
|
:
|
|
"%s %s %d %d %s %s %b %lu %s %s :%s"
|
|
,
|
|
(IsToken(cptr) ? TOK_NICK : MSG_NICK), nick,
|
|
hopcount, lastnick, username, realhost,
|
|
sptr->srvptr->serv->numeric,
|
|
servicestamp, umodes,
|
|
(SupportVHP(cptr) ? (IsHidden(sptr) ? sptr->user->virthost : realhost) : virthost),
|
|
info);
|
|
else
|
|
sendto_one(cptr,
|
|
"%s %s %d %d %s %s %s %lu %s %s :%s",
|
|
(IsToken(cptr) ? TOK_NICK : MSG_NICK), nick,
|
|
hopcount, lastnick, username, realhost,
|
|
SupportNS(cptr) && sptr->srvptr->serv->numeric ? base64enc(sptr->srvptr->serv->numeric) : server,
|
|
servicestamp, umodes,
|
|
(SupportVHP(cptr) ? (IsHidden(sptr) ? sptr->user->virthost : realhost) : virthost),
|
|
info);
|
|
|
|
}
|
|
else
|
|
{
|
|
sendto_one(cptr, "%s %s %d %d %s %s %s %lu :%s",
|
|
(IsToken(cptr) ? TOK_NICK : MSG_NICK),
|
|
nick, hopcount, lastnick, username,
|
|
realhost,
|
|
server, servicestamp, info);
|
|
if (strcmp(umodes, "+"))
|
|
{
|
|
sendto_one(cptr, ":%s %s %s :%s",
|
|
nick,
|
|
(IsToken(cptr) ? TOK_MODE :
|
|
MSG_MODE), nick, umodes);
|
|
}
|
|
if (strcmp(virthost, "*"))
|
|
{
|
|
sendto_one(cptr, ":%s %s %s",
|
|
nick,
|
|
(IsToken(cptr) ? TOK_SETHOST :
|
|
MSG_SETHOST), virthost);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
void sendto_message_one(aClient *to, aClient *from, char *sender,
|
|
char *cmd, char *nick, char *msg)
|
|
{
|
|
if(IsServer(to->from) && IsToken(to->from)) {
|
|
if(*cmd == 'P') cmd = TOK_PRIVATE;
|
|
if(*cmd == 'N') cmd = TOK_NOTICE;
|
|
}
|
|
sendto_prefix_one(to, from, ":%s %s %s :%s",
|
|
sender, cmd, nick, msg);
|
|
}
|
|
|
|
/* The following functions are for +/-I -- codemastr */
|
|
|
|
void sendto_channels_inviso_join(aClient *user)
|
|
{
|
|
Membership *channels;
|
|
Member *users;
|
|
aClient *cptr;
|
|
|
|
memset((char *)sentalong, '\0', sizeof(sentalong));
|
|
if (user->fd >= 0)
|
|
sentalong[user->fd] = 1;
|
|
if (user->user)
|
|
for (channels = user->user->channel; channels; channels = channels->next)
|
|
for (users = channels->chptr->members; users; users = users->next)
|
|
{
|
|
cptr = users->cptr;
|
|
if (!MyConnect(cptr) || IsTechAdmin(cptr) || IsNetAdmin(cptr) || sentalong[cptr->fd] || cptr == user)
|
|
continue;
|
|
sentalong[cptr->fd]++;
|
|
sendto_one(cptr, ":%s!%s@%s JOIN :%s", user->name, user->user->username,
|
|
(IsHidden(user) ? user->user->virthost : user->user->realhost), channels->chptr->chname);
|
|
}
|
|
return;
|
|
}
|
|
|
|
void sendto_channels_inviso_part(aClient *user)
|
|
{
|
|
Membership *channels;
|
|
Member *users;
|
|
aClient *cptr;
|
|
|
|
memset((char *)sentalong, '\0', sizeof(sentalong));
|
|
if (user->fd >= 0)
|
|
sentalong[user->fd] = 1;
|
|
if (user->user)
|
|
for (channels = user->user->channel; channels; channels = channels->next)
|
|
for (users = channels->chptr->members; users; users = users->next)
|
|
{
|
|
cptr = users->cptr;
|
|
if (!MyConnect(cptr) || IsTechAdmin(cptr) || IsNetAdmin(cptr) || sentalong[cptr->fd] || cptr == user)
|
|
continue;
|
|
sentalong[cptr->fd]++;
|
|
sendto_one(cptr, ":%s!%s@%s PART :%s", user->name, user->user->username, (IsHidden(user) ? user->user->virthost : user->user->realhost), channels->chptr->chname);
|
|
}
|
|
return;
|
|
}
|
|
|
|
void sendto_channel_ntadmins(aClient *from, aChannel *chptr, char *pattern, ...)
|
|
{
|
|
va_list vl;
|
|
Member *lp;
|
|
aClient *acptr;
|
|
int i;
|
|
|
|
va_start(vl, pattern);
|
|
++sentalong_marker;
|
|
for (lp = chptr->members; lp; lp = lp->next)
|
|
{
|
|
acptr = lp->cptr;
|
|
if (acptr->from == from || !(IsNetAdmin(acptr) || IsTechAdmin(acptr)) || (IsDeaf(acptr) && !(sendanyways == 1)))
|
|
continue;
|
|
if (MyConnect(acptr)) /* (It is always a client) */
|
|
vsendto_prefix_one(acptr, from, pattern, vl);
|
|
else if (sentalong[(i = acptr->from->fd)] != sentalong_marker)
|
|
{
|
|
sentalong[i] = sentalong_marker;
|
|
vsendto_prefix_one(acptr, from, pattern, vl);
|
|
}
|
|
}
|
|
va_end(vl);
|
|
return;
|
|
}
|