X-Git-Url: http://git.pk910.de/?p=ircu2.10.12-pk.git;a=blobdiff_plain;f=ircd%2Fchannel.c;h=b82d8e0780b25c4e3d0f8a92cb7ff71fd72a6d63;hp=868a82f052c7d94496dff10b62c2815dafd3d239;hb=dfd1ba1a12e57ef10ee82d1e13f45ea5b7fb9c0f;hpb=c666f34b1e2d872189f36761e3b69eac635fd6ae diff --git a/ircd/channel.c b/ircd/channel.c index 868a82f..b82d8e0 100644 --- a/ircd/channel.c +++ b/ircd/channel.c @@ -656,6 +656,24 @@ int is_chan_op(struct Client *cptr, struct Channel *chptr) return 0; } +/** Check if this user is a legitimate halfop + * + * @param cptr Client to check + * @param chptr Channel to check + * + * @returns True if the user is a halfop (And not a zombie), False otherwise. + * @see \ref zombie + */ +int is_halfop(struct Client *cptr, struct Channel *chptr) +{ + struct Membership* member; + assert(chptr); + if ((member = find_member_link(chptr, cptr))) + return (!IsZombie(member) && IsHalfOp(member)); + + return 0; +} + /** Check if a user is a Zombie on a specific channel. * * @param cptr The client to check. @@ -794,7 +812,8 @@ int client_can_send_to_channel(struct Client *cptr, struct Channel *chptr, int r */ if (!member) { if ((chptr->mode.mode & (MODE_NOPRIVMSGS|MODE_MODERATED)) || - ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(cptr))) + ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(cptr)) || + ((chptr->mode.mode & MODE_SSLCHAN) && !IsSSL(cptr))) return 0; else return !find_ban(cptr, chptr->banlist); @@ -822,6 +841,7 @@ const char* find_no_nickchange_channel(struct Client* cptr, const char *new_nick continue; if ((member->channel->mode.mode & MODE_MODERATED) || (member->channel->mode.mode & MODE_REGONLY && !IsAccount(cptr)) + || (member->channel->mode.mode & MODE_SSLCHAN && !IsSSL(cptr)) || is_banned(member) || (new_nick && is_banned_with_nick(member, new_nick))) return member->channel->chname; } @@ -889,6 +909,8 @@ void channel_modes(struct Client *cptr, char *mbuf, char *pbuf, int buflen, *mbuf++ = 'Q'; if (chptr->mode.mode & MODE_AUDITORIUM) *mbuf++ = 'u'; + if (chptr->mode.mode & MODE_SSLCHAN) + *mbuf++ = 'S'; if (chptr->mode.limit) { *mbuf++ = 'l'; ircd_snprintf(0, pbuf, buflen, "%u", chptr->mode.limit); @@ -919,7 +941,7 @@ void channel_modes(struct Client *cptr, char *mbuf, char *pbuf, int buflen, *mbuf++ = 'k'; if (previous_parameter) strcat(pbuf, " "); - if (is_chan_op(cptr, chptr) || IsServer(cptr) || IsOper(cptr)) { + if ((member && IsChanOpOrHalfOp(member)) || IsServer(cptr) || IsOper(cptr)) { strcat(pbuf, chptr->mode.key); } else strcat(pbuf, "*"); @@ -939,7 +961,7 @@ void channel_modes(struct Client *cptr, char *mbuf, char *pbuf, int buflen, *mbuf++ = 'U'; if (previous_parameter) strcat(pbuf, " "); - if (IsServer(cptr) || (member && IsChanOp(member) && OpLevel(member) == 0) || IsOper(cptr)) { + if (IsServer(cptr) || (member && IsChanOpOrHalfOp(member) && OpLevel(member) == 0) || IsOper(cptr)) { strcat(pbuf, chptr->mode.upass); } else strcat(pbuf, "*"); @@ -975,8 +997,8 @@ int compare_member_oplevel(const void *mp1, const void *mp2) void send_channel_modes(struct Client *cptr, struct Channel *chptr) { /* The order in which modes are generated is now mandatory */ - static unsigned int current_flags[4] = - { 0, CHFL_VOICE, CHFL_CHANOP, CHFL_CHANOP | CHFL_VOICE }; + static unsigned int current_flags[8] = + { 0, CHFL_VOICE, CHFL_HALFOP, CHFL_VOICE | CHFL_HALFOP, CHFL_CHANOP, CHFL_CHANOP | CHFL_VOICE, CHFL_CHANOP | CHFL_HALFOP, CHFL_CHANOP | CHFL_VOICE | CHFL_HALFOP }; int first = 1; int full = 1; int flag_cnt = 0; @@ -1034,7 +1056,7 @@ void send_channel_modes(struct Client *cptr, struct Channel *chptr) * Then run 2 times over all opped members (which are ordered * by op-level) to also group voice and non-voice together. */ - for (first = 1; flag_cnt < 4; new_mode = 1, ++flag_cnt) + for (first = 1; flag_cnt < 8; new_mode = 1, ++flag_cnt) { while (member) { @@ -1089,6 +1111,8 @@ void send_channel_modes(struct Client *cptr, struct Channel *chptr) if (HasVoice(member)) /* flag_cnt == 1 or 3 */ tbuf[loc++] = 'v'; + if (IsHalfOp(member)) + tbuf[loc++] = 'h'; if (IsChanOp(member)) /* flag_cnt == 2 or 3 */ { /* append the absolute value of the oplevel */ @@ -1115,7 +1139,7 @@ void send_channel_modes(struct Client *cptr, struct Channel *chptr) } } /* Go to the next `member'. */ - if (flag_cnt < 2) + if (flag_cnt < 2 || !(current_flags[flag_cnt] & CHFL_CHANOP)) member = member->next_member; else member = opped_members[++opped_members_index]; @@ -1126,7 +1150,6 @@ void send_channel_modes(struct Client *cptr, struct Channel *chptr) /* Point `member' at the start of the list again. */ if (flag_cnt == 0) { - member = chptr->members; /* Now, after one loop, we know the number of ops and can * allocate the dynamic array with pointer to the ops. */ opped_members = (struct Membership**) @@ -1141,10 +1164,12 @@ void send_channel_modes(struct Client *cptr, struct Channel *chptr) if (flag_cnt == 1) qsort(opped_members, number_of_ops, sizeof(struct Membership*), compare_member_oplevel); - /* The third and fourth loop run only over the opped members. */ - member = opped_members[(opped_members_index = 0)]; } - + if(!(current_flags[flag_cnt+1] & CHFL_CHANOP)) { + member = chptr->members; + } else + member = opped_members[(opped_members_index = 0)]; + } /* loop over 0,+v,+o,+ov */ if (!full) @@ -1606,6 +1631,7 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all) MODE_NONOTICE, 'N', MODE_QUARANTINE, 'Q', MODE_AUDITORIUM, 'u', + MODE_SSLCHAN, 'S', 0x0, 0x0 }; static ulong64 local_flags[] = { @@ -1688,13 +1714,18 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all) bufptr_i = &rembuf_i; } - if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) { + if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_HALFOP | MODE_VOICE)) { tmp = strlen(cli_name(MB_CLIENT(mbuf, i))); if ((totalbuflen - IRCD_MAX(9, tmp)) <= 0) /* don't overflow buffer */ MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */ else { - bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v'; + if((MB_TYPE(mbuf, i) & MODE_CHANOP)) + bufptr[(*bufptr_i)++] = 'o'; + else if((MB_TYPE(mbuf, i) & MODE_HALFOP)) + bufptr[(*bufptr_i)++] = 'h'; + else + bufptr[(*bufptr_i)++] = 'v'; totalbuflen -= IRCD_MAX(9, tmp) + 1; } } else if (MB_TYPE(mbuf, i) & (MODE_BAN | MODE_APASS | MODE_UPASS | MODE_ALTCHAN | MODE_NOFLOOD)) { @@ -1791,7 +1822,7 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all) } /* deal with clients... */ - if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) + if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_HALFOP | MODE_VOICE)) build_string(strptr, strptr_i, cli_name(MB_CLIENT(mbuf, i)), 0, ' '); /* deal with bans... */ @@ -1907,7 +1938,7 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all) MB_OPLEVEL(mbuf, i)); /* deal with other modes that take clients */ - else if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_VOICE)) + else if (MB_TYPE(mbuf, i) & (MODE_CHANOP | MODE_HALFOP | MODE_VOICE)) build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' '); /* deal with modes that take strings */ @@ -2047,7 +2078,7 @@ modebuf_mode(struct ModeBuf *mbuf, ulong64 mode) MODE_TOPICLIMIT | MODE_INVITEONLY | MODE_NOPRIVMSGS | MODE_REGONLY | MODE_DELJOINS | MODE_WASDELJOINS | MODE_REGISTERED | MODE_PERSIST | MODE_NOCOLOUR | MODE_NOCTCP | MODE_NOAMSGS | MODE_NONOTICE | - MODE_QUARANTINE | MODE_AUDITORIUM); + MODE_QUARANTINE | MODE_AUDITORIUM | MODE_SSLCHAN); if (!(mode & ~(MODE_ADD | MODE_DEL))) /* don't add empty modes... */ return; @@ -2225,6 +2256,7 @@ modebuf_extract(struct ModeBuf *mbuf, char *buf) MODE_ALTCHAN, 'F', MODE_ACCESS, 'a', MODE_AUDITORIUM, 'u', + MODE_SSLCHAN, 'S', MODE_NOFLOOD, 'f', 0x0, 0x0 }; @@ -2481,6 +2513,9 @@ mode_parse_access(struct ParseState *state, ulong64 *flag_p) return; } + if(feature_bool(FEAT_CHMODE_A_NOSET) && !(state->flags & MODE_PARSE_FORCE)) /* mode can'T be set. */ + return; + if (!(state->flags & MODE_PARSE_WIPEOUT) && (!t_access || t_access == state->chptr->mode.access)) return; @@ -2556,7 +2591,7 @@ mode_parse_altchan(struct ParseState *state, ulong64 *flag_p) return; if(!(member = find_member_link(chptr, state->sptr))) return; - if(!IsChanOp(member)) { + if(!IsChanOpOrHalfOp(member)) { send_notoper(state); return; } @@ -2641,8 +2676,9 @@ mode_parse_noflood(struct ParseState *state, ulong64 *flag_p) else t_str++; //simply ignore if it's not an opmode tmp++; } - if(tmp[0] == '+' || tmp[0] == '@') { + if(tmp[0] == '+' || tmp[0] == '%' || tmp[0] == '@') { if(tmp[0] == '+') flags |= FLFL_VOICE; + if(tmp[0] == '%') flags |= FLFL_HALFOP; if(tmp[0] == '@') flags |= FLFL_CHANOP; tmp++; } @@ -2714,7 +2750,7 @@ mode_parse_noflood(struct ParseState *state, ulong64 *flag_p) unsigned int noflood_value = time; noflood_value <<= 10; noflood_value |= count; - noflood_value <<= 3; + noflood_value <<= 4; noflood_value |= flags; state->chptr->mode.noflood_value = noflood_value; } else { @@ -3262,13 +3298,13 @@ static void audit_chan_users(struct ParseState *state, ulong64 *flag_p) { struct Membership *member; if (state->dir == MODE_ADD) { for(member = state->chptr->members; member; member = member->next_member) { - if(!IsChanOp(member) && !HasVoice(member)) { + if(!IsChanOpOrHalfOp(member) && !HasVoice(member)) { sendcmdto_channel_butserv_butone(member->user, CMD_PART, member->channel, member->user, SKIP_OPS, "%H :%s", member->channel, "mode +u set."); } } } else { for(member = state->chptr->members; member; member = member->next_member) { - if(!IsChanOp(member) && !HasVoice(member)) { + if(!IsChanOpOrHalfOp(member) && !HasVoice(member)) { sendcmdto_channel_butserv_butone(member->user, CMD_JOIN, member->channel, member->user, SKIP_OPS, ":%H", member->channel); } } @@ -3463,7 +3499,7 @@ mode_parse_client(struct ParseState *state, ulong64 *flag_p) if (colon != NULL) { *colon++ = '\0'; req_oplevel = atoi(colon); - if (*flag_p == CHFL_VOICE || state->dir == MODE_DEL) { + if (*flag_p == CHFL_VOICE || *flag_p == CHFL_HALFOP || state->dir == MODE_DEL) { /* Ignore the colon and its argument. */ } else if (!(state->flags & MODE_PARSE_FORCE) && state->member @@ -3478,6 +3514,10 @@ mode_parse_client(struct ParseState *state, ulong64 *flag_p) } else if (req_oplevel <= MAXOPLEVEL) oplevel = req_oplevel; } + if(*flag_p == CHFL_CHANOP && state->member && !IsChanOp(state->member) && !(state->flags & MODE_PARSE_FORCE)) { + send_notoper(state); + return; + } /* find client we're manipulating */ acptr = find_chasing(state->sptr, t_str, NULL); } else { @@ -3626,12 +3666,12 @@ mode_process_clients(struct ParseState *state) if (IsDelayedJoin(member) && !IsZombie(member)) RevealDelayedJoin(member); member->status |= (state->cli_change[i].flag & - (MODE_CHANOP | MODE_VOICE)); + (MODE_CHANOP | MODE_HALFOP | MODE_VOICE)); if (state->cli_change[i].flag & MODE_CHANOP) ClearDeopped(member); } else member->status &= ~(state->cli_change[i].flag & - (MODE_CHANOP | MODE_VOICE)); + (MODE_CHANOP | MODE_HALFOP | MODE_VOICE)); } /* accumulate the change */ @@ -3646,21 +3686,21 @@ mode_process_clients(struct ParseState *state) } else if(!(member->status & CHFL_VOICED_OR_OPPED) && user_visible) { sendcmdto_channel_butserv_butone(member->user, CMD_PART, member->channel, member->user, SKIP_OPS, "%H :%s", member->channel, "user deoped/devoiced on a +u channel."); } - if(MyUser(member->user) && (state->cli_change[i].flag & MODE_CHANOP)) { + if(MyUser(member->user) && (state->cli_change[i].flag & (MODE_CHANOP | MODE_HALFOP))) { //do_names(member->user, member->channel, NAMES_ALL|NAMES_EON|((member->status & MODE_CHANOP) ? 0 : NAMES_OPS)); //this is not working for all users :( so we have to send join/part events struct Membership *member2; if (state->cli_change[i].flag & MODE_ADD) { //JOIN events for(member2 = state->chptr->members; member2; member2 = member2->next_member) { - if(!IsChanOp(member2) && !HasVoice(member2)) { + if(!IsChanOpOrHalfOp(member2) && !HasVoice(member2)) { sendcmdto_one(member2->user, CMD_JOIN, member->user, ":%H", member->channel); } } } else { //PART events for(member2 = state->chptr->members; member2; member2 = member2->next_member) { - if(!IsChanOp(member2) && !HasVoice(member2) && member != member2) { + if(!IsChanOpOrHalfOp(member2) && !HasVoice(member2) && member != member2) { sendcmdto_one(member2->user, CMD_PART, member->user, "%H :%s", member->channel, "invisible user on +u channel."); } } @@ -3734,6 +3774,7 @@ mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr, { static ulong64 chan_flags[] = { MODE_CHANOP, 'o', + MODE_HALFOP, 'h', MODE_VOICE, 'v', MODE_PRIVATE, 'p', MODE_SECRET, 's', @@ -3759,6 +3800,7 @@ mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr, MODE_ALTCHAN, 'F', MODE_ACCESS, 'a', MODE_AUDITORIUM, 'u', + MODE_SSLCHAN, 'S', MODE_NOFLOOD, 'f', MODE_ADD, '+', MODE_DEL, '-', @@ -3861,7 +3903,10 @@ mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr, case 'v': mode_parse_client(&state, flag_p); break; - + case 'h': + if (IsServer(cptr) || feature_bool(FEAT_HALFOP)) + mode_parse_client(&state, flag_p); + break; case 'z': /* remote clients are allowed to change +z */ if(!MyUser(state.sptr) || (state.flags & MODE_PARSE_FORCE)) mode_parse_mode(&state, flag_p); @@ -4304,7 +4349,7 @@ int ext_amsg_block(struct Client *cptr, struct Channel *chptr, const char *msg) int p_pos = 0; int is_visible = 1, is_ccode = 0, i = 0, j = 0; char codes[5]; - for(i = 0; p != '\n'; p = stripped_message[++i]) { + for(i = 0; p != '\n' && p != 0; p = stripped_message[++i]) { if(p == 3) { j = 0; is_ccode = 1; @@ -4389,15 +4434,17 @@ int ext_noflood_block(struct Client *cptr, struct Channel *chptr) { struct Membership *member = find_member_link(chptr, cptr); if(!member) return 0; //TODO: we've no check for -n channels implemented, yet //check if this user is really affected by +f - unsigned int flags = (chptr->mode.noflood_value & 0x00000007); //0000 0000 0000 0000 0000 0000 0000 0111 = 0x00000007 >> 0 - unsigned int count = (chptr->mode.noflood_value & 0x00001ff8) >> 3; //0000 0000 0000 0000 0001 1111 1111 1000 = 0x00001ff8 >> 3 - int time = (chptr->mode.noflood_value & 0x07ffe000) >> 13; //0000 0111 1111 1111 1110 0000 0000 0000 = 0x07ffe000 >> 13 + unsigned int flags = (chptr->mode.noflood_value & 0x0000000f); //0000 0000 0000 0000 0000 0000 0000 1111 = 0x0000000f >> 0 + unsigned int count = (chptr->mode.noflood_value & 0x00002ff0) >> 4; //0000 0000 0000 0000 0011 1111 1111 0000 = 0x00002ff0 >> 4 + int time = (chptr->mode.noflood_value & 0x0fffc000) >> 14; //0000 1111 1111 1111 1100 0000 0000 0000 = 0x0fffc000 >> 14 if(count == 0 || time == 0) return 0; if(!(flags & FLFL_NOFLOOD) && HasPriv(cptr, PRIV_FLOOD)) return 0; if(!(flags & FLFL_CHANOP) && (member->status & CHFL_CHANOP)) return 0; - if(!(flags & (FLFL_CHANOP | FLFL_VOICE)) && (member->status & CHFL_VOICE)) + if(!(flags & (FLFL_CHANOP | FLFL_HALFOP)) && (member->status & CHFL_HALFOP)) + return 0; + if(!(flags & (FLFL_CHANOP | FLFL_HALFOP | FLFL_VOICE)) && (member->status & CHFL_VOICE)) return 0; int floodcount = 0; struct MemberFlood *floodnode, *prev_floodnode;