#include "hash.h"
#include "ircd.h"
#include "ircd_alloc.h"
-#include "ircd_auth.h"
#include "ircd_chattr.h"
#include "ircd_features.h"
#include "ircd_log.h"
#include "parse.h"
#include "querycmds.h"
#include "random.h"
+#include "s_auth.h"
#include "s_bsd.h"
#include "s_conf.h"
#include "s_debug.h"
/* All variables are 0 by default */
memset(cli_user(cptr), 0, sizeof(struct User));
-#ifdef DEBUGMODE
++userCount;
-#endif
cli_user(cptr)->refcnt = 1;
}
return cli_user(cptr);
assert(0 == user->channel);
MyFree(user);
-#ifdef DEBUGMODE
+ assert(userCount>0);
--userCount;
-#endif
}
}
}
-/** Copy a cleaned-up version of a username.
- * Replace all instances of '~' and "invalid" username characters
- * (!isIrcUi()) with underscores, truncating at USERLEN or the first
- * control character. \a dest and \a source may be the same buffer.
- * @param[out] dest Destination buffer.
- * @param[in] source Source buffer.
- * @param[in] tilde If non-zero, prepend a '~' to \a dest.
- */
-static char *clean_user_id(char *dest, char *source, int tilde)
-{
- char ch;
- char *d = dest;
- char *s = source;
- int rlen = USERLEN;
-
- ch = *s++; /* Store first character to copy: */
- if (tilde)
- {
- *d++ = '~'; /* If `dest' == `source', then this overwrites `ch' */
- --rlen;
- }
- while (ch && !IsCntrl(ch) && rlen--)
- {
- char nch = *s++; /* Store next character to copy */
- *d++ = IsUserChar(ch) ? ch : '_'; /* This possibly overwrites it */
- if (nch == '~')
- ch = '_';
- else
- ch = nch;
- }
- *d = 0;
- return dest;
-}
-
/*
* register_user
*
*
* @param[in] cptr Client who introduced the user.
* @param[in,out] sptr Client who has been fully introduced.
- * @param[in] nick Client's new nickname.
- * @param[in] username Client's username.
* @return Zero or CPTR_KILLED.
*/
-int register_user(struct Client *cptr, struct Client *sptr,
- const char *nick, char *username)
+int register_user(struct Client *cptr, struct Client *sptr)
{
- struct ConfItem* aconf;
char* parv[4];
char* tmpstr;
- char* tmpstr2;
- char c = 0; /* not alphanum */
- char d = 'a'; /* not a digit */
- short upper = 0;
- short lower = 0;
- short pos = 0;
- short leadcaps = 0;
- short other = 0;
- short digits = 0;
- short badid = 0;
- short digitgroups = 0;
struct User* user = cli_user(sptr);
- int killreason;
char ip_base64[25];
user->last = CurrentTime;
if (MyConnect(sptr))
{
- static time_t last_too_many1;
- static time_t last_too_many2;
-
assert(cptr == sptr);
- if (!IsIAuthed(sptr)) {
- if (iauth_active)
- return iauth_start_client(iauth_active, sptr);
- else
- SetIAuthed(sptr);
- }
- switch (conf_check_client(sptr))
- {
- case ACR_OK:
- break;
- case ACR_NO_AUTHORIZATION:
- sendto_opmask_butone(0, SNO_UNAUTH, "Unauthorized connection from %s.",
- get_client_name(sptr, HIDE_IP));
- ++ServerStats->is_ref;
- return exit_client(cptr, sptr, &me,
- "No Authorization - use another server");
- case ACR_TOO_MANY_IN_CLASS:
- if (CurrentTime - last_too_many1 >= (time_t) 60)
- {
- last_too_many1 = CurrentTime;
- sendto_opmask_butone(0, SNO_TOOMANY, "Too many connections in "
- "class %i for %s.", get_client_class(sptr),
- get_client_name(sptr, SHOW_IP));
- }
- ++ServerStats->is_ref;
- IPcheck_connect_fail(&cli_ip(sptr));
- return exit_client(cptr, sptr, &me,
- "Sorry, your connection class is full - try "
- "again later or try another server");
- case ACR_TOO_MANY_FROM_IP:
- if (CurrentTime - last_too_many2 >= (time_t) 60)
- {
- last_too_many2 = CurrentTime;
- sendto_opmask_butone(0, SNO_TOOMANY, "Too many connections from "
- "same IP for %s.",
- get_client_name(sptr, SHOW_IP));
- }
- ++ServerStats->is_ref;
- return exit_client(cptr, sptr, &me,
- "Too many connections from your host");
- case ACR_ALREADY_AUTHORIZED:
- /* Can this ever happen? */
- case ACR_BAD_SOCKET:
- ++ServerStats->is_ref;
- IPcheck_connect_fail(&cli_ip(sptr));
- return exit_client(cptr, sptr, &me, "Unknown error -- Try again");
- }
- ircd_strncpy(user->host, cli_sockhost(sptr), HOSTLEN);
- ircd_strncpy(user->realhost, cli_sockhost(sptr), HOSTLEN);
- aconf = cli_confs(sptr)->value.aconf;
- clean_user_id(user->username,
- HasFlag(sptr, FLAG_GOTID) ? cli_username(sptr) : username,
- HasFlag(sptr, FLAG_DOID) && !HasFlag(sptr, FLAG_GOTID));
-
- if ((user->username[0] == '\0')
- || ((user->username[0] == '~') && (user->username[1] == '\000')))
- return exit_client(cptr, sptr, &me, "USER: Bogus userid.");
+ Count_unknownbecomesclient(sptr, UserStats);
- if (!EmptyString(aconf->passwd)
- && !(IsDigit(*aconf->passwd) && !aconf->passwd[1])
- && strcmp(cli_passwd(sptr), aconf->passwd))
- {
- ServerStats->is_ref++;
- send_reply(sptr, ERR_PASSWDMISMATCH);
- return exit_client(cptr, sptr, &me, "Bad Password");
- }
- memset(cli_passwd(sptr), 0, sizeof(cli_passwd(sptr)));
- /*
- * following block for the benefit of time-dependent K:-lines
- */
- killreason = find_kill(sptr);
- if (killreason) {
- ServerStats->is_ref++;
- return exit_client(cptr, sptr, &me,
- (killreason == -1 ? "K-lined" : "G-lined"));
- }
/*
- * Check for mixed case usernames, meaning probably hacked. Jon2 3-94
- * Summary of rules now implemented in this patch: Ensor 11-94
- * In a mixed-case name, if first char is upper, one more upper may
- * appear anywhere. (A mixed-case name *must* have an upper first
- * char, and may have one other upper.)
- * A third upper may appear if all 3 appear at the beginning of the
- * name, separated only by "others" (-/_/.).
- * A single group of digits is allowed anywhere.
- * Two groups of digits are allowed if at least one of the groups is
- * at the beginning or the end.
- * Only one '-', '_', or '.' is allowed (or two, if not consecutive).
- * But not as the first or last char.
- * No other special characters are allowed.
- * Name must contain at least one letter.
+ * Set user's initial modes
*/
- tmpstr2 = tmpstr = (username[0] == '~' ? &username[1] : username);
- while (*tmpstr && !badid)
- {
- pos++;
- c = *tmpstr;
- tmpstr++;
- if (IsLower(c))
- {
- lower++;
- }
- else if (IsUpper(c))
- {
- upper++;
- if ((leadcaps || pos == 1) && !lower && !digits)
- leadcaps++;
- }
- else if (IsDigit(c))
- {
- digits++;
- if (pos == 1 || !IsDigit(d))
- {
- digitgroups++;
- if (digitgroups > 2)
- badid = 1;
- }
- }
- else if (c == '-' || c == '_' || c == '.')
- {
- other++;
- if (pos == 1)
- badid = 1;
- else if (d == '-' || d == '_' || d == '.' || other > 2)
- badid = 1;
- }
- else
- badid = 1;
- d = c;
- }
- if (!badid)
- {
- if (lower && upper && (!leadcaps || leadcaps > 3 ||
- (upper > 2 && upper > leadcaps)))
- badid = 1;
- else if (digitgroups == 2 && !(IsDigit(tmpstr2[0]) || IsDigit(c)))
- badid = 1;
- else if ((!lower && !upper) || !IsAlnum(c))
- badid = 1;
- }
- if (badid && (!HasFlag(sptr, FLAG_GOTID) ||
- strcmp(cli_username(sptr), username) != 0))
- {
- ServerStats->is_ref++;
-
- send_reply(cptr, SND_EXPLICIT | ERR_INVALIDUSERNAME,
- ":Your username is invalid.");
- send_reply(cptr, SND_EXPLICIT | ERR_INVALIDUSERNAME,
- ":Connect with your real username, in lowercase.");
- send_reply(cptr, SND_EXPLICIT | ERR_INVALIDUSERNAME,
- ":If your mail address were foo@bar.com, your username "
- "would be foo.");
- return exit_client(cptr, sptr, &me, "USER: Bad username");
+ tmpstr = (char*)client_get_default_umode(sptr);
+ if (tmpstr) {
+ char *umodev[] = { NULL, NULL, NULL, NULL };
+ umodev[2] = tmpstr;
+ set_user_mode(cptr, sptr, 3, umodev, ALLOWMODES_ANY);
}
- Count_unknownbecomesclient(sptr, UserStats);
- }
- else {
- ircd_strncpy(user->username, username, USERLEN);
- Count_newremoteclient(UserStats, user->server);
- }
- SetUser(sptr);
-
- if (IsInvisible(sptr))
- ++UserStats.inv_clients;
- if (IsOper(sptr))
- ++UserStats.opers;
- if (MyConnect(sptr)) {
+ SetUser(sptr);
cli_handler(sptr) = CLIENT_HANDLER;
- release_dns_reply(sptr);
SetLocalNumNick(sptr);
send_reply(sptr,
RPL_WELCOME,
feature_str(FEAT_NETWORK),
feature_str(FEAT_PROVIDER) ? " via " : "",
feature_str(FEAT_PROVIDER) ? feature_str(FEAT_PROVIDER) : "",
- nick);
+ cli_name(sptr));
/*
* This is a duplicate of the NOTICE but see below...
*/
send_reply(sptr, RPL_YOURHOST, cli_name(&me), version);
send_reply(sptr, RPL_CREATED, creation);
- send_reply(sptr, RPL_MYINFO, cli_name(&me), infousermodes, infochanmodes,
- infochanmodeswithparams, version);
+ send_reply(sptr, RPL_MYINFO, cli_name(&me), version, infousermodes,
+ infochanmodes, infochanmodeswithparams);
send_supported(sptr);
m_lusers(sptr, sptr, 1, parv);
update_load();
motd_signon(sptr);
-/* nextping = CurrentTime; */
if (cli_snomask(sptr) & SNO_NOISY)
set_snomask(sptr, cli_snomask(sptr) & SNO_NOISY, SNO_ADD);
if (feature_bool(FEAT_CONNEXIT_NOTICES))
cli_info(sptr), NumNick(cptr) /* two %s's */);
IPcheck_connect_succeeded(sptr);
- /*
- * Set user's initial modes
- */
- parv[0] = (char*)nick;
- parv[1] = (char*)nick;
- parv[2] = (char*)client_get_default_umode(sptr);
- parv[3] = NULL; /* needed in case of +s */
- set_user_mode(sptr, sptr, 3, parv);
- ClearHiddenHost(sptr); /* just in case somebody stuck +x in there */
}
- else
- /* if (IsServer(cptr)) */
- {
- struct Client *acptr;
+ else {
+ struct Client *acptr = user->server;
- acptr = user->server;
if (cli_from(acptr) != cli_from(sptr))
{
sendcmdto_one(&me, CMD_KILL, cptr, "%C :%s (%s != %s[%s])",
SetFlag(sptr, FLAG_TS8);
/*
- * Check to see if this user is being propogated
+ * Check to see if this user is being propagated
* as part of a net.burst, or is using protocol 9.
- * FIXME: This can be speeded up - its stupid to check it for
+ * FIXME: This can be sped up - its stupid to check it for
* every NICK message in a burst again --Run.
*/
- for (acptr = user->server; acptr != &me; acptr = cli_serv(acptr)->up)
+ for (; acptr != &me; acptr = cli_serv(acptr)->up)
{
if (IsBurst(acptr) || Protocol(acptr) < 10)
break;
sptr, cli_name(&me));
return exit_client(cptr, sptr, &me,"Too many connections from your host -- throttled");
}
+ SetUser(sptr);
}
+
+ /* If they get both +x and an account during registration, hide
+ * their hostmask here. Calling hide_hostmask() from IAuth's
+ * account assignment causes a numeric reply during registration.
+ */
+ if (HasHiddenHost(sptr))
+ hide_hostmask(sptr, FLAG_HIDDENHOST);
+ if (IsInvisible(sptr))
+ ++UserStats.inv_clients;
+ if (IsOper(sptr))
+ ++UserStats.opers;
+
tmpstr = umode_str(sptr);
/* Send full IP address to IPv6-grokking servers. */
sendcmdto_flag_serv_butone(user->server, CMD_NICK, cptr,
FLAG_IPV6, FLAG_LAST_FLAG,
"%s %d %Tu %s %s %s%s%s%s %s%s :%s",
- nick, cli_hopcount(sptr) + 1, cli_lastnick(sptr),
+ cli_name(sptr), cli_hopcount(sptr) + 1,
+ cli_lastnick(sptr),
user->username, user->realhost,
*tmpstr ? "+" : "", tmpstr, *tmpstr ? " " : "",
iptobase64(ip_base64, &cli_ip(sptr), sizeof(ip_base64), 1),
sendcmdto_flag_serv_butone(user->server, CMD_NICK, cptr,
FLAG_LAST_FLAG, FLAG_IPV6,
"%s %d %Tu %s %s %s%s%s%s %s%s :%s",
- nick, cli_hopcount(sptr) + 1, cli_lastnick(sptr),
+ cli_name(sptr), cli_hopcount(sptr) + 1,
+ cli_lastnick(sptr),
user->username, user->realhost,
*tmpstr ? "+" : "", tmpstr, *tmpstr ? " " : "",
iptobase64(ip_base64, &cli_ip(sptr), sizeof(ip_base64), 0),
NumNick(sptr), cli_info(sptr));
- /* Send server notice mask to client */
- if (MyUser(sptr) && (cli_snomask(sptr) != SNO_DEFAULT) && HasFlag(sptr, FLAG_SERVNOTICE))
- send_reply(sptr, RPL_SNOMASK, cli_snomask(sptr), cli_snomask(sptr));
-
+ /* Send user mode to client */
+ if (MyUser(sptr))
+ {
+ static struct Flags flags; /* automatically initialized to zeros */
+ /* To avoid sending +r to the client due to auth-on-connect, set
+ * the "old" FLAG_ACCOUNT bit to match the client's value.
+ */
+ if (IsAccount(cptr))
+ FlagSet(&flags, FLAG_ACCOUNT);
+ else
+ FlagClr(&flags, FLAG_ACCOUNT);
+ client_set_privs(sptr, NULL);
+ send_umode(cptr, sptr, &flags, ALL_UMODES);
+ if ((cli_snomask(sptr) != SNO_DEFAULT) && HasFlag(sptr, FLAG_SERVNOTICE))
+ send_reply(sptr, RPL_SNOMASK, cli_snomask(sptr), cli_snomask(sptr));
+ }
return 0;
}
const char* nick, int parc, char* parv[])
{
if (IsServer(sptr)) {
- int i;
- const char* account = 0;
- const char* p;
/*
* A server introducing a new client, change source
cli_hopcount(new_client) = atoi(parv[2]);
cli_lastnick(new_client) = atoi(parv[3]);
- if (Protocol(cptr) > 9 && parc > 7 && *parv[6] == '+')
- {
- for (p = parv[6] + 1; *p; p++)
- {
- for (i = 0; i < USERMODELIST_SIZE; ++i)
- {
- if (userModeList[i].c == *p)
- {
- SetFlag(new_client, userModeList[i].flag);
- if (userModeList[i].flag == FLAG_ACCOUNT)
- account = parv[7];
- break;
- }
- }
- }
- }
- client_set_privs(new_client, NULL); /* set privs on user */
+
/*
* Set new nick name.
*/
cli_serv(sptr)->ghost = 0; /* :server NICK means end of net.burst */
ircd_strncpy(cli_username(new_client), parv[4], USERLEN);
+ ircd_strncpy(cli_user(new_client)->username, parv[4], USERLEN);
ircd_strncpy(cli_user(new_client)->host, parv[5], HOSTLEN);
ircd_strncpy(cli_user(new_client)->realhost, parv[5], HOSTLEN);
ircd_strncpy(cli_info(new_client), parv[parc - 1], REALLEN);
- if (account) {
- int len = ACCOUNTLEN;
- if ((p = strchr(account, ':'))) {
- len = (p++) - account;
- cli_user(new_client)->acc_create = atoi(p);
- Debug((DEBUG_DEBUG, "Received timestamped account in user mode; "
- "account \"%s\", timestamp %Tu", account,
- cli_user(new_client)->acc_create));
- }
- ircd_strncpy(cli_user(new_client)->account, account, len);
+
+ Count_newremoteclient(UserStats, sptr);
+
+ if (parc > 7 && *parv[6] == '+') {
+ /* (parc-4) -3 for the ip, numeric nick, realname */
+ set_user_mode(cptr, new_client, parc-7, parv+4, ALLOWMODES_ANY);
}
- if (HasHiddenHost(new_client))
- ircd_snprintf(0, cli_user(new_client)->host, HOSTLEN, "%s.%s",
- account, feature_str(FEAT_HIDDEN_HOST));
- return register_user(cptr, new_client, cli_name(new_client), parv[4]);
+ return register_user(cptr, new_client);
}
else if ((cli_name(sptr))[0]) {
/*
}
else {
/* Local client setting NICK the first time */
-
strcpy(cli_name(sptr), nick);
- if (!cli_user(sptr)) {
- cli_user(sptr) = make_user(sptr);
- cli_user(sptr)->server = &me;
- }
hAddClient(sptr);
-
- /*
- * If the client hasn't gotten a cookie-ping yet,
- * choose a cookie and send it. -record!jegelhof@cloud9.net
- */
- if (!cli_cookie(sptr)) {
- do {
- cli_cookie(sptr) = (ircrandom() & 0x7fffffff);
- } while (!cli_cookie(sptr));
- sendrawto_one(cptr, MSG_PING " :%u", cli_cookie(sptr));
- }
- else if (*(cli_user(sptr))->host && cli_cookie(sptr) == COOKIE_VERIFIED) {
- /*
- * USER and PONG already received, now we have NICK.
- * register_user may reject the client and call exit_client
- * for it - must test this and exit m_nick too !
- */
- cli_lastnick(sptr) = TStime(); /* Always local client */
- if (register_user(cptr, sptr, nick, cli_user(sptr)->username) == CPTR_KILLED)
- return CPTR_KILLED;
- }
+ return auth_set_nick(cli_auth(sptr), nick);
}
return 0;
}
assert(cli_local(sptr));
targets = cli_targets(sptr);
- /* If user is invited to channel, give him/her a free target */
- if (IsChannelName(name) && IsInvited(sptr, target))
- return 0;
-
/*
* Same target as last time?
*/
*/
if (!created) {
if (CurrentTime < cli_nexttarget(sptr)) {
+ /* If user is invited to channel, give him/her a free target */
+ if (IsChannelName(name) && IsInvited(sptr, target))
+ return 0;
+
if (cli_nexttarget(sptr) - CurrentTime < TARGET_DELAY + 8) {
/*
* No server flooding
if (is_silenced(source, dest))
return 0;
- if (cli_user(dest)->away)
- send_reply(source, RPL_AWAY, cli_name(dest), cli_user(dest)->away);
if (is_notice)
sendcmdto_one(source, CMD_NOTICE, dest, "%C :%s", dest, text);
else
+ {
+ if (cli_user(dest)->away)
+ send_reply(source, RPL_AWAY, cli_name(dest), cli_user(dest)->away);
sendcmdto_one(source, CMD_PRIVATE, dest, "%C :%s", dest, text);
+ }
return 0;
}
for (chan = (cli_user(cptr))->channel; chan;
chan = chan->next_channel)
ClearBanValid(chan);
+ break;
default:
return 0;
}
sendcmdto_channel_butserv_butone(cptr, CMD_JOIN, chan->channel, cptr, 0,
"%H", chan->channel);
if (IsChanOp(chan) && HasVoice(chan))
- sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan->channel, cptr, 0,
+ sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, cptr, 0,
"%H +ov %C %C", chan->channel, cptr,
cptr);
else if (IsChanOp(chan) || HasVoice(chan))
- sendcmdto_channel_butserv_butone(&me, CMD_MODE, chan->channel, cptr, 0,
+ sendcmdto_channel_butserv_butone(&his, CMD_MODE, chan->channel, cptr, 0,
"%H +%c %C", chan->channel, IsChanOp(chan) ? 'o' : 'v', cptr);
}
return 0;
* @param[in] sptr Client who sent the mode change message.
* @param[in] parc Number of parameters in \a parv.
* @param[in] parv Parameters to MODE.
+ * @param[in] allow_modes ALLOWMODES_ANY for any mode, ALLOWMODES_DEFAULT for
+ * only permitting legitimate default user modes.
* @return Zero.
*/
-int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+int set_user_mode(struct Client *cptr, struct Client *sptr, int parc,
+ char *parv[], int allow_modes)
{
char** p;
char* m;
- struct Client *acptr;
int what;
int i;
struct Flags setflags;
char buf[BUFSIZE];
int prop = 0;
int do_host_hiding = 0;
+ char* account = NULL;
what = MODE_ADD;
- if (parc < 2)
- return need_more_params(sptr, "MODE");
-
- if (!(acptr = FindUser(parv[1])))
- {
- if (MyConnect(sptr))
- send_reply(sptr, ERR_NOSUCHCHANNEL, parv[1]);
- return 0;
- }
-
- if (IsServer(sptr) || sptr != acptr)
- {
- if (IsServer(cptr))
- sendwallto_group_butone(&me, WALL_WALLOPS, 0,
- "MODE for User %s from %s!%s", parv[1],
- cli_name(cptr), cli_name(sptr));
- else
- send_reply(sptr, ERR_USERSDONTMATCH);
- return 0;
- }
-
if (parc < 3)
{
m = buf;
/*
* parse mode change string(s)
*/
- for (p = &parv[2]; *p; p++) { /* p is changed in loop too */
+ for (p = &parv[2]; *p && p<&parv[parc]; p++) { /* p is changed in loop too */
for (m = *p; *m; m++) {
switch (*m) {
case '+':
if (what == MODE_ADD)
do_host_hiding = 1;
break;
+ case 'r':
+ if (*(p + 1) && (what == MODE_ADD)) {
+ account = *(++p);
+ SetAccount(sptr);
+ }
+ /* There is no -r */
+ break;
default:
send_reply(sptr, ERR_UMODEUNKNOWNFLAG, *m);
break;
ClearOper(sptr);
if (!FlagHas(&setflags, FLAG_LOCOP) && IsLocOp(sptr))
ClearLocOp(sptr);
+ if (!FlagHas(&setflags, FLAG_ACCOUNT) && IsAccount(sptr))
+ ClrFlag(sptr, FLAG_ACCOUNT);
/*
* new umode; servers can set it, local users cannot;
* prevents users from /kick'ing or /mode -o'ing
* Compare new flags with old flags and send string which
* will cause servers to update correctly.
*/
- if (!FlagHas(&setflags, FLAG_OPER) && IsOper(sptr))
- {
- /* user now oper */
- ++UserStats.opers;
- client_set_privs(sptr, NULL); /* may set propagate privilege */
- }
- /* remember propagate privilege setting */
- if (HasPriv(sptr, PRIV_PROPAGATE))
- prop = 1;
- if (FlagHas(&setflags, FLAG_OPER) && !IsOper(sptr))
- {
- /* user no longer oper */
- --UserStats.opers;
- client_set_privs(sptr, NULL); /* will clear propagate privilege */
+ if (!FlagHas(&setflags, FLAG_ACCOUNT) && IsAccount(sptr)) {
+ int len = ACCOUNTLEN;
+ char *ts;
+ if ((ts = strchr(account, ':'))) {
+ len = (ts++) - account;
+ cli_user(sptr)->acc_create = atoi(ts);
+ Debug((DEBUG_DEBUG, "Received timestamped account in user mode; "
+ "account \"%s\", timestamp %Tu", account,
+ cli_user(sptr)->acc_create));
+ }
+ ircd_strncpy(cli_user(sptr)->account, account, len);
}
- if (FlagHas(&setflags, FLAG_INVISIBLE) && !IsInvisible(sptr))
- --UserStats.inv_clients;
- if (!FlagHas(&setflags, FLAG_INVISIBLE) && IsInvisible(sptr))
- ++UserStats.inv_clients;
- if (!FlagHas(&setflags, FLAG_HIDDENHOST) && do_host_hiding)
+ if (!FlagHas(&setflags, FLAG_HIDDENHOST) && do_host_hiding && allow_modes != ALLOWMODES_DEFAULT)
hide_hostmask(sptr, FLAG_HIDDENHOST);
- send_umode_out(cptr, sptr, &setflags, prop);
+
+ if (IsRegistered(sptr)) {
+ if (!FlagHas(&setflags, FLAG_OPER) && IsOper(sptr)) {
+ /* user now oper */
+ ++UserStats.opers;
+ client_set_privs(sptr, NULL); /* may set propagate privilege */
+ }
+ /* remember propagate privilege setting */
+ if (HasPriv(sptr, PRIV_PROPAGATE)) {
+ prop = 1;
+ }
+ if (FlagHas(&setflags, FLAG_OPER) && !IsOper(sptr)) {
+ /* user no longer oper */
+ assert(UserStats.opers > 0);
+ --UserStats.opers;
+ client_set_privs(sptr, NULL); /* will clear propagate privilege */
+ }
+ if (FlagHas(&setflags, FLAG_INVISIBLE) && !IsInvisible(sptr)) {
+ assert(UserStats.inv_clients > 0);
+ --UserStats.inv_clients;
+ }
+ if (!FlagHas(&setflags, FLAG_INVISIBLE) && IsInvisible(sptr)) {
+ ++UserStats.inv_clients;
+ }
+ assert(UserStats.opers <= UserStats.clients + UserStats.unknowns);
+ assert(UserStats.inv_clients <= UserStats.clients + UserStats.unknowns);
+ send_umode_out(cptr, sptr, &setflags, prop);
+ }
return 0;
}
int i;
struct Flags c_flags = cli_flags(cptr);
- if (HasPriv(cptr, PRIV_PROPAGATE))
- FlagSet(&c_flags, FLAG_OPER);
- else
+ if (!HasPriv(cptr, PRIV_PROPAGATE))
FlagClr(&c_flags, FLAG_OPER);
for (i = 0; i < USERMODELIST_SIZE; ++i)
/** Check whether \a sptr is allowed to send a message to \a acptr.
* If \a sptr is a remote user, it means some server has an outdated
* SILENCE list for \a acptr, so send the missing SILENCE mask(s) back
- * in the direction of \a sptr.
+ * in the direction of \a sptr. Skip the check if \a sptr is a server.
* @param[in] sptr Client trying to send a message.
* @param[in] acptr Destination of message.
* @return Non-zero if \a sptr is SILENCEd by \a acptr, zero if not.
size_t buf_used, slen;
char buf[BUFSIZE];
- if (!(user = cli_user(acptr))
+ if (IsServer(sptr) || !(user = cli_user(acptr))
|| !(found = find_ban(sptr, user->silence)))
return 0;
assert(!(found->flags & BAN_EXCEPTION));
return 0; /* convenience return, if it's ever needed */
}
+
+/* vim: shiftwidth=2
+ */