/* Set the key. */ static void set_key(struct chanset_t *chan, char *k) { nfree(chan->channel.key); if (k == NULL) { chan->channel.key = (char *) channel_malloc(1); chan->channel.key[0] = 0; return; } chan->channel.key = (char *) channel_malloc(strlen(k) + 1); strcpy(chan->channel.key, k); }
/* Adds a ban, exempt or invite mask to the list * m should be chan->channel.(exempt|invite|ban) */ static void newmask(masklist *m, char *s, char *who) { for (; m && m->mask[0] && rfc_casecmp(m->mask, s); m = m->next); if (m->mask[0]) return; /* Already existent mask */ m->next = (masklist *) channel_malloc(sizeof(masklist)); m->next->next = NULL; m->next->mask = (char *) channel_malloc(1); m->next->mask[0] = 0; nfree(m->mask); m->mask = (char *) channel_malloc(strlen(s) + 1); strcpy(m->mask, s); m->who = (char *) channel_malloc(strlen(who) + 1); strcpy(m->who, who); m->timer = now; }
/* Reset channel information. */ static void reset_chan_info(struct chanset_t *chan, int reset) { char beI[4] = "\0"; /* Leave the channel if we aren't supposed to be there */ if (channel_inactive(chan)) { dprintf(DP_MODE, "PART %s\n", chan->name); return; } /* Don't reset the channel if we're already resetting it */ if (channel_pending(chan)) return; clear_channel(chan, reset); if ((reset & CHAN_RESETBANS) && !(chan->status & CHAN_ASKEDBANS)) { chan->status |= CHAN_ASKEDBANS; strcat(beI, "b"); } if ((reset & CHAN_RESETEXEMPTS) && !(chan->ircnet_status & CHAN_ASKED_EXEMPTS) && (use_exempts == 1)) { chan->ircnet_status |= CHAN_ASKED_EXEMPTS; strcat(beI, "e"); } if ((reset & CHAN_RESETINVITED) && !(chan->ircnet_status & CHAN_ASKED_INVITED) && (use_invites == 1)) { chan->ircnet_status |= CHAN_ASKED_INVITED; strcat(beI, "I"); } if (beI[0]) dprintf(DP_MODE, "MODE %s +%s\n", chan->name, beI); if (reset & CHAN_RESETMODES) { /* done here to keep expmem happy, as this is accounted in irc.mod, not channels.mod where clear_channel() resides */ nfree(chan->channel.key); chan->channel.key = (char *) channel_malloc (1); chan->channel.key[0] = 0; chan->status &= ~CHAN_ASKEDMODES; dprintf(DP_MODE, "MODE %s\n", chan->name); } if (reset & CHAN_RESETWHO) { chan->status |= CHAN_PEND; chan->status &= ~CHAN_ACTIVE; refresh_who_chan(chan->name); } if (reset & CHAN_RESETTOPIC) dprintf(DP_MODE, "TOPIC %s\n", chan->name); }
/* Removes a nick from the channel member list (returns 1 if successful) */ static int killmember(struct chanset_t *chan, char *nick) { memberlist *x, *old; old = NULL; for (x = chan->channel.member; x && x->nick[0]; old = x, x = x->next) if (!rfc_casecmp(x->nick, nick)) break; if (!x || !x->nick[0]) { if (!channel_pending(chan) && !channel_djoins(chan)) putlog(LOG_MISC, "*", "(!) killmember(%s) -> nonexistent", nick); return 0; } if (old) old->next = x->next; else chan->channel.member = x->next; nfree(x); chan->channel.members--; /* The following two errors should NEVER happen. We will try to correct * them though, to keep the bot from crashing. */ if (chan->channel.members < 0) { chan->channel.members = 0; for (x = chan->channel.member; x && x->nick[0]; x = x->next) chan->channel.members++; putlog(LOG_MISC, "*", "(!) actually I know of %d members.", chan->channel.members); } if (!chan->channel.member) { chan->channel.member = (memberlist *) channel_malloc(sizeof(memberlist)); chan->channel.member->nick[0] = 0; chan->channel.member->next = NULL; } return 1; }
/* Queue a channel mode change */ static void real_add_mode(struct chanset_t *chan, char plus, char mode, char *op) { int i, type, modes, l; masklist *m; memberlist *mx; char s[21]; /* Some IRCds do not allow halfops to set certain modes. The modes halfops * are not allowed to set can be changed in chan.h. */ #ifdef NO_HALFOP_CHANMODES if (!me_op(chan)) #else if (HALFOP_CANTDOMODE(mode)) #endif return; if (mode == 'o' || mode == 'h' || mode == 'v') { mx = ismember(chan, op); if (!mx) return; if (plus == '-' && mode == 'o') { if (chan_sentdeop(mx) || !chan_hasop(mx)) return; mx->flags |= SENTDEOP; } if (plus == '+' && mode == 'o') { if (chan_sentop(mx) || chan_hasop(mx)) return; mx->flags |= SENTOP; } if (plus == '-' && mode == 'h') { if (chan_sentdehalfop(mx) || !chan_hashalfop(mx)) return; mx->flags |= SENTDEHALFOP; } if (plus == '+' && mode == 'h') { if (chan_senthalfop(mx) || chan_hashalfop(mx)) return; mx->flags |= SENTHALFOP; } if (plus == '-' && mode == 'v') { if (chan_sentdevoice(mx) || !chan_hasvoice(mx)) return; mx->flags |= SENTDEVOICE; } if (plus == '+' && mode == 'v') { if (chan_sentvoice(mx) || chan_hasvoice(mx)) return; mx->flags |= SENTVOICE; } } if (chan->compat == 0) { if (mode == 'e' || mode == 'I') chan->compat = 2; else chan->compat = 1; } else if (mode == 'e' || mode == 'I') { if (prevent_mixing && chan->compat == 1) flush_mode(chan, NORMAL); } else if (prevent_mixing && chan->compat == 2) flush_mode(chan, NORMAL); if (mode == 'o' || mode == 'h' || mode == 'b' || mode == 'v' || mode == 'e' || mode == 'I') { type = (plus == '+' ? PLUS : MINUS) | (mode == 'o' ? CHOP : (mode == 'h' ? CHHOP : (mode == 'b' ? BAN : (mode == 'v' ? VOICE : (mode == 'e' ? EXEMPT : INVITE))))); /* * FIXME: Some networks remove overlapped bans, * IRCnet does not (poptix/drummer) * * Note: On IRCnet ischanXXX() should be used, otherwise isXXXed(). */ if ((plus == '-' && ((mode == 'b' && !ischanban(chan, op)) || (mode == 'e' && !ischanexempt(chan, op)) || (mode == 'I' && !ischaninvite(chan, op)))) || (plus == '+' && ((mode == 'b' && ischanban(chan, op)) || (mode == 'e' && ischanexempt(chan, op)) || (mode == 'I' && ischaninvite(chan, op))))) return; /* If there are already max_bans bans, max_exempts exemptions, * max_invites invitations or max_modes +b/+e/+I modes on the * channel, don't try to add one more. */ if (plus == '+' && (mode == 'b' || mode == 'e' || mode == 'I')) { int bans = 0, exempts = 0, invites = 0; for (m = chan->channel.ban; m && m->mask[0]; m = m->next) bans++; if ((mode == 'b') && (bans >= max_bans)) return; for (m = chan->channel.exempt; m && m->mask[0]; m = m->next) exempts++; if ((mode == 'e') && (exempts >= max_exempts)) return; for (m = chan->channel.invite; m && m->mask[0]; m = m->next) invites++; if ((mode == 'I') && (invites >= max_invites)) return; if (bans + exempts + invites >= max_modes) return; } /* op-type mode change */ for (i = 0; i < modesperline; i++) if (chan->cmode[i].type == type && chan->cmode[i].op != NULL && !rfc_casecmp(chan->cmode[i].op, op)) return; /* Already in there :- duplicate */ l = strlen(op) + 1; if (chan->bytes + l > mode_buf_len) flush_mode(chan, NORMAL); for (i = 0; i < modesperline; i++) if (chan->cmode[i].type == 0) { chan->cmode[i].type = type; chan->cmode[i].op = (char *) channel_malloc(l); chan->bytes += l; /* Add 1 for safety */ strcpy(chan->cmode[i].op, op); break; } } /* +k ? store key */ else if (plus == '+' && mode == 'k') { if (chan->key) nfree(chan->key); chan->key = (char *) channel_malloc(strlen(op) + 1); if (chan->key) strcpy(chan->key, op); } /* -k ? store removed key */ else if (plus == '-' && mode == 'k') { if (chan->rmkey) nfree(chan->rmkey); chan->rmkey = (char *) channel_malloc(strlen(op) + 1); if (chan->rmkey) strcpy(chan->rmkey, op); } /* +l ? store limit */ else if (plus == '+' && mode == 'l') chan->limit = atoi(op); else { /* Typical mode changes */ if (plus == '+') strcpy(s, chan->pls); else strcpy(s, chan->mns); if (!strchr(s, mode)) { if (plus == '+') { chan->pls[strlen(chan->pls) + 1] = 0; chan->pls[strlen(chan->pls)] = mode; } else { chan->mns[strlen(chan->mns) + 1] = 0; chan->mns[strlen(chan->mns)] = mode; } } } modes = modesperline; /* Check for full buffer. */ for (i = 0; i < modesperline; i++) if (chan->cmode[i].type) modes--; if (include_lk && chan->limit) modes--; if (include_lk && chan->rmkey) modes--; if (include_lk && chan->key) modes--; if (modes < 1) flush_mode(chan, NORMAL); /* Full buffer! Flush modes. */ }