* @return The new ban entry on success, NULL on failure.
*/
static struct Ban *
-apply_silence(struct Client *sptr, const char *mask)
+apply_silence(struct Client *sptr, char *mask)
{
struct Ban *sile;
int flags;
+ int res;
+ char orig_mask[NICKLEN+USERLEN+HOSTLEN+3];
assert(mask && mask[0]);
mask++;
}
- /* Make the silence, set flags, and apply it. */
- sile = make_ban(mask);
+ /* Make the silence and set additional flags. */
+ ircd_strncpy(orig_mask, mask, sizeof(orig_mask) - 1);
+ sile = make_ban(pretty_mask(mask));
sile->flags |= flags;
- return apply_ban(&cli_user(sptr)->silence, sile) ? NULL : sile;
+
+ /* If they're a local user trying to ban too broad a mask, forbid it. */
+ if (MyUser(sptr)
+ && (sile->flags & BAN_IPMASK)
+ && sile->addrbits > 0
+ && sile->addrbits < (irc_in_addr_is_ipv4(&sile->address) ? 112 : 32)) {
+ send_reply(sptr, ERR_MASKTOOWIDE, orig_mask);
+ free_ban(sile);
+ return NULL;
+ }
+
+ /* Apply it to the silence list. */
+ res = apply_ban(&cli_user(sptr)->silence, sile, 1);
+ return res ? NULL : sile;
}
/** Apply and send silence updates for a user.
accepted[ac_count++] = sile;
}
-
if (MyUser(sptr)) {
size_t siles, maxsiles, totlength, maxlength, jj;
maxlength = maxsiles * feature_int(FEAT_AVBANLEN);
siles = totlength = 0;
/* Count number of current silences and their total length. */
+ plast = &cli_user(sptr)->silence;
for (sile = cli_user(sptr)->silence; sile; sile = sile->next) {
if (sile->flags & (BAN_OVERLAPPED | BAN_ADD | BAN_DEL))
continue;
siles++;
totlength += strlen(sile->banstr);
+ plast = &sile->next;
}
for (ii = jj = 0; ii < ac_count; ++ii) {
sile = accepted[ii];
if (!(sile->flags & (BAN_OVERLAPPED | BAN_DEL))) {
slen = strlen(sile->banstr);
if ((siles >= maxsiles) || (totlength + slen >= maxlength)) {
+ *plast = NULL;
+ if (MyUser(sptr))
+ send_reply(sptr, ERR_SILELISTFULL, accepted[ii]->banstr);
free_ban(accepted[ii]);
continue;
}
/* Update counts. */
siles++;
totlength += slen;
+ plast = &sile->next;
}
/* Store the update. */
accepted[jj++] = sile;
/* Free any silence-deleting updates. */
for (ii = 0; ii < ac_count; ++ii) {
- if (accepted[ii]->flags & BAN_DEL)
+ if ((accepted[ii]->flags & (BAN_ADD | BAN_DEL)) == BAN_DEL) {
free_ban(accepted[ii]);
+ }
}
}