1
0
mirror of https://github.com/unrealircd/unrealircd.git synced 2026-07-10 20:03:14 +02:00
Files
unrealircd/src/s_serv.c
T
2000-02-28 22:45:44 +00:00

4147 lines
111 KiB
C

/************************************************************************
* IRC - Internet Relay Chat, src/s_serv.c
* Copyright (C) 1990 Jarkko Oikarinen and
* University of Oulu, Computing Center
*
* See file AUTHORS in IRC package for additional names of
* the programmers.
*
* 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 sccsid[] = "@(#)s_serv.c 2.55 2/7/94 (C) 1988 University of Oulu, Computing Center and Jarkko Oikarinen";
#endif
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "msg.h"
#include "channel.h"
#include "userload.h"
#include "version.h"
#if defined(PCS) || defined(AIX) || defined(DYNIXPTX) || defined(SVR3)
#include <time.h>
#endif
#include <sys/stat.h>
#include <fcntl.h>
#ifndef _WIN32
#include <utmp.h>
#else
#include <io.h>
#endif
#include <time.h>
#include "h.h"
ID_CVS("$Id$");
static char buf[BUFSIZE];
int max_connection_count = 1, max_client_count = 1;
/*
** m_functions execute protocol messages on this server:
**
** cptr is always NON-NULL, pointing to a *LOCAL* client
** structure (with an open socket connected!). This
** identifies the physical socket where the message
** originated (or which caused the m_function to be
** executed--some m_functions may call others...).
**
** sptr is the source of the message, defined by the
** prefix part of the message if present. If not
** or prefix not found, then sptr==cptr.
**
** (!IsServer(cptr)) => (cptr == sptr), because
** prefixes are taken *only* from servers...
**
** (IsServer(cptr))
** (sptr == cptr) => the message didn't
** have the prefix.
**
** (sptr != cptr && IsServer(sptr) means
** the prefix specified servername. (?)
**
** (sptr != cptr && !IsServer(sptr) means
** that message originated from a remote
** user (not local).
**
** combining
**
** (!IsServer(sptr)) means that, sptr can safely
** taken as defining the target structure of the
** message in this server.
**
** *Always* true (if 'parse' and others are working correct):
**
** 1) sptr->from == cptr (note: cptr->from == cptr)
**
** 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr
** *cannot* be a local connection, unless it's
** actually cptr!). [MyConnect(x) should probably
** be defined as (x == x->from) --msa ]
**
** parc number of variable parameter strings (if zero,
** parv is allowed to be NULL)
**
** parv a NULL terminated list of parameter pointers,
**
** parv[0], sender (prefix string), if not present
** this points to an empty string.
** parv[1]...parv[parc-1]
** pointers to additional parameters
** parv[parc] == NULL, *always*
**
** note: it is guaranteed that parv[0]..parv[parc-1] are all
** non-NULL pointers.
*/
#ifndef NO_FDLIST
extern fdlist serv_fdlist;
#endif
/*
** m_version
** parv[0] = sender prefix
** parv[1] = remote server
*/
int m_version(cptr, sptr, parc, parv)
aClient *sptr, *cptr;
int parc;
char *parv[];
{
extern char serveropts[];
char *x;
if (TRUEHUB == 1)
x = "(H)";
else
x = "";
if (check_registered(sptr))
return 0;
if (hunt_server(cptr,sptr,":%s VERSION :%s",1,parc,parv)==HUNTED_ISME)
sendto_one(sptr, rpl_str(RPL_VERSION), me.name,
parv[0], version, ircnetwork, debugmode, me.name,
serveropts,
(IsAnOper(sptr) ? MYOSNAME : "*"),
UnrealProtocol,
x);
return 0;
}
/*int IsMe (acptr)
aClient *acptr, server;
{
if (memcmp (acptr, server, sizeof(aClient)) == 0)
return 1;
return 0;
}*/
/*
** m_squit
** parv[0] = sender prefix
** parv[1] = server name
** parv[parc-1] = comment
*/
int m_squit(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
Reg1 aConfItem *aconf;
char *server;
Reg2 aClient *acptr;
char *comment = (parc > 2 && parv[parc-1]) ?
parv[parc-1] : cptr->name;
if (check_registered(sptr))
return 0;
if (!IsPrivileged(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if (parc > 1)
{
server = parv[1];
/*
** To accomodate host masking, a squit for a masked server
** name is expanded if the incoming mask is the same as
** the server name for that link to the name of link.
*/
while ((*server == '*') && IsServer(cptr))
{
aconf = cptr->serv->nline;
if (!aconf)
break;
if (!mycmp(server, my_name_for_link(me.name, aconf)))
server = cptr->name;
break; /* WARNING is normal here */
}
/*
** The following allows wild cards in SQUIT. Only usefull
** when the command is issued by an oper.
*/
for (acptr = client; (acptr = next_client(acptr, server));
acptr = acptr->next)
if (IsServer(acptr) || IsMe(acptr))
break;
if (acptr && IsMe(acptr))
{
acptr = cptr;
server = cptr->sockhost;
}
}
else
{
/*
** This is actually protocol error. But, well, closing
** the link is very proper answer to that...
*/
server = cptr->sockhost;
acptr = cptr;
}
/*
** SQUIT semantics is tricky, be careful...
**
** The old (irc2.2PL1 and earlier) code just cleans away the
** server client from the links (because it is never true
** "cptr == acptr".
**
** This logic here works the same way until "SQUIT host" hits
** the server having the target "host" as local link. Then it
** will do a real cleanup spewing SQUIT's and QUIT's to all
** directions, also to the link from which the orinal SQUIT
** came, generating one unnecessary "SQUIT host" back to that
** link.
**
** One may think that this could be implemented like
** "hunt_server" (e.g. just pass on "SQUIT" without doing
** nothing until the server having the link as local is
** reached). Unfortunately this wouldn't work in the real life,
** because either target may be unreachable or may not comply
** with the request. In either case it would leave target in
** links--no command to clear it away. So, it's better just
** clean out while going forward, just to be sure.
**
** ...of course, even better cleanout would be to QUIT/SQUIT
** dependant users/servers already on the way out, but
** currently there is not enough information about remote
** clients to do this... --msa
*/
if (!acptr)
{
sendto_one(sptr, err_str(ERR_NOSUCHSERVER),
me.name, parv[0], server);
return 0;
}
if (MyClient(sptr) && ((!OPCanGRoute(sptr) && !MyConnect(acptr)) ||
(!OPCanLRoute(sptr) && MyConnect(acptr))))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
/*
** Notify all opers, if my local link is remotely squitted
*/
if (MyConnect(acptr) && !IsAnOper(cptr))
{
sendto_locfailops("Received SQUIT %s from %s (%s)",
acptr->name, get_client_name(sptr,FALSE), comment);
sendto_serv_butone(&me, ":%s GLOBOPS :Received SQUIT %s from %s (%s)",
me.name, server, get_client_name(sptr,FALSE), comment);
#if defined(USE_SYSLOG) && defined(SYSLOG_SQUIT)
syslog(LOG_DEBUG,"SQUIT From %s : %s (%s)",
parv[0], server, comment);
#endif
}
else if (MyConnect(acptr)) {
if (acptr->user) {
sendto_one(sptr, ":%s NOTICE :*** Cannot do fake kill by SQUIT !!!", me.name);
sendto_ops("%s tried to do a fake kill using SQUIT (%s (%s))", sptr->name, acptr->name, comment);
sendto_serv_butone(&me, ":%s GLOBOPS :%s tried to fake kill using SQUIT (%s (%s))", me.name, sptr->name, acptr->name, comment);
return 0;
}
sendto_locfailops("Received SQUIT %s from %s (%s)",
acptr->name, get_client_name(sptr,FALSE), comment);
sendto_serv_butone(&me, ":%s GLOBOPS :Received SQUIT %s from %s (%s)",
me.name, acptr->name, get_client_name(sptr,FALSE), comment);
}
if (IsAnOper(sptr)) {
/*
* It was manually /squit'ed by a human being(we hope),
* there is a very good chance they don't want us to
* reconnect right away. -Cabal95
*/
acptr->flags |= FLAGS_SQUIT;
}
return exit_client(cptr, acptr, sptr, comment);
}
/*
* m_protoctl
* parv[0] = Sender prefix
* parv[1+] = Options
*/
int m_protoctl(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
int i;
char proto[128], *options, *equal;
static char *dummyblank=""; /* Yes, it is kind of ugly */
if (GotProtoctl(sptr)) {
/*
* But we already GOT a protoctl msg!
*/
if (!IsServer(sptr))
sendto_one(cptr, "ERROR :Already got a PROTOCTL from you.");
return 0;
}
cptr->flags |= FLAGS_PROTOCTL;
/* parv[parc - 1]*/
for (i = 1; i < parc; i++) {
strncpy(proto, parv[i], 127);
proto[127] = '\0'; /* Just to be safe... */
equal = (char *)index(proto, '=');
if (equal == NULL)
options = dummyblank;
else {
options = &equal[1]; /* Variable-byte-size safe */
equal[0] = '\0';
}
if (strcmp(proto, "NOQUIT") == 0) {
Debug((DEBUG_ERROR, "Chose protocol %s for link %s", proto, cptr->name));
SetNoQuit(cptr);
} else if (strcmp(proto, "TOKEN") == 0) {
Debug((DEBUG_ERROR, "Chose protocol %s for link %s", proto, cptr->name));
SetToken(cptr);
} else if (strcmp(proto, "HCN")==0)
{
Debug((DEBUG_ERROR, "Chose protocol %s for link %s", proto, cptr->name));
SetHybNotice(cptr);
} else if (strcmp(proto, "SJOIN")==0)
{
Debug((DEBUG_ERROR, "Chose protocol %s for link %s", proto, cptr->name));
SetSJOIN(cptr);
}
else if (strcmp(proto, "SJOIN2")==0)
{
Debug((DEBUG_ERROR, "Chose protocol %s for link %s", proto, cptr->name));
SetSJOIN2(cptr);
} else if (strcmp(proto, "NICKv2")==0)
{
Debug((DEBUG_ERROR, "Chose protocol %s for link %s", proto, cptr->name));
SetNICKv2(cptr);
}
/*
* Add other protocol extensions here, with proto
* containing the base option, and options containing
* what it equals, if anything.
*
* DO NOT error or warn on unknown proto; we just don't
* support it.
*/
}
return 0;
}
/*
** m_server
** parv[0] = sender prefix
** parv[1] = servername
** parv[2] = serverinfo/hopcount
** parv[3] = serverinfo
*/
int m_server(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
Reg1 char *ch;
Reg2 int i;
char info[REALLEN+1], *inpath, *host, *encr;
aClient *acptr, *bcptr;
aConfItem *aconf, *cconf;
int hop, ts = 0;
info[0] = '\0';
inpath = get_client_name(cptr,FALSE);
if (parc < 2 || *parv[1] == '\0')
{
sendto_one(cptr,"ERROR :No servername");
return 0;
}
hop = 0;
host = parv[1];
if (parc > 4) {
ts = atoi(parv[3]);
hop = atoi(parv[2]);
(void)strncpy(info, parv[4], REALLEN);
info[REALLEN] = '\0';
}
else if (parc > 3 && atoi(parv[2]))
{
hop = atoi(parv[2]);
(void)strncpy(info, parv[3], REALLEN);
info[REALLEN] = '\0';
}
else if (parc > 2)
{
(void)strncpy(info, parv[2], REALLEN);
if (parc > 3 && ((i = strlen(info)) < (REALLEN-2)))
{
(void)strcat(info, " ");
(void)strncat(info, parv[3], REALLEN - i - 2);
info[REALLEN] = '\0';
}
}
/*
** Check for "FRENCH " infection ;-) (actually this should
** be replaced with routine to check the hostname syntax in
** general). [ This check is still needed, even after the parse
** is fixed, because someone can send "SERVER :foo bar " ].
** Also, changed to check other "difficult" characters, now
** that parse lets all through... --msa
*/
if (strlen(host) > HOSTLEN)
host[HOSTLEN] = '\0';
for (ch = host; *ch; ch++)
if (*ch <= ' ' || *ch > '~')
break;
if (*ch || !index(host, '.'))
{
sendto_one(sptr,"ERROR :Bogus server name (%s)",
sptr->name, host);
sendto_ops("Bogus server name (%s) from %s", host,
get_client_name(cptr, TRUE));
sptr->since += 7;
return 0;
}
if (IsPerson(cptr))
{
/*
** A local link that has been identified as a USER
** tries something fishy... ;-)
*/
sendto_one(cptr, err_str(ERR_ALREADYREGISTRED),
me.name, parv[0]);
// sendto_one(cptr, ":%s NOTICE %s :Sorry, but your IRC program doesn't appear to support changing servers.", me.name, cptr->name);
sendto_ops("User %s trying to become a server %s",
get_client_name(cptr, TRUE),host);
sptr->since += 7;
return 0;
}
/* *WHEN* can it be that "cptr != sptr" ????? --msa */
/* When SERVER command (like now) has prefix. -avalon */
/* take a prepeek at the password..*/
if (IsUnknown(cptr)) {
aconf = find_conf_servern(host);
if (!aconf) {
sendto_locfailops("ERROR :No Access (No N line) %s",
inpath);
sendto_locfailops("Access denied (No N line) %s", inpath);
return exit_client(cptr, cptr, cptr, "No N line");
}
#ifdef CRYPT_LINK_PASSWORD
/* use first two chars of the password they send in as salt */
/* passwd may be NULL. Head it off at the pass... */
if(*cptr->passwd)
{
char salt[3];
extern char *crypt();
salt[0]=aconf->passwd[0];
salt[1]=aconf->passwd[1];
salt[2]='\0';
encr = crypt(cptr->passwd, salt);
}
else
encr = "";
#else
encr = cptr->passwd;
#endif /* CRYPT_LINK_PASSWORD */
if (*aconf->passwd && !StrEq(aconf->passwd, encr))
{
sendto_one(cptr, "ERROR :No Access (passwd mismatch) %s",
inpath);
sendto_locfailops("Access denied (passwd mismatch) %s", inpath);
return exit_client(cptr, cptr, cptr, "Bad Password");
}
/* bzero(cptr->passwd, sizeof(cptr->passwd));*/
}
if ((acptr = find_name(host, NULL)))
{
aClient *ocptr;
/*
* This link is trying feed me a server that I already have
* access through another path -- multiple paths not accepted
* currently, kill this link immeatedly!!
*
* Rather than KILL the link which introduced it, KILL the
* youngest of the two links. -avalon
*/
acptr = acptr->from;
ocptr = (cptr->firsttime > acptr->firsttime) ? acptr : cptr;
acptr = (cptr->firsttime > acptr->firsttime) ? cptr : acptr;
sendto_one(acptr,"ERROR :Server %s already exists from %s",
host,
(ocptr->from ? ocptr->from->name : "<nobody>"));
sendto_ops("Link %s cancelled, server %s already exists from %s",
get_client_name(acptr, TRUE), host,
(ocptr->from ? ocptr->from->name : "<nobody>"));
return exit_client(acptr, acptr, acptr, "Server Exists");
}
if ((acptr = find_client(host, NULL)))
{
/*
** Server trying to use the same name as a person. Would
** cause a fair bit of confusion. Enough to make it hellish
** for a while and servers to send stuff to the wrong place.
*/
sendto_one(cptr,"ERROR :Nickname %s already exists!", host);
sendto_locfailops("Link %s cancelled: Server/nick collision on %s",
inpath, host);
sendto_serv_butone(&me, ":%s GLOBOPS : Link %s cancelled: Server/nick collision on %s",
parv[0], inpath, host);
return exit_client(cptr, cptr, cptr, "Nick as Server");
}
if (IsServer(cptr))
{
/*
** Server is informing about a new server behind
** this link. Create REMOTE server structure,
** add it to list and propagate word to my other
** server links...
*/
if (parc == 1 || info[0] == '\0')
{
sendto_one(cptr,
"ERROR :No server info specified for %s",
host);
return 0;
}
/*
** See if the newly found server is behind a guaranteed
** leaf (L-line). If so, close the link.
*/
if ((aconf = find_conf_host(cptr->confs, host, CONF_LEAF)) &&
(!aconf->port || (hop > aconf->port)))
{
sendto_ops("Leaf-only link %s->%s - Closing",
get_client_name(cptr, TRUE),
aconf->host ? aconf->host : "*");
sendto_one(cptr, "ERROR :Leaf-only link, sorry.");
return exit_client(cptr, cptr, cptr, "Leaf Only");
}
/*
**
*/
if (!(aconf = find_conf_host(cptr->confs, host, CONF_HUB)) ||
(aconf->port && (hop > aconf->port)) )
{
sendto_ops("Non-Hub link %s introduced %s(%s).",
get_client_name(cptr, TRUE), host,
aconf ? (aconf->host ? aconf->host : "*") :
"!");
return exit_client(cptr, cptr, cptr,
"Too many servers");
}
/*
** See if the newly found server has a Q line for it in
** our conf. If it does, lose the link that brought it
** into our network. Format:
**
** Q:<unused>:<reason>:<servername>
**
** Example: Q:*:for the hell of it:eris.Berkeley.EDU
*/
if ((aconf = find_conf_name(host, CONF_QUARANTINED_SERVER)))
{
sendto_ops_butone(NULL, &me,
":%s WALLOPS * :%s brought in %s, %s %s",
me.name, get_client_name(cptr,FALSE),
host, "closing link because",
BadPtr(aconf->passwd) ? "reason unspecified" :
aconf->passwd);
sendto_one(cptr,
"ERROR :%s is not welcome: %s. %s",
host, BadPtr(aconf->passwd) ?
"reason unspecified" : aconf->passwd,
"Try another network");
return exit_client(cptr, cptr, cptr, "Q-Lined Server");
}
acptr = make_client(cptr, find_server(parv[0], NULL));
(void)make_server(acptr);
acptr->hopcount = hop;
strncpyzt(acptr->name, host, sizeof(acptr->name));
strncpyzt(acptr->info, info, sizeof(acptr->info));
strncpyzt(acptr->serv->up, parv[0], sizeof(acptr->serv->up));
SetServer(acptr);
acptr->flags|=FLAGS_TS8;
add_client_to_list(acptr);
(void)add_to_client_hash_table(acptr->name, acptr);
/*
** Old sendto_serv_but_one() call removed because we now
** need to send different names to different servers
** (domain name matching)
*/
for (i = 0; i <= highest_fd; i++)
{
if (!(bcptr = local[i]) || !IsServer(bcptr) ||
bcptr == cptr || IsMe(bcptr))
continue;
if (!(aconf = bcptr->serv->nline))
{
sendto_ops("Lost N-line for %s on %s. Closing",
get_client_name(cptr, TRUE), host);
return exit_client(cptr, cptr, cptr,
"Lost N line");
}
if (match(my_name_for_link(me.name, aconf),
acptr->name) == 0)
continue;
if (ts)
sendto_one(bcptr, ":%s SERVER %s %d %d :%s",
parv[0], acptr->name, hop+1, ts,
acptr->info);
else
sendto_one(bcptr, ":%s SERVER %s %d :%s",
parv[0], acptr->name, hop+1,
acptr->info);
}
/* Check for U-line status -- Barubary */
if (find_conf_host(cptr->confs, acptr->name, CONF_UWORLD))
acptr->flags |= FLAGS_ULINE;
return 0;
}
if (!IsUnknown(cptr) && !IsHandshake(cptr))
return 0;
/*
** A local link that is still in undefined state wants
** to be a SERVER. Check if this is allowed and change
** status accordingly...
*/
strncpyzt(cptr->name, host, sizeof(cptr->name));
strncpyzt(cptr->info, info[0] ? info:me.name, sizeof(cptr->info));
cptr->hopcount = hop;
/* check connection rules */
for (cconf = conf; cconf; cconf = cconf->next)
if ((cconf->status == CONF_CRULEALL) &&
(match(cconf->host, host) == 0))
if (crule_eval (cconf->passwd))
{
ircstp->is_ref++;
sendto_ops("Refused connection from %s.",
get_client_host(cptr));
return exit_client(cptr, cptr, cptr,
"Disallowed by connection rule");
}
switch (check_server_init(cptr))
{
case 0 :
return m_server_estab(cptr);
case 1 :
sendto_ops("Access check for %s in progress",
get_client_name(cptr,TRUE));
return 1;
default :
ircstp->is_ref++;
sendto_ops("Received unauthorized connection from %s.", get_client_host(cptr));
sendto_serv_butone(&me, ":%s GLOBOPS :Recieved unauthorized connection from %s.",
parv[0], get_client_host(cptr));
return exit_client(cptr, cptr, cptr, "No C/N conf lines");
}
}
int m_server_estab(cptr)
Reg1 aClient *cptr;
{
Reg2 aClient *acptr;
Reg3 aConfItem *aconf, *bconf;
char *inpath, *host, *s, *encr;
int split, i;
inpath = get_client_name(cptr,TRUE); /* "refresh" inpath with host */
split = mycmp(cptr->name, cptr->sockhost);
host = cptr->name;
current_load_data.conn_count++;
update_load();
if (!(aconf = find_conf(cptr->confs, host, CONF_NOCONNECT_SERVER)))
{
ircstp->is_ref++;
sendto_one(cptr,
"ERROR :Access denied. No N line for server %s",
inpath);
sendto_ops("Access denied. No N line for server %s", inpath);
return exit_client(cptr, cptr, cptr, "No N line for server");
}
if (!(bconf = find_conf(cptr->confs, host, CONF_CONNECT_SERVER)))
{
ircstp->is_ref++;
sendto_one(cptr, "ERROR :Only N (no C) field for server %s",
inpath);
sendto_ops("Only N (no C) field for server %s",inpath);
return exit_client(cptr, cptr, cptr, "No C line for server");
}
#ifdef CRYPT_LINK_PASSWORD
/* use first two chars of the password they send in as salt */
/* passwd may be NULL. Head it off at the pass... */
if(*cptr->passwd)
{
char salt[3];
extern char *crypt();
salt[0]=aconf->passwd[0];
salt[1]=aconf->passwd[1];
salt[2]='\0';
encr = crypt(cptr->passwd, salt);
}
else
encr = "";
#else
encr = cptr->passwd;
#endif /* CRYPT_LINK_PASSWORD */
if (*aconf->passwd && !StrEq(aconf->passwd, encr))
{
ircstp->is_ref++;
sendto_one(cptr, "ERROR :No Access (passwd mismatch) %s",
inpath);
sendto_ops("Access denied (passwd mismatch) %s", inpath);
return exit_client(cptr, cptr, cptr, "Bad Password");
}
bzero(cptr->passwd, sizeof(cptr->passwd));
#ifndef HUB
for (i = 0; i <= highest_fd; i++)
if (local[i] && IsServer(local[i]))
{
ircstp->is_ref++;
sendto_one(cptr, "ERROR :I'm a leaf not a hub");
return exit_client(cptr, cptr, cptr, "I'm a leaf");
}
#endif
if (IsUnknown(cptr))
{
sendto_one(cptr, "PROTOCTL %s", PROTOCTL_SERVER);
if (bconf->passwd[0])
sendto_one(cptr,"PASS :%s",bconf->passwd);
/*
** Pass my info to the new server
*/
sendto_one(cptr, "SERVER %s 1 :%s",
my_name_for_link(me.name, aconf),
(me.info[0]) ? (me.info) : "IRCers United");
}
else
{
s = (char *)index(aconf->host, '@');
*s = '\0'; /* should never be NULL */
Debug((DEBUG_INFO, "Check Usernames [%s]vs[%s]",
aconf->host, cptr->username));
if (match(aconf->host, cptr->username))
{
*s = '@';
ircstp->is_ref++;
sendto_ops("Username mismatch [%s]v[%s] : %s",
aconf->host, cptr->username,
get_client_name(cptr, TRUE));
sendto_one(cptr, "ERROR :No Username Match");
return exit_client(cptr, cptr, cptr, "Bad User");
}
*s = '@';
sendto_one(cptr, "PROTOCTL %s", PROTOCTL_SERVER);
}
det_confs_butmask(cptr,
CONF_LEAF|CONF_HUB|CONF_NOCONNECT_SERVER|CONF_UWORLD);
/*
** *WARNING*
** In the following code in place of plain server's
** name we send what is returned by get_client_name
** which may add the "sockhost" after the name. It's
** *very* *important* that there is a SPACE between
** the name and sockhost (if present). The receiving
** server will start the information field from this
** first blank and thus puts the sockhost into info.
** ...a bit tricky, but you have been warned, besides
** code is more neat this way... --msa
*/
SetServer(cptr);
#ifndef NO_FDLIST
addto_fdlist(cptr->fd,&serv_fdlist);
#endif
if (find_conf_host(cptr->confs, cptr->name, CONF_UWORLD))
cptr->flags |= FLAGS_ULINE;
cptr->flags|=FLAGS_TS8;
nextping = TStime();
if (TRUEHUB == 1)
sendto_serv_butone(&me, ":%s GLOBOPS :Link with %s established.",
me.name, inpath);
sendto_locfailops("Link with %s established.", inpath);
/* Insert here */
(void)add_to_client_hash_table(cptr->name, cptr);
/* doesnt duplicate cptr->serv if allocted this struct already */
(void)make_server(cptr);
(void)strcpy(cptr->serv->up, me.name);
cptr->srvptr = &me;
cptr->serv->nline = aconf;
if (find_conf_host(cptr->confs, cptr->name, CONF_UWORLD))
cptr->flags |= FLAGS_ULINE;
/*
** Old sendto_serv_but_one() call removed because we now
** need to send different names to different servers
** (domain name matching) Send new server to other servers.
*/
for (i = 0; i <= highest_fd; i++)
{
if (!(acptr = local[i]) || !IsServer(acptr) ||
acptr == cptr || IsMe(acptr))
continue;
if ((aconf = acptr->serv->nline) &&
!match(my_name_for_link(me.name, aconf), cptr->name))
continue;
if (split)
sendto_one(acptr,":%s %s %s 2 :%s",
me.name,
(IsToken(cptr) ? TOK_SERVER : MSG_SERVER),
cptr->name,
cptr->info);
else
sendto_one(acptr,":%s %s %s 2 :%s",
me.name,
(IsToken(cptr) ? TOK_SERVER : MSG_SERVER),
cptr->name, cptr->info);
}
/*
** Pass on my client information to the new server
**
** First, pass only servers (idea is that if the link gets
** cancelled beacause the server was already there,
** there are no NICK's to be cancelled...). Of course,
** if cancellation occurs, all this info is sent anyway,
** and I guess the link dies when a read is attempted...? --msa
**
** Note: Link cancellation to occur at this point means
** that at least two servers from my fragment are building
** up connection this other fragment at the same time, it's
** a race condition, not the normal way of operation...
**
** ALSO NOTE: using the get_client_name for server names--
** see previous *WARNING*!!! (Also, original inpath
** is destroyed...)
*/
aconf = cptr->serv->nline;
for (acptr = &me; acptr; acptr = acptr->prev)
{
/* acptr->from == acptr for acptr == cptr */
if (acptr->from == cptr)
continue;
if (IsServer(acptr))
{
if (match(my_name_for_link(me.name, aconf),
acptr->name) == 0)
continue;
split = (MyConnect(acptr) &&
mycmp(acptr->name, acptr->sockhost));
if (split)
sendto_one(cptr, ":%s %s %s %d :%s",
acptr->serv->up,
(IsToken(cptr) ? TOK_SERVER : MSG_SERVER),
acptr->name,
acptr->hopcount+1,
acptr->info);
else
sendto_one(cptr, ":%s %s %s %d :%s",
acptr->serv->up,
(IsToken(cptr) ? TOK_SERVER : MSG_SERVER),
acptr->name,
acptr->hopcount+1, acptr->info);
}
}
for (acptr = &me; acptr; acptr = acptr->prev)
{
/* acptr->from == acptr for acptr == cptr */
if (acptr->from == cptr)
continue;
if (IsPerson(acptr))
{
/*
** IsPerson(x) is true only when IsClient(x) is true.
** These are only true when *BOTH* NICK and USER have
** been received. -avalon
** Apparently USER command was forgotten... -Donwulff
*/
if (!SupportNICKv2(cptr))
{
sendto_one(cptr,"%s %s %d %d %s %s %s %lu :%s",
(IsToken(cptr)?TOK_NICK:MSG_NICK),
acptr->name, acptr->hopcount + 1, acptr->lastnick,
acptr->user->username, acptr->user->realhost,
acptr->user->server, acptr->user->servicestamp,
acptr->info);
send_umode(cptr, acptr, 0, SEND_UMODES, buf);
if (IsHidden(acptr))
sendto_one(cptr, ":%s %s %s", acptr->name,
(IsToken(cptr)?TOK_SETHOST:MSG_SETHOST),
acptr->user->virthost);
}
else
{
send_umode(NULL, acptr, 0, SEND_UMODES, buf);
sendto_one(cptr,"%s %s %d %d %s %s %s %lu %s %s :%s",
(IsToken(cptr)?TOK_NICK:MSG_NICK),
acptr->name, acptr->hopcount + 1, acptr->lastnick,
acptr->user->username, acptr->user->realhost,
acptr->user->server,
acptr->user->servicestamp,
(!buf || *buf == '\0' ? "+" : buf),
((IsHidden(acptr) && (acptr->umodes & UMODE_SETHOST)) ? acptr->user->virthost : "*"),
acptr->info);
}
if (acptr->user->away)
sendto_one(cptr,":%s %s :%s", acptr->name,
(IsToken(cptr)?TOK_AWAY:MSG_AWAY),
acptr->user->away);
if (acptr->user->swhois)
if (*acptr->user->swhois != '\0')
sendto_one(cptr, "%s %s :%s",
(IsToken(cptr)?TOK_SWHOIS:MSG_SWHOIS),
acptr->name, acptr->user->swhois);
if (!SupportSJOIN(cptr))
send_user_joins(cptr, acptr);
}
else if (IsService(acptr))
{
sendto_one(cptr,"NICK %s :%d",
acptr->name, acptr->hopcount + 1);
sendto_one(cptr,":%s SERVICE * * :%s",
acptr->name, acptr->info);
}
}
/*
** Last, pass all channels plus statuses
*/
{
Reg1 aChannel *chptr;
for (chptr = channel; chptr; chptr = chptr->nextch)
{
if (!SupportSJOIN(cptr))
send_channel_modes(cptr, chptr);
else
send_channel_modes_sjoin(cptr, chptr);
if (chptr->topic_time)
sendto_one(cptr,"%s %s %s %lu :%s",
(IsToken(cptr)?TOK_TOPIC:MSG_TOPIC),
chptr->chname, chptr->topic_nick,
chptr->topic_time, chptr->topic);
}
}
/* pass on TKLs */
tkl_synch(cptr);
/*
** Pass on all services based q-lines
*/
{
Reg1 aSqlineItem *tmp;
for(tmp=sqline;tmp;tmp=tmp->next) {
if(tmp->status != CONF_ILLEGAL)
if(tmp->reason)
sendto_one(cptr,":%s %s %s :%s", me.name,
(IsToken(cptr)?TOK_SQLINE:MSG_SQLINE),
tmp->sqline, tmp->reason);
else
sendto_one(cptr,":%s %s %s", me.name,
tmp->sqline);
}
}
sendto_one(cptr, "%s %li %li %li 0 0 0 0 :%s",
(IsToken(cptr)?TOK_NETINFO:MSG_NETINFO),
lu_mglobalu,
TStime(),
UnrealProtocol,
ircnetwork);
return 0;
}
/*
** m_links
** parv[0] = sender prefix
** parv[1] = servername mask
** or
** parv[0] = sender prefix
** parv[1] = server to query
** parv[2] = servername mask
*/
int m_links(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
char *mask;
aClient *acptr;
if (check_registered_user(sptr))
return 0;
if (parc > 2 && IsOper(cptr))
{
if (hunt_server(cptr, sptr, ":%s LINKS %s :%s", 1, parc, parv)
!= HUNTED_ISME)
return 0;
mask = parv[2];
}
else
mask = parc < 2 ? NULL : parv[1];
for (acptr = client, (void)collapse(mask); acptr; acptr = acptr->next)
{
if (!IsServer(acptr) && !IsMe(acptr))
continue;
if (!BadPtr(mask) && match(mask, acptr->name))
continue;
if (HIDE_ULINES == 1) {
if (IsULine(acptr, acptr) && !IsAnOper(sptr))
continue;
}
sendto_one(sptr, rpl_str(RPL_LINKS),
me.name, parv[0], acptr->name, acptr->serv->up,
acptr->hopcount, (acptr->info[0] ? acptr->info :
"(Unknown Location)"));
}
sendto_one(sptr, rpl_str(RPL_ENDOFLINKS), me.name, parv[0],
BadPtr(mask) ? "*" : mask);
return 0;
}
/*
** m_netinfo
** by Stskeeps
** parv[0] = sender prefix
** parv[1] = max global count
** parv[2] = time of end sync
** parv[3] = unreal protocol using (numeric)
** parv[4] = free(for unrealprotocol > 2100)
** parv[5] = free(**)
** parv[6] = free(**)
** parv[7] = free(**)
** parv[8] = ircnet
**/
int m_netinfo(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
long lmax;
time_t xx;
long endsync, protocol;
if (IsPerson(sptr))
return 0;
if (!IsServer(cptr))
return 0;
if (parc < 3) {
/* Talking to a UnProtocol 2090 */
sendto_realops("Link %s is using a too old UnProtocol - (parc < 3)", cptr->name);
if (KILLDIFF == 1) {
sendto_realops("Dropped link %s - unProtocol 2090 is not compatible with unProtocol %li", cptr->name, UnrealProtocol);
sendto_one(cptr, "ERROR :unProtocol 2090 is not compatible with unProtocol %li",
UnrealProtocol);
exit_client(cptr, cptr, cptr, "Link using unProtocol 2090");
}
return 0;
}
if (parc < 9) {
return 0;
}
if (GotNetInfo(cptr)) {
sendto_realops("Already got NETINFO from Link %s", cptr->name);
return 0;
}
/* is a long therefore not ATOI */
lmax = atol(parv[1]);
endsync = atol(parv[2]);
protocol = atol(parv[3]);
/* update stats */
check_lusers();
/* max global count != max_global_count --sts */
if (lmax > lu_mglobalu) {
lu_mglobalu = lmax;
sendto_realops("Max Global Count is now %li (set by link %s)", lmax, cptr->name);
}
xx = TStime();
if ((xx - endsync) < 0) {
sendto_realops("Possible negative TS split at link %s (%li - %li = %li)",
cptr->name,
(xx),
(endsync),
(xx - endsync));
sendto_serv_butone(&me, ":%s SMO o :\2(sync)\2 Possible negative TS split at link %s (%li - %li = %li)",
me.name,
cptr->name,
(xx),
(endsync),
(xx - endsync));
}
sendto_realops("Link %s -> %s is now synced [secs: %li recv: %li.%li sent: %li.%li]",
cptr->name,
me.name,
(TStime() - endsync),
sptr->receiveK,
sptr->receiveB,
sptr->sendK,
sptr->sendB);
sendto_serv_butone(&me, ":%s SMO o :\2(sync)\2 Link %s -> %s is now synced [secs: %li recv: %li.%li sent: %li.%li]",
me.name,
cptr->name,
me.name,
(TStime() - endsync),
sptr->receiveK,
sptr->receiveB,
sptr->sendK,
sptr->sendB);
if (!(strcmp(ircnetwork, parv[8])==0)) {
sendto_realops("Network name mismatch from link %s (%s != %s)", cptr->name, parv[8], ircnetwork);
sendto_serv_butone(&me, ":%s SMO o :\2(sync)\2 Network name mismatch from link %s (%s != %s)", me.name, cptr->name, parv[8], ircnetwork);
}
if (protocol != UnrealProtocol) {
sendto_realops("Link %s is running Protocol u%li while we are running %li!",
cptr->name, protocol, UnrealProtocol);
sendto_serv_butone(&me, ":%s SMO o :\2(sync)\2 Link %s is running u%li while %s is running %li!",
me.name, cptr->name, protocol,me.name,UnrealProtocol);
}
SetNetInfo(cptr);
}
#ifndef IRCDTOTALVERSION
#define IRCDTOTALVERSION BASE_VERSION PATCH1 PATCH2 PATCH3 PATCH4 PATCH5 PATCH6 PATCH7 PATCH8 PATCH9
#endif
/*
* sends m_info into to sptr
*/
void m_info_send(sptr)
aClient *sptr;
{
sendto_one(sptr, ":%s %d %s :=-=-=-=-=-==-== %s =-=-=-=-=-==-==",
me.name, RPL_INFO, sptr->name, ircnetwork);
sendto_one(sptr, ":%s %d %s :|Web Page: | http://www.%s",
me.name, RPL_INFO, sptr->name, netdomain);
sendto_one(sptr, ":%s %d %s :|FTP Archive: | ftp://ftp.%s",
me.name, RPL_INFO, sptr->name, netdomain);
sendto_one(sptr, ":%s %d %s :|Help channel: | %s",
me.name, RPL_INFO, sptr->name, helpchan);
sendto_one(sptr, ":%s %d %s :|=-=-=-=-=-==-==|-=-=-=-=-=-=-==-==-=-=-=-=-=-=-=",
me.name, RPL_INFO, sptr->name);
sendto_one(sptr, ":%s %d %s :|IRCd version: | %s",
me.name, RPL_INFO, sptr->name, IRCDTOTALVERSION);
sendto_one(sptr, ":%s %d %s :| Developers: | Stskeeps <stskeeps@tspre.org>",
me.name, RPL_INFO, sptr->name);
sendto_one(sptr, ":%s %d %s :| | codemastr <codemastr@tspre.org>>",
me.name, RPL_INFO, sptr->name);
#ifdef _WIN32
#ifdef WIN32_SPECIFY
sendto_one(sptr, ":%s %d %s :| wIRCd porter: | %s",
me.name, RPL_INFO, sptr->name, WIN32_PORTER);
sendto_one(sptr, ":%s %d %s :| >>URL: | %s",
me.name, RPL_INFO, sptr->name, WIN32_URL);
#endif
#endif
sendto_one(sptr, ":%s %d %s :|Credits: | Type /Credits",
me.name, RPL_INFO, sptr->name);
sendto_one(sptr, ":%s %d %s :|DALnet Credits | Type /DalInfo",
me.name, RPL_INFO, sptr->name);
sendto_one(sptr, ":%s %d %s :-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-",
me.name, RPL_INFO, sptr->name);
sendto_one(sptr, ":%s %d %s :Birth Date: %s, compile # %s",
me.name, RPL_INFO, sptr->name, creation, generation);
sendto_one(sptr, ":%s %d %s :On-line since %s",
me.name, RPL_INFO, sptr->name,
myctime(me.firsttime));
sendto_one(sptr, ":%s %d %s :ReleaseID (%s)",
me.name, RPL_INFO, sptr->name,
RELEASEID);
sendto_one(sptr, rpl_str(RPL_ENDOFINFO), me.name, sptr->name);
}
/*
** m_info
** parv[0] = sender prefix
** parv[1] = servername
** Modified for hardcode by Stskeeps
*/
int m_info(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
char **text = infotext;
if (check_registered(sptr))
return 0;
if (hunt_server(cptr,sptr,":%s INFO :%s",1,parc,parv) == HUNTED_ISME)
{
m_info_send(sptr);
}
return 0;
}
/*
** m_dalinfo
** parv[0] = sender prefix
** parv[1] = servername
*/
int m_dalinfo(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
char **text = dalinfotext;
if (check_registered(sptr))
return 0;
if (hunt_server(cptr,sptr,":%s DALINFO :%s",1,parc,parv) == HUNTED_ISME)
{
while (*text)
sendto_one(sptr, rpl_str(RPL_INFO),
me.name, parv[0], *text++);
sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], "");
sendto_one(sptr,
":%s %d %s :Birth Date: %s, compile # %s",
me.name, RPL_INFO, parv[0], creation, generation);
sendto_one(sptr, ":%s %d %s :On-line since %s",
me.name, RPL_INFO, parv[0],
myctime(me.firsttime));
sendto_one(sptr, rpl_str(RPL_ENDOFINFO), me.name, parv[0]);
}
return 0;
}
/*
** m_license
** parv[0] = sender prefix
** parv[1] = servername
*/
int m_license(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
char **text = gnulicense;
if (check_registered(sptr))
return 0;
if (hunt_server(cptr,sptr,":%s LICENSE :%s",1,parc,parv) == HUNTED_ISME)
{
while (*text)
sendto_one(sptr, rpl_str(RPL_INFO),
me.name, parv[0], *text++);
sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], "");
sendto_one(sptr, rpl_str(RPL_ENDOFINFO), me.name, parv[0]);
}
return 0;
}
/*
** m_credits
** parv[0] = sender prefix
** parv[1] = servername
*/
int m_credits(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
char **text = unrealcredits;
if (check_registered(sptr))
return 0;
if (hunt_server(cptr,sptr,":%s CREDITS :%s",1,parc,parv) == HUNTED_ISME)
{
while (*text)
sendto_one(sptr, rpl_str(RPL_INFO),
me.name, parv[0], *text++);
sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], "");
sendto_one(sptr,
":%s %d %s :Birth Date: %s, compile # %s",
me.name, RPL_INFO, parv[0], creation, generation);
sendto_one(sptr, ":%s %d %s :On-line since %s",
me.name, RPL_INFO, parv[0],
myctime(me.firsttime));
sendto_one(sptr, rpl_str(RPL_ENDOFINFO), me.name, parv[0]);
}
return 0;
}
/*
* RPL_NOWON - Online at the moment (Succesfully added to WATCH-list)
* RPL_NOWOFF - Offline at the moement (Succesfully added to WATCH-list)
* RPL_WATCHOFF - Succesfully removed from WATCH-list.
* ERR_TOOMANYWATCH - Take a guess :> Too many WATCH entries.
*/
static void show_watch(cptr, name, rpl1, rpl2)
aClient *cptr;
char *name;
int rpl1, rpl2;
{
aClient *acptr;
if ((acptr = find_person(name, NULL))) {
make_virthost(acptr->user->realhost, acptr->user->virthost);
sendto_one(cptr, rpl_str(rpl1), me.name, cptr->name,
acptr->name, acptr->user->username,
acptr->user->virthost, acptr->lastnick);
}
else
sendto_one(cptr, rpl_str(rpl2), me.name, cptr->name,
name, "*", "*", 0);
}
/*
* m_watch
*/
int m_watch(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
char namebuf[USERLEN+HOSTLEN+4];
Reg1 aClient *acptr;
Reg2 char *s, **pav = parv, *user;
Reg3 int len;
char *p = NULL, *def = "l";
if (check_registered(sptr))
return 0;
if (parc < 2) {
/*
* Default to 'l' - list who's currently online
*/
parc = 2;
parv[1] = def;
}
for (s = (char *)strtoken(&p, *++pav, " "); s;
s = (char *)strtoken(&p, NULL, " ")) {
if ((user = (char *)index(s, '!')))
*user++ = '\0'; /* Not used */
/*
* Prefix of "+", they want to add a name to their WATCH
* list.
*/
if (*s == '+') {
if (do_nick_name(s+1)) {
if (sptr->notifies >= MAXWATCH) {
sendto_one(sptr, err_str(ERR_TOOMANYWATCH),
me.name, cptr->name, s+1);
continue;
}
add_to_notify_hash_table(s+1, sptr);
}
show_watch(sptr, s+1, RPL_NOWON, RPL_NOWOFF);
continue;
}
/*
* Prefix of "-", coward wants to remove somebody from their
* WATCH list. So do it. :-)
*/
if (*s == '-') {
del_from_notify_hash_table(s+1, sptr);
show_watch(sptr, s+1, RPL_WATCHOFF, RPL_WATCHOFF);
continue;
}
/*
* Fancy "C" or "c", they want to nuke their WATCH list and start
* over, so be it.
*/
if (*s == 'C' || *s == 'c') {
hash_del_notify_list(sptr);
continue;
}
/*
* Now comes the fun stuff, "S" or "s" returns a status report of
* their WATCH list. I imagine this could be CPU intensive if its
* done alot, perhaps an auto-lag on this?
*/
if (*s == 'S' || *s == 's') {
Link *lp;
aNotify *anptr;
int count = 0;
/*
* Send a list of how many users they have on their WATCH list
* and how many WATCH lists they are on.
*/
anptr = hash_get_notify(sptr->name);
if (anptr)
for (lp = anptr->notify, count = 1; (lp = lp->next); count++)
;
sendto_one(sptr, rpl_str(RPL_WATCHSTAT), me.name, parv[0],
sptr->notifies, count);
/*
* Send a list of everybody in their WATCH list. Be careful
* not to buffer overflow.
*/
if ((lp = sptr->notify) == NULL) {
sendto_one(sptr, rpl_str(RPL_ENDOFWATCHLIST), me.name, parv[0],
*s);
continue;
}
*buf = '\0';
strcpy(buf, lp->value.nptr->nick);
count = strlen(parv[0])+strlen(me.name)+10+strlen(buf);
while ((lp = lp->next)) {
if (count+strlen(lp->value.nptr->nick)+1 > BUFSIZE - 2) {
sendto_one(sptr, rpl_str(RPL_WATCHLIST), me.name,
parv[0], buf);
*buf = '\0';
count = strlen(parv[0])+strlen(me.name)+10;
}
strcat(buf, " ");
strcat(buf, lp->value.nptr->nick);
count += (strlen(lp->value.nptr->nick)+1);
}
sendto_one(sptr, rpl_str(RPL_WATCHLIST), me.name, parv[0], buf);
sendto_one(sptr, rpl_str(RPL_ENDOFWATCHLIST), me.name, parv[0],
*s);
continue;
}
/*
* Well that was fun, NOT. Now they want a list of everybody in
* their WATCH list AND if they are online or offline? Sheesh,
* greedy arn't we?
*/
if (*s == 'L' || *s == 'l') {
Link *lp = sptr->notify;
while (lp) {
if ((acptr = find_person(lp->value.nptr->nick, NULL))) {
make_virthost(acptr->user->realhost, acptr->user->virthost);
sendto_one(sptr, rpl_str(RPL_NOWON), me.name, parv[0],
acptr->name, acptr->user->username,
acptr->user->virthost, acptr->lastnick);
}
/*
* But actually, only show them offline if its a capital
* 'L' (full list wanted).
*/
else if (isupper(*s))
sendto_one(sptr, rpl_str(RPL_NOWOFF), me.name, parv[0],
lp->value.nptr->nick, "*", "*",
lp->value.nptr->lasttime);
lp = lp->next;
}
sendto_one(sptr, rpl_str(RPL_ENDOFWATCHLIST), me.name, parv[0],
*s);
continue;
}
/*
* Hmm.. unknown prefix character.. Ignore it. :-)
*/
}
return 0;
}
/*
** m_summon should be redefined to ":prefix SUMMON host user" so
** that "hunt_server"-function could be used for this too!!! --msa
** As of 2.7.1e, this was the case. -avalon
**
** parv[0] = sender prefix
** parv[1] = user
** parv[2] = server
** parv[3] = channel (optional)
*/
int m_summon(cptr, sptr, parc, parv)
aClient *sptr, *cptr;
int parc;
char *parv[];
{
char *host, *user, *chname;
#ifdef ENABLE_SUMMON
char hostbuf[17], namebuf[10], linebuf[10];
# ifdef LEAST_IDLE
char linetmp[10], ttyname[15]; /* Ack */
struct stat stb;
time_t ltime = (time_t)0;
# endif
int fd, flag = 0;
#endif
if (check_registered_user(sptr))
return 0;
if (parc < 2 || *parv[1] == '\0')
{
sendto_one(sptr, err_str(ERR_NORECIPIENT),
me.name, parv[0], "SUMMON");
return 0;
}
user = parv[1];
host = (parc < 3 || BadPtr(parv[2])) ? me.name : parv[2];
chname = (parc > 3) ? parv[3] : "*";
/*
** Summoning someone on remote server, find out which link to
** use and pass the message there...
*/
parv[1] = user;
parv[2] = host;
parv[3] = chname;
parv[4] = NULL;
if (hunt_server(cptr, sptr, ":%s SUMMON %s %s %s", 2, parc, parv) ==
HUNTED_ISME)
{
#ifdef ENABLE_SUMMON
if ((fd = utmp_open()) == -1)
{
sendto_one(sptr, err_str(ERR_FILEERROR),
me.name, parv[0], "open", UTMP);
return 0;
}
# ifndef LEAST_IDLE
while ((flag = utmp_read(fd, namebuf, linebuf, hostbuf,
sizeof(hostbuf))) == 0)
if (StrEq(namebuf,user))
break;
# else
/* use least-idle tty, not the first
* one we find in utmp. 10/9/90 Spike@world.std.com
* (loosely based on Jim Frost jimf@saber.com code)
*/
while ((flag = utmp_read(fd, namebuf, linetmp, hostbuf,
sizeof(hostbuf))) == 0)
{
if (StrEq(namebuf,user))
{
(void)sprintf(ttyname,"/dev/%s",linetmp);
if (stat(ttyname,&stb) == -1)
{
sendto_one(sptr,
err_str(ERR_FILEERROR),
me.name, sptr->name,
"stat", ttyname);
return 0;
}
if (!ltime)
{
ltime= stb.st_mtime;
(void)strcpy(linebuf,linetmp);
}
else if (stb.st_mtime > ltime) /* less idle */
{
ltime= stb.st_mtime;
(void)strcpy(linebuf,linetmp);
}
}
}
# endif
(void)utmp_close(fd);
# ifdef LEAST_IDLE
if (ltime == 0)
# else
if (flag == -1)
# endif
sendto_one(sptr, err_str(ERR_NOLOGIN),
me.name, parv[0], user);
else
summon(sptr, user, linebuf, chname);
#else
sendto_one(sptr, err_str(ERR_SUMMONDISABLED),
me.name, parv[0]);
#endif /* ENABLE_SUMMON */
}
return 0;
}
/*
** m_stats
** parv[0] = sender prefix
** parv[1] = statistics selector (defaults to Message frequency)
** parv[2] = server name (current server defaulted, if omitted)
**
** Currently supported are:
** M = Message frequency (the old stat behaviour)
** L = Local Link statistics
** C = Report C and N configuration lines
*/
/*
** m_stats/stats_conf
** Report N/C-configuration lines from this server. This could
** report other configuration lines too, but converting the
** status back to "char" is a bit akward--not worth the code
** it needs...
**
** Note: The info is reported in the order the server uses
** it--not reversed as in ircd.conf!
*/
static int report_array[18][3] = {
{ CONF_CONNECT_SERVER, RPL_STATSCLINE, 'C'},
{ CONF_NOCONNECT_SERVER, RPL_STATSNLINE, 'N'},
{ CONF_CLIENT, RPL_STATSILINE, 'I'},
{ CONF_KILL, RPL_STATSKLINE, 'K'},
{ CONF_EXCEPT, RPL_STATSKLINE, 'E'},
{ CONF_ZAP, RPL_STATSKLINE, 'Z'},
{ CONF_QUARANTINED_NICK, RPL_STATSQLINE, 'Q'},
{ CONF_LEAF, RPL_STATSLLINE, 'L'},
{ CONF_OPERATOR, RPL_STATSOLINE, 'O'},
{ CONF_HUB, RPL_STATSHLINE, 'H'},
{ CONF_LOCOP, RPL_STATSOLINE, 'o'},
{ CONF_CRULEALL, RPL_STATSDLINE, 'D'},
{ CONF_CRULEAUTO, RPL_STATSDLINE, 'd'},
{ CONF_UWORLD, RPL_STATSULINE, 'U'},
{ CONF_MISSING, RPL_STATSXLINE, 'X'},
{ CONF_TLINE, RPL_STATSTLINE, 't'},
{ 0, 0}
};
static void report_sqlined_nicks(sptr)
aClient *sptr;
{
aSqlineItem *tmp;
char *nickmask, *reason;
for(tmp = sqline; tmp; tmp=tmp->next) {
if(tmp->status != CONF_ILLEGAL) {
nickmask = BadPtr(tmp->sqline) ? "<NULL>" : tmp->sqline;
reason = BadPtr(tmp->reason) ? "<NULL>" : tmp->reason;
sendto_one(sptr, rpl_str(RPL_SQLINE_NICK), me.name,
sptr->name, nickmask, reason);
}
}
}
static void report_configured_links(sptr, mask)
aClient *sptr;
int mask;
{
static char null[] = "<NULL>";
aConfItem *tmp;
int *p, port, tmpmask;
char c, *host, *pass, *name;
char *pp, *ppx;
tmpmask = (mask == CONF_MISSING) ? CONF_CONNECT_SERVER : mask;
for (tmp = conf; tmp; tmp = tmp->next)
if (tmp->status & tmpmask)
{
for (p = &report_array[0][0]; *p; p += 3)
if (*p == tmp->status)
break;
if (!*p)
continue;
c = (char)*(p+2);
host = BadPtr(tmp->host) ? null : tmp->host;
pass = BadPtr(tmp->passwd) ? null : tmp->passwd;
name = BadPtr(tmp->name) ? null : tmp->name;
port = (int)tmp->port;
/*
* On K line the passwd contents can be
* displayed on STATS reply. -Vesa
*/
/* Same with Z-lines and q/Q-lines -- Barubary */
if ((tmp->status == CONF_KILL) || (tmp->status &
CONF_QUARANTINE) || (tmp->status & CONF_EXCEPT)
||
(tmp->status == CONF_ZAP))
{
/* These mods are to tell the difference between the different kinds
* of klines. the only effect it has is in the display. --Russell
*/
/* Now translates spaces to _'s to show comments in klines -- Barubary */
char *temp;
if (!pass) strcpy(buf, "<NULL>");
else {
strcpy(buf, pass);
for (temp = buf; *temp; temp++)
if (*temp == ' ') *temp = '_';
}
/* semicolon intentional -- Barubary */
if (tmp->status == CONF_QUARANTINED_NICK);
/* Hide password for servers -- Barubary */
else if (tmp->status & CONF_QUARANTINE)
strcpy(buf, "*");
else {
/* This wasn't documented before - comments aren't displayed for akills
because they are all the same. -- Barubary */
if (tmp->tmpconf == KLINE_AKILL)
strcpy(buf, "*");
/* Show comments in E:Lines..
if (tmp->tmpconf == KLINE_EXCEPT)
strcpy(buf, "*");
*/
/* KLINE_PERM == 0 - watch out when doing
Z-lines. -- Barubary */
if (tmp->status != CONF_ZAP)
{
if (tmp->tmpconf == KLINE_PERM) c = 'K';
if (tmp->tmpconf == KLINE_TEMP) c = 'k';
if (tmp->tmpconf == KLINE_AKILL) c = 'A';
if (tmp->tmpconf == KLINE_EXCEPT) c = 'E';
}
else
{
if (tmp->tmpconf == KLINE_PERM) c = 'Z';
if (tmp->tmpconf == KLINE_TEMP) c = 'z';
if (tmp->tmpconf == KLINE_AKILL) c = 'S';
if (tmp->tmpconf == KLINE_EXCEPT) c = 'e';
}
}
sendto_one(sptr, rpl_str(p[1]), me.name,
sptr->name, c, host,
buf, name, port,
get_conf_class(tmp));
}
else if (mask & CONF_OPS)
{
sendto_one(sptr, rpl_str(p[1]), me.name,
sptr->name,c,host,name, oflagstr(port),
get_conf_class(tmp));
}
/* connect rules are classless */
else if (tmp->status & CONF_CRULE)
sendto_one(sptr, rpl_str(p[1]), me.name,
sptr->name, c, host, name);
/* Only display on X if server is missing */
else if (mask == CONF_MISSING) {
if (!find_server(name, NULL))
sendto_one(sptr, rpl_str(RPL_STATSXLINE), me.name,
sptr->name, name, port);
}
else if (mask == CONF_TLINE)
{
sendto_one(sptr, rpl_str(RPL_STATSTLINE), me.name,
sptr->name, host, pass, name);
}
/* else if (mask == CONF_EXCEPT)
{
ppx = MyMalloc(strlen(tmp->passwd) + 1);
strcpy(ppx, tmp->passwd);
for (pp = ppx; *pp != '\0'; pp++) {
if (*pp == ' ')
*pp = '_';
}
sendto_one(sptr, rpl_str(RPL_STATSKLINE), me.name,
sptr->name, "E", host, ppx, name, 0,0, -1);
MyFree(ppx);
} */
else {
if(!IsOper(sptr)&&(mask&CONF_NOCONNECT_SERVER ||
mask&CONF_CONNECT_SERVER))
sendto_one(sptr, rpl_str(p[1]), me.name,
sptr->name, c, "*", name, port,
get_conf_class(tmp));
else
sendto_one(sptr, rpl_str(p[1]), me.name,
sptr->name, c, host, name, port,
get_conf_class(tmp));
}
}
return;
}
/* Used to blank out ports -- Barubary */
char *get_client_name2(aClient *acptr, int showports)
{
char *pointer = get_client_name(acptr, TRUE);
if (!pointer) return NULL;
if (showports) return pointer;
if (!strrchr(pointer, '.')) return NULL;
strcpy((char *) strrchr((char *) pointer, '.'), ".0]");
return pointer;
}
int m_stats(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
#ifndef DEBUGMODE
static char Sformat[] = ":%s %d %s SendQ SendM SendBytes RcveM RcveBytes Open_since :Idle";
static char Lformat[] = ":%s %d %s %s %u %u %u %u %u %u :%u";
#else
static char Sformat[] = ":%s %d %s SendQ SendM SendBytes RcveM RcveBytes Open_since CPU :Idle";
static char Lformat[] = ":%s %d %s %s %u %u %u %u %u %u %s";
char pbuf[96]; /* Should be enough for to ints */
#endif
struct Message *mptr;
aClient *acptr;
char stat = parc > 1 ? parv[1][0] : '\0';
Reg1 int i;
int doall = 0, wilds = 0, showports = IsAnOper(sptr), remote=0;
char *name;
if (check_registered(sptr))
return 0;
#ifdef STATS_ONLYOPER
if (!IsAnOper(sptr))
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
#endif
if (hunt_server(cptr,sptr,":%s STATS %s :%s",2,parc,parv)!=HUNTED_ISME)
return 0;
if (parc > 2)
{
name = parv[2];
if (!mycmp(name, me.name))
doall = 2;
else if (match(name, me.name) == 0)
doall = 1;
if (index(name, '*') || index(name, '?'))
wilds = 1;
}
else
name = me.name;
if (stat != '\0')
sendto_umode(UMODE_EYES,"Stats \'%c\' requested by %s (%s@%s)", stat, sptr->name,
sptr->user->username, IsHidden(sptr) ? sptr->user->virthost : sptr->user->realhost);
else
sendto_umode(UMODE_EYES,"Stats \'NULL\' requested by %s (%s@%s)", sptr->name,
sptr->user->username, IsHidden(sptr) ? sptr->user->virthost : sptr->user->realhost);
switch (stat)
{
case 'L' : case 'l' :
/*
* send info about connections which match, or all if the
* mask matches me.name. Only restrictions are on those who
* are invisible not being visible to 'foreigners' who use
* a wild card based search to list it.
*/
sendto_one(sptr, Sformat, me.name, RPL_STATSLINKINFO, parv[0]);
if (IsServer(cptr)) {
remote = 1;
wilds = 0;
}
for (i = 0; i <= highest_fd; i++)
{
if (!(acptr = local[i]))
continue;
if (IsInvisible(acptr) && (doall || wilds) &&
!(MyConnect(sptr) && IsOper(sptr)) &&
!IsAnOper(acptr) && (acptr != sptr))
continue;
if (remote && doall && !IsServer(acptr) &&
!IsMe(acptr))
continue;
if (remote && !doall && IsServer(acptr))
continue;
if (!doall && wilds && match(name, acptr->name))
continue;
if (!(parc == 2 && IsServer(acptr)) &&
!(doall || wilds) && mycmp(name, acptr->name))
continue;
#ifdef DEBUGMODE
sprintf(pbuf, "%d :%d", acptr->cputime,
(acptr->user && MyConnect(acptr)) ?
TStime() - acptr->user->last : 0);
#endif
if(IsOper(sptr)) {
sendto_one(sptr, Lformat, me.name,
RPL_STATSLINKINFO, parv[0],
(isupper(stat)) ?
get_client_name2(acptr, showports) :
get_client_name(acptr, FALSE),
(int)DBufLength(&acptr->sendQ),
(int)acptr->sendM, (int)acptr->sendK,
(int)acptr->receiveM, (int)acptr->receiveK,
TStime() - acptr->firsttime,
#ifndef DEBUGMODE
(acptr->user && MyConnect(acptr)) ?
TStime() - acptr->user->last : 0);
#else
pbuf);
#endif
if (!IsServer(acptr) && IsAnOper(acptr))
sendto_one(acptr, ":%s NOTICE %s :*** %s did a /stats L on you! IP may have been shown", me.name, acptr->name, sptr->name);
}
else if(!strchr(acptr->name,'.'))
sendto_one(sptr, Lformat, me.name,
RPL_STATSLINKINFO, parv[0],
IsHidden(acptr) ? acptr->name :
(isupper(stat)) ? /* Potvin - PreZ */
get_client_name2(acptr, showports) :
get_client_name(acptr, FALSE),
(int)DBufLength(&acptr->sendQ),
(int)acptr->sendM, (int)acptr->sendK,
(int)acptr->receiveM, (int)acptr->receiveK,
TStime() - acptr->firsttime,
#ifndef DEBUGMODE
(acptr->user && MyConnect(acptr)) ?
TStime() - acptr->user->last : 0);
#else
pbuf);
#endif
}
break;
case 'C' : case 'c' :
report_configured_links(sptr, CONF_CONNECT_SERVER|
CONF_NOCONNECT_SERVER);
break;
case 'f' : case 'F' :
report_flines(sptr);
break;
case 'G' : case 'g' :
tkl_stats (sptr);
break;
case 'H' : case 'h' :
report_configured_links(sptr, CONF_HUB|CONF_LEAF);
break;
case 'I' : case 'i' :
report_configured_links(sptr, CONF_CLIENT);
break;
case 'E' : case 'e' :
report_configured_links(sptr, CONF_EXCEPT);
break;
case 'K' : case 'k' :
report_configured_links(sptr, CONF_KILL|CONF_ZAP|CONF_EXCEPT);
break;
case 'M' : case 'm' :
for (mptr = msgtab; mptr->cmd; mptr++)
if (mptr->count)
#ifndef DEBUGMODE
sendto_one(sptr, rpl_str(RPL_STATSCOMMANDS),
me.name, parv[0], mptr->cmd,
mptr->count, mptr->bytes);
#else
sendto_one(sptr, rpl_str(RPL_STATSCOMMANDS),
me.name, parv[0], mptr->cmd,
mptr->count, mptr->bytes,
mptr->lticks,
mptr->lticks/CLOCKS_PER_SEC,
mptr->rticks,
mptr->rticks/CLOCKS_PER_SEC);
#endif
break;
case 'N': case 'n':
if (IsOper(sptr))
report_network(sptr);
break;
case 'o' : case 'O' :
/* if (SHOWOPERS == 1) {
if(IsOper(sptr)) {
report_configured_links(sptr, CONF_OPS);
break;
}
}
else
if (SHOWOPERS == 0) {
report_configured_links(sptr, CONF_OPS);
*/
if (SHOWOPERS == 0 && (IsOper(sptr))) {
report_configured_links(sptr, CONF_OPS);
break;
}
if (SHOWOPERS == 1)
report_configured_links(sptr, CONF_OPS);
break;
case 'Q' :
report_configured_links(sptr, CONF_QUARANTINE);
break;
case 'q' :
report_sqlined_nicks(sptr);
break;
case 'R' :
#ifdef DEBUGMODE
send_usage(sptr,parv[0]);
#endif
break;
case 'S' :
if (IsOper(sptr))
report_dynconf(sptr);
break;
case 'D' :
report_configured_links(sptr, CONF_CRULEALL);
break;
case 'd' :
report_configured_links(sptr, CONF_CRULE);
break;
case 'r' :
cr_report(sptr);
break;
case 't' :
report_configured_links(sptr, CONF_TLINE);
break;
case 'T' : /* /stats T not t:lines .. */
tstats(sptr, parv[0]);
break;
case 'U' :
report_configured_links(sptr, CONF_UWORLD);
break;
case 'u' :
{
register time_t tmpnow;
tmpnow = TStime() - me.since;
sendto_one(sptr, rpl_str(RPL_STATSUPTIME), me.name, parv[0],
tmpnow/86400, (tmpnow/3600)%24, (tmpnow/60)%60, tmpnow%60);
sendto_one(sptr, rpl_str(RPL_STATSCONN), me.name, parv[0],
max_connection_count, max_client_count);
break;
}
case 'v' : case 'V' :
vhost_report(sptr);
break;
case 'W' : case 'w' :
calc_load(sptr, parv[0]);
break;
case 'X' : case 'x' :
report_configured_links(sptr, CONF_MISSING);
break;
case 'Y' : case 'y' :
report_classes(sptr);
break;
case 'Z' : case 'z' :
count_memory(sptr, parv[0]);
break;
default :
stat = '*';
break;
}
sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], stat);
return 0;
}
/*
** m_users
** parv[0] = sender prefix
** parv[1] = servername
*/
int m_users(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
#ifdef ENABLE_USERS
char namebuf[10],linebuf[10],hostbuf[17];
int fd, flag = 0;
#endif
if (check_registered_user(sptr))
return 0;
if (hunt_server(cptr,sptr,":%s USERS :%s",1,parc,parv) == HUNTED_ISME)
{
#ifdef ENABLE_USERS
if ((fd = utmp_open()) == -1)
{
sendto_one(sptr, err_str(ERR_FILEERROR),
me.name, parv[0], "open", UTMP);
return 0;
}
sendto_one(sptr, rpl_str(RPL_USERSSTART), me.name, parv[0]);
while (utmp_read(fd, namebuf, linebuf,
hostbuf, sizeof(hostbuf)) == 0)
{
flag = 1;
sendto_one(sptr, rpl_str(RPL_USERS), me.name, parv[0],
namebuf, linebuf, hostbuf);
}
if (flag == 0)
sendto_one(sptr, rpl_str(RPL_NOUSERS),
me.name, parv[0]);
sendto_one(sptr, rpl_str(RPL_ENDOFUSERS), me.name, parv[0]);
(void)utmp_close(fd);
#else
sendto_one(sptr, err_str(ERR_USERSDISABLED), me.name, parv[0]);
#endif
}
return 0;
}
/*
** Note: At least at protocol level ERROR has only one parameter,
** although this is called internally from other functions
** --msa
**
** parv[0] = sender prefix
** parv[*] = parameters
*/
int m_error(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
Reg1 char *para;
para = (parc > 1 && *parv[1] != '\0') ? parv[1] : "<>";
Debug((DEBUG_ERROR,"Received ERROR message from %s: %s",
sptr->name, para));
/*
** Ignore error messages generated by normal user clients
** (because ill-behaving user clients would flood opers
** screen otherwise). Pass ERROR's from other sources to
** the local operator...
*/
if (IsPerson(cptr) || IsUnknown(cptr) || IsService(cptr))
return 0;
if (cptr == sptr) {
sendto_serv_butone(&me, ":%s GLOBOPS :ERROR from %s -- %s",
me.name, get_client_name(cptr, FALSE), para);
sendto_locfailops("ERROR :from %s -- %s",
get_client_name(cptr, FALSE), para);
}
else {
sendto_serv_butone(&me, ":%s GLOBOPS :ERROR from %s via %s -- %s",
me.name, sptr->name, get_client_name(cptr, FALSE), para);
sendto_ops("ERROR :from %s via %s -- %s", sptr->name,
get_client_name(cptr,FALSE), para);
}
return 0;
}
Link *helpign=NULL;
/* Now just empty ignore-list, in future reload dynamic help.
* Move out to help.c -Donwulff */
void reset_help() {
free_str_list(helpign);
}
/*
** m_help (help/write to +h currently online) -Donwulff
** parv[0] = sender prefix
** parv[1] = optional message text
*/
int m_help(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
int i;
char *message, *pv[4], *s;
Link *tmpl;
if (check_registered(sptr))
return 0;
message = parc > 1 ? parv[1] : NULL;
/* Drags along from wallops code... I'm not sure what it's supposed to do,
at least it won't do that gracefully, whatever it is it does - but
checking whether or not it's a person _is_ good... -Donwulff */
if (!IsServer(sptr) && MyConnect(sptr) && !IsPerson(sptr))
{
check_registered(sptr);
return 0;
}
if (IsServer(sptr) || IsHelpOp(sptr)) {
if(BadPtr(message)) return 0;
if(message[0]=='?') {
parse_help(sptr, parv[0], message+1);
return 0;
}
if (message[1]=='!')
sendto_serv_butone(IsServer(cptr) ? cptr : NULL,
":%s HELP %s", parv[0], message);
if(!myncmp(message, "IGNORE ", 7)) {
tmpl=make_link();
DupString(tmpl->value.cp, message+7);
tmpl->next = helpign;
helpign=tmpl;
}
sendto_helpops("from %s (HelpOp): %s", parv[0], message);
} else if (MyConnect(sptr)) {
/* New syntax: ?... never goes out, !... always does. */
if(!BadPtr(message)) {
parse_help(sptr, parv[0], message);
return 0;
}
if((!BadPtr(message)&&!(message[0]=='!'))||BadPtr(message))
if(parse_help(sptr, parv[0], message)) return 0;
s = make_nick_user_host(cptr->name, cptr->user->username,
cptr->user->realhost);
for (tmpl = helpign; tmpl; tmpl = tmpl->next)
if (match(tmpl->value.cp, s) == 0) {
sendto_one(sptr, rpl_str(RPL_HELPIGN), me.name, parv[0]);
return 0;
}
sendto_serv_butone(IsServer(cptr) ? cptr : NULL,
":%s HELP %s", parv[0], message);
sendto_helpops("from %s (Local): %s", parv[0], message);
sendto_one(sptr, rpl_str(RPL_HELPFWD), me.name, parv[0]);
} else {
sendto_serv_butone(IsServer(cptr) ? cptr : NULL,
":%s HELP %s", parv[0], message);
sendto_helpops("from %s: %s", parv[0], message);
}
return 0;
}
/*
* parv[0] = sender
* parv[1] = host/server mask.
* parv[2] = server to query
*/
int m_lusers(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
int s_count, c_count, u_count, i_count;
int o_count, m_client, m_client_local, m_server;
char mydom_mask[HOSTLEN + 1];
aClient *acptr;
if (check_registered_user(sptr))
return 0;
/* Doesn't work anyways --Stskeeps
if (parc > 2)
if(hunt_server(cptr, sptr, ":%s LUSERS %s :%s", 2, parc, parv)
!= HUNTED_ISME)
return 0;
*/
mydom_mask[0] = '*';
strncpy(&mydom_mask[1], DOMAINNAME, HOSTLEN - 1);
if(parc==1) {
s_count = lu_serv;
c_count = lu_noninv;
u_count = lu_unknown;
i_count = lu_inv;
o_count = lu_oper;
m_client = lu_lu;
m_client_local = lu_lulocal;
m_server = lu_lserv;
global_count=lu_cglobalu;
}
else {
s_count=c_count=u_count=i_count=o_count=m_client=
m_client_local=m_server=0;
(void)collapse(parv[1]);
for (acptr = client; acptr; acptr = acptr->next)
{
if (parc>1)
if (!IsServer(acptr) && acptr->user)
{
if (match(parv[1], acptr->user->server))
continue;
}
else
if (match(parv[1], acptr->name))
continue;
switch (acptr->status)
{
case STAT_SERVER:
if (MyConnect(acptr))
m_server++;
case STAT_ME:
s_count++;
break;
case STAT_CLIENT:
if (IsOper(acptr))
o_count++;
if (MyConnect(acptr)) {
m_client++;
if (match(mydom_mask, acptr->sockhost) == 0)
m_client_local++;
}
if (!IsInvisible(acptr))
c_count++;
else
i_count++;
break;
default:
u_count++;
break;
}
}
}
sendto_one(sptr, rpl_str(RPL_LUSERCLIENT), me.name, parv[0],
c_count, i_count, s_count);
max_client_count = lu_mlu;
max_global_count = lu_mglobalu;
if (o_count)
sendto_one(sptr, rpl_str(RPL_LUSEROP),
me.name, parv[0], o_count);
if (u_count > 0)
sendto_one(sptr, rpl_str(RPL_LUSERUNKNOWN),
me.name, parv[0], u_count);
if ((c_count = count_channels(sptr))>0)
sendto_one(sptr, rpl_str(RPL_LUSERCHANNELS),
me.name, parv[0], lu_channel);
sendto_one(sptr, rpl_str(RPL_LUSERME),
me.name, parv[0], m_client, m_server);
sendto_one(sptr, rpl_str(RPL_LOCALUSERS),
me.name, parv[0], m_client, max_client_count);
sendto_one(sptr, rpl_str(RPL_GLOBALUSERS),
me.name, parv[0], global_count, max_global_count);
if ((m_client + m_server) > max_connection_count) {
max_connection_count = m_client + m_server;
if (max_connection_count % 10 == 0) /* only send on even tens */
sendto_ops("Maximum connections: %d (%d clients)",
max_connection_count, max_client_count);
}
current_load_data.local_count = m_client_local;
current_load_data.client_count = m_client;
current_load_data.conn_count = m_client + m_server;
return 0;
}
void save_tunefile(void)
{
FILE *tunefile;
tunefile = fopen(IRCDTUNE, "w+");
if (!tunefile) {
#if !defined(_WIN32) && !defined(_AMIGA)
sendto_ops("Unable to write tunefile.. %s", strerror(errno));
#else
sendto_ops("Unable to write tunefile..");
#endif
return;
}
fprintf(tunefile, "%li\n", TSoffset);
fprintf(tunefile, "%li\n", lu_mlu);
fclose(tunefile);
}
void load_tunefile(void)
{
FILE *tunefile;
char buf[1024];
tunefile = fopen(IRCDTUNE, "r");
if (!tunefile)
return;
fprintf(stderr, "* Loading tunefile..\n");
fgets(buf, 1023, tunefile);
TSoffset = atol(buf);
fgets(buf, 1023, tunefile);
lu_mlu = atol(buf);
fclose(tunefile);
}
/***********************************************************************
* m_connect() - Added by Jto 11 Feb 1989
***********************************************************************/
/*
** m_connect
** parv[0] = sender prefix
** parv[1] = servername
** parv[2] = port number
** parv[3] = remote server
*/
int m_connect(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
int port, tmpport, retval;
aConfItem *aconf, *cconf;
aClient *acptr;
if (check_registered(sptr))
return 0;
if (!IsPrivileged(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return -1;
}
if (MyClient(sptr) && !OPCanGRoute(sptr) && parc > 3)
{ /* Only allow LocOps to make */
/* local CONNECTS --SRB */
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if (MyClient(sptr) && !OPCanLRoute(sptr) && parc <= 3)
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if (hunt_server(cptr,sptr,":%s CONNECT %s %s :%s",
3,parc,parv) != HUNTED_ISME)
return 0;
if (parc < 2 || *parv[1] == '\0')
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
me.name, parv[0], "CONNECT");
return -1;
}
if ((acptr = find_server(parv[1], NULL)))
{
sendto_one(sptr, ":%s NOTICE %s :Connect: Server %s %s %s.",
me.name, parv[0], parv[1], "already exists from",
acptr->from->name);
return 0;
}
for (aconf = conf; aconf; aconf = aconf->next)
if (aconf->status == CONF_CONNECT_SERVER &&
match(parv[1], aconf->name) == 0)
break;
/* Checked first servernames, then try hostnames. */
if (!aconf)
for (aconf = conf; aconf; aconf = aconf->next)
if (aconf->status == CONF_CONNECT_SERVER &&
(match(parv[1], aconf->host) == 0 ||
match(parv[1], index(aconf->host, '@')+1) == 0))
break;
if (!aconf)
{
sendto_one(sptr,
"NOTICE %s :Connect: Host %s not listed in ircd.conf",
parv[0], parv[1]);
return 0;
}
/*
** Get port number from user, if given. If not specified,
** use the default form configuration structure. If missing
** from there, then use the precompiled default.
*/
tmpport = port = aconf->port;
if (parc > 2 && !BadPtr(parv[2]))
{
if ((port = atoi(parv[2])) <= 0)
{
sendto_one(sptr,
"NOTICE %s :Connect: Illegal port number",
parv[0]);
return 0;
}
}
else if (port <= 0 && (port = PORTNUM) <= 0)
{
sendto_one(sptr, ":%s NOTICE %s :Connect: missing port number",
me.name, parv[0]);
return 0;
}
/*
** Evaluate connection rules... If no rules found, allow the
** connect. Otherwise stop with the first true rule (ie: rules
** are ored together. Oper connects are effected only by D
** lines (CRULEALL) not d lines (CRULEAUTO).
*/
for (cconf = conf; cconf; cconf = cconf->next)
if ((cconf->status == CONF_CRULEALL) &&
(match(cconf->host, aconf->name) == 0))
if (crule_eval (cconf->passwd))
{
sendto_one(sptr,
"NOTICE %s :Connect: Disallowed by rule: %s",
parv[0], cconf->name);
return 0;
}
/*
** Notify all operators about remote connect requests
*/
if (!IsAnOper(cptr))
{
sendto_serv_butone(&me,
":%s GLOBOPS :Remote CONNECT %s %s from %s",
me.name, parv[1], parv[2] ? parv[2] : "",
get_client_name(sptr,FALSE));
#if defined(USE_SYSLOG) && defined(SYSLOG_CONNECT)
syslog(LOG_DEBUG, "CONNECT From %s : %s %d", parv[0], parv[1], parv[2] ? parv[2] : "");
#endif
}
aconf->port = port;
switch (retval = connect_server(aconf, sptr, NULL))
{
case 0:
sendto_one(sptr,
":%s NOTICE %s :*** Connecting to %s[%s].",
me.name, parv[0], aconf->host, aconf->name);
break;
case -1:
sendto_one(sptr, ":%s NOTICE %s :*** Couldn't connect to %s.",
me.name, parv[0], aconf->host);
break;
case -2:
sendto_one(sptr, ":%s NOTICE %s :*** Host %s is unknown.",
me.name, parv[0], aconf->host);
break;
default:
sendto_one(sptr,
":%s NOTICE %s :*** Connection to %s failed: %s",
me.name, parv[0], aconf->host, strerror(retval));
}
aconf->port = tmpport;
return 0;
}
/*
** m_wallops (write to *all* opers currently online)
** parv[0] = sender prefix
** parv[1] = message text
*/
int m_wallops(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
char *message, *pv[4];
if (check_registered(sptr))
return 0;
message = parc > 1 ? parv[1] : NULL;
if (BadPtr(message))
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
me.name, parv[0], "WALLOPS");
return 0;
}
if (MyClient(sptr) && !OPCanWallOps(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
sendto_ops_butone(IsServer(cptr) ? cptr : NULL, sptr,
":%s WALLOPS :%s", parv[0], message);
return 0;
}
/* m_gnotice (Russell) sort of like wallop, but only to +g clients on
** this server.
** parv[0] = sender prefix
** parv[1] = message text
*/
int m_gnotice(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
char *message, *pv[4];
if (check_registered(sptr))
return 0;
message = parc > 1 ? parv[1] : NULL;
if (BadPtr(message))
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
me.name, parv[0], "GNOTICE");
return 0;
}
if (!IsServer(sptr) && MyConnect(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
sendto_serv_butone(IsServer(cptr) ? cptr : NULL, ":%s GNOTICE :%s",
parv[0], message);
sendto_failops("from %s: %s", parv[0], message);
return 0;
}
/*
** m_addline (write a line to ircd.conf)
**
** De-Potvinized by codemastr
*/
int m_addline(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
FILE *conf;
int i;
char *text;
text = parc > 1 ? parv[1] : NULL;
if (check_registered(sptr))
return 0;
if (!(IsAdmin(sptr) || IsCoAdmin(sptr)))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if (parc < 2)
{
sendto_one (sptr, err_str(ERR_NEEDMOREPARAMS),
me.name, parv[0], "ADDLINE");
return 0;
}
conf = fopen (CPATH, "a");
if (conf == NULL)
{
return 0;
}
/* Display what they wrote too */
sendto_one(sptr, ":%s NOTICE %s :*** Wrote (%s) to ircd.conf",
me.name, parv[0], text);
fprintf(conf, "# Added by %s\n", make_nick_user_host(sptr->name,sptr->user->username,sptr->user->realhost));
/* for (i=1 ; i<parc ; i++)
{
if (i!=parc-1)
fprintf (conf,"%s ",parv[i]);
else
fprintf (conf,"%s\n",parv[i]);
}
/* I dunno what Potvin was smoking when he made this code, but it plain SUX
* this should work just as good, and no need for a loop -- codemastr */
fprintf(conf, "%s\n", text);
fclose (conf);
return 1;
}
/*
** m_addmotd (write a line to ircd.motd)
**
** De-Potvinized by codemastr
*/
int m_addmotd(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
FILE *conf;
char *text;
int i;
text = parc > 1 ? parv[1] : NULL;
if (check_registered(sptr))
return 0;
if (!MyConnect(sptr))
return 0;
if (!(IsAdmin(sptr) || IsCoAdmin(sptr)))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if (parc < 2)
{
sendto_one (sptr, err_str(ERR_NEEDMOREPARAMS),
me.name, parv[0], "ADDMOTD");
return 0;
}
conf = fopen (MOTD, "a");
if (conf == NULL)
{
return 0;
}
sendto_one(sptr, ":%s NOTICE %s :*** Wrote (%s) to file: ircd.motd",
me.name, parv[0], text);
/* for (i=1 ; i<parc ; i++)
{
if (i!=parc-1)
fprintf (conf,"%s ",parv[i]);
else
fprintf (conf,"%s\n",parv[i]);
} */
fprintf(conf, "%s\n", text);
fclose (conf);
return 1;
}
/*
** m_svsmotd
**
*/
int m_svsmotd(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
FILE *conf = NULL;
int i;
if (check_registered(sptr))
return 0;
if (!IsULine(cptr, sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if (parc < 2)
{
sendto_one (sptr, err_str(ERR_NEEDMOREPARAMS),
me.name, parv[0], "SVSMOTD");
return 0;
}
if ((*parv[1] != '!') && parc < 3) {
sendto_one (sptr, err_str(ERR_NEEDMOREPARAMS),
me.name, parv[0], "SVSMOTD");
return 0;
}
switch (*parv[1]) {
case '#' : conf = fopen(VPATH, "a");
sendto_ops("Added '%s' to services motd", parv[2]);
break;
case '!' : {
remove(VPATH);
sendto_ops("Wiped out services motd data");
break;
}
default: break;
}
sendto_serv_butone(cptr, ":%s SVSMOTD %s :%s", parv[0], parv[1], parv[2]);
if (conf == NULL)
{
return 0;
}
if (parc < 3 && (*parv[1]=='!')) {
fclose(conf);
return 1;
}
fprintf(conf, "%s\n", parv[2]);
if (*parv[1]=='!')
sendto_ops("Added '%s' to services motd", parv[2]);
fclose (conf);
return 1;
}
/*
** m_addomotd (write a line to opermotd)
**
** De-Potvinized by codemastr
*/
int m_addomotd(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
FILE *conf;
char *text;
int i;
text = parc > 1 ? parv[1] : NULL;
if (check_registered(sptr))
return 0;
if (!MyConnect(sptr))
return 0;
if (!(IsAdmin(sptr) || IsCoAdmin(sptr)))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if (parc < 2)
{
sendto_one (sptr, err_str(ERR_NEEDMOREPARAMS),
me.name, parv[0], "ADDMOTD");
return 0;
}
conf = fopen (OPATH, "a");
if (conf == NULL)
{
return 0;
}
sendto_one(sptr, ":%s NOTICE %s :*** Wrote (%s) to OperMotd",
me.name, parv[0], text);
/* for (i=1 ; i<parc ; i++)
{
if (i!=parc-1)
fprintf (conf,"%s ",parv[i]);
else
fprintf (conf,"%s\n",parv[i]);
} */
fprintf(conf, "%s\n", text);
fclose (conf);
return 1;
}
/*
** m_globops (write to opers who are +g currently online)
** parv[0] = sender prefix
** parv[1] = message text
*/
int m_globops(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
char *message, *pv[4];
if (check_registered(sptr))
return 0;
message = parc > 1 ? parv[1] : NULL;
if (BadPtr(message))
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
me.name, parv[0], "GLOBOPS");
return 0;
}
if (MyClient(sptr) && !OPCanGlobOps(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
sendto_serv_butone(IsServer(cptr) ? cptr : NULL,
":%s GLOBOPS :%s", parv[0], message);
sendto_failops_whoare_opers("from %s: %s", parv[0], message);
return 0;
}
/*
** m_locops (write to opers who are +g currently online *this* server)
** parv[0] = sender prefix
** parv[1] = message text
*/
int m_locops(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
char *message, *pv[4];
if (check_registered_user(cptr))
return 0;
message = parc > 1 ? parv[1] : NULL;
if (BadPtr(message))
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
me.name, parv[0], "LOCOPS");
return 0;
}
if (MyClient(sptr) && !OPCanLocOps(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
sendto_locfailops("from %s: %s", parv[0], message);
return 0;
}
/*
** m_chatops (write to opers who are +b currently online)
** parv[0] = sender prefix
** parv[1] = message text
*/
int m_chatops(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
char *message, *pv[4];
if (check_registered(sptr))
return 0;
message = parc > 1 ? parv[1] : NULL;
if (BadPtr(message))
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
me.name, parv[0], "CHATOPS");
return 0;
}
if (ALLOW_CHATOPS == 1) {
if (MyClient(sptr) && !SendChatops(sptr)) {
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
}
else {
if (MyClient(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
}
sendto_serv_butone(IsServer(cptr) ? cptr : NULL,
":%s CHATOPS :%s", parv[0], message);
if (ALLOW_CHATOPS == 1)
/* sendto_chatops("from %s: %s", parv[0], message); */
sendto_umode(UMODE_CHATOP, "*** ChatOps -- from %s: %s", parv[0], message);
return 0;
}
/* m_goper (Russell) sort of like wallop, but only to ALL +o clients on
** every server.
** parv[0] = sender prefix
** parv[1] = message text
*/
int m_goper(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
char *message, *pv[4];
if (check_registered(sptr))
return 0;
message = parc > 1 ? parv[1] : NULL;
if (BadPtr(message))
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
me.name, parv[0], "GOPER");
return 0;
}
/* if (!IsServer(sptr) && MyConnect(sptr) && !IsAnOper(sptr))*/
if (!IsServer(sptr) || !IsULine(cptr,sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
sendto_serv_butone(IsServer(cptr) ? cptr : NULL, ":%s GOPER :%s",
parv[0], message);
sendto_opers("from %s: %s", parv[0], message);
return 0;
}
/*
** m_time
** parv[0] = sender prefix
** parv[1] = servername
*/
int m_time(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
if (check_registered_user(sptr))
return 0;
if (hunt_server(cptr,sptr,":%s TIME :%s",1,parc,parv) == HUNTED_ISME)
sendto_one(sptr, rpl_str(RPL_TIME), me.name,
parv[0], me.name, date((long)0));
return 0;
}
/*
** m_svskill
** parv[0] = servername
** parv[1] = client
** parv[2] = kill message
*/
int m_svskill(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
aClient *acptr;
char *comment;
(parc > 2 && parv[2]) ? parv[2] : "SVS Killed";
if (parc < 2)
return -1;
if (parc == 3)
comment = parv[2];
if (parc == 2)
comment = "SVS Killed";
if(!IsULine(cptr, sptr))
return -1;
/* if (hunt_server(cptr,sptr,":%s SVSKILL %s :%s",1,parc,parv) != HUNTED_ISME)
return 0;
*/
if(parc < 1 || (!(acptr = find_client(parv[1], NULL))))
return 0;
sendto_serv_butone(cptr, ":%s SVSKILL %s :%s", parv[0], parv[1], comment);
return exit_client(cptr, acptr, sptr, comment);
}
/*
** m_admin
** parv[0] = sender prefix
** parv[1] = servername
*/
int m_admin(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
aConfItem *aconf;
/* Users may want to get the address in case k-lined, etc. -- Barubary
if (check_registered(sptr))
return 0; */
/* Only allow remote ADMINs if registered -- Barubary */
if (IsPerson(sptr) || IsServer(cptr))
if (hunt_server(cptr,sptr,":%s ADMIN :%s",1,parc,parv) != HUNTED_ISME)
return 0;
if ((aconf = find_admin()))
{
sendto_one(sptr, rpl_str(RPL_ADMINME),
me.name, parv[0], me.name);
sendto_one(sptr, rpl_str(RPL_ADMINLOC1),
me.name, parv[0],
(aconf->host ? aconf->host : "-"));
sendto_one(sptr, rpl_str(RPL_ADMINLOC2),
me.name, parv[0],
(aconf->passwd ? aconf->passwd : "-"));
sendto_one(sptr, rpl_str(RPL_ADMINEMAIL),
me.name, parv[0],
(aconf->name ? aconf->name : "-"));
}
else
sendto_one(sptr, err_str(ERR_NOADMININFO),
me.name, parv[0], me.name);
return 0;
}
/*
** m_rehash
** remote rehash by binary
** now allows the -flags in remote rehash
** ugly code but it seems to work :) -- codemastr
*/
int m_rehash(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
int x;
/* if ((!MyClient(sptr) && !(IsNetAdmin(sptr) || IsTechAdmin(sptr)) && !IsULine(cptr, sptr)) ||
(MyClient(sptr) && !OPCanRehash(sptr)))
*/ if (MyClient(sptr) && !OPCanRehash(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if (!MyClient(sptr) && !(IsTechAdmin(sptr) ||IsNetAdmin(sptr)) && !IsULine(cptr, sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
x = 0;
if (!BadPtr(parv[1]))
{
if (*parv[1] == '-')
{
if (!match("-dcc*", parv[1]))
{
sendto_ops("Rehashing dccdeny.conf on request of %s", sptr->name);
dcc_rehash();
return 0;
}
if (!match("-dyn*", parv[1]))
{
if (!IsAdmin(sptr))
return 0;
sendto_ops("Rehashing dynamic configuration on request of %s", sptr->name);
load_conf(ZCONF, 1);
return 0;
}
if (!match("-rest*", parv[1]))
{
if (!IsAdmin(sptr))
return 0;
sendto_ops("Rehashing channel restrict configuration on request of %s", sptr->name);
cr_rehash();
return 0;
}
if (!match("-vhos*", parv[1]))
{
if (!IsAdmin(sptr))
return 0;
sendto_ops("Rehashing vhost configuration on request of %s", sptr->name);
vhost_rehash();
return 0;
}
}
if (MyClient(sptr) && !(IsNetAdmin(sptr) || IsTechAdmin(sptr)))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
/* This little number allows us to send a -param to another server,
* but only if it exists -- codemastr*/
if (parv[2] != NULL) {
if ((x=hunt_server(cptr,sptr,":%s REHASH %s %s",1,parc,parv))
!= HUNTED_ISME)
return 0;
}
if (parv[2] == NULL) {
if ((x=hunt_server(cptr,sptr,":%s REHASH %s",1,parc,parv))
!= HUNTED_ISME)
return 0;
}
}
if (cptr != sptr)
{
#ifndef REMOTE_REHASH
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
#else
if (parv[2] == NULL) {
sendto_serv_butone(&me, ":%s GLOBOPS :%s is remotely rehashing server config file",
me.name, sptr->name);
sendto_ops("%s is remotely rehashing server config file", parv[0]);
}
/* Then we have a hack here to parse the flags (thats the ugly part) */
else {
if (!BadPtr(parv[2]))
{
if (*parv[2] == '-')
{
if (!match("-dcc*", parv[2]))
{
sendto_serv_butone(&me, ":%s GLOBOPS :%s is remotely rehashing dccdeny.conf",
me.name, sptr->name);
sendto_ops("Remotely rehashing dccdeny.conf on request of %s", sptr->name);
dcc_rehash();
return 0;
}
if (!match("-dyn*", parv[2]))
{
sendto_serv_butone(&me, ":%s GLOBOPS :%s is remotely rehashing dynamic configuration",
me.name, sptr->name);
sendto_ops("Remotely rehashing dynamic configuration on request of %s", sptr->name);
load_conf(ZCONF, 1);
return 0;
}
if (!match("-rest*", parv[2]))
{
sendto_serv_butone(&me, ":%s GLOBOPS :%s is remotely rehashing channel restrict configuration",
me.name, sptr->name);
sendto_ops("Remotely rehashing channel restrict configuration on request of %s", sptr->name);
cr_rehash();
return 0;
}
if (!match("-vhos*", parv[2]))
{
sendto_serv_butone(&me, ":%s GLOBOPS :%s is remotely rehashing vhost configuration",
me.name, sptr->name);
sendto_ops("Remotely rehashing vhost configuration on request of %s", sptr->name);
vhost_rehash();
return 0;
}
}
}
}
#endif
}
else {
sendto_ops("%s is rehashing server config file", parv[0]);
}
sendto_one(sptr, rpl_str(RPL_REHASHING), me.name, parv[0], configfile);
#ifdef USE_SYSLOG
syslog(LOG_INFO, "REHASH From %s\n", get_client_name(sptr, FALSE));
#endif
return rehash(cptr, sptr, (parc > 1) ? ((*parv[1] == 'q')?2:0) : 0);
}
/*
** m_restart
**
** parv[1] - password *OR* reason if no X:line
** parv[2] - reason for restart (optional & only if X:line exists)
**
** The password is only valid if there is a matching X line in the
** config file. If it is not, then it becomes the
*/
int m_restart(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
char *pass = NULL;
int x;
if (check_registered(sptr))
return 0;
if (MyClient(sptr) && !OPCanRestart(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if (!MyClient(sptr) && !(IsTechAdmin(sptr) ||IsNetAdmin(sptr)) && !IsULine(cptr, sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if (parc > 2)
{
/* Remote restart. */
if (MyClient(sptr) && !(IsNetAdmin(sptr) || IsTechAdmin(sptr)))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if ((x=hunt_server(cptr,sptr,":%s RESTART %s %s :%s",2,parc,parv))
!= HUNTED_ISME)
return 0;
}
if (cptr != sptr) {
sendto_serv_butone(&me, ":%s GLOBOPS :%s is remotely restarting server (%s)",
me.name, sptr->name, parv[3]);
sendto_ops("%s is remotely restarting IRCd (%s)", parv[0], parv[3]);
}
if ((pass = find_restartpass()))
{
if (parc < 2)
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "RESTART");
return 0;
}
if (strcmp(pass, parv[1]))
{
sendto_one(sptr, err_str(ERR_PASSWDMISMATCH), me.name, parv[0]);
return 0;
}
/* Hack to make the code after this if { } easier: we assign the comment to the
* first param, as if we had not had an X:line. We do not need the password
* now anyways. Accordingly we decrement parc ;) -- NikB
*/
parv[1] = parv[2];
parc--;
}
#ifdef USE_SYSLOG
syslog(LOG_WARNING, "Server RESTART by %s - %s\n",
get_client_name(sptr,FALSE),
(!MyClient(sptr) ? (parc > 2 ? parv[3] : "No reason")
: (parc > 1 ? parv[2] : "No reason")));
#endif
sendto_ops("Server is Restarting by request of %s", parv[0]);
server_reboot((!MyClient(sptr) ? (parc > 2 ? parv[3] : "No reason")
: (parc > 1 ? parv[2] : "No reason")));
return 0;
}
/*
** m_trace
** parv[0] = sender prefix
** parv[1] = servername
*/
int m_trace(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
Reg1 int i;
Reg2 aClient *acptr, *acptr2;
aClass *cltmp;
char *tname;
int doall, link_s[MAXCONNECTIONS], link_u[MAXCONNECTIONS];
int cnt = 0, wilds, dow;
time_t now;
if (check_registered(sptr))
return 0;
if (parc > 2)
if (hunt_server(cptr, sptr, ":%s TRACE %s :%s",
2, parc, parv))
return 0;
if (parc > 1)
tname = parv[1];
else
tname = me.name;
if(!IsOper(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
switch (hunt_server(cptr, sptr, ":%s TRACE :%s", 1, parc, parv))
{
case HUNTED_PASS: /* note: gets here only if parv[1] exists */
{
aClient *ac2ptr;
ac2ptr = next_client(client, tname);
sendto_one(sptr, rpl_str(RPL_TRACELINK), me.name, parv[0],
version, debugmode, tname, ac2ptr->from->name);
return 0;
}
case HUNTED_ISME:
break;
default:
return 0;
}
doall = (parv[1] && (parc > 1)) ? !match(tname, me.name): TRUE;
wilds = !parv[1] || index(tname, '*') || index(tname, '?');
dow = wilds || doall;
#ifndef _WIN32
for (i = 0; i < MAXCONNECTIONS; i++)
link_s[i] = 0, link_u[i] = 0;
#else
bzero(link_s, sizeof(link_s));
bzero(link_u, sizeof(link_u));
#endif
if (doall)
for (acptr = client; acptr; acptr = acptr->next)
#ifdef SHOW_INVISIBLE_LUSERS
if (IsPerson(acptr))
link_u[acptr->from->fd]++;
#else
if (IsPerson(acptr) &&
(!IsInvisible(acptr) || IsOper(sptr)))
link_u[acptr->from->fd]++;
#endif
else if (IsServer(acptr))
link_s[acptr->from->fd]++;
/* report all direct connections */
now = TStime();
for (i = 0; i <= highest_fd; i++)
{
char *name;
int class;
if (!(acptr = local[i])) /* Local Connection? */
continue;
/* More bits of code to allow oers to see all users on remote traces
* if (IsInvisible(acptr) && dow &&
* if (dow &&
* !(MyConnect(sptr) && IsOper(sptr)) && */
if (!IsOper(sptr) &&
!IsAnOper(acptr) && (acptr != sptr))
continue;
if (!doall && wilds && match(tname, acptr->name))
continue;
if (!dow && mycmp(tname, acptr->name))
continue;
name = get_client_name(acptr,FALSE);
class = get_client_class(acptr);
switch(acptr->status)
{
case STAT_CONNECTING:
sendto_one(sptr, rpl_str(RPL_TRACECONNECTING), me.name,
parv[0], class, name);
cnt++;
break;
case STAT_HANDSHAKE:
sendto_one(sptr, rpl_str(RPL_TRACEHANDSHAKE), me.name,
parv[0], class, name);
cnt++;
break;
case STAT_ME:
break;
case STAT_UNKNOWN:
sendto_one(sptr, rpl_str(RPL_TRACEUNKNOWN),
me.name, parv[0], class, name);
cnt++;
break;
case STAT_CLIENT:
/* Only opers see users if there is a wildcard
* but anyone can see all the opers.
*/
/* if (IsOper(sptr) &&
* Allow opers to see invisible users on a remote trace or wildcard
* search ... sure as hell helps to find clonebots. --Russell
* (MyClient(sptr) || !(dow && IsInvisible(acptr)))
* || !dow || IsAnOper(acptr)) */
if (IsOper(sptr) ||
(IsAnOper(acptr) && !IsInvisible(acptr)))
{
if (IsAnOper(acptr))
sendto_one(sptr,
rpl_str(RPL_TRACEOPERATOR),
me.name,
parv[0], class, acptr->name, IsHidden(acptr) ? acptr->user->virthost : acptr->user->realhost,
now - acptr->lasttime);
else
sendto_one(sptr,rpl_str(RPL_TRACEUSER),
me.name, parv[0],
class, acptr->name, acptr->user->realhost,
now - acptr->lasttime);
cnt++;
}
break;
case STAT_SERVER:
if (acptr->serv->user)
sendto_one(sptr, rpl_str(RPL_TRACESERVER),
me.name, parv[0], class, link_s[i],
link_u[i], name, acptr->serv->by,
acptr->serv->user->username,
acptr->serv->user->realhost,
now - acptr->lasttime);
else
sendto_one(sptr, rpl_str(RPL_TRACESERVER),
me.name, parv[0], class, link_s[i],
link_u[i], name, *(acptr->serv->by) ?
acptr->serv->by : "*", "*", me.name,
now - acptr->lasttime);
cnt++;
break;
case STAT_SERVICE:
sendto_one(sptr, rpl_str(RPL_TRACESERVICE),
me.name, parv[0], class, name);
cnt++;
break;
case STAT_LOG:
sendto_one(sptr, rpl_str(RPL_TRACELOG), me.name,
parv[0], LOGFILE, acptr->port);
cnt++;
break;
default: /* ...we actually shouldn't come here... --msa */
sendto_one(sptr, rpl_str(RPL_TRACENEWTYPE), me.name,
parv[0], name);
cnt++;
break;
}
}
/*
* Add these lines to summarize the above which can get rather long
* and messy when done remotely - Avalon
*/
if (!IsAnOper(sptr) || !cnt)
{
if (cnt)
return 0;
/* let the user have some idea that its at the end of the
* trace
*/
sendto_one(sptr, rpl_str(RPL_TRACESERVER),
me.name, parv[0], 0, link_s[me.fd],
link_u[me.fd], me.name, "*", "*", me.name);
return 0;
}
for (cltmp = FirstClass(); doall && cltmp; cltmp = NextClass(cltmp))
if (Links(cltmp) > 0)
sendto_one(sptr, rpl_str(RPL_TRACECLASS), me.name,
parv[0], Class(cltmp), Links(cltmp));
return 0;
}
/*
** m_motd
** parv[0] = sender prefix
** parv[1] = servername
** Modified for T:Lines by Stskeeps
*/
int m_motd(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
int fd, nr;
char line[80];
Reg1 char *tmp;
struct stat sb;
struct tm *tm;
aConfItem *motdconf;
int svsnofile = 0;
if (check_registered(sptr))
return 0;
if (hunt_server(cptr, sptr, ":%s MOTD :%s", 1,parc,parv)!=HUNTED_ISME)
return 0;
/*
* stop NFS hangs...most systems should be able to open a file in
* 3 seconds. -avalon (curtesy of wumpus)
*/
/*
Remote. - Should this be replaced by a
find_conf_host(conf, "Remote", CONF_TLINE) ?
-Sts
*/
if (!MyConnect(sptr))
#ifndef TLINE_Remote
fd = open(MOTD, O_RDONLY);
#else
{
motdconf = find_tline("Remote");
if (motdconf == NULL) /* no match found*/
fd = open(MOTD, O_RDONLY);
else {
fd = open(motdconf->passwd, O_RDONLY);
if (fd == -1)
{
/* Actually there is a T:Line but not a MOTD.. */
/* I choose to use default MOTD instead */
#ifndef TLINE_REPORT_MISSING
fd = open(MOTD, O_RDONLY);
#endif
}
}
}
#endif
else {
motdconf = (aConfItem *) find_tline((char *)sptr->user->realhost);
if (motdconf == NULL) /* no match found*/
fd = open(MOTD, O_RDONLY);
else {
fd = open((char *)motdconf->passwd, O_RDONLY);
if (fd == -1)
{
/* Actually there is a T:Line but not a MOTD.. */
/* I choose to use default MOTD instead */
#ifndef TLINE_REPORT_MISSING
fd = open(MOTD, O_RDONLY);
#endif
}
}
}
if (fd == -1)
{
sendto_one(sptr, err_str(ERR_NOMOTD), me.name, parv[0]);
svsnofile = 1;
goto svsmotd;
}
(void)fstat(fd, &sb);
sendto_one(sptr, rpl_str(RPL_MOTDSTART), me.name, parv[0], me.name);
tm = localtime(&sb.st_mtime);
sendto_one(sptr, ":%s %d %s :- %d/%d/%d %d:%02d", me.name, RPL_MOTD,
parv[0], tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year,
tm->tm_hour, tm->tm_min);
(void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
while ((nr=dgets(fd, line, sizeof(line)-1)) > 0)
{
line[nr]='\0';
if ((tmp = (char *)index(line,'\n')))
*tmp = '\0';
if ((tmp = (char *)index(line,'\r')))
*tmp = '\0';
sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv[0], line);
}
(void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
(void)close(fd);
svsmotd:
/* SVSMOTD */
if ((fd = open(VPATH, O_RDONLY)) == -1) {
}
else
{
(void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
while ((nr=dgets(fd, line, sizeof(line)-1)) > 0)
{
line[nr]='\0';
if ((tmp = (char *)index(line,'\n')))
*tmp = '\0';
if ((tmp = (char *)index(line,'\r')))
*tmp = '\0';
sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv[0], line);
}
(void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
(void)close(fd);
}
if (svsnofile==0)
sendto_one(sptr, rpl_str(RPL_ENDOFMOTD), me.name, parv[0]);
return 0;
}
/*
** m_opermotd
** parv[0] = sender prefix
** parv[1] = servername
*/
int m_opermotd(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
int fd, nr;
char line[80];
Reg1 char *tmp;
struct stat sb;
struct tm *tm;
if (check_registered(sptr))
return 0;
if (!MyConnect(sptr))
return 0;
if (!IsAnOper(sptr))
return 0;
/*
* stop NFS hangs...most systems should be able to open a file in
* 3 seconds. -avalon (curtesy of wumpus)
*/
fd = open(OPATH, O_RDONLY);
if (fd == -1)
{
sendto_one(sptr, err_str(ERR_NOOPERMOTD), me.name, parv[0]);
return 0;
}
(void)fstat(fd, &sb);
sendto_one(sptr, rpl_str(RPL_MOTDSTART), me.name, parv[0], me.name);
tm = localtime(&sb.st_mtime);
sendto_one(sptr, ":%s %d %s :- %d/%d/%d %d:%02d", me.name, RPL_MOTD,
parv[0], tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year,
tm->tm_hour, tm->tm_min);
sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv[0], "\2IRC Operator Message of the Day\2");
(void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
while ((nr=dgets(fd, line, sizeof(line)-1)) > 0)
{
line[nr]='\0';
if ((tmp = (char *)index(line,'\n')))
*tmp = '\0';
if ((tmp = (char *)index(line,'\r')))
*tmp = '\0';
sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv[0], line);
}
(void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
sendto_one(sptr, rpl_str(RPL_ENDOFMOTD), me.name, parv[0]);
(void)close(fd);
return 0;
}
/*
** m_botmotd
** same as motd but is for bot specific rules, reads from bot.motd
** cloned from the origional m_motd in dream forge -- codemastr
** parv[0] = sender prefix
** parv[1] = servername
*/
int m_botmotd(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
int fd, nr;
char line[80];
Reg1 char *tmp;
struct stat sb;
struct tm *tm;
if (check_registered(sptr))
return 0;
if (hunt_server(cptr, sptr, ":%s BOTMOTD :%s", 1,parc,parv)!=HUNTED_ISME)
return 0;
/*
* stop NFS hangs...most systems should be able to open a file in
* 3 seconds. -avalon (curtesy of wumpus)
*/
fd = open("bot.motd", O_RDONLY);
if (fd == -1)
{
sendto_one(sptr, ":%s NOTICE AUTH :BOTMOTD File not found", me.name);
return 0;
}
(void)fstat(fd, &sb);
sendto_one(sptr, ":%s NOTICE AUTH :- %s Bot Message of the Day - ", me.name, me.name);
tm = localtime(&sb.st_mtime);
sendto_one(sptr, ":%s NOTICE AUTH :- %d/%d/%d %d:%02d", me.name, tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year,
tm->tm_hour, tm->tm_min);
(void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
while ((nr=dgets(fd, line, sizeof(line)-1)) > 0)
{
line[nr]='\0';
if ((tmp = (char *)index(line,'\n')))
*tmp = '\0';
if ((tmp = (char *)index(line,'\r')))
*tmp = '\0';
sendto_one(sptr, ":%s NOTICE AUTH :- %s", me.name, line);
}
(void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
sendto_one(sptr, ":%s NOTICE AUTH :End of /BOTMOTD command.", me.name);
(void)close(fd);
return 0;
}
/*
** m_rules
** parv[0] = sender prefix
** parv[1] = servername
** Modified for T:Lines by Codemastr (cloned from m_motd)
** Included in unrealircd by stskeeps
*/
int m_rules(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
int fd, nr;
char line[80];
Reg1 char *tmp;
struct stat sb;
struct tm *tm;
aConfItem *rulesconf;
if (check_registered(sptr))
return 0;
if (hunt_server(cptr, sptr, ":%s RULES :%s", 1,parc,parv)!=HUNTED_ISME)
return 0;
/*
* stop NFS hangs...most systems should be able to open a file in
* 3 seconds. -avalon (curtesy of wumpus)
*/
/*
Remote. - Should this be replaced by a
find_conf_host(conf, "Remote", CONF_TLINE) ?
-Sts
*/
if (!MyConnect(sptr))
#ifndef TLINE_Remote
fd = open(RPATH, O_RDONLY);
#else
{
rulesconf = (aConfItem *) find_tline("Remote");
if (rulesconf == NULL) /* no match found*/
fd = open(RPATH, O_RDONLY);
else {
fd = open(rulesconf->name, O_RDONLY);
if (fd == -1)
{
/* Actually there is a T:Line but not a MOTD.. */
/* I choose to use default MOTD instead */
#ifndef TLINE_REPORT_MISSING
fd = open(RPATH, O_RDONLY);
#endif
}
}
}
#endif
else {
rulesconf = (aConfItem *) find_tline(sptr->user->realhost);
if (rulesconf == NULL) /* no match found*/
fd = open(RPATH, O_RDONLY);
else {
fd = open((char *)rulesconf->name, O_RDONLY);
if (fd == -1)
{
/* Actually there is a T:Line but not a MOTD.. */
/* I choose to use default MOTD instead */
#ifndef TLINE_REPORT_MISSING
fd = open(RPATH, O_RDONLY);
#endif
}
}
}
if (fd == -1)
{
sendto_one(sptr, err_str(ERR_NORULES), me.name, parv[0]);
return 0;
}
(void)fstat(fd, &sb);
sendto_one(sptr, rpl_str(RPL_RULESSTART), me.name, parv[0], me.name);
tm = localtime(&sb.st_mtime);
sendto_one(sptr, ":%s %d %s :- %d/%d/%d %d:%02d", me.name, RPL_RULES,
parv[0], tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year,
tm->tm_hour, tm->tm_min);
(void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
while ((nr=dgets(fd, line, sizeof(line)-1)) > 0)
{
line[nr]='\0';
if ((tmp = (char *)index(line,'\n')))
*tmp = '\0';
if ((tmp = (char *)index(line,'\r')))
*tmp = '\0';
sendto_one(sptr, rpl_str(RPL_RULES), me.name, parv[0], line);
}
(void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
(void)close(fd);
/* SVSMOTD */
#ifndef SVSRULES
if ((fd = open(VPATH, O_RDONLY)) == -1) {
}
else
{
(void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
while ((nr=dgets(fd, line, sizeof(line)-1)) > 0)
{
line[nr]='\0';
if ((tmp = (char *)index(line,'\n')))
*tmp = '\0';
if ((tmp = (char *)index(line,'\r')))
*tmp = '\0';
sendto_one(sptr, rpl_str(RPL_RULES), me.name, parv[0], line);
}
(void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
(void)close(fd);
}
#endif
sendto_one(sptr, rpl_str(RPL_ENDOFRULES), me.name, parv[0]);
return 0;
}
/*
** m_close - added by Darren Reed Jul 13 1992.
*/
int m_close(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
Reg1 aClient *acptr;
Reg2 int i;
int closed = 0;
if (check_registered(sptr))
return 0;
if (!MyOper(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
for (i = highest_fd; i; i--)
{
if (!(acptr = local[i]))
continue;
if (!IsUnknown(acptr) && !IsConnecting(acptr) &&
!IsHandshake(acptr))
continue;
sendto_one(sptr, rpl_str(RPL_CLOSING), me.name, parv[0],
get_client_name(acptr, TRUE), acptr->status);
(void)exit_client(acptr, acptr, acptr, "Oper Closing");
closed++;
}
sendto_one(sptr, rpl_str(RPL_CLOSEEND), me.name, parv[0], closed);
sendto_ops("%s!%s@%s closed %d unknown connections", sptr->name, sptr->user->username, sptr->user->realhost, closed);
return 0;
}
/* m_die, this terminates the server, and it intentionally does not
* have a reason. If you use it you should first do a GLOBOPS and
* then a server notice to let everyone know what is going down...
*/
int m_die(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
Reg1 aClient *acptr;
Reg2 int i;
char *pass = NULL;
if (check_registered(sptr))
return 0;
if (!MyClient(sptr) || !OPCanDie(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if ((pass = find_diepass())) /* See if we have and DIE/RESTART password */
{
if (parc < 2) /* And if so, require a password :) */
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "DIE");
return 0;
}
if (strcmp(pass, parv[1]))
{
sendto_one(sptr, err_str(ERR_PASSWDMISMATCH), me.name, parv[0]);
return 0;
}
}
/* Let the +s know what is going on */
sendto_ops("Server Terminating by request of %s", parv[0]);
for (i = 0; i <= highest_fd; i++)
{
if (!(acptr = local[i]))
continue;
if (IsClient(acptr))
sendto_one(acptr,
":%s NOTICE %s :Server Terminating. %s",
me.name, acptr->name,
get_client_name(sptr, TRUE));
else if (IsServer(acptr))
sendto_one(acptr, ":%s ERROR :Terminated by %s",
me.name, get_client_name(sptr, TRUE));
}
(void)s_die();
return 0;
}
char servername[128][128];
int server_usercount[128];
int numservers=0;
/*
* New /MAP format -Potvin
* dump_map function.
*/
void dump_map(cptr, server, mask, prompt_length, length)
aClient *cptr, *server;
char *mask;
register int prompt_length;
int length;
{
static char prompt[64];
register char *p = &prompt[prompt_length];
register int cnt = 0, local = 0;
aClient *acptr;
*p='\0';
if (prompt_length > 60)
sendto_one(cptr, rpl_str(RPL_MAPMORE), me.name, cptr->name, prompt, server->name);
else
{
for (acptr = client; acptr; acptr = acptr->next)
{
if (IsPerson(acptr))
{
++cnt; /* == */
if (!strcmp(acptr->user->server, server->name)) ++local;
}
}
sendto_one(cptr, rpl_str(RPL_MAP), me.name, cptr->name, prompt, length, server->name, local, (local*100)/cnt );
cnt = 0;
}
if (prompt_length > 0)
{
p[-1] = ' ';
if (p[-2] == '`') p[-2] = ' ';
}
if (prompt_length > 60) return;
strcpy(p, "|-");
for (acptr = client; acptr ; acptr = acptr->next)
{
#ifdef HIDE_ULINES
if (IsServer(acptr) && IsULine(acptr, acptr) && !IsAnOper(cptr))
continue;
#endif
if ( !IsServer (acptr) || strcmp(acptr->serv->up, server->name)) continue;
if ( match(mask, acptr->name) )
acptr->flags &= ~FLAGS_MAP;
else
{
acptr->flags |= FLAGS_MAP;
cnt++;
}
}
for (acptr = client; acptr ; acptr = acptr->next)
{
if ( ! (acptr->flags & FLAGS_MAP) || /* != */
!IsServer (acptr) || strcmp(acptr->serv->up, server->name)) continue;
if (--cnt == 0) *p = '`';
dump_map (cptr, acptr, mask, prompt_length+2, length-2);
}
if (prompt_length > 0) p[-1] = '-';
}
/*
** New /MAP format. -Potvin
** m_map (NEW)
**
** parv[0] = sender prefix
** parv[1] = server mask
**/
int m_map(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
aClient *acptr;
int longest=strlen(me.name);
if (check_registered(sptr))
return 0;
if (parc < 2)
parv[1]="*";
for (acptr = client; acptr; acptr = acptr->next)
if (IsServer(acptr) && ( strlen(acptr->name) + acptr->hopcount*2 ) > longest) longest = strlen(acptr->name) + acptr->hopcount*2;
if (longest > 60) longest = 60;
longest += 2;
dump_map(sptr, &me, "*", 0, longest);
sendto_one(sptr, rpl_str(RPL_MAPEND), me.name, parv[0]);
return 0;
}
#ifdef _WIN32
/*
* Added to let the local console shutdown the server without just
* calling exit(-1), in Windows mode. -Cabal95
*/
int localdie(void)
{
Reg1 aClient *acptr;
Reg2 int i;
for (i = 0; i <= highest_fd; i++)
{
if (!(acptr = local[i]))
continue;
if (IsClient(acptr))
sendto_one(acptr,
":%s NOTICE %s :Server Terminated by local console",
me.name, acptr->name);
else if (IsServer(acptr))
sendto_one(acptr, ":%s ERROR :Terminated by local console",
me.name);
}
(void)s_die();
return 0;
}
#endif