+static void
+mode_parse_noflood(struct ParseState *state, ulong64 *flag_p)
+{
+ char *t_str;
+ char *tmp;
+ unsigned int count = 0, time = 0, flags = 0;
+
+ if (state->dir == MODE_ADD) { /* convert arg only if adding noflood */
+ if (MyUser(state->sptr) && state->max_args <= 0) /* too many args? */
+ return;
+
+ if (state->parc <= 0) { /* warn if not enough args */
+ if (MyUser(state->sptr))
+ need_more_params(state->sptr, "MODE +f");
+ return;
+ }
+
+ t_str = state->parv[state->args_used++]; /* grab arg */
+ state->parc--;
+ state->max_args--;
+
+ tmp = t_str;
+
+ if(tmp[0] == '!') {
+ if(state->flags & MODE_PARSE_FORCE) flags |= FLFL_NOFLOOD;
+ else t_str++; //simply ignore if it's not an opmode
+ tmp++;
+ }
+ if(tmp[0] == '+' || tmp[0] == '@') {
+ if(tmp[0] == '+') flags |= FLFL_VOICE;
+ if(tmp[0] == '@') flags |= FLFL_CHANOP;
+ tmp++;
+ }
+ char *p;
+ for(p = tmp; p[0]; p++) {
+ if(p[0] == ':') {
+ char tmpchar = p[0];
+ p[0] = '\0';
+ count = strtoul(tmp,0,10);
+ p[0] = tmpchar;
+ p++;
+ time = strtoul(p,0,10);
+ break;
+ }
+ }
+ if(count <= 0 || time <= 0 || count > 100 || time > 600) return;
+
+ if (!(state->flags & MODE_PARSE_WIPEOUT) &&
+ (!t_str || t_str == state->chptr->mode.noflood))
+ return;
+ } else
+ t_str = state->chptr->mode.noflood;
+
+ /* If they're not an oper, they can't change modes */
+ if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) {
+ send_notoper(state);
+ return;
+ }
+
+ /* Can't remove a noflood that's not there */
+ if (state->dir == MODE_DEL && !*state->chptr->mode.noflood)
+ return;
+
+ /* Skip if this is a burst and a lower noflood than this is set already */
+ if ((state->flags & MODE_PARSE_BURST) &&
+ *(state->chptr->mode.noflood))
+ return;
+
+ if (state->done & DONE_NOFLOOD) /* allow noflood to be set only once */
+ return;
+ state->done |= DONE_NOFLOOD;
+
+ if (!state->mbuf)
+ return;
+
+ if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD &&
+ !ircd_strcmp(state->chptr->mode.noflood, t_str))
+ return; /* no change */
+
+ if (state->flags & MODE_PARSE_BOUNCE) {
+ if (*state->chptr->mode.noflood) /* reset old noflood */
+ modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0], state->chptr->mode.noflood, 0);
+ else /* remove new bogus noflood */
+ modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0);
+ } else /* send new noflood */
+ modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0);
+
+ if (state->flags & MODE_PARSE_SET) {
+ if (state->dir == MODE_DEL) /* remove the old noflood */
+ *state->chptr->mode.noflood = '\0';
+ else
+ ircd_strncpy(state->chptr->mode.noflood, t_str, CHANNELLEN);
+ }
+
+ if (state->dir == MODE_ADD) {
+ unsigned int noflood_value = time;
+ noflood_value <<= 10;
+ noflood_value |= count;
+ noflood_value <<= 3;
+ noflood_value |= flags;
+ state->chptr->mode.noflood_value = noflood_value;
+ } else {
+ //removed the mode so free all flood objects
+ struct Membership *member;
+ for(member = state->chptr->members; member; member = member->next_member) {
+ struct MemberFlood *floodnode;
+ for(floodnode = member->flood; floodnode; floodnode = floodnode->next_memberflood) {} //simply walk to the end
+ floodnode->next_memberflood = free_MemberFlood;
+ free_MemberFlood = floodnode;
+ member->flood = NULL;
+ }
+ }
+}
+