-/*
- * Check and try to apply the channel modes passed in the parv array for
- * the client ccptr to channel chptr. The resultant changes are printed
- * into mbuf and pbuf (if any) and applied to the channel.
- */
-int set_mode(struct Client* cptr, struct Client* sptr,
- struct Channel* chptr, int parc, char* parv[],
- char* mbuf, char* pbuf, char* npbuf, int* badop)
-{
- /*
- * This size is only needed when a broken
- * server sends more then MAXMODEPARAMS
- * parameters
- */
- static struct SLink chops[MAXPARA - 2];
- static int flags[] = {
- MODE_PRIVATE, 'p',
- MODE_SECRET, 's',
- MODE_MODERATED, 'm',
- MODE_NOPRIVMSGS, 'n',
- MODE_TOPICLIMIT, 't',
- MODE_INVITEONLY, 'i',
- MODE_VOICE, 'v',
- MODE_KEY, 'k',
- 0x0, 0x0
- };
-
- char bmodebuf[MODEBUFLEN];
- char bparambuf[MODEBUFLEN];
- char nbparambuf[MODEBUFLEN]; /* "Numeric" Bounce Parameter Buffer */
- struct SLink* lp;
- char* curr = parv[0];
- char* cp = NULL;
- int* ip;
- struct Membership* member_x;
- struct Membership* member_y;
- unsigned int whatt = MODE_ADD;
- unsigned int bwhatt = 0;
- int limitset = 0;
- int bounce;
- int add_banid_called = 0;
- size_t len;
- size_t nlen;
- size_t blen;
- size_t nblen;
- int keychange = 0;
- unsigned int nusers = 0;
- unsigned int newmode;
- int opcnt = 0;
- int banlsent = 0;
- int doesdeop = 0;
- int doesop = 0;
- int hacknotice = 0;
- int change;
- int gotts = 0;
- struct Client* who;
- struct Mode* mode;
- struct Mode oldm;
- static char numeric[16];
- char* bmbuf = bmodebuf;
- char* bpbuf = bparambuf;
- char* nbpbuf = nbparambuf;
- time_t newtime = 0;
- struct ConfItem* aconf;
-
- *mbuf = *pbuf = *npbuf = *bmbuf = *bpbuf = *nbpbuf = '\0';
- *badop = 0;
- if (parc < 1)
- return 0;
- /*
- * Mode is accepted when sptr is a channel operator
- * but also when the mode is received from a server.
- * At this point, let any member pass, so they are allowed
- * to see the bans.
- */
- member_y = find_channel_member(sptr, chptr);
- if (!(IsServer(cptr) || member_y))
- return 0;
-
-#ifdef OPER_MODE_LCHAN
- if (IsOperOnLocalChannel(sptr, chptr->chname) && !IsChanOp(member_y))
- LocalChanOperMode = 1;
-#endif
-
- mode = &(chptr->mode);
- memcpy(&oldm, mode, sizeof(struct Mode));
-
- newmode = mode->mode;
-
- while (curr && *curr) {
- switch (*curr) {
- case '+':
- whatt = MODE_ADD;
- break;
- case '-':
- whatt = MODE_DEL;
- break;
- case 'o':
- case 'v':
- if (--parc <= 0)
- break;
- parv++;
- if (MyUser(sptr) && opcnt >= MAXMODEPARAMS)
- break;
- /*
- * Check for nickname changes and try to follow these
- * to make sure the right client is affected by the
- * mode change.
- * Even if we find a nick with find_chasing() there
- * is still a reason to ignore in a special case.
- * We need to ignore the mode when:
- * - It is part of a net.burst (from a server and
- * a MODE_ADD). Ofcourse we don't ignore mode
- * changes from Uworld.
- * - The found nick is not on the right side off
- * the net.junction.
- * This fixes the bug that when someone (tries to)
- * ride a net.break and does so with the nick of
- * someone on the otherside, that he is nick collided
- * (killed) but his +o still ops the other person.
- */
- if (MyUser(sptr))
- {
- if (!(who = find_chasing(sptr, parv[0], NULL)))
- break;
- }
- else
- {
- if (!(who = findNUser(parv[0])))
- break;
- }
- if (whatt == MODE_ADD && IsServer(sptr) && who->from != sptr->from &&
- !find_conf_byhost(cptr->confs, sptr->name, CONF_UWORLD))
- break;
-
- if (!(member_x = find_member_link(chptr, who)) ||
- (MyUser(sptr) && IsZombie(member_x)))
- {
- send_reply(cptr, ERR_USERNOTINCHANNEL, who->name, chptr->chname);
- break;
- }
- /*
- * if the user is +k, prevent a deop from local user
- */
- if (whatt == MODE_DEL && IsChannelService(who) && *curr == 'o') {
- /*
- * XXX - CHECKME
- */
- if (MyUser(cptr)) {
- send_reply(cptr, ERR_ISCHANSERVICE, parv[0], chptr->chname);
- break;
- }
- else {
- sprintf_irc(sendbuf,":%s NOTICE * :*** Notice -- Deop of +k user on %s by %s",
- me.name,chptr->chname,cptr->name);
- }
- }
-#ifdef NO_OPER_DEOP_LCHAN
- /*
- * if the user is an oper on a local channel, prevent him
- * from being deoped. that oper can deop himself though.
- */
- if (whatt == MODE_DEL && IsOperOnLocalChannel(who, chptr->chname) &&
- (who != sptr) && MyUser(cptr) && *curr == 'o')
- {
- send_reply(cptr, ERR_ISOPERLCHAN, parv[0], chptr->chname);
- break;
- }
-#endif
- if (whatt == MODE_ADD)
- {
- lp = &chops[opcnt++];
- lp->value.cptr = who;
- if (IsServer(sptr) && (!(who->flags & FLAGS_TS8) || ((*curr == 'o') &&
- !(member_x->status & (CHFL_SERVOPOK | CHFL_CHANOP)))))
- *badop = ((member_x->status & CHFL_DEOPPED) && (*curr == 'o')) ? 2 : 3;
- lp->flags = (*curr == 'o') ? MODE_CHANOP : MODE_VOICE;
- lp->flags |= MODE_ADD;
- }
- else if (whatt == MODE_DEL)
- {
- lp = &chops[opcnt++];
- lp->value.cptr = who;
- doesdeop = 1; /* Also when -v */
- lp->flags = (*curr == 'o') ? MODE_CHANOP : MODE_VOICE;
- lp->flags |= MODE_DEL;
- }
- if (*curr == 'o')
- doesop = 1;
- break;
- case 'k':
- if (--parc <= 0)
- break;
- parv++;
- /* check now so we eat the parameter if present */
- if (keychange)
- break;
- else
- {
- char *s = &(*parv)[-1];
- unsigned short count = KEYLEN + 1;
-
- while (*++s > ' ' && *s != ':' && --count);
- *s = '\0';
- if (!**parv) /* nothing left in key */
- break;
- }
- if (MyUser(sptr) && opcnt >= MAXMODEPARAMS)
- break;
- if (whatt == MODE_ADD)
- {
- if (*mode->key && !IsServer(cptr))
- send_reply(cptr, ERR_KEYSET, chptr->chname);
- else if (!*mode->key || IsServer(cptr))
- {
- lp = &chops[opcnt++];
- lp->value.cp = *parv;
- if (strlen(lp->value.cp) > KEYLEN)
- lp->value.cp[KEYLEN] = '\0';
- lp->flags = MODE_KEY | MODE_ADD;
- keychange = 1;
- }
- }
- else if (whatt == MODE_DEL)
- {
- /* Debug((DEBUG_INFO, "removing key: mode->key: >%s< *parv: >%s<", mode->key, *parv)); */
- if (0 == ircd_strcmp(mode->key, *parv) || IsServer(cptr))
- {
- /* Debug((DEBUG_INFO, "key matched")); */
- lp = &chops[opcnt++];
- lp->value.cp = mode->key;
- lp->flags = MODE_KEY | MODE_DEL;
- keychange = 1;
- }
- }
- break;
- case 'b':
- if (--parc <= 0) {
- if (0 == banlsent) {
- /*
- * Only send it once
- */
- send_ban_list(cptr, chptr);
- banlsent = 1;
- }
- break;
- }
- parv++;
- if (EmptyString(*parv))
- break;
- if (MyUser(sptr))
- {
- if ((cp = strchr(*parv, ' ')))
- *cp = 0;
- if (opcnt >= MAXMODEPARAMS || **parv == ':' || **parv == '\0')
- break;
- }
- if (whatt == MODE_ADD)
- {
- lp = &chops[opcnt++];
- lp->value.cp = *parv;
- lp->flags = MODE_ADD | MODE_BAN;
- }
- else if (whatt == MODE_DEL)
- {
- lp = &chops[opcnt++];
- lp->value.cp = *parv;
- lp->flags = MODE_DEL | MODE_BAN;
- }
- break;
- case 'l':
- /*
- * limit 'l' to only *1* change per mode command but
- * eat up others.
- */
- if (limitset)
- {
- if (whatt == MODE_ADD && --parc > 0)
- parv++;
- break;
- }
- if (whatt == MODE_DEL)
- {
- limitset = 1;
- nusers = 0;
- break;
- }
- if (--parc > 0)
- {
- if (EmptyString(*parv))
- break;
- if (MyUser(sptr) && opcnt >= MAXMODEPARAMS)
- break;
- if (!(nusers = atoi(*++parv)))
- continue;
- lp = &chops[opcnt++];
- lp->flags = MODE_ADD | MODE_LIMIT;
- limitset = 1;
- break;
- }
- need_more_params(cptr, "MODE +l");
- break;
- case 'i': /* falls through for default case */
- if (whatt == MODE_DEL)
- while ((lp = chptr->invites))
- del_invite(lp->value.cptr, chptr);
- default:
- for (ip = flags; *ip; ip += 2)
- if (*(ip + 1) == *curr)
- break;
-
- if (*ip)
- {
- if (whatt == MODE_ADD)
- {
- if (*ip == MODE_PRIVATE)
- newmode &= ~MODE_SECRET;
- else if (*ip == MODE_SECRET)
- newmode &= ~MODE_PRIVATE;
- newmode |= *ip;
- }
- else
- newmode &= ~*ip;
- }
- else if (!IsServer(cptr))
- send_reply(cptr, ERR_UNKNOWNMODE, *curr);
- break;
- }
- curr++;
- /*
- * Make sure mode strings such as "+m +t +p +i" are parsed
- * fully.
- */
- if (!*curr && parc > 0)
- {
- curr = *++parv;
- parc--;
- /* If this was from a server, and it is the last
- * parameter and it starts with a digit, it must
- * be the creationtime. --Run
- */
- if (IsServer(sptr))
- {
- if (parc == 1 && IsDigit(*curr))
- {
- newtime = atoi(curr);
- if (newtime && chptr->creationtime == MAGIC_REMOTE_JOIN_TS)
- {
- chptr->creationtime = newtime;
- *badop = 0;
- }
- gotts = 1;
- if (newtime == 0)
- {
- *badop = 2;
- hacknotice = 1;
- }
- else if (newtime > chptr->creationtime)
- { /* It is a net-break ride if we have ops.
- bounce modes if we have ops. --Run */
- if (doesdeop)
- *badop = 2;
- else if (chptr->creationtime == 0)
- {
- if (chptr->creationtime == 0 || doesop)
- chptr->creationtime = newtime;
- *badop = 0;
- }
- /* Bounce: */
- else
- *badop = 1;
- }
- /*
- * A legal *badop can occur when two
- * people join simultaneously a channel,
- * Allow for 10 min of lag (and thus hacking
- * on channels younger then 10 min) --Run
- */
- else if (*badop == 0 ||
- chptr->creationtime > (TStime() - TS_LAG_TIME))
- {
- if (newtime < chptr->creationtime)
- chptr->creationtime = newtime;
- *badop = 0;
- }
- break;
- }
- }
- else
- *badop = 0;
- }
- } /* end of while loop for MODE processing */
-
-#ifdef OPER_MODE_LCHAN
- /*
- * Now reject non chan ops. Accept modes from opers on local channels
- * even if they are deopped
- */
- if (!IsServer(cptr) &&
- (!member_y || !(IsChanOp(member_y) ||
- IsOperOnLocalChannel(sptr, chptr->chname))))
-#else
- if (!IsServer(cptr) && (!member_y || !IsChanOp(member_y)))
-#endif
- {
- *badop = 0;
- return (opcnt || newmode != mode->mode || limitset || keychange) ? 0 : -1;
- }
-
- if (doesop && newtime == 0 && IsServer(sptr))
- *badop = 2;
-
- if (*badop >= 2 &&
- (aconf = find_conf_byhost(cptr->confs, sptr->name, CONF_UWORLD)))
- *badop = 4;
-
-#ifdef OPER_MODE_LCHAN
- bounce = (*badop == 1 || *badop == 2 ||
- (is_deopped(sptr, chptr) &&
- !IsOperOnLocalChannel(sptr, chptr->chname))) ? 1 : 0;
-#else
- bounce = (*badop == 1 || *badop == 2 || is_deopped(sptr, chptr)) ? 1 : 0;
-#endif
-
- whatt = 0;
- for (ip = flags; *ip; ip += 2) {
- if ((*ip & newmode) && !(*ip & oldm.mode))
- {
- if (bounce)
- {
- if (bwhatt != MODE_DEL)
- {
- *bmbuf++ = '-';
- bwhatt = MODE_DEL;
- }
- *bmbuf++ = *(ip + 1);
- }
- else
- {
- if (whatt != MODE_ADD)
- {
- *mbuf++ = '+';
- whatt = MODE_ADD;
- }
- mode->mode |= *ip;
- *mbuf++ = *(ip + 1);
- }
- }
- }
- for (ip = flags; *ip; ip += 2) {
- if ((*ip & oldm.mode) && !(*ip & newmode))
- {
- if (bounce)
- {
- if (bwhatt != MODE_ADD)
- {
- *bmbuf++ = '+';
- bwhatt = MODE_ADD;
- }
- *bmbuf++ = *(ip + 1);
- }
- else
- {
- if (whatt != MODE_DEL)
- {
- *mbuf++ = '-';
- whatt = MODE_DEL;
- }
- mode->mode &= ~*ip;
- *mbuf++ = *(ip + 1);
- }
- }
- }
- blen = nblen = 0;
- if (limitset && !nusers && mode->limit)
- {
- if (bounce)
- {
- if (bwhatt != MODE_ADD)
- {
- *bmbuf++ = '+';
- bwhatt = MODE_ADD;
- }
- *bmbuf++ = 'l';
- sprintf(numeric, "%-15d", mode->limit);
- if ((cp = strchr(numeric, ' ')))
- *cp = '\0';
- strcat(bpbuf, numeric);
- blen += strlen(numeric);
- strcat(bpbuf, " ");
- strcat(nbpbuf, numeric);
- nblen += strlen(numeric);
- strcat(nbpbuf, " ");
- }
- else
- {
- if (whatt != MODE_DEL)
- {
- *mbuf++ = '-';
- whatt = MODE_DEL;
- }
- mode->mode &= ~MODE_LIMIT;
- mode->limit = 0;
- *mbuf++ = 'l';
- }
- }
- /*
- * Reconstruct "+bkov" chain.
- */
- if (opcnt)
- {
- int i = 0;
- char c = 0;
- unsigned int prev_whatt = 0;
-
- for (; i < opcnt; i++)
- {
- lp = &chops[i];
- /*
- * make sure we have correct mode change sign
- */
- if (whatt != (lp->flags & (MODE_ADD | MODE_DEL)))
- {
- if (lp->flags & MODE_ADD)
- {
- *mbuf++ = '+';
- prev_whatt = whatt;
- whatt = MODE_ADD;
- }
- else
- {
- *mbuf++ = '-';
- prev_whatt = whatt;
- whatt = MODE_DEL;
- }
- }
- len = strlen(pbuf);
- nlen = strlen(npbuf);
- /*
- * get c as the mode char and tmp as a pointer to
- * the parameter for this mode change.
- */
- switch (lp->flags & MODE_WPARAS)
- {
- case MODE_CHANOP:
- c = 'o';
- cp = lp->value.cptr->name;
- break;
- case MODE_VOICE:
- c = 'v';
- cp = lp->value.cptr->name;
- break;
- case MODE_BAN:
- /*
- * I made this a bit more user-friendly (tm):
- * nick = nick!*@*
- * nick!user = nick!user@*
- * user@host = *!user@host
- * host.name = *!*@host.name --Run
- */
- c = 'b';
- cp = pretty_mask(lp->value.cp);
- break;
- case MODE_KEY:
- c = 'k';
- cp = lp->value.cp;
- break;
- case MODE_LIMIT:
- c = 'l';
- sprintf(numeric, "%-15d", nusers);
- if ((cp = strchr(numeric, ' ')))
- *cp = '\0';
- cp = numeric;
- break;
- }
-
- /* What could be added: cp+' '+' '+<TS>+'\0' */
- if (len + strlen(cp) + 13 > MODEBUFLEN ||
- nlen + strlen(cp) + NUMNICKLEN + 12 > MODEBUFLEN)
- break;
-
- switch (lp->flags & MODE_WPARAS)
- {
- case MODE_KEY:
- if (strlen(cp) > KEYLEN)
- *(cp + KEYLEN) = '\0';
- if ((whatt == MODE_ADD && (*mode->key == '\0' ||
- 0 != ircd_strcmp(mode->key, cp))) ||
- (whatt == MODE_DEL && (*mode->key != '\0')))
- {
- if (bounce)
- {
- if (*mode->key == '\0')
- {
- if (bwhatt != MODE_DEL)
- {
- *bmbuf++ = '-';
- bwhatt = MODE_DEL;
- }
- strcat(bpbuf, cp);
- blen += strlen(cp);
- strcat(bpbuf, " ");
- blen++;
- strcat(nbpbuf, cp);
- nblen += strlen(cp);
- strcat(nbpbuf, " ");
- nblen++;
- }
- else
- {
- if (bwhatt != MODE_ADD)
- {
- *bmbuf++ = '+';
- bwhatt = MODE_ADD;
- }
- strcat(bpbuf, mode->key);
- blen += strlen(mode->key);
- strcat(bpbuf, " ");
- blen++;
- strcat(nbpbuf, mode->key);
- nblen += strlen(mode->key);
- strcat(nbpbuf, " ");
- nblen++;
- }
- *bmbuf++ = c;
- mbuf--;
- if (*mbuf != '+' && *mbuf != '-')
- mbuf++;
- else
- whatt = prev_whatt;
- }
- else
- {
- *mbuf++ = c;
- strcat(pbuf, cp);
- len += strlen(cp);
- strcat(pbuf, " ");
- len++;
- strcat(npbuf, cp);
- nlen += strlen(cp);
- strcat(npbuf, " ");
- nlen++;
- if (whatt == MODE_ADD)
- ircd_strncpy(mode->key, cp, KEYLEN);
- else
- *mode->key = '\0';
- }
- }
- break;
- case MODE_LIMIT:
- if (nusers && nusers != mode->limit)
- {
- if (bounce)
- {
- if (mode->limit == 0)
- {
- if (bwhatt != MODE_DEL)
- {
- *bmbuf++ = '-';
- bwhatt = MODE_DEL;
- }
- }
- else
- {
- if (bwhatt != MODE_ADD)
- {
- *bmbuf++ = '+';
- bwhatt = MODE_ADD;
- }
- sprintf(numeric, "%-15d", mode->limit);
- if ((cp = strchr(numeric, ' ')))
- *cp = '\0';
- strcat(bpbuf, numeric);
- blen += strlen(numeric);
- strcat(bpbuf, " ");
- blen++;
- strcat(nbpbuf, numeric);
- nblen += strlen(numeric);
- strcat(nbpbuf, " ");
- nblen++;
- }
- *bmbuf++ = c;
- mbuf--;
- if (*mbuf != '+' && *mbuf != '-')
- mbuf++;
- else
- whatt = prev_whatt;
- }
- else
- {
- *mbuf++ = c;
- strcat(pbuf, cp);
- len += strlen(cp);
- strcat(pbuf, " ");
- len++;
- strcat(npbuf, cp);
- nlen += strlen(cp);
- strcat(npbuf, " ");
- nlen++;
- mode->limit = nusers;
- }
- }
- break;
- case MODE_CHANOP:
- case MODE_VOICE:
- member_y = find_member_link(chptr, lp->value.cptr);
- if (lp->flags & MODE_ADD)
- {
- change = (~member_y->status) & CHFL_VOICED_OR_OPPED & lp->flags;
- if (change && bounce)
- {
- if (lp->flags & MODE_CHANOP)
- SetDeopped(member_y);
-
- if (bwhatt != MODE_DEL)
- {
- *bmbuf++ = '-';
- bwhatt = MODE_DEL;
- }
- *bmbuf++ = c;
- strcat(bpbuf, lp->value.cptr->name);
- blen += strlen(lp->value.cptr->name);
- strcat(bpbuf, " ");
- blen++;
- sprintf_irc(nbpbuf + nblen, "%s%s ", NumNick(lp->value.cptr));
- nblen += strlen(nbpbuf + nblen);
- change = 0;
- }
- else if (change)
- {
- member_y->status |= lp->flags & CHFL_VOICED_OR_OPPED;
- if (IsChanOp(member_y))
- {
- ClearDeopped(member_y);
- if (IsServer(sptr))
- ClearServOpOk(member_y);
- }
- }
- }
- else
- {
- change = member_y->status & CHFL_VOICED_OR_OPPED & lp->flags;
- if (change && bounce)
- {
- if (lp->flags & MODE_CHANOP)
- ClearDeopped(member_y);
- if (bwhatt != MODE_ADD)
- {
- *bmbuf++ = '+';
- bwhatt = MODE_ADD;
- }
- *bmbuf++ = c;
- strcat(bpbuf, lp->value.cptr->name);
- blen += strlen(lp->value.cptr->name);
- strcat(bpbuf, " ");
- blen++;
- sprintf_irc(nbpbuf + nblen, "%s%s ", NumNick(lp->value.cptr));
- blen += strlen(bpbuf + blen);
- change = 0;
- }
- else
- {
- member_y->status &= ~change;
- if ((change & MODE_CHANOP) && IsServer(sptr))
- SetDeopped(member_y);
- }
- }
- if (change || *badop == 2 || *badop == 4)
- {
- *mbuf++ = c;
- strcat(pbuf, cp);
- len += strlen(cp);
- strcat(pbuf, " ");
- len++;
- sprintf_irc(npbuf + nlen, "%s%s ", NumNick(lp->value.cptr));
- nlen += strlen(npbuf + nlen);
- npbuf[nlen++] = ' ';
- npbuf[nlen] = 0;
- }
- else
- {
- mbuf--;
- if (*mbuf != '+' && *mbuf != '-')
- mbuf++;
- else
- whatt = prev_whatt;
- }
- break;
- case MODE_BAN:
-/*
- * Only bans aren't bounced, it makes no sense to bounce last second
- * bans while propagating bans done before the net.rejoin. The reason
- * why I don't bounce net.rejoin bans is because it is too much
- * work to take care of too long strings adding the necessary TS to
- * net.burst bans -- RunLazy
- * We do have to check for *badop==2 now, we don't want HACKs to take
- * effect.
- *
- * Since BURST - I *did* implement net.rejoin ban bouncing. So now it
- * certainly makes sense to also bounce 'last second' bans (bans done
- * after the net.junction). -- RunHardWorker
- */
- if ((change = (whatt & MODE_ADD) &&
- !add_banid(sptr, chptr, cp, !bounce, !add_banid_called)))
- add_banid_called = 1;
- else
- change = (whatt & MODE_DEL) && !del_banid(chptr, cp, !bounce);
-
- if (bounce && change)
- {
- change = 0;
- if ((whatt & MODE_ADD))
- {
- if (bwhatt != MODE_DEL)
- {
- *bmbuf++ = '-';
- bwhatt = MODE_DEL;
- }
- }
- else if ((whatt & MODE_DEL))
- {
- if (bwhatt != MODE_ADD)
- {
- *bmbuf++ = '+';
- bwhatt = MODE_ADD;
- }
- }
- *bmbuf++ = c;
- strcat(bpbuf, cp);
- blen += strlen(cp);
- strcat(bpbuf, " ");
- blen++;
- strcat(nbpbuf, cp);
- nblen += strlen(cp);
- strcat(nbpbuf, " ");
- nblen++;
- }
- if (change)
- {
- *mbuf++ = c;
- strcat(pbuf, cp);
- len += strlen(cp);
- strcat(pbuf, " ");
- len++;
- strcat(npbuf, cp);
- nlen += strlen(cp);
- strcat(npbuf, " ");
- nlen++;
- }
- else
- {
- mbuf--;
- if (*mbuf != '+' && *mbuf != '-')
- mbuf++;
- else
- whatt = prev_whatt;
- }
- break;
- }
- } /* for (; i < opcnt; i++) */
- } /* if (opcnt) */
-
- *mbuf++ = '\0';
- *bmbuf++ = '\0';
-
- /* Bounce here */
- if (!hacknotice && *bmodebuf && chptr->creationtime)
- {
- sendcmdto_one(&me, CMD_MODE, cptr, "%H %s %s %Tu", chptr, bmodebuf,
- nbparambuf, *badop == 2 ? (time_t) 0 : chptr->creationtime);
- }
- /* If there are possibly bans to re-add, bounce them now */
- if (add_banid_called && bounce)
- {
- struct SLink *ban[6]; /* Max 6 bans at a time */
- size_t len[6], sblen, total_len;
- int cnt, delayed = 0;
- while (delayed || (ban[0] = next_overlapped_ban()))
- {
- len[0] = strlen(ban[0]->value.ban.banstr);
- cnt = 1; /* We already got one ban :) */
- /* XXX sendbuf used to send ban bounces! */
- sblen = sprintf_irc(sendbuf, ":%s MODE %s +b",
- me.name, chptr->chname) - sendbuf;
- total_len = sblen + 1 + len[0]; /* 1 = ' ' */
- /* Find more bans: */
- delayed = 0;
- while (cnt < 6 && (ban[cnt] = next_overlapped_ban()))
- {
- len[cnt] = strlen(ban[cnt]->value.ban.banstr);
- if (total_len + 5 + len[cnt] > BUFSIZE) /* 5 = "b \r\n\0" */
- {
- delayed = cnt + 1; /* != 0 */
- break; /* Flush */
- }
- sendbuf[sblen++] = 'b';
- total_len += 2 + len[cnt++]; /* 2 = "b " */
- }
- while (cnt--)
- {
- sendbuf[sblen++] = ' ';
- strcpy(sendbuf + sblen, ban[cnt]->value.ban.banstr);
- sblen += len[cnt];
- }
- sendbufto_one(cptr); /* Send bounce to uplink */
- if (delayed)
- ban[0] = ban[delayed - 1];
- }
- }
- /* Send -b's of overlapped bans to clients to keep them synchronized */
- if (add_banid_called && !bounce)
- {
- struct SLink *ban;
- char *banstr[6]; /* Max 6 bans at a time */
- size_t len[6], sblen, psblen, total_len;
- int cnt, delayed = 0;
- struct Membership* member_z;
- struct Client *acptr;
- if (IsServer(sptr))
- /* XXX sendbuf used to send ban bounces! */
- psblen = sprintf_irc(sendbuf, ":%s MODE %s -b",
- sptr->name, chptr->chname) - sendbuf;
- else /* We rely on IsRegistered(sptr) being true for MODE */
- psblen = sprintf_irc(sendbuf, ":%s!%s@%s MODE %s -b", sptr->name,
- sptr->user->username, sptr->user->host, chptr->chname) - sendbuf;
- while (delayed || (ban = next_removed_overlapped_ban()))
- {
- if (!delayed)
- {
- len[0] = strlen((banstr[0] = ban->value.ban.banstr));
- ban->value.ban.banstr = NULL;
- }
- cnt = 1; /* We already got one ban :) */
- sblen = psblen;
- total_len = sblen + 1 + len[0]; /* 1 = ' ' */
- /* Find more bans: */
- delayed = 0;
- while (cnt < 6 && (ban = next_removed_overlapped_ban()))
- {
- len[cnt] = strlen((banstr[cnt] = ban->value.ban.banstr));
- ban->value.ban.banstr = NULL;
- if (total_len + 5 + len[cnt] > BUFSIZE) /* 5 = "b \r\n\0" */
- {
- delayed = cnt + 1; /* != 0 */
- break; /* Flush */
- }
- sendbuf[sblen++] = 'b';
- total_len += 2 + len[cnt++]; /* 2 = "b " */
- }
- while (cnt--)
- {
- sendbuf[sblen++] = ' ';
- strcpy(sendbuf + sblen, banstr[cnt]);
- MyFree(banstr[cnt]);
- sblen += len[cnt];
- }
- for (member_z = chptr->members; member_z; member_z = member_z->next_member) {
- acptr = member_z->user;
- if (MyConnect(acptr) && !IsZombie(member_z))
- sendbufto_one(acptr);
- }
- if (delayed)
- {
- banstr[0] = banstr[delayed - 1];
- len[0] = len[delayed - 1];
- }
- }
- }
-
- return gotts ? 1 : -1;
-}
-
-/* We are now treating the <key> part of /join <channel list> <key> as a key
- * ring; that is, we try one key against the actual channel key, and if that
- * doesn't work, we try the next one, and so on. -Kev -Texaco
- * Returns: 0 on match, 1 otherwise
- * This version contributed by SeKs <intru@info.polymtl.ca>
- */
-static int compall(char *key, char *keyring)
-{
- char *p1;
-
-top:
- p1 = key; /* point to the key... */
- while (*p1 && *p1 == *keyring)
- { /* step through the key and ring until they
- don't match... */
- p1++;
- keyring++;
- }
-
- if (!*p1 && (!*keyring || *keyring == ','))
- /* ok, if we're at the end of the and also at the end of one of the keys
- in the keyring, we have a match */
- return 0;
-
- if (!*keyring) /* if we're at the end of the key ring, there
- weren't any matches, so we return 1 */
- return 1;
-
- /* Not at the end of the key ring, so step
- through to the next key in the ring: */
- while (*keyring && *(keyring++) != ',');
-
- goto top; /* and check it against the key */
-}
-
-int can_join(struct Client *sptr, struct Channel *chptr, char *key)
-{
- struct SLink *lp;
- int overrideJoin = 0;
-
- /*
- * Now a banned user CAN join if invited -- Nemesi
- * Now a user CAN escape channel limit if invited -- bfriendly
- * Now a user CAN escape anything if invited -- Isomer
- */
-
- for (lp = sptr->user->invited; lp; lp = lp->next)
- if (lp->value.chptr == chptr)
- return 0;
-
-#ifdef OPER_WALK_THROUGH_LMODES
- /* An oper can force a join on a local channel using "OVERRIDE" as the key.
- a HACK(4) notice will be sent if he would not have been supposed
- to join normally. */
- if (IsOperOnLocalChannel(sptr,chptr->chname) && !BadPtr(key) && compall("OVERRIDE",key) == 0)
- {
- overrideJoin = MAGIC_OPER_OVERRIDE;
- }
-#endif
-
- if (chptr->mode.mode & MODE_INVITEONLY)
- return overrideJoin + ERR_INVITEONLYCHAN;
-
- if (chptr->mode.limit && chptr->users >= chptr->mode.limit)
- return overrideJoin + ERR_CHANNELISFULL;
-
- if (is_banned(sptr, chptr, NULL))
- return overrideJoin + ERR_BANNEDFROMCHAN;
-
- /*
- * now using compall (above) to test against a whole key ring -Kev
- */
- if (*chptr->mode.key && (EmptyString(key) || compall(chptr->mode.key, key)))
- return overrideJoin + ERR_BADCHANNELKEY;
-
- if (overrideJoin)
- return ERR_DONTCHEAT;
-
- return 0;
-}
-
-/*
- * Remove bells and commas from channel name
- */
-void clean_channelname(char *cn)
-{
- int i;
-
- for (i = 0; cn[i]; i++) {
- if (i >= CHANNELLEN || !IsChannelChar(cn[i])) {
- cn[i] = '\0';
- return;
- }
- if (IsChannelLower(cn[i])) {
- cn[i] = ToLower(cn[i]);
-#ifndef FIXME
- /*
- * Remove for .08+
- * toupper(0xd0)
- */
- if ((unsigned char)(cn[i]) == 0xd0)
- cn[i] = (char) 0xf0;
-#endif
- }
- }
-}
-
-/*
- * Get Channel block for i (and allocate a new channel