/************************************************************************
* IRC - Internet Relay Chat, src/s_user.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 softwmare; 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.
*/
/* $Id: s_user.c,v 1.25 2006/06/25 22:53:01 sheik Exp $ */
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "msg.h"
#include "channel.h"
#include "throttle.h"
#include "clones.h"
#include <sys/stat.h>
#include <utmp.h>
#include <fcntl.h>
#include "h.h"
#ifdef FLUD
#include "blalloc.h"
#endif /* FLUD */
#include "userban.h"
#include "hooks.h"
#include "memcount.h"
#if defined( HAVE_STRING_H)
#include <string.h>
#else
#include <strings.h>
#endif
#include <ctype.h>
int do_user(char *, aClient *, aClient *, char *, char *, char *,
unsigned long, unsigned int, char *);
extern char motd_last_changed_date[];
extern int send_motd(aClient *, aClient *, int, char **);
extern void send_topic_burst(aClient *);
extern void outofmemory(void); /* defined in list.c */
#ifdef MAXBUFFERS
extern void reset_sock_opts();
extern int send_lusers(aClient *,aClient *,int, char **);
#endif
extern int server_was_split;
static char buf[BUFSIZE], buf2[BUFSIZE];
int user_modes[] =
{
UMODE_o, 'o', /* use mode */
UMODE_O, 'O', /* oper only */
UMODE_i, 'i', /* oper only */
UMODE_w, 'w', /* oper only */
UMODE_s, 's', /* oper only */
UMODE_c, 'c', /* oper only */
UMODE_r, 'r', /* oper only */
UMODE_R, 'R', /* use mode */
UMODE_k, 'k', /* oper only */
UMODE_y, 'y', /* oper only */
UMODE_d, 'd', /* oper only */
#ifdef DCCALLOW
UMODE_e, 'e',
#endif
UMODE_g, 'g', /* oper only */
UMODE_b, 'b', /* oper only */
UMODE_a, 'a', /* oper only */
UMODE_A, 'A', /* oper only */
UMODE_f, 'f', /* oper only */
UMODE_n, 'n', /* oper only */
UMODE_m, 'm', /* oper only */
UMODE_h, 'h', /* oper only */
#ifdef NO_OPER_FLOOD
UMODE_F, 'F',
#endif
UMODE_x, 'x', /* oper only */
UMODE_X, 'X', /* oper only */
UMODE_j, 'j', /* oper only */
UMODE_K, 'K', /* oper only */
UMODE_v, 'v', /* use mode */
UMODE_Y, 'Y', /* use mode */
UMODE_C, 'C', /* oper only */
UMODE_H, 'H', /* oper only */
UMODE_W, 'W', /* oper only */
#ifdef HAVE_SSL
UMODE_z, 'z', /* use mode */
#endif
0, 0
};
/* externally defined functions */
extern Link *find_channel_link(Link *, aChannel *); /* defined in list.c */
#ifdef FLUD
int flud_num = FLUD_NUM;
int flud_time = FLUD_TIME;
int flud_block = FLUD_BLOCK;
extern BlockHeap *free_fludbots;
extern BlockHeap *free_Links;
void announce_fluder(aClient *, aClient *, aChannel *, int);
struct fludbot *remove_fluder_reference(struct fludbot **, aClient *);
Link *remove_fludee_reference(Link **, void *);
int check_for_fludblock(aClient *, aClient *, aChannel *, int);
int check_for_flud(aClient *, aClient *, aChannel *, int);
void free_fluders(aClient *, aChannel *);
void free_fludees(aClient *);
#endif
#ifdef ANTI_SPAMBOT
int spam_time = MIN_JOIN_LEAVE_TIME;
int spam_num = MAX_JOIN_LEAVE_COUNT;
#endif
/* defines for check_ctcp results */
#define CTCP_NONE 0
#define CTCP_YES 1
#define CTCP_DCC 2
#ifdef DCCALLOW
#define CTCP_DCCSEND 3
#endif
/*
* cptr:
** always NON-NULL, pointing to a *LOCAL* client
** structure (with an open socket connected!). This
** is the physical socket where the message originated (or
** which caused the m_function to be executed--some
** m_functions may call others...).
*
* sptr:
** the source of the message, defined by the
** prefix part of the message if present. If not or
** prefix not found, then sptr==cptr.
*
* *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 his points to
*** an empty string.
*
** [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.
*/
/*
* * next_client
* Local function to find the next matching
* client. The search can be continued from the specified client
* entry. Normal usage loop is:
*
* for (x = client; x = next_client(x,mask); x = x->next)
* HandleMatchingClient;
*
*/
aClient *
next_client(aClient *next, char *ch)
{
/* search string (may include wilds) */
aClient *tmp = next;
next = find_client(ch, tmp);
if (tmp && tmp->prev == next)
return ((aClient *) NULL);
if (next != tmp)
return next;
while(next)
{
if (!match(ch, next->name))
break;
next = next->next;
}
return next;
}
/* this slow version needs to be used for hostmasks *sigh * */
aClient *
next_client_double(aClient *next, char *ch)
{
/* search string (may include wilds) */
aClient *tmp = next;
next = find_client(ch, tmp);
if (tmp && tmp->prev == next)
return NULL;
if (next != tmp)
return next;
while(next)
{
if (!match(ch, next->name) || !match(next->name, ch))
break;
next = next->next;
}
return next;
}
/*
* hunt_server
*
* Do the basic thing in delivering the message (command)
* across the relays to the specific server (server) for
* actions.
*
* Note: The command is a format string and *MUST* be
* of prefixed style (e.g. ":%s COMMAND %s ...").
* Command can have only max 8 parameters.
*
* server parv[server] is the parameter identifying the target server.
*
* *WARNING*
* parv[server] is replaced with the pointer to the
* real servername from the matched client
* I'm lazy now --msa
*
* intelligence rewrite -Quension [May 2005]
*
* returns: (see #defines)
*/
int
hunt_server(aClient *cptr, aClient *sptr, char *command, int server,
int parc, char *parv[])
{
aClient *acptr = NULL;
/* Assume it's me, if no server */
if (parc <= server || BadPtr(parv[server]))
return (HUNTED_ISME);
collapse(parv[server]);
/* check self first, due to the weirdness of STAT_ME */
if (!match(parv[server], me.name))
return HUNTED_ISME;
if (strchr(parv[server], '?') || strchr(parv[server], '*'))
{
/* it's a mask, find the server manually */
for (acptr = client; acptr; acptr = acptr->next)
{
if (!IsServer(acptr))
continue;
if (!match(parv[server], acptr->name))
{
parv[server] = acptr->name;
break;
}
}
}
else
{
/* no wildcards, hash lookup */
acptr = find_client(parv[server], NULL);
if (acptr && !IsRegistered(acptr))
acptr = NULL;
}
if (!acptr)
{
sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name, parv[0],
parv[server]);
return HUNTED_NOSUCH;
}
#ifdef NO_USER_OPERTARGETED_COMMANDS
if (MyClient(sptr) && !IsAnOper(sptr) && IsUmodeW(acptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return HUNTED_NOSUCH;
}
#endif
if (MyClient(acptr))
return HUNTED_ISME;
sendto_one(acptr, command, parv[0], parv[1], parv[2], parv[3], parv[4],
parv[5], parv[6], parv[7], parv[8]);
return HUNTED_PASS;
}
/*
* canonize
*
* reduce a string of duplicate list entries to contain only the unique
* items. Unavoidably O(n^2).
*/
char *
canonize(char *buffer)
{
static char cbuf[BUFSIZ];
char *s, *t, *cp = cbuf;
int l = 0;
char *p = NULL, *p2;
*cp = '\0';
for (s = strtoken(&p, buffer, ","); s; s = strtoken(&p, NULL, ","))
{
if (l)
{
for (p2 = NULL, t = strtoken(&p2, cbuf, ","); t;
t = strtoken(&p2, NULL, ","))
if (!mycmp(s, t))
break;
else if (p2)
p2[-1] = ',';
}
else
t = NULL;
if (!t)
{
if (l)
*(cp - 1) = ',';
else
l = 1;
(void) strcpy(cp, s);
if (p)
cp += (p - s);
}
else if (p2)
p2[-1] = ',';
}
return cbuf;
}
#define B_BASE 1000
static int Maskchecksum(char *data, int len)
{
int i,j=0;
for (i = 0; len--; i++)
j += *data++ * (i < 16 ? (i+1)*(i+1) : i*(i-15));
return (j+B_BASE)%0xffff;
}
/* Creates a hostmask */
static void make_hostmask(aClient *sptr)
{
static char mask[HOSTLEN+1];
static char ipmask[HOSTIPLEN+1];
char *s, *dot;
int csum,i,isdns=0;
memset(mask, 0, 128);
s = sptr->sockhost;
csum = Maskchecksum (s, strlen(s));
if (strlen (s) > 127)
s[128] = 0;
for (i=0; i<strlen(s) ; i++)
{
if (IsAlpha(s[i]))
{
isdns = 1;
break;
}
}
if (isdns)
{
dot = strchr (s, '.');
if (dot==NULL)
ircsprintf (mask, "%s-%d.%s",HostPrefix, csum, s);
else
ircsprintf (mask, "%s-%d.%s",HostPrefix, csum, dot+1);
}
else
{
int sum;
strncpy(ipmask, s, sizeof(ipmask));
ipmask[sizeof(ipmask)-1]='\0';
while((dot = strrchr(ipmask, '.')))
*dot = '-';
sum = Maskchecksum(ipmask, strlen(ipmask));
ircsprintf(mask, "%s-%d.c%d.usr.%s",
HostPrefix, sum, csum, HostDomain);
#ifdef ENABLE_CHANNEL_MODE_D
/*FIXME*/
SetURSL(sptr);
sendto_one(sptr, ":%s NOTICE %s :*** You have been marked has an unresolved client.",
me.name, sptr->name);
#endif
}
strncpy(sptr->user->maskhost, mask, HOSTLEN+1);
strcpy(sptr->user->host, sptr->user->maskhost);
}
/* Sets a hostmask accordingly */
void set_hostmask(aClient *sptr)
{
if (IsAnOper(sptr) && !IsUmodeH(sptr))
{
if (IsSAdmin(sptr))
strncpyzt(sptr->user->host, Staff_Address, HOSTLEN+1);
else if (IsAdmin(sptr))
strncpyzt(sptr->user->host, Staff_Address, HOSTLEN+1);
else if (IsOper(sptr))
strncpyzt(sptr->user->host, Staff_Address, HOSTLEN+1);
else
strncpyzt(sptr->user->host, Staff_Address, HOSTLEN+1);
}
else if (!IsUmodev(sptr))
{
strncpyzt(sptr->user->host, sptr->user->realhost, HOSTLEN+1);
}
/* Looks like we have not made a hostmask this user, do it now. */
else if (*sptr->user->maskhost == '\0')
make_hostmask(sptr);
/* A hostmasking was already done for this user,
* since we stored it, we can use it again */
else
strncpyzt(sptr->user->host, sptr->user->maskhost, HOSTLEN+1);
sendto_serv_butone(NULL, ":%s SVHOST %s %s", me.name,
sptr->name, sptr->user->host);
}
#if (RIDICULOUS_PARANOIA_LEVEL>=1)
static int
check_oper_can_mask(aClient *sptr, char *name, char *password, char **onick)
{
aOper *aoper;
char *encr;
extern char *crypt();
if(!(aoper = find_oper(name, sptr->user->username, sptr->user->host,
sptr->hostip)))
{
sendto_realops("Failed OPERMASK attempt by %s (%s@%s) [No Entry for "
"%s]", sptr->name, sptr->user->username,
sptr->user->host, name);
return 0;
}
/* use first two chars of the password they send in as salt */
/* passwd may be NULL pointer. Head it off at the pass... */
if(confopts & FLAGS_CRYPTPASS)
{
if (password && *aoper->passwd)
encr = crypt(password, aoper->passwd);
else
encr = "";
}
else
encr = password;
if(StrEq(encr, aoper->passwd))
{
#ifdef USE_SYSLOG
syslog(LOG_INFO, "OPERMASK: %s (%s!%s@%s)", aoper->nick, sptr->name,
sptr->user->username, sptr->user->host);
#endif
*onick = aoper->nick;
sendto_realops("%s [%s] (%s@<hidden>) has masked their hostname.",
sptr->name, aoper->nick, sptr->user->username);
return 1;
}
sendto_realops("Failed OPERMASK attempt by %s (%s@%s) [Bad Password]",
sptr->name, sptr->user->username, sptr->user->host);
return 0;
}
#endif
/* used by m_user, m_put, m_post */
static int
reject_proxy(aClient *cptr, char *cmd, char *args)
{
sendto_realops_lev(REJ_LEV, "proxy attempt from %s: %s %s",
inetntoa((char *)&cptr->ip), cmd, args ? args : "");
return exit_client(cptr, cptr, &me, "relay connection");
}
/*
* * register_user
* This function is called when both NICK and USER messages
* have been accepted for the client, in whatever order. Only
* after this, is the USER message propagated.
*
* NICK's must be propagated at once when received, although
* it would be better to delay them too until full info is
* available. Doing it is not so simple though, would have to
* implement the following:
*
* (actually it has been implemented already for a while)
* -orabidoo
*
* 1 user telnets in and gives only "NICK foobar" and waits
* 2 another user far away logs in normally with the nick
* "foobar" quite legal, as this server didnt propagate it.
* 3 now this server gets nick "foobar" from outside, but has
* already the same defined locally. Current server would just
* issue "KILL foobar" to clean out dups. But, this is not
* fair. It should actually request another nick from local user
* or kill him/her...
*/
int
register_user(aClient *cptr, aClient *sptr, char *nick, char *username)
{
aAllow *pwaconf = NULL;
char *parv[3];
static char ubuf[12];
char *p;
short oldstatus = sptr->status;
anUser *user = sptr->user;
struct userBan *ban;
aMotd *smotd;
int i, dots;
int bad_dns; /* flag a bad dns name */
#ifdef ANTI_SPAMBOT
char spamchar = '\0';
#endif
char tmpstr2[512];
user->last = timeofday;
parv[0] = sptr->name;
parv[1] = parv[2] = NULL;
p = inetntoa((char *) &sptr->ip);
strncpyzt(sptr->hostip, p, HOSTIPLEN + 1);
if (MyConnect(sptr))
{
if ((i = check_client(sptr)))
{
switch (i)
{
case -1:
ircstp->is_ref++;
sendto_realops_lev(REJ_LEV, "%s from %s [Unauthorized"
" client connection]",
get_client_name(sptr, FALSE), p);
return exit_client(cptr, sptr, &me, "You are not"
" authorized to use this server");
case -2:
return exit_client(cptr, sptr, &me, "Socket Error");
case -3:
ircstp->is_ref++;
sendto_realops_lev(REJ_LEV, "%s for %s [Allow class is"
" full (server is full)]",
get_client_name(sptr, FALSE), p);
return exit_client(cptr, sptr, &me, "No more connections"
" allowed in your connection class (the"
" server is full)");
default:
sendto_realops_lev(DEBUG_LEV, "I don't know why I dropped"
" %s (%d)", get_client_name(sptr,FALSE),
i);
return exit_client(cptr, sptr, &me, "Internal error");
}
}
if (sptr->user->allow->flags & CONF_FLAGS_NOTHROTTLE)
throttle_remove(cptr->hostip);
if (sptr->user->allow->flags & CONF_FLAGS_FORCEFLOOD)
SetNoMsgThrottle(sptr);
#ifdef ANTI_SPAMBOT
/* This appears to be broken */
/* Check for single char in user->host -ThemBones */
if (*(user->host + 1) == '\0')
spamchar = *user->host;
#endif
strncpyzt(user->host, sptr->sockhost, HOSTLEN);
strncpyzt(user->realhost, sptr->sockhost, HOSTLEN);
user->maskhost[0] = '\0';
dots = 0;
p = user->host;
bad_dns = NO;
while (*p)
{
if (!IsAlnum(*p))
{
#ifdef RFC1035_ANAL
if ((*p != '-') && (*p != '.'))
#else
if ((*p != '-') && (*p != '.') && (*p != '_') &&
(*p != '/'))
#endif /* RFC1035_ANAL */
bad_dns = YES;
}
if (*p == '.')
dots++;
p++;
}
/*
* Check that the hostname has AT LEAST ONE dot (.) in it. If
* not, drop the client (spoofed host) -ThemBones
*/
if (!dots)
{
sendto_realops("Invalid hostname for %s, dumping user %s",
sptr->hostip, sptr->name);
return exit_client(cptr, sptr, &me, "Invalid hostname");
}
if (bad_dns)
{
sendto_one(sptr, ":%s NOTICE %s :*** Notice -- You have a bad "
"character in your hostname", me.name, cptr->name);
strcpy(user->host, sptr->hostip);
strcpy(sptr->sockhost, sptr->hostip);
}
pwaconf = sptr->user->allow;
if (sptr->flags & FLAGS_DOID && !(sptr->flags & FLAGS_GOTID))
{
/* because username may point to user->username */
char temp[USERLEN + 1];
strncpyzt(temp, username, USERLEN + 1);
*user->username = '~';
(void) strncpy(&user->username[1], temp, USERLEN);
user->username[USERLEN] = '\0';
#ifdef IDENTD_COMPLAIN
/* tell them to install identd -Taner */
sendto_one(sptr, ":%s NOTICE %s :*** Notice -- It seems that you "
"don't have identd installed on your host.",
me.name, cptr->name);
sendto_one(sptr, ":%s NOTICE %s :*** Notice -- If you wish to "
"have your username show up without the ~ (tilde),",
me.name, cptr->name);
sendto_one(sptr, ":%s NOTICE %s :*** Notice -- then install "
"identd.", me.name, cptr->name);
/* end identd hack */
#endif
}
else if (sptr->flags & FLAGS_GOTID && *sptr->username != '-')
strncpyzt(user->username, sptr->username, USERLEN + 1);
else if(username != user->username) /* don't overlap */
strncpyzt(user->username, username, USERLEN + 1);
if (!BadPtr(pwaconf->passwd))
{
char *tmpptr = strchr(sptr->passwd, ':');
char tmppwd[PASSWDLEN + 1];
/*
* If there's a : in the password, fix it so after this function,
* sptr->passwd changes from:
* moo:cow:test:asdf
* to
* cow:test:asdf
*/
if(tmpptr)
{
*tmpptr++ = '\0';
strcpy(tmppwd, tmpptr);
}
if(!StrEq(sptr->passwd, pwaconf->passwd))
{
ircstp->is_ref++;
sendto_one(sptr, err_str(ERR_PASSWDMISMATCH),
me.name, parv[0]);
return exit_client(cptr, sptr, &me, "Bad Password");
}
if(tmpptr)
strcpy(sptr->passwd, tmppwd);
else
sptr->passwd[0] = '\0';
}
/* Limit clients */
/*
* We want to be able to have servers and F-line clients connect,
* so save room for "buffer" connections. Smaller servers may
* want to decrease this, and it should probably be just a
* percentage of the MAXCLIENTS... -Taner
* Flines are now no different than Elines
* And now there are no special clients, and this is the only thing
* MAXCLIENTS is checked against. So no more buffer space.
*/
if (Count.local > MAXCLIENTS)
{
sendto_realops_lev(SPY_LEV, "Too many clients, rejecting %s[%s].",
nick, sptr->sockhost);
ircstp->is_ref++;
return exit_client(cptr, sptr, &me,
"Sorry, server is full - try later");
}
#ifdef ANTI_SPAMBOT
/* It appears, this is catching normal clients */
/* Reject single char user-given user->host's */
if (spamchar == 'x')
{
sendto_realops_lev(REJ_LEV, "Rejecting possible Spambot: %s "
"(Single char user-given userhost: %c)",
get_client_name(sptr, FALSE), spamchar);
ircstp->is_ref++;
return exit_client(cptr, sptr, sptr, "Spambot detected, "
"rejected.");
}
#endif
/* i really dont like the fact that we're calling m_oper from here.
* perhaps there is a better method...? Will investigate later
* -epi */
if (oldstatus == STAT_MASTER && MyConnect(sptr))
m_oper(&me, sptr, 1, parv);
/* hostile username checks begin here */
{
char *tmpstr;
u_char c, cc;
int lower, upper, special;
lower = upper = special = cc = 0;
/* check for "@" in identd reply -Taner */
if ((strchr(user->username, '@') != NULL) ||
(strchr(username, '@') != NULL))
{
sendto_realops_lev(REJ_LEV,
"Illegal \"@\" in username: %s (%s)",
get_client_name(sptr, FALSE), username);
ircstp->is_ref++;
(void) ircsprintf(tmpstr2,
"Invalid username [%s] - '@' is not allowed",
username);
return exit_client(cptr, sptr, sptr, tmpstr2);
}
/* First check user->username... */
#ifdef IGNORE_FIRST_CHAR
tmpstr = (user->username[0] == '~' ? &user->username[2] :
&user->username[1]);
/*
* Ok, we don't want to TOTALLY ignore the first character. We
* should at least check it for control characters, etc -
* ThemBones
*/
cc = (user->username[0] == '~' ? user->username[1] :
user->username[0]);
if ((!IsAlnum(cc) && !strchr(" -_.", cc)) || (cc > 127))
special++;
#else
tmpstr = (user->username[0] == '~' ? &user->username[1] :
user->username);
#endif /* IGNORE_FIRST_CHAR */
while (*tmpstr)
{
c = *(tmpstr++);
if (IsLower(c))
{
lower++;
continue;
}
if (IsUpper(c))
{
upper++;
continue;
}
if ((!IsAlnum(c) && !strchr(" -_.", c)) || (c > 127) || (c<32))
special++;
}
if (special)
{
sendto_realops_lev(REJ_LEV, "Invalid username: %s (%s@%s)",
nick, user->username, user->host);
ircstp->is_ref++;
ircsprintf(tmpstr2, "Invalid username [%s]", user->username);
return exit_client(cptr, sptr, &me, tmpstr2);
}
/* Ok, now check the username they provided, if different */
lower = upper = special = cc = 0;
if (strcmp(user->username, username))
{
#ifdef IGNORE_FIRST_CHAR
tmpstr = (username[0] == '~' ? &username[2] : &username[1]);
/*
* Ok, we don't want to TOTALLY ignore the first character.
* We should at least check it for control charcters, etc
* -ThemBones
*/
cc = (username[0] == '~' ? username[1] : username[0]);
if ((!IsAlnum(cc) && !strchr(" -_.", cc)) || (cc > 127))
special++;
#else
tmpstr = (username[0] == '~' ? &username[1] : username);
#endif /* IGNORE_FIRST_CHAR */
while (*tmpstr)
{
c = *(tmpstr++);
if (IsLower(c))
{
lower++;
continue;
}
if (IsUpper(c))
{
upper++;
continue;
}
if ((!IsAlnum(c) && !strchr(" -_.", c)) || (c > 127))
special++;
}
#ifdef NO_MIXED_CASE
if (lower && upper)
{
sendto_realops_lev(REJ_LEV, "Invalid username: %s (%s@%s)",
nick, username, user->host);
ircstp->is_ref++;
ircsprintf(tmpstr2, "Invalid username [%s]", username);
return exit_client(cptr, sptr, &me, tmpstr2);
}
#endif /* NO_MIXED_CASE */
if (special)
{
sendto_realops_lev(REJ_LEV, "Invalid username: %s (%s@%s)",
nick, username, user->host);
ircstp->is_ref++;
ircsprintf(tmpstr2, "Invalid username [%s]", username);
return exit_client(cptr, sptr, &me, tmpstr2);
}
} /* usernames different */
}
/*
* reject single character usernames which aren't alphabetic i.e.
* reject jokers who have '?@somehost' or '.@somehost'
*
* -Dianora
*/
if ((user->username[1] == '\0') && !IsAlpha(user->username[0]))
{
sendto_realops_lev(REJ_LEV, "Invalid username: %s (%s@%s)",
nick, user->username, user->host);
ircstp->is_ref++;
ircsprintf(tmpstr2, "Invalid username [%s]", user->username);
return exit_client(cptr, sptr, &me, tmpstr2);
}
if (!(user->allow->flags & CONF_FLAGS_SKIPCLONES) &&
(i = clones_check(cptr)))
{
ircstp->is_ref++;
return exit_client(cptr, sptr, &me, i == 1
? "Too many connections from your host"
: "Too many connections from your site");
}
if(!(ban = check_userbanned(sptr, UBAN_IP|UBAN_CIDR4, UBAN_WILDUSER)))
ban = check_userbanned(sptr, UBAN_HOST, 0);
if(ban)
{
if (ban->flags & UBAN_SHUN)
{
SetShun(sptr);
sendto_ops(SHUN_NAME" active for %s",
get_client_name(sptr, FALSE));
}
else
{
char *reason, *ktype;
int local = (ban->flags & UBAN_LOCAL) ? 1 : 0;
if (ban->flags & UBAN_GLINE)
ktype = NETWORK_GLINNED_NAME;
else
ktype = local ? LOCAL_BANNED_NAME : NETWORK_BANNED_NAME;
reason = ban->reason ? ban->reason : ktype;
sendto_one(sptr, err_str(ERR_YOUREBANNEDCREEP), me.name,
sptr->name, ktype);
sendto_one(sptr, ":%s NOTICE %s :*** You are not welcome on"
" this %s.", me.name, sptr->name,
local ? "server" : "network");
sendto_one(sptr, ":%s NOTICE %s :*** %s for %s",
me.name, sptr->name, ktype, reason);
sendto_one(sptr, ":%s NOTICE %s :*** Your hostmask is %s!%s@%s",
me.name, sptr->name, sptr->name, sptr->user->username,
sptr->sockhost);
sendto_one(sptr, ":%s NOTICE %s :*** Your IP is %s",
me.name, sptr->name, inetntoa((char *)&sptr->ip.s_addr));
sendto_one(sptr, ":%s NOTICE %s :*** For assistance, please"
" email %s and include everything shown here.",
me.name, sptr->name,
local ? Local_Kline_Address : Network_Kline_Address);
ircstp->is_ref++;
ircstp->is_ref_2++;
throttle_force(sptr->hostip);
return exit_client(cptr, sptr, &me, reason);
}
}
if(call_hooks(CHOOK_POSTACCESS, sptr) == FLUSH_BUFFER)
return FLUSH_BUFFER;
Count.unknown--;
if ((++Count.local) > Count.max_loc)
{
Count.max_loc = Count.local;
if (!(Count.max_loc % 10))
sendto_ops("New Max Local Clients: %d", Count.max_loc);
}
if ((NOW - Count.day) > 86400)
{
Count.today = 0;
Count.day = NOW;
}
if ((NOW - Count.week) > 604800)
{
Count.weekly = 0;
Count.week = NOW;
}
if ((NOW - Count.month) > 2592000)
{
Count.monthly = 0;
Count.month = NOW;
}
if ((NOW - Count.year) > 31536000)
{
Count.yearly = 0;
Count.year = NOW;
}
Count.today++;
Count.weekly++;
Count.monthly++;
Count.yearly++;
if(sptr->flags & FLAGS_BAD_DNS)
sendto_realops_lev(SPY_LEV, "DNS lookup: %s (%s@%s) is a possible "
"cache polluter", sptr->name,
sptr->user->username, sptr->user->host);
}
else
strncpyzt(user->username, username, USERLEN + 1);
SetClient(sptr);
/* Increment our total user count here */
if (++Count.total > Count.max_tot)
Count.max_tot = Count.total;
if(IsInvisible(sptr)) Count.invisi++;
if (MyConnect(sptr))
{
set_effective_class(sptr);
#ifdef MAXBUFFERS
/* Let's try changing the socket options for the client here... */
reset_sock_opts(sptr->fd, 0);
/* End sock_opt hack */
#endif
sendto_one(sptr, rpl_str(RPL_WELCOME), me.name, nick, Network_Name,
nick, sptr->user->username, sptr->user->host);
/*
* This is a duplicate of the NOTICE but see below...
* um, why were we hiding it? they did make it on to the
* server and all.. -wd
*/
sendto_one(sptr, rpl_str(RPL_YOURHOST), me.name, nick, me.name,
version);
#ifdef IRCII_KLUDGE
/* Don't mess with this one - IRCII needs it! -Avalon */
sendto_one(sptr, "NOTICE %s :*** Your host is %s, running version %s",
nick, me.name, version);
#endif
sendto_one(sptr, rpl_str(RPL_CREATED), me.name, nick, creation);
sendto_one(sptr, rpl_str(RPL_MYINFO), me.name, parv[0],
me.name, version);
send_rplisupport(sptr);
#ifdef FORCE_EVERYONE_HIDDEN
sptr->umode |= UMODE_W;
#endif
#if (RIDICULOUS_PARANOIA_LEVEL>=1)
if(!BadPtr(sptr->passwd) && (pwaconf->flags & CONF_FLAGS_I_OPERPORT))
do
{
char *onptr = sptr->passwd;
char *opptr;
char *onick;
char *tmpptr;
char tmppwd[PASSWDLEN + 1];
if(!(opptr = strchr(onptr, ':')))
break;
*opptr++ = '\0';
if((tmpptr = strchr(opptr, ':')))
*tmpptr++ = '\0';
if(check_oper_can_mask(sptr, onptr, opptr, &onick) != 0)
{
sendto_one(sptr, ":%s NOTICE %s :*** Your hostname has "
"been masked.",
me.name, sptr->name);
#ifdef DEFAULT_MASKED_HIDDEN
sptr->umode |= UMODE_W;
#endif
throttle_remove(sptr->hostip);
sptr->user->real_oper_host =
MyMalloc(strlen(sptr->user->host) + 1);
sptr->user->real_oper_username =
MyMalloc(strlen(sptr->user->username) + 1);
sptr->user->real_oper_ip =
MyMalloc(strlen(sptr->hostip) + 1);
strcpy(sptr->user->real_oper_host, sptr->user->host);
strcpy(sptr->user->real_oper_username, sptr->user->username);
strcpy(sptr->user->real_oper_ip, sptr->hostip);
strncpyzt(sptr->user->host, Staff_Address, HOSTLEN + 1);
strncpyzt(sptr->user->username, onick, USERLEN + 1);
strncpyzt(sptr->username, onick, USERLEN + 1);
sptr->flags |= FLAGS_GOTID; /* fake ident */
sptr->ip.s_addr = 0;
strcpy(sptr->hostip, "0.0.0.0");
strncpy(sptr->sockhost, Staff_Address, HOSTLEN + 1);
}
if(tmpptr)
{
strcpy(tmppwd, tmpptr);
strcpy(sptr->passwd, tmppwd);
}
else
sptr->passwd[0] = '\0';
} while(0);
#endif
/* Now we can tell if the user connecting is a ssl connection or not.*/
#ifdef HAVE_SSL
sendto_realops_lev(CCONN_LEV, "Client connecting: %s (%s@%s) [%s] {%d} %s",
nick, user->username, user->host, sptr->hostip,
sptr->class->name, IsSSL(sptr) ? "SSL-User" : "");
#else
sendto_realops_lev(CCONN_LEV, "Client connecting: %s (%s@%s) [%s] {%s}",
nick, user->username, user->host, sptr->hostip,
sptr->class->name);
#endif
sendto_serv_butone(NULL, ":%s CONOPS :Client connecting: %s (%s@%s) [%s] {%s}",
me.name, nick, user->username, sptr->sockhost ?
sptr->sockhost : user->host,
sptr->hostip, sptr->class->name);
send_lusers(sptr, sptr, 1, parv);
if(motd != NULL)
{
sendto_one(sptr, ":%s NOTICE %s :*** Notice -- motd was last"
" changed at %s", me.name, nick, motd_last_changed_date);
}
if(confopts & FLAGS_SMOTD)
{
if(motd != NULL)
{
sendto_one(sptr, ":%s NOTICE %s :*** Notice -- Please read the"
" motd if you haven't read it", me.name, nick);
}
sendto_one(sptr, rpl_str(RPL_MOTDSTART), me.name, parv[0], me.name);
if((smotd = shortmotd) == NULL)
sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv[0],
"*** This is the short motd ***");
else
while (smotd)
{
sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv[0],
smotd->line);
smotd = smotd->next;
}
sendto_one(sptr, rpl_str(RPL_ENDOFMOTD), me.name, parv[0]);
}
else
send_motd(sptr, sptr, 1, parv);
if((confopts & FLAGS_WGMON) == FLAGS_WGMON)
{
sendto_one(sptr, ":%s NOTICE %s :*** Notice -- This server runs an "
"open proxy monitor to prevent abuse.", me.name, nick);
sendto_one(sptr, ":%s NOTICE %s :*** Notice -- If you see"
" connections on various ports from %s", me.name,
nick, ProxyMonHost);
sendto_one(sptr, ":%s NOTICE %s :*** Notice -- please disregard"
" them, as they are the monitor in action.", me.name,
nick);
sendto_one(sptr, ":%s NOTICE %s :*** Notice -- For more information"
" please visit %s", me.name, nick, ProxyMonURL);
}
/* do this late because of oper masking */
if (sptr->ip.s_addr)
clones_add(sptr);
}
else if (IsServer(cptr))
{
aClient *acptr;
/* do this early because exit_client() calls clones_remove() */
if (sptr->ip.s_addr)
clones_add(sptr);
if ((acptr = find_server(user->server, NULL)) &&
acptr->from != sptr->from)
{
sendto_realops_lev(DEBUG_LEV,
"Bad User [%s] :%s USER %s@%s %s, != %s[%s]",
cptr->name, nick, user->username,
user->host, user->server,
acptr->name, acptr->from->name);
sendto_one(cptr, ":%s KILL %s :%s (%s != %s USER from wrong "
"direction)", me.name, sptr->name, me.name,
user->server, acptr->from->name);
sptr->flags |= FLAGS_KILLED;
return exit_client(sptr, sptr, &me, "USER server wrong direction");
}
/*
* Super GhostDetect: If we can't find the server the user is
* supposed to be on, then simply blow the user away. -Taner
*/
if (!acptr)
{
sendto_one(cptr,
":%s KILL %s :%s GHOST (no server %s on the net)",
me.name, sptr->name, me.name, user->server);
sendto_realops("No server %s for user %s[%s@%s] from %s",
user->server, sptr->name, user->username,
user->host, sptr->from->name);
sptr->flags |= FLAGS_KILLED;
return exit_client(sptr, sptr, &me, "Ghosted Client");
}
/* scan for aliases too */
if(IsULine(sptr))
{
AliasInfo *ai;
for (ai = aliastab; ai->nick; ai++)
{
if (!mycmp(ai->server, user->server)
&& !mycmp(ai->nick, sptr->name))
{
user->alias = ai;
ai->client = sptr;
break;
}
}
}
}
send_umode(NULL, sptr, 0, SEND_UMODES, ubuf);
if (!*ubuf)
{
ubuf[0] = '+';
ubuf[1] = '\0';
}
hash_check_watch(sptr, RPL_LOGON);
sendto_serv_butone(cptr, "NICK %s %d %ld %s %s %s %s %lu %lu :%s",
nick, sptr->hopcount + 1, sptr->tsinfo, ubuf,
user->username, user->host, user->server,
sptr->user->servicestamp,
htonl(sptr->ip.s_addr), sptr->info);
if(MyClient(sptr))
{
/* if the I:line doesn't have a password and the user does
* send it over to NickServ
*/
if (sptr->passwd[0] && aliastab[AII_NS].client)
sendto_alias(&aliastab[AII_NS], sptr, "SIDENTIFY %s",sptr->passwd);
memset(sptr->passwd, '\0', PASSWDLEN);
if (ubuf[1]) send_umode(cptr, sptr, 0, ALL_UMODES, ubuf);
if (IsUmodev(sptr))
set_hostmask(sptr);
if(call_hooks(CHOOK_POSTMOTD, sptr) == FLUSH_BUFFER)
return FLUSH_BUFFER;
}
#ifdef RWHO_PROBABILITY
probability_add(sptr);
#endif
return 0;
}
#ifdef DCCALLOW
char *exploits_2char[] =
{
"js",
"pl",
NULL
};
char *exploits_3char[] =
{
"exe",
"com",
"bat",
"dll",
"ini",
"vbs",
"pif",
"mrc",
"scr",
"doc",
"xls",
"lnk",
"shs",
"htm",
"zip",
"rar",
"sit",
NULL
};
char *exploits_4char[] =
{
"html",
NULL
};
static int
allow_dcc(aClient *to, aClient *from)
{
Link *lp;
for(lp = to->user->dccallow; lp; lp = lp->next)
{
if(lp->flags == DCC_LINK_ME && lp->value.cptr == from)
return 1;
}
return 0;
}
static int
check_dccsend(aClient *from, aClient *to, char *msg)
{
/*
* we already know that msg will consist of "DCC SEND" so we can skip
* to the end
*/
char *filename = msg + 8;
char *ext;
char **farray = NULL;
int arraysz;
int len = 0, extlen = 0, i;
/* people can send themselves stuff all the like..
* opers need to be able to send cleaner files
* sanity checks..
*/
if(from == to || !IsPerson(from) || IsAnOper(from) || !MyClient(to))
return 0;
while(*filename == ' ')
filename++;
if(!(*filename)) return 0;
while(*(filename + len) != ' ')
{
if(!(*(filename + len))) break;
len++;
}
for(ext = filename + len;; ext--)
{
if(ext == filename)
return 0;
if(*ext == '.')
{
ext++;
extlen--;
break;
}
extlen++;
}
switch(extlen)
{
case 0:
arraysz = 0;
break;
case 2:
farray = exploits_2char;
arraysz = 2;
break;
case 3:
farray = exploits_3char;
arraysz = 3;
break;
case 4:
farray = exploits_4char;
arraysz = 4;
break;
/* no executable file here.. */
default:
return 0;
}
if (arraysz != 0)
{
for(i = 0; farray[i]; i++)
{
if(myncmp(farray[i], ext, arraysz) == 0)
break;
}
if(farray[i] == NULL)
return 0;
}
if(!allow_dcc(to, from))
{
char tmpext[8];
char tmpfn[128];
Link *tlp, *flp;
aChannel *chptr = NULL;
strncpy(tmpext, ext, extlen);
tmpext[extlen] = '\0';
if(len > 127)
len = 127;
strncpy(tmpfn, filename, len);
tmpfn[len] = '\0';
/* use notices!
* server notices are hard to script around.
* server notices are not ignored by clients.
*/
sendto_one(from, ":%s NOTICE %s :The user %s is not accepting DCC "
"sends of filetype *.%s from you. Your file %s was not "
"sent.", me.name, from->name, to->name, tmpext, tmpfn);
sendto_one(to, ":%s NOTICE %s :%s (%s@%s) has attempted to send you a "
"file named %s, which was blocked.", me.name, to->name,
from->name, from->user->username, from->user->host, tmpfn);
if(!SeenDCCNotice(to))
{
SetDCCNotice(to);
sendto_one(to, ":%s NOTICE %s :The majority of files sent of this "
"type are malicious viruses and trojan horses."
" In order to prevent the spread of this problem, we "
"are blocking DCC sends of these types of"
" files by default.", me.name, to->name);
sendto_one(to, ":%s NOTICE %s :If you trust %s, and want him/her "
"to send you this file, you may obtain"
" more information on using the dccallow system by "
"typing /dccallow help",
me.name, to->name, from->name, to->name);
}
for(tlp = to->user->channel; tlp && !chptr; tlp = tlp->next)
{
for(flp = from->user->channel; flp && !chptr; flp = flp->next)
{
if(tlp->value.chptr == flp->value.chptr)
chptr = tlp->value.chptr;
}
}
if(chptr)
sendto_realops_lev(DCCSEND_LEV, "%s (%s@%s) sending forbidden "
"filetyped file %s to %s (channel %s)",
from->name, from->user->username,
from->user->host, tmpfn, to->name,
chptr->chname);
else
sendto_realops_lev(DCCSEND_LEV, "%s (%s@%s) sending forbidden "
"filetyped file %s to %s", from->name,
from->user->username, from->user->host, tmpfn,
to->name);
return 1;
}
return 0;
}
#endif /* DCCALLOW */
/*
* check target limit: message target rate limiting
* anti spam control!
* should only be called for local PERSONS!
* sptr: client sending message
* acptr: client receiving message
*
* return value:
* 1: block
* 0: do nothing
*/
#ifdef MSG_TARGET_LIMIT
int check_target_limit(aClient *sptr, aClient *acptr)
{
int ti;
int max_targets;
time_t tmin = MSG_TARGET_TIME; /* minimum time to wait before
* another message can be sent */
/* don't limit opers, people talking to themselves,
* or people talking to services */
if(IsOper(sptr) || sptr == acptr || IsULine(acptr) || NoMsgThrottle(sptr))
return 0;
max_targets = ((NOW - sptr->firsttime) > MSG_TARGET_MINTOMAXTIME)
? MSG_TARGET_MAX : MSG_TARGET_MIN;
for(ti = 0; ti < max_targets; ti++)
{
if (sptr->targets[ti].cli == NULL || sptr->targets[ti].cli == acptr ||
sptr->targets[ti].sent < (NOW - MSG_TARGET_TIME))
{
sptr->targets[ti].cli = acptr;
sptr->targets[ti].sent = NOW;
break;
}
else if((NOW - sptr->targets[ti].sent) < tmin)
tmin = NOW - sptr->targets[ti].sent;
}
if(ti == max_targets)
{
sendto_one(sptr, err_str(ERR_TARGETTOFAST), me.name, sptr->name,
acptr->name, MSG_TARGET_TIME - tmin);
sptr->since += 2; /* penalize them 2 seconds for this! */
sptr->num_target_errors++;
if(sptr->last_target_complain + 60 <= NOW)
{
sendto_realops_lev(SPAM_LEV, "Target limited: %s (%s@%s)"
" [%d failed targets]", sptr->name,
sptr->user->username, sptr->user->host,
sptr->num_target_errors);
sptr->num_target_errors = 0;
sptr->last_target_complain = NOW;
}
return 1;
}
return 0;
}
#endif
/*
* This function checks to see if a CTCP message (other than ACTION) is
* contained in the passed string. This might seem easier than I am
* doing it, but a CTCP message can be changed together, even after a
* normal message.
*
* If the message is found, and it's a DCC message, pass it back in
* *dccptr.
*
* Unfortunately, this makes for a bit of extra processing in the
* server.
*/
static int
check_for_ctcp(char *str, char **dccptr)
{
char *p = str;
while ((p = strchr(p, 1)) != NULL)
{
if (myncmp(++p, "DCC", 3) == 0)
{
if(dccptr)
*dccptr = p;
#ifdef DCCALLOW
if(myncmp(p+3, " SEND", 5) == 0)
return CTCP_DCCSEND;
else
#endif
return CTCP_DCC;
}
/* p was increased twice. 'ACTION' could not be found. -- nicobn */
if (myncmp(p, "ACTION", 6) != 0)
return CTCP_YES;
if ((p = strchr(p, 1)) == NULL)
return CTCP_NONE;
if(!(*(++p)))
break;;
}
return CTCP_NONE;
}
/* is_silenced - Returns 1 if a sptr is silenced by acptr */
static int
is_silenced(aClient *sptr, aClient *acptr)
{
Link *lp;
anUser *user;
char sender[HOSTLEN+NICKLEN+USERLEN+5];
if (!(acptr->user)||!(lp=acptr->user->silence)||!(user=sptr->user))
return 0;
ircsprintf(sender,"%s!%s@%s",sptr->name,user->username,user->host);
while(lp)
{
if (!match(lp->value.cp, sender))
{
if (!MyConnect(sptr))
{
sendto_one(sptr->from, ":%s SILENCE %s :%s",acptr->name,
sptr->name, lp->value.cp);
lp->flags = 1;
}
return 1;
}
lp = lp->next;
}
return 0;
}
static inline void
send_msg_error(aClient *sptr, char *parv[], char *nick, int ret)
{
if(ret == ERR_NOCTRLSONCHAN)
sendto_one(sptr, err_str(ERR_NOCTRLSONCHAN), me.name,
parv[0], nick, parv[2]);
else if(ret == ERR_NEEDREGGEDNICK)
sendto_one(sptr, err_str(ERR_NEEDREGGEDNICK), me.name,
parv[0], nick, "speak in", aliastab[AII_NS].nick,
aliastab[AII_NS].server, NS_Register_URL);
else
sendto_one(sptr, err_str(ERR_CANNOTSENDTOCHAN), me.name,
parv[0], nick);
}
/*
* m_message (used in m_private() and m_notice()) the general
* function to deliver MSG's between users/channels
*
* parv[0] = sender prefix
* parv[1] = receiver list
* parv[2] = message text
*
* massive cleanup * rev argv 6/91
* again -Quension [Jul 2004]
*
*/
static int
m_message(aClient *cptr, aClient *sptr, int parc, char *parv[], int notice)
{
aClient *acptr;
aChannel *chptr;
char *cmd;
int ismine;
int ret;
char *s;
char *p = NULL;
char *target;
char *dccmsg;
int tleft = MAXRECIPIENTS; /* targets left */
/* If User is in freezed mode then don't send text */
if (cptr->user && cptr->user->special_mode) {
switch (cptr->user->special_mode) {
case 3:
#ifdef ERROR_FREEZE_NOTICE
sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
#endif
return 0;
}
}
if IsShunned(sptr) {
#ifdef ERROR_FREEZE_NOTICE
sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
#endif
return 0;
}
cmd = notice ? MSG_NOTICE : MSG_PRIVATE;
ismine = MyClient(sptr);
if (parc < 2 || *parv[1] == 0)
{
sendto_one(sptr, err_str(ERR_NORECIPIENT), me.name, parv[0], cmd);
return -1;
}
if (parc < 3 || *parv[2] == 0)
{
sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
return -1;
}
if (ismine)
{
/* if squelched or spamming, allow only messages to self */
if ((IsSquelch(sptr)
#if defined(ANTI_SPAMBOT) && !defined(ANTI_SPAMBOT_WARN_ONLY)
|| (sptr->join_leave_count >= MAX_JOIN_LEAVE_COUNT)
#endif
) && mycmp(parv[0], parv[1]))
{
if (IsWSquelch(sptr) && !notice)
sendto_one(sptr, ":%s NOTICE %s :You are currently squelched."
" Message not sent.", me.name, parv[0]);
return 0;
}
if (call_hooks(CHOOK_MSG, sptr, notice, parv[2]) == FLUSH_BUFFER)
return FLUSH_BUFFER;
parv[1] = canonize(parv[1]);
#ifdef TOYS
/* Toy routines */
if (sptr->user && sptr->user->special)
{
char silly_buffer[BUFSIZE];
switch (sptr->user->special)
{
case 1:
strcpy(silly_buffer, "Whee");
add_punctuation(parv[2], silly_buffer);
parv[2] = silly_buffer;
break;
case 2:
encode_chef(parv[2], silly_buffer, sizeof(silly_buffer));
parv[2] = silly_buffer;
break;
default:
break;
}
}
#endif
}
/* loop on comma-separated targets, until tleft is gone */
for (target = strtoken(&p, parv[1], ",");
target && tleft--;
target = strtoken(&p, NULL, ","))
{
int chflags = 0; /* channel op/voice prefixes */
/* additional penalty for lots of targets */
if (ismine && tleft < (MAXRECIPIENTS/2) && !NoMsgThrottle(sptr))
#ifdef NO_OPER_FLOOD
if (!IsAnOper(sptr))
#endif
sptr->since += 4;
/* [@][+]#channel preprocessing */
s = target;
while (1)
{
if (*s == '@')
chflags |= CHFL_CHANOP;
else if (*s == '+')
chflags |= CHFL_VOICE;
else if (*s == '%')
chflags |= CHFL_HALFOP;
else
break;
s++;
}
/* target is a channel */
if (IsChannelName(s))
{
if (!(chptr = find_channel(s, NULL)))
{
if (ismine && !notice)
sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0],
target);
continue;
}
if (ismine && call_hooks(CHOOK_CHANMSG, sptr, chptr, notice,
parv[2]) == FLUSH_BUFFER)
return FLUSH_BUFFER;
/* super sources get free sends */
if (!IsULine(sptr))
{
if (!notice)
switch (check_for_ctcp(parv[2], NULL))
{
case CTCP_NONE:
break;
#ifdef DCCALLOW
case CTCP_DCCSEND:
#endif
case CTCP_DCC:
if (ismine)
sendto_one(sptr, ":%s NOTICE %s :You may not"
" send a DCC command to a channel"
" (%s)", me.name, parv[0], target);
continue;
#ifdef FLUD
default:
if (check_for_flud(sptr, NULL, chptr, 1))
return 0;
#endif
}
if ((ret = can_send(sptr, chptr, parv[2])))
{
if (ismine && !notice)
send_msg_error(sptr, parv, target, ret);
continue;
}
}
if (chflags)
{
/* don't let clients do stuff like @+@@+++@+@@@#channel */
if (chflags & CHFL_CHANOP)
*--s = '@';
if (chflags & CHFL_HALFOP)
*--s = '%';
if (chflags & CHFL_VOICE)
*--s = '+';
sendto_channelflags_butone(cptr, sptr, chptr, chflags,
":%s %s %s :%s", parv[0], cmd, s,
parv[2]);
}
else
sendto_channel_butone(cptr, sptr, chptr, ":%s %s %s :%s",
parv[0], cmd, target, parv[2]);
/* next target */
continue;
}
/* prefixes are only valid for channel targets */
if (s != target)
{
if (!notice)
sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0],
target);
continue;
}
/* target is a $servermask */
if (*target == '$')
{
s++;
/* allow $$servermask */
if (*s == '$')
s++;
if (ismine)
{
/* need appropriate privs */
if (!OPCanLNotice(sptr) ||
(mycmp(me.name, s) && !OPCanGNotice(sptr)))
{
sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name,
parv[0], target);
continue;
}
}
sendto_all_servmask(sptr, s, ":%s %s %s :%s", parv[0], cmd,
target, parv[2]);
/* next target */
continue;
}
/* target is a nick@server */
if ((s = strchr(target, '@')))
*s = 0;
/* target is a client */
if ((acptr = find_client(target, NULL)))
{
if (s)
*s++ = '@';
if (ismine && IsMe(acptr))
{
if (call_hooks(CHOOK_MYMSG, sptr, notice, parv[2])
== FLUSH_BUFFER)
return FLUSH_BUFFER;
continue;
}
if (!IsClient(acptr))
acptr = NULL;
}
/* nonexistent client or wrong @server */
if (!acptr || (s && mycmp(acptr->user->server, s)))
{
if (!notice)
sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0],
target);
continue;
}
/* super targets get special treatment */
if (IsULine(acptr))
{
AliasInfo *ai;
if ((confopts & FLAGS_SERVHUB) && notice)
continue;
if (ismine && !notice && (ai = acptr->user->alias))
{
#ifdef DENY_SERVICES_MSGS
if (!s && (acptr->from->serv->uflags & ULF_REQTARGET))
{
sendto_one(sptr, err_str(ERR_MSGSERVICES), me.name,
parv[0], ai->nick, ai->nick, ai->server,
ai->nick);
continue;
}
#endif
#ifdef PASS_SERVICES_MSGS
if (s) /* if passing, skip this and use generic send below */
#endif
{
sendto_alias(ai, sptr, "%s", parv[2]);
continue;
}
}
/* no flood/dcc/whatever checks, just send */
sendto_one(acptr, ":%s %s %s :%s", parv[0], cmd, target,
parv[2]);
continue;
}
#ifdef SUPER_TARGETS_ONLY
else if (s && ismine)
{
if (!notice)
sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0],
target);
continue;
}
#endif
if (ismine)
{
if (call_hooks(CHOOK_USERMSG, sptr, acptr, notice, parv[2])
== FLUSH_BUFFER)
return FLUSH_BUFFER;
#ifdef MSG_TARGET_LIMIT
if (check_target_limit(sptr, acptr))
continue;
#endif
}
/* super sources skip flood/silence checks */
if (!IsULine(sptr))
{
if (IsNoNonReg(acptr) && !IsRegNick(sptr) && !IsOper(sptr))
{
/* We really shouldnt tell users their private message was
* blocked, if it was actually a notice. Let's tell
* them which it was. - Unim4trix0
*/
if (ismine && !notice) {
sendto_one(sptr, err_str(ERR_NONONREG), me.name, parv[0],
"private message", target);
}
else if (ismine && notice) {
sendto_one(sptr, err_str(ERR_NONONREG), me.name, parv[0],
"notice", target);
}
else {
sendto_realops_lev(DEBUG_LEV, "Blocked a message "
"from %s to %s, which didn't match as a PRIVMSG "
"or NOTICE!", sptr->name, acptr->name);
}
continue;
}
#ifdef PLUS_R_TO_NONREG_WARN
/* Warn +R users that their target cannot reply - Unim4trix0 */
if (IsNoNonReg(sptr) && !IsRegNick(acptr) && !IsOper(acptr))
{
sendto_one(sptr, ":%s NOTICE %s :*** Notice -- %s cannot "
"reply to you because you are +R and they "
"are not identified to a registered nickname",
me.name, sptr->name, acptr->name);
}
#endif
#ifdef FLUD
if (!notice && MyFludConnect(acptr))
#else
if (!notice && MyConnect(acptr))
#endif
{
switch (check_for_ctcp(parv[2], &dccmsg))
{
case CTCP_NONE:
break;
#ifdef DCCALLOW
case CTCP_DCCSEND:
#ifdef FLUD
if (check_for_flud(sptr, acptr, NULL, 1))
return 0;
#endif
if (check_dccsend(sptr, acptr, dccmsg))
continue;
break;
#endif
#ifdef FLUD
default:
if (check_for_flud(sptr, acptr, NULL, 1))
return 0;
#endif
}
}
if (is_silenced(sptr, acptr))
continue;
}
if (!notice && ismine && acptr->user->away)
sendto_one(sptr, rpl_str(RPL_AWAY), me.name, parv[0], acptr->name,
acptr->user->away);
sendto_prefix_one(acptr, sptr, ":%s %s %s :%s", parv[0], cmd, target,
parv[2]);
/* next target */
continue;
}
/* too many targets */
if (target)
{
if (!notice)
sendto_one(sptr, err_str(ERR_TOOMANYTARGETS), me.name, parv[0],
target);
if (sptr->user)
sendto_realops_lev(SPY_LEV, "User %s (%s@%s) tried to %s more than"
" %d targets", sptr->name, sptr->user->username,
sptr->user->host, notice ? "notice" : "msg",
MAXRECIPIENTS);
}
return 0;
}
/*
* m_private
* parv[0] = sender prefix
* parv[1] = receiver list
* parv[2] = message text
*/
int
m_private(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
return m_message(cptr, sptr, parc, parv, 0);
}
/*
* m_notice *
* parv[0] = sender prefix
* parv[1] = receiver list
* parv[2] = notice text
*/
int
m_notice(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
return m_message(cptr, sptr, parc, parv, 1);
}
/*
* get_mode_str
*
* Returns an ASCII string of modes
*/
char *get_mode_str(aClient *acptr)
{
char *m;
int flag, len, *s;
m = buf;
*m++ = '+';
for (s = user_modes, len = 0; (flag = *s) && (len < (BUFSIZE - 4)); s += 2)
if (acptr->umode & flag) {
*m++ = (char)s[1];
len++;
}
*m = 0;
return buf;
}
/*
* m_whois
* parv[0] = sender prefix
* parv[1] = nickname masklist
*/
int
m_whois(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
Link *lp;
anUser *user;
aClient *acptr, *a2cptr;
aChannel *chptr;
char *nick, *tmp, *name;
char *p = NULL;
int len, mlen;
if (parc < 2)
{
sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN),
me.name, parv[0]);
return 0;
}
if (parc > 2)
{
#ifdef NO_USER_OPERTARGETED_COMMANDS
/*
* Block /whois <anything> <nick1,nick2,nick3>
* Also block /whois <server> <nick> for +I users
*/
if(!IsAnOper(sptr))
{
acptr = hash_find_client(parv[2], (aClient *) NULL);
if (!acptr || !IsPerson(acptr))
{
sendto_one(sptr, err_str(ERR_NOSUCHNICK),
me.name, parv[0], parv[2]);
return 0;
}
if(IsUmodeW(acptr))
{
/* allow /whois nick nick, but nothing else */
if(mycmp(parv[1], parv[2]) == 0)
parv[1] = acptr->user->server; /* And kludge it */
else if(MyClient(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name,
parv[0]);
return 0;
}
}
}
#endif
if (hunt_server(cptr, sptr, ":%s WHOIS %s :%s", 1, parc, parv) !=
HUNTED_ISME)
return 0;
parv[1] = parv[2];
}
for (p = NULL, tmp = parv[1]; (nick = strtoken(&p, tmp, ",")); tmp = NULL)
{
int invis, member, showchan;
acptr = hash_find_client(nick, (aClient *) NULL);
if (!acptr || !IsPerson(acptr))
{
sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], nick);
continue;
}
user = acptr->user;
name = (!*acptr->name) ? "?" : acptr->name;
invis = IsInvisible(acptr);
member = (user->channel) ? 1 : 0;
a2cptr = acptr->uplink;
/* The WHOIS Notice code has been ported from solid 2.2.20.
* It was originaly written by Toshi Morita(tm2)
* It has been slightly modified for solid-ircd3.4.7 by Sheik on 16/05/05
*
*/
if (IsUmodey(acptr))
sendto_one(acptr, ":%s NOTICE %s :*** Notice -- /WHOIS command used on you by: %s (%s@%s)",
me.name, acptr->name, sptr->name, sptr->user->username, sptr->user->realhost);
sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name, parv[0], name,
user->username, user->host, acptr->info);
#if (RIDICULOUS_PARANOIA_LEVEL>=1)
#if (RIDICULOUS_PARANOIA_LEVEL==1)
if(MyConnect(acptr) && user->real_oper_host &&
(IsAdmin(sptr) || (sptr == acptr)))
sendto_one(sptr, rpl_str(RPL_WHOISACTUALLY), me.name, sptr->name,
name, user->real_oper_username, user->real_oper_host,
user->real_oper_ip);
#endif
#if (RIDICULOUS_PARANOIA_LEVEL==2)
if(MyConnect(acptr) && user->real_oper_host &&
(IsAdmin(sptr) || (sptr == acptr)) && MyConnect(sptr))
sendto_one(sptr, rpl_str(RPL_WHOISACTUALLY), me.name, sptr->name,
name, user->real_oper_username, user->real_oper_host,
user->real_oper_ip);
#endif
#endif
if (IsAnOper(sptr) || (sptr==acptr))
{
sendto_one(sptr, rpl_str(RPL_WHOISACTUALLY), me.name, sptr->name,
name, user->username, user->realhost, acptr->hostip);
sendto_one(sptr, rpl_str(RPL_WHOISMODES),
me.name, parv[0], name, get_mode_str(acptr));
}
mlen = strlen(me.name) + strlen(parv[0]) + 6 + strlen(name);
for (len = 0, *buf = '\0', lp = user->channel; lp; lp = lp->next)
{
chptr = lp->value.chptr;
showchan=ShowChannel(sptr,chptr);
if (showchan || IsAdmin(sptr))
{
if (len + strlen(chptr->chname) > (size_t) BUFSIZE - 4 - mlen)
{
sendto_one(sptr, ":%s %d %s %s :%s", me.name,
RPL_WHOISCHANNELS, parv[0], name, buf);
*buf = '\0';
len = 0;
}
if(!showchan) /* if we're not really supposed to show the chan
* but do it anyways, mark it as such! */
*(buf + len++) = '%';
if (is_chan_op(acptr, chptr))
*(buf + len++) = '@';
else if (has_voice(acptr, chptr))
*(buf + len++) = '+';
if (len)
*(buf + len) = '\0';
strcpy(buf + len, chptr->chname);
len += strlen(chptr->chname);
strcat(buf + len, " ");
len++;
}
}
if (buf[0] != '\0')
sendto_one(sptr, rpl_str(RPL_WHOISCHANNELS), me.name,
parv[0], name, buf);
if(!(IsUmodeW(acptr) && !IsAnOper(sptr)) || (acptr == sptr))
{
sendto_one(sptr, rpl_str(RPL_WHOISSERVER), me.name, parv[0], name,
user->server, a2cptr ? a2cptr->info : "*Not On This Net*");
}
else /* hidden oper! */
{
sendto_one(sptr, rpl_str(RPL_WHOISSERVER), me.name, parv[0],
name, HiddenServName,HiddenServDesc);
}
if(IsAnOper(sptr) && IsSquelch(acptr))
sendto_one(sptr, rpl_str(RPL_WHOISTEXT), me.name, parv[0],
IsWSquelch(acptr) ? "User is squelched (warned)" :
"User is squelched (silent)");
if(IsRegNick(acptr))
sendto_one(sptr, rpl_str(RPL_WHOISREGNICK), me.name, parv[0], name);
if (user->away)
sendto_one(sptr, rpl_str(RPL_AWAY), me.name, parv[0], name,
user->away);
buf[0] = '\0';
if (IsAnOper(acptr) && (!IsUmodeH(acptr) || IsAnOper(cptr)))
{
if (IsSAdmin(acptr))
strcat(buf, "an \2IRC Operator - Services Administrator\2");
else if (IsAdmin(acptr))
strcat(buf, "an \2IRC Operator - Server Administrator\2");
else if (IsOper(acptr))
strcat(buf, "an \2IRC Operator\2");
else
strcat(buf, "a \2Local Operator\2");
}
if (buf[0])
sendto_one(sptr, rpl_str(RPL_WHOISOPERATOR), me.name, parv[0],
name, buf);
#ifdef HAVE_SSL
if (IsUmodez(acptr))
sendto_one(sptr, rpl_str(RPL_ISSSL), me.name, parv[0], name);
#endif
#ifdef ENABLE_CHANNEL_MODE_D
if (!(IsOper(acptr)) && (IsURSL(acptr)))
sendto_one(sptr, rpl_str(RPL_ISNOTRSL), me.name, parv[0], name);
#endif
/* don't give away that this oper is on this server if they're hidden! */
if (acptr->user && MyConnect(acptr) && ((sptr == acptr) ||
!IsUmodeW(acptr) || (parc > 2) || IsAnOper(sptr)))
sendto_one(sptr, rpl_str(RPL_WHOISIDLE), me.name, parv[0], name,
timeofday - user->last, acptr->firsttime);
continue;
}
sendto_one(sptr, rpl_str(RPL_ENDOFWHOIS), me.name, parv[0], parv[1]);
return 0;
}
/*
* m_user
* parv[0] = sender prefix
* parv[1] = username (login name, account)
* parv[2] = client host name (used only from other servers)
* parv[3] = server host name (used only from other servers)
* parv[4] = users real name info
*/
int
m_user(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
char *username, *host, *server, *realname;
struct simBan *ban;
/* FTP proxy */
if (!IsRegistered(cptr) && parc == 2 && cptr->receiveM == 1)
return reject_proxy(cptr, "USER", parv[1]);
if (parc > 2 && (username = (char *) strchr(parv[1], '@')))
*username = '\0';
if (parc < 5 || *parv[1] == '\0' || *parv[2] == '\0' ||
*parv[3] == '\0' || *parv[4] == '\0')
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "USER");
if (IsServer(cptr))
sendto_realops("bad USER param count for %s from %s",
parv[0], get_client_name(cptr, FALSE));
else
return 0;
}
/* Copy parameters into better documenting variables */
username = (parc < 2 || BadPtr(parv[1])) ? "<bad-boy>" : parv[1];
host = (parc < 3 || BadPtr(parv[2])) ? "<nohost>" : parv[2];
server = (parc < 4 || BadPtr(parv[3])) ? "<noserver>" : parv[3];
realname = (parc < 5 || BadPtr(parv[4])) ? "<bad-realname>" : parv[4];
if ((ban = check_mask_simbanned(realname, SBAN_GCOS)))
return exit_client(cptr, sptr, sptr, BadPtr(ban->reason) ?
"Bad GCOS: Reason unspecified" : ban->reason);
return do_user(parv[0], cptr, sptr, username, host, server, 0,0, realname);
}
/* do_user */
int
do_user(char *nick, aClient *cptr, aClient *sptr, char *username, char *host,
char *server, unsigned long serviceid, unsigned int ip, char *realname)
{
anUser *user;
long oflags;
user = make_user(sptr);
oflags = sptr->umode;
/*
* changed the goto into if-else... -Taner
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GOOD FOR YOU Taner!!! - Dianora
*/
if (!MyConnect(sptr))
{
user->server = find_or_add(server);
strncpyzt(user->host, host, sizeof(user->host));
strncpyzt(user->realhost, host, sizeof(user->host));
}
else
{
if (!IsUnknown(sptr))
{
sendto_one(sptr, err_str(ERR_ALREADYREGISTRED),
me.name, nick);
return 0;
}
sptr->umode |= (USER_UMODES & atoi(host));
#ifndef NO_DEFAULT_INVISIBLE
sptr->umode |= UMODE_i;
#endif
if (confopts & FLAGS_AUTOUMODE_v)
SetUmodev(sptr);
if (confopts & FLAGS_AUTOUMODE_R)
SetNoNonReg(sptr);
#ifdef HAVE_SSL
if (CanUmodez(sptr))
SetUmodez(sptr);
#endif
#ifdef NO_USER_SERVERKILLS
sptr->umode &= ~UMODE_k;
#endif
#ifdef NO_USER_OPERKILLS
sptr->umode &= ~UMODE_s;
#endif
strncpyzt(user->host, host, sizeof(user->host));
strncpyzt(user->realhost, host, sizeof(user->host));
user->server = me.name;
}
strncpyzt(sptr->info, realname, sizeof(sptr->info));
sptr->user->servicestamp = serviceid;
if (!MyConnect(sptr))
{
sptr->ip.s_addr=ntohl(ip);
/* add non-local clients to the throttle checker. obviously, we only
* do this for REMOTE clients!@$$@! throttle_check() is called
* elsewhere for the locals! -wd */
#ifdef THROTTLE_ENABLE
if (ip != 0)
throttle_check(inetntoa((char *)&sptr->ip), -1, sptr->tsinfo);
#endif
}
if(MyConnect(sptr))
sptr->oflag=0;
if (sptr->name[0]) /* NICK already received, now I have USER... */
return register_user(cptr, sptr, sptr->name, username);
else
strncpyzt(sptr->user->username, username, USERLEN + 1);
return 0;
}
/*
* m_quit
* parv[0] = sender prefix
* parv[1] = comment
*/
int
m_quit(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
char *reason = (parc > 1 && parv[1]) ? parv[1] : cptr->name;
char comment[TOPICLEN + 1];
sptr->flags |= FLAGS_NORMALEX;
if (!IsServer(cptr))
{
/* Check to see if rquit is on & if user is register. -Sheik 21/05/2005 */
if (!(confopts & FLAGS_RQUIT) || IsRegNick(sptr))
{
strcpy(comment, "Quit: ");
strncpy(comment + 6, reason, TOPICLEN - 6);
}
else
strcpy(comment, "Client Quit");
comment[TOPICLEN] = 0;
return exit_client(cptr, sptr, sptr, comment);
}
else
return exit_client(cptr, sptr, sptr, reason);
}
/*
* m_kill
* parv[0] = sender prefix
* parv[1] = kill victim
* parv[2] = kill path
*/
int
m_kill(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
aClient *acptr;
char *user, *path, *p, *nick, *reason;
char mypath[KILLLEN + 1];
char mymsg[KILLLEN + 1];
char *unknownfmt = "<Unknown>"; /*
* AFAIK this shouldnt happen
* but -Raist
*/
int chasing = 0, kcount = 0;
if (parc < 2 || *parv[1] == '\0')
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "KILL");
return 0;
}
user = parv[1];
path = parv[2]; /* Either defined or NULL (parc >= 2!!) */
if (!IsPrivileged(cptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if (!BadPtr(path))
if (strlen(path) > (size_t) KILLLEN)
path[KILLLEN] = '\0';
if (MyClient(sptr))
user = canonize(user);
for (p = NULL, nick = strtoken(&p, user, ","); nick;
nick = strtoken(&p, NULL, ","))
{
chasing = 0;
if (!(acptr = find_client(nick, NULL)))
{
/*
* If the user has recently changed nick, we automaticly
* rewrite the KILL for this new nickname--this keeps
* servers in synch when nick change and kill collide
*/
if (!(acptr = get_history(nick, (long) KILLCHASETIMELIMIT)))
{
sendto_one(sptr, err_str(ERR_NOSUCHNICK),
me.name, parv[0], nick);
return 0;
}
sendto_one(sptr, ":%s NOTICE %s :KILL changed from %s to %s",
me.name, parv[0], nick, acptr->name);
chasing = 1;
}
if((!MyConnect(acptr) && MyClient(cptr) && !OPCanGKill(cptr)) ||
(MyConnect(acptr) && MyClient(cptr) && !OPCanLKill(cptr)))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
continue;
}
if(IsServer(acptr) || IsMe(acptr) || (MyClient(sptr) && IsULine(acptr)))
{
sendto_one(sptr, err_str(ERR_CANTKILLSERVER),
me.name, parv[0]);
continue;
}
kcount++;
if (!IsServer(sptr) && (kcount > MAXKILLS))
{
sendto_one(sptr,":%s NOTICE %s :Too many targets, kill list was "
"truncated. Maximum is %d.", me.name, sptr->name,
MAXKILLS);
break;
}
if(MyClient(sptr))
{
char myname[HOSTLEN+1], *s;
if(!BadPtr(path))
{
ircsnprintf(mymsg, KILLLEN + 1, "(%s)", path);
reason = mymsg;
}
else
reason = "(No reason specified)";
strncpy(myname, me.name, HOSTLEN + 1);
if((s = strchr(myname, '.')))
*s = 0;
ircsnprintf(mypath, KILLLEN + 1, "%s!%s!%s", myname,
sptr->user->host, sptr->name);
}
else
{
if(BadPtr(path) || !(reason = strchr(path, ' ')))
{
path = sptr->name;
reason = "(No reason specified)";
}
else
{
*reason = '\0';
reason++;
}
strncpyzt(mypath, path, KILLLEN + 1);
}
/*
* Notify all *local* opers about the KILL, this includes the
* one originating the kill, if from this server--the special
* numeric reply message is not generated anymore.
*
* Note: "acptr->name" is used instead of "user" because we may
* have changed the target because of the nickname change.
*/
if (IsLocOp(sptr) && !MyConnect(acptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if(IsULine(sptr))
sendto_realops_lev(USKILL_LEV,
"Received KILL message for %s!%s@%s. "
"From %s Path: %s %s", acptr->name,
acptr->user ? acptr->user->username : unknownfmt,
acptr->user ? acptr->user->host : unknownfmt,
parv[0], mypath, reason);
else if (IsAnOper(sptr))
sendto_ops_lev(0,
"Received KILL message for %s!%s@%s. From %s "
"Path: %s %s", acptr->name,
acptr->user ? acptr->user->username : unknownfmt,
acptr->user ? acptr->user->host : unknownfmt,
parv[0], mypath, reason);
else
sendto_ops_lev(SKILL_LEV,
"Received KILL message for %s!%s@%s. "
"From %s Path: %s %s", acptr->name,
acptr->user ? acptr->user->username : unknownfmt,
acptr->user ? acptr->user->host : unknownfmt,
parv[0], mypath, reason);
#if defined(USE_SYSLOG) && defined(SYSLOG_KILL)
if (IsOper(sptr))
syslog(LOG_INFO, "KILL From %s!%s@%s For %s Path %s %s",
parv[0], acptr->name,
acptr->user ? acptr->user->username : unknownfmt,
acptr->user ? acptr->user->host : unknownfmt, mypath, reason);
#endif
/*
* And pass on the message to other servers. Note, that if KILL
* was changed, the message has to be sent to all links, also
* back. Suicide kills are NOT passed on --SRB
*/
/*
* Set FLAGS_KILLED. This prevents exit_one_client from sending
* the unnecessary QUIT for this. ,This flag should never be
* set in any other place...
*/
if(!MyConnect(acptr) || !MyConnect(sptr) || !IsAnOper(sptr))
{
sendto_serv_butone(cptr, ":%s KILL %s :%s %s",
parv[0], acptr->name, mypath, reason);
if (chasing && IsServer(cptr))
sendto_one(cptr, ":%s KILL %s :%s %s",
me.name, acptr->name, mypath, reason);
acptr->flags |= FLAGS_KILLED;
}
/*
* Tell the victim she/he has been zapped, but *only* if the
* victim is on current server--no sense in sending the
* notification chasing the above kill, it won't get far anyway
* as this user don't exist there any more either
*/
#ifndef HIDE_KILL_ORIGINS
if (MyConnect(acptr))
sendto_prefix_one(acptr, sptr, ":%s KILL %s :%s %s",
parv[0], acptr->name, mypath, reason);
if (MyConnect(acptr) && MyConnect(sptr) && IsAnOper(sptr))
ircsprintf(buf2, "Local kill by %s %s", sptr->name, reason);
else
ircsprintf(buf2, "Killed (%s %s)", sptr->name, reason);
#else
if (MyConnect(acptr))
sendto_one(acptr, ":%s KILL %s :%s %s",
HiddenServName, acptr->name,
HiddenServName, reason);
ircsprintf(buf2, "Killed (%s %s)", HiddenServName, reason);
#endif
if (exit_client(cptr, acptr, sptr, buf2) == FLUSH_BUFFER)
return FLUSH_BUFFER;
}
return 0;
}
/***********************************************************************
* m_away() - Added 14 Dec 1988 by jto.
* Not currently really working, I don't like this
* call at all...
*
* ...trying to make it work. I don't like it either,
* but perhaps it's worth the load it causes to net.
* This requires flooding of the whole net like NICK,
* USER, MODE, etc messages... --msa
*
* Added FLUD-style limiting for those lame scripts out there.
***********************************************************************/
/*
* m_away
* parv[0] = sender prefix
* parv[1] = away message
*/
int
m_away(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
char *away, *awy2 = parv[1];
/* make sure the user exists */
if (!(sptr->user))
{
sendto_realops_lev(DEBUG_LEV, "Got AWAY from nil user, from %s (%s)\n",
cptr->name, sptr->name);
return 0;
}
away = sptr->user->away;
#ifdef NO_AWAY_FLUD
if(MyClient(sptr))
{
if ((sptr->alas + MAX_AWAY_TIME) < NOW)
sptr->acount = 0;
sptr->alas = NOW;
sptr->acount++;
}
#endif
if (parc < 2 || !*awy2)
{
/* Marking as not away */
if (away)
{
MyFree(away);
sptr->user->away = NULL;
/* Don't spam unaway unless they were away - lucas */
sendto_serv_butone_super(cptr, ULF_NOAWAY, ":%s AWAY", parv[0]);
}
if (MyConnect(sptr))
sendto_one(sptr, rpl_str(RPL_UNAWAY), me.name, parv[0]);
return 0;
}
/* Marking as away */
#ifdef NO_AWAY_FLUD
/* we dont care if they are just unsetting away, hence this is here */
/* only care about local non-opers */
if (MyClient(sptr) && (sptr->acount > MAX_AWAY_COUNT) && !IsAnOper(sptr))
{
sendto_one(sptr, err_str(ERR_TOOMANYAWAY), me.name, parv[0]);
return 0;
}
#endif
if (strlen(awy2) > (size_t) TOPICLEN)
awy2[TOPICLEN] = '\0';
/*
* some lamers scripts continually do a /away, hence making a lot of
* unnecessary traffic. *sigh* so... as comstud has done, I've
* commented out this sendto_serv_butone() call -Dianora
* readded because of anti-flud stuffs -epi
*/
sendto_serv_butone_super(cptr, ULF_NOAWAY, ":%s AWAY :%s", parv[0],
parv[1]);
if (away)
MyFree(away);
away = (char *) MyMalloc(strlen(awy2) + 1);
strcpy(away, awy2);
sptr->user->away = away;
if (MyConnect(sptr))
sendto_one(sptr, rpl_str(RPL_NOWAWAY), me.name, parv[0]);
return 0;
}
/*
* m_ping
* parv[0] = sender prefix
* parv[1] = origin
* parv[2] = destination
*/
int
m_ping(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
aClient *acptr;
char *origin, *destination;
if (parc < 2 || *parv[1] == '\0')
{
sendto_one(sptr, err_str(ERR_NOORIGIN), me.name, parv[0]);
return 0;
}
origin = parv[1];
destination = parv[2]; /* Will get NULL or pointer (parc >= 2!!) */
acptr = find_client(origin, NULL);
if (!acptr)
acptr = find_server(origin, NULL);
if (acptr && acptr != sptr)
origin = cptr->name;
if (!BadPtr(destination) && mycmp(destination, me.name) != 0)
{
if ((acptr = find_server(destination, NULL)))
sendto_one(acptr, ":%s PING %s :%s", parv[0], origin, destination);
else
{
sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name, parv[0],
destination);
return 0;
}
}
else
sendto_one(sptr, ":%s PONG %s :%s", me.name,
(destination) ? destination : me.name, origin);
return 0;
}
/*
* m_pong
* parv[0] = sender prefix
* parv[1] = origin
* parv[2] = destination
*/
int
m_pong(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
aClient *acptr;
char *origin, *destination;
if (parc < 2 || *parv[1] == '\0')
{
sendto_one(sptr, err_str(ERR_NOORIGIN), me.name, parv[0]);
return 0;
}
origin = parv[1];
destination = parv[2];
cptr->flags &= ~FLAGS_PINGSENT;
sptr->flags &= ~FLAGS_PINGSENT;
/* if it's my client and it's a server.. */
if(sptr == cptr && IsServer(cptr))
{
if(sptr->flags & FLAGS_USERBURST)
{
sptr->flags &= ~FLAGS_USERBURST;
sendto_gnotice("from %s: %s has processed user/channel burst, "
"sending topic burst.", me.name, sptr->name);
send_topic_burst(sptr);
sptr->flags |= FLAGS_PINGSENT|FLAGS_SOBSENT;
sendto_one(sptr, "PING :%s", me.name);
}
else if(sptr->flags & FLAGS_TOPICBURST)
{
sptr->flags &= ~FLAGS_TOPICBURST;
sendto_gnotice("from %s: %s has processed topic burst (synched "
"to network data).", me.name, sptr->name);
if(server_was_split)
server_was_split = NO;
if(confopts & FLAGS_HUB)
sendto_serv_butone(sptr, ":%s GNOTICE :%s has synched to"
" network data.", me.name, sptr->name);
/* Kludge: Get the "sync" message on small networks
* immediately */
sendto_one(sptr, "PING :%s", me.name);
}
}
/*
* Now attempt to route the PONG, comstud pointed out routable PING
* is used for SPING. routable PING should also probably be left in
* -Dianora That being the case, we will route, but only for
* registered clients (a case can be made to allow them only from
* servers). -Shadowfax
*/
if (!BadPtr(destination) && (mycmp(destination, me.name) != 0)
&& IsRegistered(sptr))
{
if ((acptr = find_client(destination, NULL)) ||
(acptr = find_server(destination, NULL)))
sendto_one(acptr, ":%s PONG %s %s", parv[0], origin, destination);
else
{
sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name, parv[0],
destination);
return 0;
}
}
#ifdef DEBUGMODE
else
Debug((DEBUG_NOTICE, "PONG: %s %s", origin,
destination ? destination : "*"));
#endif
return 0;
}
/* added Sat Jul 25 07:30:42 EST 1992 */
/*
* extra argument evenTS added to send to TS servers or not -orabidoo
*
* extra argument evenTS no longer needed with TS only th+hybrid server
* -Dianora
*/
static inline void
send_umode_out(aClient *cptr, aClient *sptr, int old)
{
aClient *acptr;
DLink *lp;
send_umode(NULL, sptr, old, SEND_UMODES, buf);
if(*buf)
{
for(lp = server_list; lp; lp = lp->next)
{
acptr = lp->value.cptr;
if((acptr != cptr) && (acptr != sptr))
sendto_one(acptr, ":%s MODE %s :%s", sptr->name,
sptr->name, buf);
}
}
if (cptr && MyClient(cptr))
send_umode(cptr, sptr, old, ALL_UMODES, buf);
}
/*
* m_oper
* parv[0] = sender prefix
* parv[1] = oper name
* parv[2] = oper password
*/
int m_oper(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
aOper *aoper;
char *name, *password, *encr, *oper_ip;
extern char *crypt();
name = parc > 1 ? parv[1] : (char *) NULL;
password = parc > 2 ? parv[2] : (char *) NULL;
if (!IsServer(cptr) && (BadPtr(name) || BadPtr(password)))
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "OPER");
return 0;
}
/* if message arrived from server, trust it, and set to oper */
/* an OPER message should never come from a server. complain */
if ((IsServer(cptr) || IsMe(cptr)) && !IsOper(sptr))
{
sendto_realops("Why is %s sending me an OPER? Contact Coders",
cptr->name);
/* sanity */
if (!IsPerson(sptr))
return 0;
#ifdef DEFAULT_HELP_MODE
sptr->umode |= UMODE_o;
sptr->umode |= UMODE_h;
sendto_serv_butone(cptr, ":%s MODE %s :+oh", parv[0], parv[0]);
#else
sptr->umode |= UMODE_o;
sendto_serv_butone(cptr, ":%s MODE %s :+o", parv[0], parv[0]);
#endif
#ifdef ALL_OPERS_HIDDEN
sptr->umode |= UMODE_H;
sendto_serv_butone(cptr, ":%s MODE %s :+H", parv[0], parv[0]);
#endif
Count.oper++;
if (IsMe(cptr))
sendto_one(sptr, rpl_str(RPL_YOUREOPER), me.name, parv[0]);
return 0;
}
else if (IsAnOper(sptr) && MyConnect(sptr))
{
send_rplisupportoper(sptr);
sendto_one(sptr, rpl_str(RPL_YOUREOPER), me.name, parv[0]);
return 0;
}
#if (RIDICULOUS_PARANOIA_LEVEL>=1)
if(!sptr->user->real_oper_host)
{
#endif
if(!(aoper = find_oper(name, sptr->user->username, sptr->user->realhost,
sptr->hostip)))
{
sendto_one(sptr, err_str(ERR_NOOPERHOST), me.name, parv[0]);
sendto_realops("Failed OPER attempt by %s (%s@%s)", parv[0],
sptr->user->username, sptr->user->realhost);
return 0;
}
oper_ip = sptr->hostip;
#if (RIDICULOUS_PARANOIA_LEVEL>=1)
}
else
{
if (!(aoper = find_oper(name, sptr->user->real_oper_username,
sptr->user->real_oper_host,
sptr->user->real_oper_ip)))
{
sendto_one(sptr, err_str(ERR_NOOPERHOST), me.name, parv[0]);
sendto_realops("Failed OPER attempt by %s (%s@%s)", parv[0],
sptr->user->username, sptr->user->realhost);
return 0;
}
oper_ip = sptr->user->real_oper_ip;
}
#endif
/* use first two chars of the password they send in as salt */
/* passwd may be NULL pointer. Head it off at the pass... */
if(confopts & FLAGS_CRYPTPASS)
{
if (password && *aoper->passwd)
encr = crypt(password, aoper->passwd);
else
encr = "";
}
else
encr = password;
if (StrEq(encr, aoper->passwd))
{
int old = (sptr->umode & ALL_UMODES);
/* attach our conf */
sptr->user->oper = aoper;
aoper->opers++;
if (!(aoper->flags & OFLAG_ISGLOBAL))
SetLocOp(sptr);
else
SetOper(sptr);
#ifdef DEFAULT_HELP_MODE
sptr->umode|=(UMODE_s|UMODE_g|UMODE_w|UMODE_n|UMODE_h);
#else
sptr->umode|=(UMODE_s|UMODE_g|UMODE_w|UMODE_n);
#endif
sptr->oflag = aoper->flags;
Count.oper++;
add_to_list(&oper_list, sptr);
throttle_remove(oper_ip);
if (OPIsSAdmin(sptr))
{
sptr->umode|=(UMODE_a|UMODE_A|UMODE_o);
sendto_ops("%s (%s@%s) is now a \2Services Administrator\2 (a)", parv[0],
sptr->user->username, sptr->sockhost);
}
else if (OPIsAdmin(sptr))
{
sptr->umode|=(UMODE_A|UMODE_o);
sendto_ops("%s (%s@%s) is now a \2Server Administrator\2 (A)", parv[0],
sptr->user->username, sptr->sockhost);
}
else if (aoper->flags & OFLAG_ISGLOBAL)
{
sptr->umode|=(UMODE_o);
sendto_ops("%s (%s@%s) is now an \2IRC Operator\2 (o)", parv[0],
sptr->user->username, sptr->sockhost);
}
else
{
SetLocOp(sptr);
sendto_ops("%s (%s@%s) is now a \2Local Operator\2 (O)", parv[0],
sptr->user->username, sptr->sockhost);
}
set_hostmask(sptr);
send_umode_out(cptr, sptr, old);
send_rplisupportoper(sptr);
sendto_one(sptr, rpl_str(RPL_YOUREOPER), me.name, parv[0]);
set_effective_class(sptr);
#if defined(USE_SYSLOG) && defined(SYSLOG_OPER)
syslog(LOG_INFO, "OPER (%s) (%s) by (%s!%s@%s)",
name, encr, parv[0], sptr->user->username, sptr->sockhost);
#endif
#ifdef MAXBUFFERS
/* give them server-sized socket buffers, throughput++ */
reset_sock_opts(sptr->fd, 1);
#endif
#if defined(FNAME_OPERLOG)
{
int logfile;
/*
* This conditional makes the logfile active only after it's
* been created - thus logging can be turned off by removing
* the file.
*
* stop NFS hangs...most systems should be able to open a file in
* 3 seconds. -avalon (curtesy of wumpus)
*/
alarm(3);
if (IsPerson(sptr) &&
(logfile = open(FNAME_OPERLOG, O_WRONLY | O_APPEND)) != -1)
{
alarm(0);
ircsprintf(buf, "%s OPER (%s) (%s) by (%s!%s@%s)\n",
myctime(timeofday), name, encr,
parv[0], sptr->user->username,
sptr->sockhost);
alarm(3);
write(logfile, buf, strlen(buf));
alarm(0);
close(logfile);
}
alarm(0);
/* Modification by pjg */
}
#endif
}
else
{
sendto_one(sptr, err_str(ERR_PASSWDMISMATCH), me.name, parv[0]);
#ifdef FAILED_OPER_NOTICE
sendto_realops("Failed OPER attempt by %s (%s@%s)",
parv[0], sptr->user->username, sptr->sockhost);
#endif
}
return 0;
}
/***************************************************************************
* m_pass() - Added Sat, 4 March 1989
***************************************************************************/
/*
* m_pass
* parv[0] = sender prefix
* parv[1] = password
* parv[2] = optional extra version information
*/
int
m_pass(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
char *password = parc > 1 ? parv[1] : NULL;
if (BadPtr(password))
{
sendto_one(cptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "PASS");
return 0;
}
if (!MyConnect(sptr) || (!IsUnknown(cptr) && !IsHandshake(cptr)))
{
sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]);
return 0;
}
strncpyzt(cptr->passwd, password, sizeof(cptr->passwd));
if (parc > 2)
{
int l = strlen(parv[2]);
if (l < 2)
return 0;
if (parv[2][0] == 'T' && parv[2][1] == 'S')
cptr->tsinfo = (ts_val) TS_DOESTS;
}
return 0;
}
/*
* m_userhost added by Darren Reed 13/8/91 to aid clients and reduce
* the need for complicated requests like WHOIS. It returns user/host
* information only (no spurious AWAY labels or channels).
*/
int
m_userhost(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
char *s, *p = NULL;
aClient *acptr;
int i, len, res = 0;
ircsprintf(buf, rpl_str(RPL_USERHOST), me.name, parv[0]);
len = strlen(buf);
for (i = 5, s = strtoken(&p, parv[1], " "); i && s;
s = strtoken(&p, (char *) NULL, " "), i--)
if ((acptr = find_person(s, NULL)))
{
if (++res > 1)
buf[len++] = ' ';
len += ircsnprintf(buf + len, sizeof(buf) - (len + 1),
"%s%s=%c%s@%s", acptr->name,
IsAnOper(acptr) ? "*" : "",
(acptr->user->away) ? '-' : '+',
acptr->user->username, acptr->user->host);
}
sendto_one(sptr, "%s", buf);
return 0;
}
int
m_userip(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
char *s, *p = NULL;
aClient *acptr;
int i, len, res = 0;
if(!IsAnOper(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
ircsprintf(buf, rpl_str(RPL_USERHOST), me.name, parv[0]);
len = strlen(buf);
for (i = 5, s = strtoken(&p, parv[1], " "); i && s;
s = strtoken(&p, (char *) NULL, " "), i--)
if ((acptr = find_person(s, NULL)))
{
if (++res > 1)
buf[len++] = ' ';
len += ircsnprintf(buf + len, sizeof(buf) - (len + 1),
"%s%s=%c%s@%s", acptr->name,
IsAnOper(acptr) ? "*" : "",
(acptr->user->away) ? '-' : '+',
acptr->user->username,
IsULine(acptr) ? "0.0.0.0" : acptr->hostip);
}
sendto_one(sptr, "%s", buf);
return 0;
}
/*
* m_ison added by Darren Reed 13/8/91 to act as an efficent user
* indicator with respect to cpu/bandwidth used. Implemented for NOTIFY
* feature in clients. Designed to reduce number of whois requests. Can
* process nicknames in batches as long as the maximum buffer length.
*
* format: ISON :nicklist
*/
/* Take care of potential nasty buffer overflow problem -Dianora */
int
m_ison(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
aClient *acptr;
char *s, **pav = parv;
char *p = (char *) NULL;
int len, len2;
if (parc < 2)
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "ISON");
return 0;
}
ircsprintf(buf, rpl_str(RPL_ISON), me.name, *parv);
len = strlen(buf);
if (!IsOper(cptr))
cptr->priority += 20; /* this keeps it from moving to 'busy' list */
for (s = strtoken(&p, *++pav, " "); s;
s = strtoken(&p, (char *) NULL, " "))
if ((acptr = find_person(s, NULL)))
{
len2 = strlen(acptr->name);
if ((len + len2 + 5) < sizeof(buf)) /* make sure can never */
{ /* overflow */
strcat(buf, acptr->name);
len += len2;
strcat(buf, " ");
len++;
}
else
break;
}
sendto_one(sptr, "%s", buf);
return 0;
}
/*
* m_umode() added 15/10/91 By Darren Reed.
* parv[0] - sender
* parv[1] - username to change mode for
* parv[2] - modes to change
*/
int
m_umode(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
int flag, *s, setflags, what = MODE_ADD, badflag = NO;
char **p, *m;
aClient *acptr;
if (parc < 2)
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "MODE");
return 0;
}
if(IsServer(sptr))
return 0;
if (!(acptr = find_person(parv[1], NULL)))
{
if (MyConnect(sptr))
sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0],
parv[1]);
return 0;
}
if ((sptr != acptr) || (acptr->from != sptr->from))
{
sendto_one(sptr, err_str(ERR_USERSDONTMATCH), me.name, parv[0]);
return 0;
}
if (parc < 3)
{
m = buf;
*m++ = '+';
for (s = user_modes; (flag = *s) && (m - buf < BUFSIZE - 4); s += 2)
{
if (sptr->umode & (flag & ALL_UMODES))
*m++ = (char) (*(s + 1));
}
*m = '\0';
sendto_one(sptr, rpl_str(RPL_UMODEIS), me.name, parv[0], buf);
return 0;
}
/* find flags already set for user */
setflags = 0;
for (s = user_modes; (flag = *s); s += 2)
if (sptr->umode & flag)
setflags |= flag;
/* parse mode change string(s) */
for (p = &parv[2]; p && *p; p++)
for (m = *p; *m; m++)
switch (*m)
{
case '+':
what = MODE_ADD;
break;
case '-':
what = MODE_DEL;
break;
/* we may not get these, but they shouldnt be in default */
case ' ':
case '\r':
case '\n':
case '\t':
break;
#ifdef STRICT_HOSTMASK
case 'v': /* Users Can't unset themselves +v*/
sendto_one(sptr, ":%s NOTICE %s :Permission denied, this network does not allow you to unset +v. For more information visit", WEBSITE, me.name,
parv[0], sptr->user->host);
break;
#endif
case 'r':
case 'x':
case 'X':
break; /* users can't set themselves +r,+x, or +X! */
case 'A':
/* set auto +a if user is setting +A */
if (MyClient(sptr) && (what == MODE_ADD))
sptr->umode |= UMODE_a;
default:
for (s = user_modes; (flag = *s); s += 2)
if (*m == (char) (*(s + 1)))
{
if (what == MODE_ADD)
sptr->umode |= flag;
else
sptr->umode &= ~flag;
break;
}
if (flag == 0 && MyConnect(sptr))
badflag = YES;
break;
}
if (badflag)
sendto_one(sptr, err_str(ERR_UMODEUNKNOWNFLAG), me.name, parv[0]);
/* stop users making themselves operators too easily */
if (!(setflags & UMODE_o) && IsOper(sptr) && !IsServer(cptr))
ClearOper(sptr);
if (!(setflags & UMODE_O) && IsLocOp(sptr) && !IsServer(cptr))
sptr->umode &= ~UMODE_O;
if ((setflags & (UMODE_o | UMODE_O)) && !IsAnOper(sptr) && MyConnect(sptr))
{
set_effective_class(sptr);
sptr->oflag = 0;
}
if (!(setflags & (UMODE_o | UMODE_O)) && IsAnOper(sptr))
Count.oper++;
if ((setflags & (UMODE_o | UMODE_O)) && !IsAnOper(sptr))
{
Count.oper--;
if (MyConnect(sptr))
{
remove_from_list(&oper_list, sptr, NULL);
/*
* Now that the user is no longer opered, let's return
* them back to the appropriate Y:class -srd
*/
sptr->user->oper->opers--;
sptr->user->oper = NULL;
set_effective_class(sptr);
}
}
if (!(setflags & UMODE_i) && IsInvisible(sptr))
Count.invisi++;
if ((setflags & UMODE_i) && !IsInvisible(sptr))
Count.invisi--;
/* Check if its my connect, if not we trust the server */
if (MyConnect(sptr))
{
if (!(setflags & UMODE_v) && IsUmodev(sptr))
{
set_hostmask(sptr);
sendto_one(sptr, ":%s NOTICE %s :Your host is now masked (%s).", me.name,
parv[0], sptr->user->host);
}
if ((setflags & UMODE_v) && !IsUmodev(sptr))
{
set_hostmask(sptr);
sendto_one(sptr, ":%s NOTICE %s :Your host is no longer masked.", me.name, parv[0]);
}
if ((setflags & UMODE_H) && !IsUmodeH(sptr) && IsOper(sptr))
{
set_hostmask(sptr);
}
if (!(setflags & UMODE_H) && IsUmodeH(sptr) && IsOper(sptr))
{
set_hostmask(sptr);
}
if ((setflags & UMODE_Y) && !IsDeaf(sptr))
{
sptr->umode &= ~UMODE_Y;
sendto_one (sptr, ":%s NOTICE %s :*** Notice -- You are no longer marked as deaf and will receive channel messages and notices as normal..",
me.name, sptr->name);
}
if (!(setflags & UMODE_Y) && IsDeaf(sptr))
{
sptr->umode |= UMODE_Y;
sendto_one (sptr, ":%s NOTICE %s :*** Notice -- You have marked yourself as deaf and will no longer receive channel messages or notices from any channel.",
me.name, sptr->name);
}
#ifdef HAVE_SSL
if (!(confopts & FLAGS_LETUMODE_z))
{
if ((setflags & UMODE_z) && CanUmodez(sptr) && !IsServer(cptr))
sptr->umode |= UMODE_z;
if (!(setflags & UMODE_z) && !CanUmodez(sptr) && !IsServer(cptr))
sptr->umode &= ~UMODE_z;
}
if (IsUmodez(sptr) && !CanUmodez(sptr)) ClearUmodez(sptr);
#endif
}
/*
* compare new flags with old flags and send string which will cause
* servers to update correctly.
*/
if (!IsAnOper(sptr) && !IsServer(cptr))
{
sptr->umode &= ~OPER_UMODES;
#ifdef NO_USER_SERVERKILLS
sptr->umode &= ~UMODE_k;
#endif
#ifdef NO_USER_OPERKILLS
sptr->umode &= ~UMODE_s;
#endif
}
if(MyClient(sptr))
{
if (IsAdmin(sptr) && !OPIsAdmin(sptr)) ClearAdmin(sptr);
if (IsSAdmin(sptr) && !OPIsSAdmin(sptr)) ClearSAdmin(sptr);
if (IsUmodef(sptr) && !OPCanUModef(sptr)) ClearUmodef(sptr);
if (IsUmodec(sptr) && !OPCanUModec(sptr)) ClearUmodec(sptr);
if (IsUmodej(sptr) && !OPCanUModec(sptr)) ClearUmodej(sptr);
if (IsUmodey(sptr) && !OPCanUModey(sptr)) ClearUmodey(sptr);
if (IsUmoded(sptr) && !OPCanUModed(sptr)) ClearUmoded(sptr);
if (IsUmodeb(sptr) && !OPCanUModeb(sptr)) ClearUmodeb(sptr);
if (NoMsgThrottle(sptr) && !OPCanUModeF(sptr)) ClearNoMsgThrottle(sptr);
#ifdef ALLOW_HIDDEN_OPERS
# ifdef FORCE_EVERYONE_HIDDEN
sptr->umode |= UMODE_W;
# else
# if (RIDICULOUS_PARANOIA_LEVEL>=1)
if (IsUmodeW(sptr) && !(sptr->user->real_oper_host || IsAnOper(sptr)))
ClearUmodeW(sptr);
# endif
# ifdef FORCE_OPERS_HIDDEN
if (IsAnOper(sptr)
# if (RIDICULOUS_PARANOIA_LEVEL>=1)
|| (sptr->user->real_oper_host != NULL)
# endif
) sptr->umode |= UMODE_W;
# endif /* FORCE_OPERS_HIDDEN */
# endif /* FORCE_EVERYONE_HIDDEN */
#else /* ALLOW_HIDDEN_OPERS */
if (IsUmodeW(sptr)) ClearUmodeW(sptr);
#endif
if (sptr->user->allow->flags & CONF_FLAGS_FORCEFLOOD)
SetNoMsgThrottle(sptr);
}
send_umode_out(cptr, sptr, setflags);
return 0;
}
/* send the MODE string for user (user) to connection cptr -avalon */
void
send_umode(aClient *cptr, aClient *sptr, int old, int sendmask, char *umode_buf)
{
int *s, flag, what = MODE_NULL;
char *m;
/*
* build a string in umode_buf to represent the change in the user's
* mode between the new (sptr->flag) and 'old'.
*/
m = umode_buf;
*m = '\0';
for (s = user_modes; (flag = *s); s += 2)
{
if (MyClient(sptr) && !(flag & sendmask))
continue;
if ((flag & old) && !(sptr->umode & flag))
{
if (what == MODE_DEL)
*m++ = *(s + 1);
else
{
what = MODE_DEL;
*m++ = '-';
*m++ = *(s + 1);
}
}
else if (!(flag & old) && (sptr->umode & flag))
{
if (what == MODE_ADD)
*m++ = *(s + 1);
else
{
what = MODE_ADD;
*m++ = '+';
*m++ = *(s + 1);
}
}
}
*m = '\0';
if (*umode_buf && cptr)
sendto_one(cptr, ":%s MODE %s :%s", sptr->name, sptr->name, umode_buf);
}
/* Shadowfax's FLUD code */
#ifdef FLUD
void
announce_fluder(aClient *fluder, aClient *cptr, aChannel *chptr, int type)
{
char *fludee;
if (cptr)
fludee = cptr->name;
else
fludee = chptr->chname;
sendto_realops_lev(FLOOD_LEV, "Flooder %s [%s@%s] on %s target: %s",
fluder->name, fluder->user->username, fluder->user->host,
fluder->user->server, fludee);
}
/*
* This is really just a "convenience" function. I can only keep three
* or * four levels of pointer dereferencing straight in my head. This
* remove * an entry in a fluders list. Use this when working on a
* fludees list :)
*/
struct fludbot *
remove_fluder_reference(struct fludbot **fluders, aClient *fluder)
{
struct fludbot *current, *prev, *next;
prev = NULL;
current = *fluders;
while (current)
{
next = current->next;
if (current->fluder == fluder)
{
if (prev)
prev->next = next;
else
*fluders = next;
BlockHeapFree(free_fludbots, current);
}
else
prev = current;
current = next;
}
return (*fluders);
}
/* Another function to unravel my mind. */
Link *
remove_fludee_reference(Link **fludees, void *fludee)
{
Link *current, *prev, *next;
prev = NULL;
current = *fludees;
while (current)
{
next = current->next;
if (current->value.cptr == (aClient *) fludee)
{
if (prev)
prev->next = next;
else
*fludees = next;
BlockHeapFree(free_Links, current);
}
else
prev = current;
current = next;
}
return (*fludees);
}
int
check_for_fludblock(aClient *fluder, aClient *cptr, aChannel *chptr, int type)
{
time_t now;
int blocking;
/* If it's disabled, we don't need to process all of this */
if ((confopts & FLAGS_HUB) || (flud_block == 0))
return 0;
/* It's either got to be a client or a channel being fluded */
if ((cptr == NULL) && (chptr == NULL))
return 0;
if (cptr && !MyFludConnect(cptr))
{
sendto_ops("check_for_fludblock() called for non-local client");
return 0;
}
/* Are we blocking fluds at this moment? */
time(&now);
if (cptr)
blocking = (cptr->fludblock > (now - flud_block));
else
blocking = (chptr->fludblock > (now - flud_block));
return (blocking);
}
int
check_for_flud(aClient *fluder, aClient *cptr, aChannel *chptr, int type)
{
time_t now;
struct fludbot *current, *prev, *next;
int blocking, count, found;
Link *newfludee;
/* If it's disabled, we don't need to process all of this */
if ((confopts & (FLAGS_HUB|FLAGS_SERVHUB)) || (flud_block == 0))
return 0;
/* It's either got to be a client or a channel being fluded */
if ((cptr == NULL) && (chptr == NULL))
return 0;
if (cptr && !MyFludConnect(cptr))
{
sendto_ops("check_for_flud() called for non-local client");
return 0;
}
/* Are we blocking fluds at this moment? */
time(&now);
if (cptr)
blocking = (cptr->fludblock > (now - flud_block));
else
blocking = (chptr->fludblock > (now - flud_block));
/* Collect the Garbage */
if (!blocking)
{
if (cptr)
current = cptr->fluders;
else
current = chptr->fluders;
prev = NULL;
while (current)
{
next = current->next;
if (current->last_msg < (now - flud_time))
{
if (cptr)
remove_fludee_reference(¤t->fluder->fludees,
(void *) cptr);
else
remove_fludee_reference(¤t->fluder->fludees,
(void *) chptr);
if (prev)
prev->next = current->next;
else if (cptr)
cptr->fluders = current->next;
else
chptr->fluders = current->next;
BlockHeapFree(free_fludbots, current);
}
else
prev = current;
current = next;
}
}
/*
* Find or create the structure for the fluder, and update the
* counter * and last_msg members. Also make a running total count
*/
if (cptr)
current = cptr->fluders;
else
current = chptr->fluders;
count = found = 0;
while (current)
{
if (current->fluder == fluder)
{
current->last_msg = now;
current->count++;
found = 1;
}
if (current->first_msg < (now - flud_time))
count++;
else
count += current->count;
current = current->next;
}
if (!found)
{
if ((current = BlockHeapALLOC(free_fludbots, struct fludbot)) != NULL)
{
current->fluder = fluder;
current->count = 1;
current->first_msg = now;
current->last_msg = now;
if (cptr)
{
current->next = cptr->fluders;
cptr->fluders = current;
}
else
{
current->next = chptr->fluders;
chptr->fluders = current;
}
count++;
if ((newfludee = BlockHeapALLOC(free_Links, Link)) != NULL)
{
if (cptr)
{
newfludee->flags = 0;
newfludee->value.cptr = cptr;
}
else
{
newfludee->flags = 1;
newfludee->value.chptr = chptr;
}
newfludee->next = fluder->fludees;
fluder->fludees = newfludee;
}
else
outofmemory();
/*
* If we are already blocking now, we should go ahead * and
* announce the new arrival
*/
if (blocking)
announce_fluder(fluder, cptr, chptr, type);
}
else
outofmemory();
}
/*
* Okay, if we are not blocking, we need to decide if it's time to *
* begin doing so. We already have a count of messages received in *
* the last flud_time seconds
*/
if (!blocking && (count > flud_num))
{
blocking = 1;
ircstp->is_flud++;
/*
* if we are going to say anything to the fludee, now is the *
* time to mention it to them.
*/
if (cptr)
sendto_one(cptr,
":%s NOTICE %s :*** Notice -- Server flood protection "
"activated for %s", me.name, cptr->name, cptr->name);
else
sendto_channel_butserv(chptr, &me,
":%s NOTICE %s :*** Notice -- Server "
"flood protection activated for %s",
me.name, chptr->chname, chptr->chname);
/*
* Here we should go back through the existing list of * fluders
* and announce that they were part of the game as * well.
*/
if (cptr)
current = cptr->fluders;
else
current = chptr->fluders;
while (current)
{
announce_fluder(current->fluder, cptr, chptr, type);
current = current->next;
}
}
/*
* update blocking timestamp, since we received a/another CTCP
* message
*/
if (blocking)
{
if (cptr)
cptr->fludblock = now;
else
chptr->fludblock = now;
}
return (blocking);
}
void
free_fluders(aClient *cptr, aChannel *chptr)
{
struct fludbot *fluders, *next;
if ((cptr == NULL) && (chptr == NULL))
{
sendto_ops("free_fluders(NULL, NULL)");
return;
}
if (cptr && !MyFludConnect(cptr))
return;
if (cptr)
fluders = cptr->fluders;
else
fluders = chptr->fluders;
while (fluders)
{
next = fluders->next;
if (cptr)
remove_fludee_reference(&fluders->fluder->fludees, (void *) cptr);
else
remove_fludee_reference(&fluders->fluder->fludees, (void *) chptr);
BlockHeapFree(free_fludbots, fluders);
fluders = next;
}
}
void
free_fludees(aClient *badguy)
{
Link *fludees, *next;
if (badguy == NULL)
{
sendto_ops("free_fludees(NULL)");
return;
}
fludees = badguy->fludees;
while (fludees)
{
next = fludees->next;
if (fludees->flags)
remove_fluder_reference(&fludees->value.chptr->fluders, badguy);
else
{
if (!MyFludConnect(fludees->value.cptr))
sendto_ops("free_fludees() encountered non-local client");
else
remove_fluder_reference(&fludees->value.cptr->fluders, badguy);
}
BlockHeapFree(free_Links, fludees);
fludees = next;
}
}
#endif /* FLUD */
int del_silence(aClient *sptr, char *mask)
{
Link **lp, *tmp;
for (lp=&(sptr->user->silence);*lp;lp=&((*lp)->next))
if (mycmp(mask, (*lp)->value.cp)==0)
{
tmp = *lp;
*lp = tmp->next;
MyFree(tmp->value.cp);
free_link(tmp);
return 0;
}
return 1;
}
static int add_silence(aClient *sptr,char *mask)
{
Link *lp;
int cnt=0, len=0;
for (lp=sptr->user->silence;lp;lp=lp->next)
{
len += strlen(lp->value.cp);
if (MyClient(sptr))
{
if ((len > MAXSILELENGTH) || (++cnt >= MAXSILES))
{
sendto_one(sptr, err_str(ERR_SILELISTFULL), me.name,
sptr->name, mask);
return -1;
}
else
{
if (!match(lp->value.cp, mask))
return -1;
}
}
else if (!mycmp(lp->value.cp, mask))
return -1;
}
lp = make_link();
lp->next = sptr->user->silence;
lp->value.cp = (char *)MyMalloc(strlen(mask)+1);
strcpy(lp->value.cp, mask);
sptr->user->silence = lp;
return 0;
}
/* m_silence
* parv[0] = sender prefix
* From local client:
* parv[1] = mask (NULL sends the list)
* From remote client:
* parv[1] = nick that must be silenced
* parv[2] = mask
*/
int
m_silence(aClient *cptr,aClient *sptr,int parc,char *parv[])
{
Link *lp;
aClient *acptr=NULL;
char c, *cp;
if (MyClient(sptr))
{
acptr = sptr;
if (parc < 2 || *parv[1]=='\0' || (acptr = find_person(parv[1], NULL)))
{
if (!(acptr->user))
return 0;
for (lp = acptr->user->silence; lp; lp = lp->next)
sendto_one(sptr, rpl_str(RPL_SILELIST), me.name,
sptr->name, acptr->name, lp->value.cp);
sendto_one(sptr, rpl_str(RPL_ENDOFSILELIST), me.name, acptr->name);
return 0;
}
cp = parv[1];
c = *cp;
if (c=='-' || c=='+')
cp++;
else if (!(strchr(cp, '@') || strchr(cp, '.') ||
strchr(cp, '!') || strchr(cp, '*')))
{
sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0],
parv[1]);
return 0;
}
else c = '+';
cp = pretty_mask(cp);
if ((c=='-' && !del_silence(sptr,cp)) ||
(c!='-' && !add_silence(sptr,cp)))
{
sendto_prefix_one(sptr, sptr, ":%s SILENCE %c%s", parv[0], c, cp);
if (c=='-')
sendto_serv_butone(NULL, ":%s SILENCE * -%s", sptr->name, cp);
}
}
else if (parc < 3 || *parv[2]=='\0')
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0],
"SILENCE");
return -1;
}
else if ((c = *parv[2])=='-' || (acptr = find_person(parv[1], NULL)))
{
if (c=='-')
{
if (!del_silence(sptr,parv[2]+1))
sendto_serv_butone(cptr, ":%s SILENCE %s :%s",
parv[0], parv[1], parv[2]);
}
else
{
add_silence(sptr,parv[2]);
if (!MyClient(acptr))
sendto_one(acptr, ":%s SILENCE %s :%s",
parv[0], parv[1], parv[2]);
}
}
else
{
sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], parv[1]);
return 0;
}
return 0;
}
#ifdef DCCALLOW
static int
add_dccallow(aClient *sptr, aClient *optr)
{
Link *lp;
int cnt = 0;
for(lp = sptr->user->dccallow; lp; lp = lp->next)
{
if(lp->flags != DCC_LINK_ME)
continue;
if((++cnt >= MAXDCCALLOW) && !IsAnOper(sptr))
{
sendto_one(sptr, err_str(ERR_TOOMANYDCC), me.name, sptr->name,
optr->name, MAXDCCALLOW);
return 0;
}
else if(lp->value.cptr == optr)
return 0;
}
lp = make_link();
lp->value.cptr = optr;
lp->flags = DCC_LINK_ME;
lp->next = sptr->user->dccallow;
sptr->user->dccallow = lp;
lp = make_link();
lp->value.cptr = sptr;
lp->flags = DCC_LINK_REMOTE;
lp->next = optr->user->dccallow;
optr->user->dccallow = lp;
sendto_one(sptr, rpl_str(RPL_DCCSTATUS), me.name, sptr->name, optr->name,
"added to");
return 0;
}
static int
del_dccallow(aClient *sptr, aClient *optr)
{
Link **lpp, *lp;
int found = 0;
for (lpp = &(sptr->user->dccallow); *lpp; lpp=&((*lpp)->next))
{
if((*lpp)->flags != DCC_LINK_ME)
continue;
if((*lpp)->value.cptr == optr)
{
lp = *lpp;
*lpp = lp->next;
free_link(lp);
found++;
break;
}
}
if(!found)
{
sendto_one(sptr, ":%s %d %s :%s is not in your DCC allow list",
me.name, RPL_DCCINFO, sptr->name, optr->name);
return 0;
}
for (found = 0, lpp = &(optr->user->dccallow); *lpp; lpp=&((*lpp)->next))
{
if((*lpp)->flags != DCC_LINK_REMOTE)
continue;
if((*lpp)->value.cptr == sptr)
{
lp = *lpp;
*lpp = lp->next;
free_link(lp);
found++;
break;
}
}
if(!found)
sendto_realops_lev(DEBUG_LEV, "%s was in dccallowme list of %s but "
"not in dccallowrem list!", optr->name, sptr->name);
sendto_one(sptr, rpl_str(RPL_DCCSTATUS), me.name, sptr->name, optr->name,
"removed from");
return 0;
}
int
m_dccallow(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
Link *lp;
char *p, *s;
char *cn;
aClient *acptr, *lastcptr = NULL;
int didlist = 0, didhelp = 0, didanything = 0;
char **ptr;
static char *dcc_help[] =
{
"/DCCALLOW [<+|->nick[,<+|->nick, ...]] [list] [help]",
"You may allow DCCs of filetypes which are otherwise blocked by "
"the IRC server",
"by specifying a DCC allow for the user you want to recieve files "
"from.",
"For instance, to allow the user bob to send you file.exe, you "
"would type:",
"/dccallow +bob",
"and bob would then be able to send you files. bob will have to "
"resend the file",
"if the server gave him an error message before you added him to "
"your allow list.",
"/dccallow -bob",
"Will do the exact opposite, removing him from your dcc allow "
"list.",
"/dccallow list",
"Will list the users currently on your dcc allow list.",
NULL
};
if(!MyClient(sptr))
return 0;
if(parc < 2)
{
sendto_one(sptr, ":%s NOTICE %s :No command specified for DCCALLOW. "
"Type /dccallow help for more information.", me.name,
sptr->name);
return 0;
}
for (p = NULL, s = strtoken(&p, parv[1], ", "); s;
s = strtoken(&p, NULL, ", "))
{
if(*s == '+')
{
didanything++;
cn = s + 1;
if(*cn == '\0')
continue;
acptr = find_person(cn, NULL);
if(acptr == sptr) continue;
if(!acptr)
{
sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name,
sptr->name, cn);
continue;
}
if(lastcptr == acptr)
sendto_realops_lev(SPY_LEV, "User %s (%s@%s) may be flooding "
"dccallow: add %s", sptr->name,
sptr->user->username, sptr->user->host,
acptr->name);
lastcptr = acptr;
add_dccallow(sptr, acptr);
}
else if(*s == '-')
{
didanything++;
cn = s + 1;
if(*cn == '\0')
continue;
acptr = find_person(cn, NULL);
if(acptr == sptr)
continue;
if(!acptr)
{
sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name,
sptr->name, cn);
continue;
}
if(lastcptr == acptr)
sendto_realops_lev(SPY_LEV, "User %s (%s@%s) may be flooding "
"dccallow: del %s", sptr->name,
sptr->user->username, sptr->user->host,
acptr->name);
lastcptr = acptr;
del_dccallow(sptr, acptr);
}
else
{
if(!didlist && myncmp(s, "list", 4) == 0)
{
didanything++;
didlist++;
sendto_one(sptr, ":%s %d %s :The following users are on your "
"dcc allow list:", me.name, RPL_DCCINFO,
sptr->name);
for(lp = sptr->user->dccallow; lp; lp = lp->next)
{
if(lp->flags == DCC_LINK_REMOTE)
continue;
sendto_one(sptr, ":%s %d %s :%s (%s@%s)", me.name,
RPL_DCCLIST, sptr->name, lp->value.cptr->name,
lp->value.cptr->user->username,
lp->value.cptr->user->host);
}
sendto_one(sptr, rpl_str(RPL_ENDOFDCCLIST), me.name,
sptr->name, s);
}
else if(!didhelp && myncmp(s, "help", 4) == 0)
{
didanything++;
didhelp++;
for(ptr = dcc_help; *ptr; ptr++)
sendto_one(sptr, ":%s %d %s :%s", me.name, RPL_DCCINFO,
sptr->name, *ptr);
sendto_one(sptr, rpl_str(RPL_ENDOFDCCLIST), me.name,
sptr->name, s);
}
}
}
if(!didanything)
{
sendto_one(sptr, ":%s NOTICE %s :Invalid syntax for DCCALLOW. Type "
"/dccallow help for more information.", me.name,
sptr->name);
return 0;
}
return 0;
}
#endif
int
m_put(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
/* HTTP PUT proxy */
if (!IsRegistered(cptr) && cptr->receiveM == 1)
return reject_proxy(cptr, "PUT", parv[1]);
return 0;
}
int
m_post(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
/* HTTP POST proxy */
if (!IsRegistered(cptr) && cptr->receiveM == 1)
return reject_proxy(cptr, "POST", parv[1]);
return 0;
}
u_long
memcount_s_user(MCs_user *mc)
{
aClient *acptr;
Link *lp;
#ifdef FLUD
struct fludbot *fb;
#endif
mc->file = __FILE__;
for (acptr = client; acptr; acptr = acptr->next)
{
if (!IsMe(acptr)) /* me is static */
{
if (acptr->from == acptr)
mc->e_local_clients++;
else
mc->e_remote_clients++;
}
if (acptr->user)
{
mc->e_users++;
if (acptr->user->away)
{
mc->aways.c++;
mc->aways.m += strlen(acptr->user->away) + 1;
}
for (lp = acptr->user->silence; lp; lp = lp->next)
{
mc->silences.c++;
mc->silences.m += strlen(lp->value.cp) + 1;
mc->e_silence_links++;
}
mc->e_channel_links += mc_links(acptr->user->channel);
mc->e_invite_links += mc_links(acptr->user->invited);
#ifdef DCCALLOW
mc->e_dccallow_links += mc_links(acptr->user->dccallow);
#endif
#if (RIDICULOUS_PARANOIA_LEVEL>=1)
if (acptr->user->real_oper_host)
{
mc->opermasks.c++;
mc->opermasks.m += strlen(acptr->user->real_oper_host) + 1;
mc->opermasks.m += strlen(acptr->user->real_oper_username) + 1;
mc->opermasks.m += strlen(acptr->user->real_oper_ip) + 1;
}
#endif
}
if (acptr->serv)
{
mc->servers.c++;
mc->servers.m += sizeof(aServer);
#ifdef HAVE_ENCRYPTION_ON
if (acptr->serv->rc4_in)
mc->e_rc4states++;
if (acptr->serv->rc4_out)
mc->e_rc4states++;
#endif
if (acptr->serv->zip_in)
mc->e_zipin_sessions++;
if (acptr->serv->zip_out)
mc->e_zipout_sessions++;
}
mc->e_watch_links += mc_links(acptr->watch);
#ifdef FLUD
mc->e_flud_links += mc_links(acptr->fludees);
if (acptr->from == acptr) /* local client */
for (fb = acptr->fluders; fb; fb = fb->next)
mc->e_fludbots++;
#endif
}
mc->total.c = mc->aways.c + mc->silences.c + mc->servers.c;
mc->total.m = mc->aways.m + mc->silences.m + mc->servers.m;
#if (RIDICULOUS_PARANOIA_LEVEL>=1)
mc->total.c += mc->opermasks.c;
mc->total.m += mc->opermasks.m;
#endif
return mc->total.m;
}
syntax highlighted by Code2HTML, v. 0.9.1