int delay_flush_all (void *arg, char *sub) { char buffer[BIG_BUFFER_SIZE+1]; char *args = (char *)arg; char *serv_num = NULL; char *channel = NULL; int ofs = from_server; channel = next_arg(args, &args); if ((serv_num = next_arg(args, &args))) from_server = atoi(serv_num); if (channel && *channel && mode_str && user) { sprintf(buffer, "MODE %s %s%s %s\r\n", channel, plus_mode, mode_str, user); push_len = strlen(buffer); add_mode_buffer(buffer, push_len); mode_str_len = 0; new_free(&mode_str); new_free(&user); memset(plus_mode, 0, sizeof(plus_mode)); push_len = 0; } flush_mode(NULL); new_free(&arg); from_server = ofs; return 0; }
/* Flush the modes for EVERY channel. */ static void flush_modes() { struct chanset_t *chan; memberlist *m; if (modesperline > MODES_PER_LINE_MAX) modesperline = MODES_PER_LINE_MAX; for (chan = chanset; chan; chan = chan->next) { for (m = chan->channel.member; m && m->nick[0]; m = m->next) { if (m->delay && m->delay <= now) { m->delay = 0L; m->flags &= ~FULL_DELAY; if (chan_sentop(m)) { m->flags &= ~SENTOP; add_mode(chan, '+', 'o', m->nick); } if (chan_senthalfop(m)) { m->flags &= ~SENTHALFOP; add_mode(chan, '+', 'h', m->nick); } if (chan_sentvoice(m)) { m->flags &= ~SENTVOICE; add_mode(chan, '+', 'v', m->nick); } } } flush_mode(chan, NORMAL); } }
void add_mode(ChannelList *chan, char *mode, int plus, char *nick, char *reason, int max_modes) { char buffer[BIG_BUFFER_SIZE+1]; if (mode_len >= (IRCD_BUFFER_SIZE-100)) { flush_mode(chan); push_len = 0; } if (reason) { sprintf(buffer, "KICK %s %s :%s\r\n", chan->channel, nick, reason); push_len = strlen(buffer); add_mode_buffer(buffer, push_len); } else { mode_str_len++; strcat(plus_mode, plus ? "+" : "-"); malloc_strcat(&mode_str, mode); m_s3cat(&user, space, nick); if (mode_str_len >= max_modes) { sprintf(buffer, "MODE %s %s%s %s\r\n", chan->channel, plus_mode, mode_str, user); push_len = strlen(buffer); add_mode_buffer(buffer, push_len); new_free(&mode_str); new_free(&user); memset(plus_mode, 0, sizeof(plus_mode)); mode_str_len = push_len = 0; } } }
void flush_mode_all(ChannelList *chan) { char buffer[BIG_BUFFER_SIZE+1]; if (mode_str && user) { sprintf(buffer, "MODE %s %s%s %s\r\n", chan->channel, plus_mode, mode_str, user); push_len = strlen(buffer); add_mode_buffer(buffer, push_len); mode_str_len = 0; new_free(&mode_str); new_free(&user); memset(plus_mode, 0, sizeof(plus_mode)); push_len = 0; } flush_mode(chan); }
/* Dependant on revenge_mode, punish the offender. */ static void punish_badguy(struct chanset_t *chan, char *whobad, struct userrec *u, char *badnick, char *victim, int mevictim, int type) { char reason[1024], ct[81], *kick_msg; memberlist *m; struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 }; m = ismember(chan, badnick); if (!m) return; get_user_flagrec(u, &fr, chan->dname); /* Get current time into a string */ egg_strftime(ct, 7, "%d %b", localtime(&now)); /* Put together log and kick messages */ reason[0] = 0; switch (type) { case REVENGE_KICK: kick_msg = IRC_KICK_PROTECT; simple_sprintf(reason, "kicked %s off %s", victim, chan->dname); break; case REVENGE_DEOP: simple_sprintf(reason, "deopped %s on %s", victim, chan->dname); kick_msg = IRC_DEOP_PROTECT; break; default: kick_msg = "revenge!"; } putlog(LOG_MISC, chan->dname, "Punishing %s (%s)", badnick, reason); /* Set the offender +d */ if ((chan->revenge_mode > 0) && !(chan_deop(fr) || glob_deop(fr))) { char s[UHOSTLEN], s1[UHOSTLEN]; memberlist *mx = NULL; /* Removing op */ if (chan_op(fr) || (glob_op(fr) && !chan_deop(fr))) { fr.match = FR_CHAN; if (chan_op(fr)) fr.chan &= ~USER_OP; else fr.chan |= USER_DEOP; set_user_flagrec(u, &fr, chan->dname); putlog(LOG_MISC, "*", "No longer opping %s[%s] (%s)", u->handle, whobad, reason); } /* ... or just setting to deop */ else if (u) { /* In the user list already, cool :) */ fr.match = FR_CHAN; fr.chan |= USER_DEOP; set_user_flagrec(u, &fr, chan->dname); simple_sprintf(s, "(%s) %s", ct, reason); putlog(LOG_MISC, "*", "Now deopping %s[%s] (%s)", u->handle, whobad, s); } /* ... or creating new user and setting that to deop */ else { strcpy(s1, whobad); maskaddr(s1, s, chan->ban_type); strcpy(s1, badnick); /* If that handle exists use "badX" (where X is an increasing number) * instead. */ while (get_user_by_handle(userlist, s1)) { if (!strncmp(s1, "bad", 3)) { int i; i = atoi(s1 + 3); simple_sprintf(s1 + 3, "%d", i + 1); } else strcpy(s1, "bad1"); /* Start with '1' */ } userlist = adduser(userlist, s1, s, "-", 0); fr.match = FR_CHAN; fr.chan = USER_DEOP; fr.udef_chan = 0; u = get_user_by_handle(userlist, s1); if ((mx = ismember(chan, badnick))) mx->user = u; set_user_flagrec(u, &fr, chan->dname); simple_sprintf(s, "(%s) %s (%s)", ct, reason, whobad); set_user(&USERENTRY_COMMENT, u, (void *) s); putlog(LOG_MISC, "*", "Now deopping %s (%s)", whobad, reason); } } /* Always try to deop the offender */ if (!mevictim) add_mode(chan, '-', 'o', badnick); /* Ban. Should be done before kicking. */ if (chan->revenge_mode > 2) { char s[UHOSTLEN], s1[UHOSTLEN]; splitnick(&whobad); maskaddr(whobad, s1, chan->ban_type); simple_sprintf(s, "(%s) %s", ct, reason); u_addban(chan, s1, botnetnick, s, now + (60 * chan->ban_time), 0); if (!mevictim && HALFOP_CANDOMODE('b')) { add_mode(chan, '+', 'b', s1); flush_mode(chan, QUICK); } } /* Kick the offender */ if (!mevictim && (chan->revenge_mode > 1) && (!channel_dontkickops(chan) || (!chan_op(fr) && (!glob_op(fr) || chan_deop(fr)))) && !chan_sentkick(m) && (me_op(chan) || (me_halfop(chan) && !chan_hasop(m) && (strchr(NOHALFOPS_MODES, 'b') == NULL)))) { dprintf(DP_MODE, "KICK %s %s :%s\n", chan->name, badnick, kick_msg); m->flags |= SENTKICK; } }
/* 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. */ }