From 362239ace2f74ae33afd0e0b935f9e3acb736968 Mon Sep 17 00:00:00 2001 From: Perry Lorier Date: Wed, 6 Mar 2002 09:31:28 +0000 Subject: [PATCH] Author: Carlo Wood (Via Isomer ) Log message: Run's Patches: apass1.diff apass1-2.diff map_update.patch apass2-3.diff git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@662 c9e4aea6-c8fd-4c43-8297-357d70d61c8c --- ChangeLog | 82 ++++++++ include/channel.h | 20 +- include/numeric.h | 8 +- ircd/Makefile.in | 1 + ircd/channel.c | 511 ++++++++++++++++++++++++++++++++++++++++------ ircd/ircd.c | 3 + ircd/m_burst.c | 107 ++++++++-- ircd/m_endburst.c | 7 +- ircd/m_join.c | 5 +- ircd/m_mode.c | 16 +- ircd/m_opmode.c | 6 +- ircd/s_err.c | 4 +- ircd/s_misc.c | 4 +- 13 files changed, 669 insertions(+), 105 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6a372ee..bd548ba 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,85 @@ + +2002-03-01 Carlo Wood + + * include/channel.h: struct Channel: new attribute destruct_event. + Prototype for destruct_channel(). + + * include/destruct_event.h: new header file for destruct_event.c. + + * ircd/Makefile.in: New source file: destruct_event.c. + + * ircd/channel.c: sub1_from_channel: Don't destruct channel + immedeately but instead schedule it for destruction after + some time when a channel becomes empty (and clear invite + only and limit in that case). + destruct_channel: new function, was previously the destructing + part of sub1_from_channel. + add_user_to_channel: remove destruction request if any. + + * ircd/destruct_event.c: New file. Implementation of functions + schedule_destruct_event_1m, schedule_destruct_event_48h, + remove_destruct_event and exec_expired_destruct_events. + + * ircd/ircd.c: destruct_event_timer: new timer. + main: use destruct_event_timer to call exec_expired_destruct_events + once per minute. + + * ircd/m_endburst.c: ms_end_of_burst: Don't complain about empty + channels. Schedule new empty channels for destruction. + + * ircd/m_join.c: m_join: Destruct just-created channel immedeately. + +2002-03-01 Carlo Wood + * ircd/s_misc.c: exit_client: Only call map_update() + for servers. + +2002-02-28 Carlo Wood + * include/channel.h: New attribute 'oplevel' in struct Membership. + Added defines MAXOPLEVELDIGITS and MAXOPLEVEL. + New macros: OpLevel(member): returns op-level of member and + SetOpLevel(member, value): sets op-level of member. + Prototype of add_user_to_channel: add oplevel to parameters. + Prototype of mode_parse: add member to to parameters. + + * include/numeric.h: added ERR_NOTLOWEROPLEVEL. + + * ircd/s_err.c: idem. + + * ircd/channel.c: Removed unmatched '{' braces from comments + (confuses vi). add_user_to_channel: oplevel is passed to function + and added in the created MemberShip structure. send_channel_modes: + Generate the nick:mode list of the BURST msg in the new style (with + op-levels). DONE_UPASS/DONE_APASS: fixed typo in comment. struct + ParseState: New attribute: member. mode_process_clients: Disallow + deopping someone with an equal or higher op-level, take care of + inheritance of op-level. mode_parse: member is passed to function + and added in the created ParseState structure. joinbuf_join: pass 0 + as oplevel to add_user_to_channel as needed initialization of oplevel + in struct MemberShip. + + * ircd/m_burst.c: ms_burst: Implementation of op-levels in the + decoding of a BURST message and passing on a BURST message. + Renamed default_mode to current_mode. + + * ircd/m_mode.c: m_mode/ms_mode: pass on `member' to mode_parse. + + * ircd/m_opmode.c: ms_opmode/mo_opmode: pass on NULL as member + to mode_parse (causes opped member to get op-level 0). + +2002-02-25 Carlo Wood + * include/channel.h: Added two new strings to struct Mode, + upass and apass, both with maximum length PASSLEN (a new + define in this file). Two new mode defines MODE_UPASS and + MODE_APASS. + + * ircd/channel.c: is_level0_op: Added as dummy function. + channel_modes/modebuf_flush_int/modebuf_extract/mode_parse: + Added support for MODE_APASS (+A) and MODE_UPASS (+u). + mode_parse_upass: New function to parse mode +u. + mode_parse_apass: New function to parse mode +A. + + * ircd/s_err.c: Added 'A' and 'u' to mode list (RPL_MYINFO). + 2002-02-25 Carlo Wood * ircd/m_server.c: remove unused variables diff --git a/include/channel.h b/include/channel.h index 66ba3d5..2825da7 100644 --- a/include/channel.h +++ b/include/channel.h @@ -40,6 +40,7 @@ struct Client; #define MODEBUFLEN 200 #define KEYLEN 23 +#define PASSLEN 23 #define CHANNELLEN 200 #define MAXJOINARGS 15 /* number of slots for join buffer */ @@ -89,10 +90,12 @@ struct Client; #define MODE_SAVE 0x20000 /* save this mode-with-arg 'til later */ #define MODE_FREE 0x40000 /* string needs to be passed to MyFree() */ #define MODE_BURSTADDED 0x80000 /* channel was created by a BURST */ +#define MODE_UPASS 0x100000 +#define MODE_APASS 0x200000 /* * mode flags which take another parameter (With PARAmeterS) */ -#define MODE_WPARAS (MODE_CHANOP|MODE_VOICE|MODE_BAN|MODE_KEY|MODE_LIMIT) +#define MODE_WPARAS (MODE_CHANOP|MODE_VOICE|MODE_BAN|MODE_KEY|MODE_LIMIT|MODE_APASS|MODE_UPASS) #define HoldChannel(x) (!(x)) /* name invisible */ @@ -165,13 +168,18 @@ struct Membership { struct Membership* next_channel; struct Membership* prev_channel; unsigned int status; + unsigned short oplevel; }; +#define MAXOPLEVELDIGITS 3 +#define MAXOPLEVEL 999 + #define IsZombie(x) ((x)->status & CHFL_ZOMBIE) #define IsDeopped(x) ((x)->status & CHFL_DEOPPED) #define IsBanned(x) ((x)->status & CHFL_BANNED) #define IsBanValid(x) ((x)->status & CHFL_BANVALID) #define IsChanOp(x) ((x)->status & CHFL_CHANOP) +#define OpLevel(x) ((x)->oplevel) #define HasVoice(x) ((x)->status & CHFL_VOICE) #define IsServOpOk(x) ((x)->status & CHFL_SERVOPOK) #define IsBurstJoined(x) ((x)->status & CHFL_BURST_JOINED) @@ -183,6 +191,7 @@ struct Membership { #define SetServOpOk(x) ((x)->status |= CHFL_SERVOPOK) #define SetBurstJoined(x) ((x)->status |= CHFL_BURST_JOINED) #define SetZombie(x) ((x)->status |= CHFL_ZOMBIE) +#define SetOpLevel(x, v) (void)((x)->oplevel = (v)) #define ClearBanned(x) ((x)->status &= ~CHFL_BANNED) #define ClearBanValid(x) ((x)->status &= ~CHFL_BANVALID) @@ -195,12 +204,15 @@ struct Mode { unsigned int mode; unsigned int limit; char key[KEYLEN + 1]; + char upass[PASSLEN + 1]; + char apass[PASSLEN + 1]; }; struct Channel { struct Channel* next; struct Channel* prev; struct Channel* hnext; + struct DestructEvent* destruct_event; time_t creationtime; time_t topic_time; unsigned int users; @@ -296,9 +308,10 @@ extern struct Channel *get_channel(struct Client *cptr, extern struct Membership* find_member_link(struct Channel * chptr, const struct Client* cptr); extern int sub1_from_channel(struct Channel* chptr); +extern int destruct_channel(struct Channel* chptr); extern int can_join(struct Client *sptr, struct Channel *chptr, char *key); extern void add_user_to_channel(struct Channel* chptr, struct Client* who, - unsigned int flags); + unsigned int flags, int oplevel); extern void cancel_mode(struct Client *sptr, struct Channel *chptr, char m, const char *param, int *count); extern void add_token_to_sendbuf(char *token, size_t *sblenp, int *firstp, @@ -351,7 +364,8 @@ extern void mode_invite_clear(struct Channel *chan); extern int mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr, struct Channel *chptr, - int parc, char *parv[], unsigned int flags); + int parc, char *parv[], unsigned int flags, + struct Membership* member); #define MODE_PARSE_SET 0x01 /* actually set channel modes */ #define MODE_PARSE_STRICT 0x02 /* +m +n +t style not supported */ diff --git a/include/numeric.h b/include/numeric.h index b16d284..40343af 100644 --- a/include/numeric.h +++ b/include/numeric.h @@ -439,12 +439,14 @@ extern const struct Numeric* get_error_numeric(int err); #define ERR_TOOMANYUSERS 519 /* Undernet extension -Kev */ /* ERR_OPERONLY 520 unreal */ #define ERR_MASKTOOWIDE 520 /* Undernet extension -Kev */ -/* ERR_WHOTRUNC 520 austnet */ -#define ERR_LASTERROR 521 -/* ERR_LISTSYNTAX 521 dalnet +/* ERR_WHOTRUNC 520 austnet + ERR_LISTSYNTAX 521 dalnet ERR_WHOSYNTAX 522 dalnet ERR_WHOLIMEXCEED 523 dalnet */ +#define ERR_NOTLOWEROPLEVEL 550 +#define ERR_LASTERROR 551 + /* RPL_LOGON 600 dalnet,unreal RPL_LOGOFF 601 dalnet,unreal RPL_WATCHOFF 602 dalnet,unreal diff --git a/ircd/Makefile.in b/ircd/Makefile.in index 93c36d7..7a553cd 100644 --- a/ircd/Makefile.in +++ b/ircd/Makefile.in @@ -83,6 +83,7 @@ IRCD_SRC = \ client.c \ crule.c \ dbuf.c \ + destruct_event.c \ fda.c \ fileio.c \ gline.c \ diff --git a/ircd/channel.c b/ircd/channel.c index 1db9475..1c3d491 100644 --- a/ircd/channel.c +++ b/ircd/channel.c @@ -23,6 +23,7 @@ #include "channel.h" #include "client.h" +#include "destruct_event.h" #include "hash.h" #include "ircd.h" #include "ircd_alloc.h" @@ -186,14 +187,11 @@ static char *make_nick_user_ip(char *ipbuf, char *nick, char *name, /* * Subtract one user from channel i (and free channel * block, if channel became empty). - * Returns: true (1) if channel still exists - * false (0) if the channel was destroyed + * Returns: true (1) if channel still has members. + * false (0) if the channel is now empty. */ int sub1_from_channel(struct Channel* chptr) { - struct SLink *tmp; - struct SLink *obtmp; - if (chptr->users > 1) /* Can be 0, called for an empty channel too */ { assert(0 != chptr->members); @@ -201,6 +199,39 @@ int sub1_from_channel(struct Channel* chptr) return 1; } + chptr->users = 0; + + /* + * Also channels without Apass set need to be kept alive, + * otherwise Bad Guys(tm) would be able to takeover + * existing channels too easily, and then set an Apass! + * However, if a channel without Apass becomes empty + * then we try to be kind to them and remove possible + * limiting modes. + */ + chptr->mode.mode &= ~MODE_INVITEONLY; + chptr->mode.limit = 0; + /* + * We do NOT reset a possible key or bans because when + * the 'channel owners' can't get in because of a key + * or ban then apparently there was a fight/takeover + * on the channel and we want them to contact IRC opers + * who then will educate them on the use of Apass/upass. + */ + + if (TStime() - chptr->creationtime < 172800) /* Channel younger than 48 hours? */ + schedule_destruct_event_1m(chptr); /* Get rid of it in approximately 4-5 minutes */ + else + schedule_destruct_event_48h(chptr); /* Get rid of it in approximately 48 hours */ + + return 0; +} + +int destruct_channel(struct Channel* chptr) +{ + struct SLink *tmp; + struct SLink *obtmp; + assert(0 == chptr->members); /* Channel became (or was) empty: Remove channel */ @@ -465,7 +496,7 @@ static int is_banned(struct Client *cptr, struct Channel *chptr, * chain. */ void add_user_to_channel(struct Channel* chptr, struct Client* who, - unsigned int flags) + unsigned int flags, int oplevel) { assert(0 != chptr); assert(0 != who); @@ -484,6 +515,7 @@ void add_user_to_channel(struct Channel* chptr, struct Client* who, member->user = who; member->channel = chptr; member->status = flags; + member->oplevel = oplevel; member->next_member = chptr->members; if (member->next_member) @@ -497,6 +529,8 @@ void add_user_to_channel(struct Channel* chptr, struct Client* who, member->prev_channel = 0; (cli_user(who))->channel = member; + if (chptr->destruct_event) + remove_destruct_event(chptr); ++chptr->users; ++((cli_user(who))->joined); } @@ -587,6 +621,11 @@ int is_chan_op(struct Client *cptr, struct Channel *chptr) return 0; } +int is_level0_op(struct Client *cptr, struct Channel *chptr) +{ + return 0; +} + int is_zombie(struct Client *cptr, struct Channel *chptr) { struct Membership* member; @@ -684,6 +723,8 @@ const char* find_no_nickchange_channel(struct Client* cptr) void channel_modes(struct Client *cptr, char *mbuf, char *pbuf, int buflen, struct Channel *chptr) { + int previous_parameter = 0; + assert(0 != mbuf); assert(0 != pbuf); assert(0 != chptr); @@ -706,27 +747,58 @@ void channel_modes(struct Client *cptr, char *mbuf, char *pbuf, int buflen, if (chptr->mode.limit) { *mbuf++ = 'l'; ircd_snprintf(0, pbuf, buflen, "%u", chptr->mode.limit); + previous_parameter = 1; } if (*chptr->mode.key) { *mbuf++ = 'k'; - if (chptr->mode.limit) + if (previous_parameter) strcat(pbuf, " "); if (is_chan_op(cptr, chptr) || IsServer(cptr)) { strcat(pbuf, chptr->mode.key); } else strcat(pbuf, "*"); + previous_parameter = 1; + } + if (*chptr->mode.apass) { + *mbuf++ = 'A'; + if (previous_parameter) + strcat(pbuf, " "); + if (IsServer(cptr)) { + strcat(pbuf, chptr->mode.apass); + } else + strcat(pbuf, "*"); + previous_parameter = 1; + } + if (*chptr->mode.upass) { + *mbuf++ = 'u'; + if (previous_parameter) + strcat(pbuf, " "); + if (is_level0_op(cptr, chptr) || IsServer(cptr)) { + strcat(pbuf, chptr->mode.upass); + } else + strcat(pbuf, "*"); } *mbuf = '\0'; } +int compare_member_oplevel(const void *mp1, const void *mp2) +{ + struct Membership const* member1 = *(struct Membership const**)mp1; + struct Membership const* member2 = *(struct Membership const**)mp2; + if (member1->oplevel == member2->oplevel) + return 0; + return (member1->oplevel < member2->oplevel) ? -1 : 1; +} + /* * send "cptr" a full list of the modes for channel chptr. */ 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_CHANOP | CHFL_VOICE, CHFL_VOICE, CHFL_CHANOP }; + { 0, CHFL_VOICE, CHFL_CHANOP, CHFL_CHANOP | CHFL_VOICE }; int first = 1; int full = 1; int flag_cnt = 0; @@ -737,6 +809,10 @@ void send_channel_modes(struct Client *cptr, struct Channel *chptr) char modebuf[MODEBUFLEN]; char parabuf[MODEBUFLEN]; struct MsgBuf *mb; + int number_of_ops = 0; + int opped_members_index = 0; + struct Membership** opped_members = NULL; + int last_oplevel = 0; assert(0 != cptr); assert(0 != chptr); @@ -760,7 +836,7 @@ void send_channel_modes(struct Client *cptr, struct Channel *chptr) mb = msgq_make(&me, "%C " TOK_BURST " %H %Tu", &me, chptr, chptr->creationtime); - if (first && modebuf[1]) /* Add simple modes (iklmnpst) + if (first && modebuf[1]) /* Add simple modes (Aiklmnpstu) if first message */ { /* prefix: " B [ [ ]]" */ @@ -773,52 +849,119 @@ void send_channel_modes(struct Client *cptr, struct Channel *chptr) /* * Attach nicks, comma seperated " nick[:modes],nick[:modes],..." * - * Run 4 times over all members, to group the members with the - * same mode together + * First find all opless members. + * Run 2 times over all members, to group the members with + * and without voice together. + * 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; - member = chptr->members, new_mode = 1, flag_cnt++) + for (first = 1; flag_cnt < 4; new_mode = 1, ++flag_cnt) { - for (; member; member = member->next_member) + while (member) { - if ((member->status & CHFL_VOICED_OR_OPPED) != - current_flags[flag_cnt]) - continue; /* Skip members with different flags */ - if (msgq_bufleft(mb) < NUMNICKLEN + 4) - /* The 4 is a possible ",:ov" */ - { - full = 1; /* Make sure we continue after - sending it so far */ - new_mode = 1; /* Ensure the new BURST line contains the current - mode. --Gte */ - break; /* Do not add this member to this message */ - } - msgq_append(&me, mb, "%c%C", first ? ' ' : ',', member->user); - first = 0; /* From now on, us comma's to add new nicks */ - - /* - * Do we have a nick with a new mode ? - * Or are we starting a new BURST line? - */ - if (new_mode) - { - new_mode = 0; - if (IsVoicedOrOpped(member)) { - char tbuf[4] = ":"; + if (flag_cnt < 2 && IsChanOp(member)) + { + /* + * The first loop (to find all non-voice/op), we count the ops. + * The second loop (to find all voiced non-ops), store the ops + * in a dynamic array. + */ + if (flag_cnt == 0) + ++number_of_ops; + else + opped_members[opped_members_index++] = member; + } + /* Only handle the members with the flags that we are interested in. */ + if ((member->status & CHFL_VOICED_OR_OPPED) == current_flags[flag_cnt]) + { + if (msgq_bufleft(mb) < NUMNICKLEN + 3 + MAXOPLEVELDIGITS) + /* The 3 + MAXOPLEVELDIGITS is a possible ",:v999". */ + { + full = 1; /* Make sure we continue after + sending it so far */ + /* Ensure the new BURST line contains the current + * ":mode", except when there is no mode yet. */ + new_mode = (flag_cnt > 0) ? 1 : 0; + break; /* Do not add this member to this message */ + } + msgq_append(&me, mb, "%c%C", first ? ' ' : ',', member->user); + first = 0; /* From now on, use commas to add new nicks */ + + /* + * Do we have a nick with a new mode ? + * Or are we starting a new BURST line? + */ + if (new_mode) + { + /* + * This means we are at the _first_ member that has only + * voice, or the first member that has only ops, or the + * first member that has voice and ops (so we get here + * at most three times, plus once for every start of + * a continued BURST line where only these modes is current. + * In the two cases where the current mode includes ops, + * we need to add the _absolute_ value of the oplevel to the mode. + */ + char tbuf[3 + MAXOPLEVELDIGITS] = ":"; int loc = 1; - if (IsChanOp(member)) - tbuf[loc++] = 'o'; - if (HasVoice(member)) + if (HasVoice(member)) /* flag_cnt == 1 or 3 */ tbuf[loc++] = 'v'; + if (IsChanOp(member)) /* flag_cnt == 2 or 3 */ + { + /* append the absolute value of the oplevel */ + loc += ircd_snprintf(0, tbuf + loc, sizeof(tbuf) - loc, "%u", member->oplevel); + last_oplevel = member->oplevel; + } tbuf[loc] = '\0'; msgq_append(&me, mb, tbuf); - } - } + new_mode = 0; + } + else if (flag_cnt > 1 && last_oplevel != member->oplevel) + { + /* + * This can't be the first member of a (continued) BURST + * message because then either flag_cnt == 0 or new_mode == 1 + * Now we need to append the incremental value of the oplevel. + */ + char tbuf[2 + MAXOPLEVELDIGITS]; + ircd_snprintf(0, tbuf, sizeof(tbuf), ":%u", member->oplevel - last_oplevel); + last_oplevel = member->oplevel; + msgq_append(&me, mb, tbuf); + } + } + /* Go to the next `member'. */ + if (flag_cnt < 2) + member = member->next_member; + else + member = opped_members[++opped_members_index]; } if (full) - break; - } + break; + + /* 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**) + MyMalloc((number_of_ops + 1) * sizeof(struct Membership*)); + opped_members[number_of_ops] = NULL; /* Needed for loop termination */ + } + else + { + /* At the end of the second loop, sort the opped members with + * increasing op-level, so that we will output them in the + * correct order (and all op-level increments stay positive) */ + 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)]; + } + + } /* loop over 0,+v,+o,+ov */ if (!full) { @@ -844,6 +987,8 @@ void send_channel_modes(struct Client *cptr, struct Channel *chptr) msgq_clean(mb); } /* Continue when there was something that didn't fit (full==1) */ + if (opped_members) + MyFree(opped_members); } /* @@ -1342,6 +1487,8 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all) /* MODE_KEY, 'k', */ /* MODE_BAN, 'b', */ /* MODE_LIMIT, 'l', */ +/* MODE_APASS, 'A', */ +/* MODE_UPASS, 'u', */ 0x0, 0x0 }; int i; @@ -1416,13 +1563,29 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all) bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_CHANOP ? 'o' : 'v'; totalbuflen -= IRCD_MAX(5, tmp) + 1; } - } else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN)) { + } else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS)) { tmp = strlen(MB_STRING(mbuf, i)); if ((totalbuflen - tmp) <= 0) /* don't overflow buffer */ MB_TYPE(mbuf, i) |= MODE_SAVE; /* save for later */ else { - bufptr[(*bufptr_i)++] = MB_TYPE(mbuf, i) & MODE_KEY ? 'k' : 'b'; + char mode_char; + switch(MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS)) + { + case MODE_APASS: + mode_char = 'A'; + break; + case MODE_UPASS: + mode_char = 'u'; + break; + case MODE_KEY: + mode_char = 'k'; + break; + default: + mode_char = 'b'; + break; + } + bufptr[(*bufptr_i)++] = mode_char; totalbuflen -= tmp + 1; } } else if (MB_TYPE(mbuf, i) & MODE_LIMIT) { @@ -1474,6 +1637,10 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all) else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN)) build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' '); + /* deal with invisible passwords */ + else if (MB_TYPE(mbuf, i) & (MODE_APASS | MODE_UPASS)) + build_string(strptr, strptr_i, "*", 0, ' '); + /* * deal with limit; note we cannot include the limit parameter if we're * removing it @@ -1566,7 +1733,7 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all) build_string(strptr, strptr_i, NumNick(MB_CLIENT(mbuf, i)), ' '); /* deal with modes that take strings */ - else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN)) + else if (MB_TYPE(mbuf, i) & (MODE_KEY | MODE_BAN | MODE_APASS | MODE_UPASS)) build_string(strptr, strptr_i, MB_STRING(mbuf, i), 0, ' '); /* @@ -1794,6 +1961,8 @@ modebuf_extract(struct ModeBuf *mbuf, char *buf) MODE_INVITEONLY, 'i', MODE_NOPRIVMSGS, 'n', MODE_KEY, 'k', + MODE_APASS, 'A', + MODE_UPASS, 'u', /* MODE_BAN, 'b', */ MODE_LIMIT, 'l', MODE_REGONLY, 'r', @@ -1803,6 +1972,7 @@ modebuf_extract(struct ModeBuf *mbuf, char *buf) int i, bufpos = 0, len; int *flag_p; char *key = 0, limitbuf[20]; + char *apass, *upass; assert(0 != mbuf); assert(0 != buf); @@ -1813,12 +1983,16 @@ modebuf_extract(struct ModeBuf *mbuf, char *buf) for (i = 0; i < mbuf->mb_count; i++) { /* find keys and limits */ if (MB_TYPE(mbuf, i) & MODE_ADD) { - add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT); + add |= MB_TYPE(mbuf, i) & (MODE_KEY | MODE_LIMIT | MODE_APASS | MODE_UPASS); if (MB_TYPE(mbuf, i) & MODE_KEY) /* keep strings */ key = MB_STRING(mbuf, i); else if (MB_TYPE(mbuf, i) & MODE_LIMIT) ircd_snprintf(0, limitbuf, sizeof(limitbuf), "%u", MB_UINT(mbuf, i)); + else if (MB_TYPE(mbuf, i) & MODE_UPASS) + upass = MB_STRING(mbuf, i); + else if (MB_TYPE(mbuf, i) & MODE_APASS) + apass = MB_STRING(mbuf, i); } } @@ -1836,6 +2010,10 @@ modebuf_extract(struct ModeBuf *mbuf, char *buf) build_string(buf, &bufpos, key, 0, ' '); else if (buf[i] == 'l') build_string(buf, &bufpos, limitbuf, 0, ' '); + else if (buf[i] == 'u') + build_string(buf, &bufpos, upass, 0, ' '); + else if (buf[i] == 'A') + build_string(buf, &bufpos, apass, 0, ' '); } buf[bufpos] = '\0'; @@ -1871,12 +2049,15 @@ mode_invite_clear(struct Channel *chan) #define DONE_BANLIST 0x04 /* We've sent the ban list */ #define DONE_NOTOPER 0x08 /* We've sent a "Not oper" error */ #define DONE_BANCLEAN 0x10 /* We've cleaned bans... */ +#define DONE_UPASS 0x20 /* We've set user pass */ +#define DONE_APASS 0x40 /* We've set admin pass */ struct ParseState { struct ModeBuf *mbuf; struct Client *cptr; struct Client *sptr; struct Channel *chptr; + struct Membership *member; int parc; char **parv; unsigned int flags; @@ -2045,6 +2226,168 @@ mode_parse_key(struct ParseState *state, int *flag_p) } } +/* + * Helper function to convert user passes + */ +static void +mode_parse_upass(struct ParseState *state, int *flag_p) +{ + char *t_str, *s; + int t_len; + + if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */ + return; + + if (state->parc <= 0) { /* warn if not enough args */ + if (MyUser(state->sptr)) + need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" : + "MODE -u"); + return; + } + + t_str = state->parv[state->args_used++]; /* grab arg */ + state->parc--; + state->max_args--; + + /* If they're not an oper, they can't change modes */ + if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) { + send_notoper(state); + return; + } + + if (state->done & DONE_UPASS) /* allow upass to be set only once */ + return; + state->done |= DONE_UPASS; + + t_len = PASSLEN + 1; + + /* clean up the upass string */ + s = t_str; + while (*++s > ' ' && *s != ':' && --t_len) + ; + *s = '\0'; + + if (!*t_str) { /* warn if empty */ + if (MyUser(state->sptr)) + need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +u" : + "MODE -u"); + return; + } + + if (!state->mbuf) + return; + + /* can't add a upass if one is set, nor can one remove the wrong upass */ + if (!(state->flags & MODE_PARSE_FORCE)) + if ((state->dir == MODE_ADD && *state->chptr->mode.upass) || + (state->dir == MODE_DEL && + ircd_strcmp(state->chptr->mode.upass, t_str))) { + send_reply(state->sptr, ERR_KEYSET, state->chptr->chname); + return; + } + + if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD && + !ircd_strcmp(state->chptr->mode.upass, t_str)) + return; /* no upass change */ + + if (state->flags & MODE_PARSE_BOUNCE) { + if (*state->chptr->mode.upass) /* reset old upass */ + modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0], + state->chptr->mode.upass, 0); + else /* remove new bogus upass */ + modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0); + } else /* send new upass */ + modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0); + + if (state->flags & MODE_PARSE_SET) { + if (state->dir == MODE_ADD) /* set the new upass */ + ircd_strncpy(state->chptr->mode.upass, t_str, PASSLEN); + else /* remove the old upass */ + *state->chptr->mode.upass = '\0'; + } +} + +/* + * Helper function to convert admin passes + */ +static void +mode_parse_apass(struct ParseState *state, int *flag_p) +{ + char *t_str, *s; + int t_len; + + if (MyUser(state->sptr) && state->max_args <= 0) /* drop if too many args */ + return; + + if (state->parc <= 0) { /* warn if not enough args */ + if (MyUser(state->sptr)) + need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" : + "MODE -A"); + return; + } + + t_str = state->parv[state->args_used++]; /* grab arg */ + state->parc--; + state->max_args--; + + /* If they're not an oper, they can't change modes */ + if (state->flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) { + send_notoper(state); + return; + } + + if (state->done & DONE_APASS) /* allow apass to be set only once */ + return; + state->done |= DONE_APASS; + + t_len = PASSLEN + 1; + + /* clean up the apass string */ + s = t_str; + while (*++s > ' ' && *s != ':' && --t_len) + ; + *s = '\0'; + + if (!*t_str) { /* warn if empty */ + if (MyUser(state->sptr)) + need_more_params(state->sptr, state->dir == MODE_ADD ? "MODE +A" : + "MODE -A"); + return; + } + + if (!state->mbuf) + return; + + /* can't add a apass if one is set, nor can one remove the wrong apass */ + if (!(state->flags & MODE_PARSE_FORCE)) + if ((state->dir == MODE_ADD && *state->chptr->mode.apass) || + (state->dir == MODE_DEL && + ircd_strcmp(state->chptr->mode.apass, t_str))) { + send_reply(state->sptr, ERR_KEYSET, state->chptr->chname); + return; + } + + if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD && + !ircd_strcmp(state->chptr->mode.apass, t_str)) + return; /* no apass change */ + + if (state->flags & MODE_PARSE_BOUNCE) { + if (*state->chptr->mode.apass) /* reset old apass */ + modebuf_mode_string(state->mbuf, MODE_DEL | flag_p[0], + state->chptr->mode.apass, 0); + else /* remove new bogus apass */ + modebuf_mode_string(state->mbuf, MODE_ADD | flag_p[0], t_str, 0); + } else /* send new apass */ + modebuf_mode_string(state->mbuf, state->dir | flag_p[0], t_str, 0); + + if (state->flags & MODE_PARSE_SET) { + if (state->dir == MODE_ADD) /* set the new apass */ + ircd_strncpy(state->chptr->mode.apass, t_str, PASSLEN); + else /* remove the old apass */ + *state->chptr->mode.apass = '\0'; + } +} + /* * Helper function to convert bans */ @@ -2356,17 +2699,41 @@ mode_process_clients(struct ParseState *state) } } - /* don't allow local opers to be deopped on local channels */ - if (MyUser(state->sptr) && state->cli_change[i].client != state->sptr && - IsLocalChannel(state->chptr->chname) && - HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) { - send_reply(state->sptr, ERR_ISOPERLCHAN, - cli_name(state->cli_change[i].client), - state->chptr->chname); - continue; + /* check deop for local user */ + if (MyUser(state->sptr)) { + + /* don't allow local opers to be deopped on local channels */ + if (state->cli_change[i].client != state->sptr && + IsLocalChannel(state->chptr->chname) && + HasPriv(state->cli_change[i].client, PRIV_DEOP_LCHAN)) { + send_reply(state->sptr, ERR_ISOPERLCHAN, + cli_name(state->cli_change[i].client), + state->chptr->chname); + continue; + } + + /* don't allow to deop members with an op level that is <= our own level */ + if (state->sptr != state->cli_change[i].client /* but allow to deop oneself */ + && state->member + && OpLevel(member) <= OpLevel(state->member)) { + int equal = (OpLevel(member) == OpLevel(state->member)); + send_reply(state->sptr, ERR_NOTLOWEROPLEVEL, + cli_name(state->cli_change[i].client), + state->chptr->chname, + OpLevel(state->member), OpLevel(member), + "deop", equal ? "the same" : "a higher"); + continue; + } } } + /* set op-level of member being opped */ + if ((state->cli_change[i].flag & (MODE_ADD | MODE_CHANOP)) == + (MODE_ADD | MODE_CHANOP)) { + int old_level = (state->member == NULL) ? -1 : OpLevel(state->member); + SetOpLevel(member, old_level == MAXOPLEVEL ? MAXOPLEVEL : (old_level + 1)); + } + /* accumulate the change */ modebuf_mode_client(state->mbuf, state->cli_change[i].flag, state->cli_change[i].client); @@ -2382,7 +2749,7 @@ mode_process_clients(struct ParseState *state) member->status &= ~(state->cli_change[i].flag & (MODE_CHANOP | MODE_VOICE)); } - } /* for (i = 0; state->cli_change[i].flags; i++) { */ + } /* for (i = 0; state->cli_change[i].flags; i++) */ } /* @@ -2428,7 +2795,8 @@ mode_parse_mode(struct ParseState *state, int *flag_p) */ int mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr, - struct Channel *chptr, int parc, char *parv[], unsigned int flags) + struct Channel *chptr, int parc, char *parv[], unsigned int flags, + struct Membership* member) { static int chan_flags[] = { MODE_CHANOP, 'o', @@ -2440,6 +2808,8 @@ mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr, MODE_INVITEONLY, 'i', MODE_NOPRIVMSGS, 'n', MODE_KEY, 'k', + MODE_APASS, 'A', + MODE_UPASS, 'u', MODE_BAN, 'b', MODE_LIMIT, 'l', MODE_REGONLY, 'r', @@ -2463,6 +2833,7 @@ mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr, state.cptr = cptr; state.sptr = sptr; state.chptr = chptr; + state.member = member; state.parc = parc; state.parv = parv; state.flags = flags; @@ -2513,6 +2884,14 @@ mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr, mode_parse_key(&state, flag_p); break; + case 'A': /* deal with Admin passes */ + mode_parse_apass(&state, flag_p); + break; + + case 'u': /* deal with user passes */ + mode_parse_upass(&state, flag_p); + break; + case 'b': /* deal with bans */ mode_parse_ban(&state, flag_p); break; @@ -2525,8 +2904,8 @@ mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr, default: /* deal with other modes */ mode_parse_mode(&state, flag_p); break; - } /* switch (*modestr) { */ - } /* for (; *modestr; modestr++) { */ + } /* switch (*modestr) */ + } /* for (; *modestr; modestr++) */ if (state.flags & MODE_PARSE_BURST) break; /* don't interpret any more arguments */ @@ -2555,7 +2934,7 @@ mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr, break; /* break out of while loop */ } } - } /* while (*modestr) { */ + } /* while (*modestr) */ /* * the rest of the function finishes building resultant MODEs; if the @@ -2592,6 +2971,12 @@ mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr, if (*state.chptr->mode.key && !(state.done & DONE_KEY)) modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY, state.chptr->mode.key, 0); + if (*state.chptr->mode.upass && !(state.done & DONE_UPASS)) + modebuf_mode_string(state.mbuf, MODE_DEL | MODE_UPASS, + state.chptr->mode.upass, 0); + if (*state.chptr->mode.apass && !(state.done & DONE_APASS)) + modebuf_mode_string(state.mbuf, MODE_DEL | MODE_APASS, + state.chptr->mode.apass, 0); } if (state.done & DONE_BANCLEAN) /* process bans */ @@ -2674,7 +3059,7 @@ joinbuf_join(struct JoinBuf *jbuf, struct Channel *chan, unsigned int flags) remove_user_from_channel(jbuf->jb_source, chan); } else { /* Add user to channel */ - add_user_to_channel(chan, jbuf->jb_source, flags); + add_user_to_channel(chan, jbuf->jb_source, flags, 0); /* send notification to all servers */ if (jbuf->jb_type != JOINBUF_TYPE_CREATE && !IsLocalChannel(chan->chname)) diff --git a/ircd/ircd.c b/ircd/ircd.c index f4666e4..1300dec 100644 --- a/ircd/ircd.c +++ b/ircd/ircd.c @@ -26,6 +26,7 @@ #include "class.h" #include "client.h" #include "crule.h" +#include "destruct_event.h" #include "hash.h" #include "ircd_alloc.h" #include "ircd_events.h" @@ -103,6 +104,7 @@ static char *dpath = DPATH; static struct Timer connect_timer; /* timer structure for try_connections() */ static struct Timer ping_timer; /* timer structure for check_pings() */ +static struct Timer destruct_event_timer; /* timer structure for exec_expired_destruct_events() */ static struct Daemon thisServer = { 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0 }; @@ -617,6 +619,7 @@ int main(int argc, char **argv) { IPcheck_init(); timer_add(timer_init(&connect_timer), try_connections, 0, TT_RELATIVE, 1); timer_add(timer_init(&ping_timer), check_pings, 0, TT_RELATIVE, 1); + timer_add(timer_init(&destruct_event_timer), exec_expired_destruct_events, 0, TT_PERIODIC, 60); CurrentTime = time(NULL); diff --git a/ircd/m_burst.c b/ircd/m_burst.c index 8b84667..0f1e8bf 100644 --- a/ircd/m_burst.c +++ b/ircd/m_burst.c @@ -99,10 +99,12 @@ #include "send.h" #include "struct.h" #include "support.h" +#include "ircd_snprintf.h" #include #include #include +#include /* * ms_burst - server message handler @@ -122,14 +124,46 @@ * parv[n] = % ... * If parv[n] starts with another character: * parv[n] = [:],[:],... - * where is the channel mode (ov) of nick and all following nicks. + * where defines the mode and op-level + * for nick and all following nicks until the + * next field. + * Digits in the field have of two meanings: + * 1) if it is the first field in this BURST message + * that contains digits, and/or when a 'v' is + * present in the : + * The absolute value of the op-level. + * 2) if there are only digits in this field and + * it is not the first field with digits: + * An op-level increment relative to the previous + * op-level. + * First all modeless nicks must be emmitted, + * then all combinations of modes without ops + * (currently that is only 'v') followed by the same + * series but then with ops (currently 'o','ov'). * * Example: - * "S BURST #channel 87654321 +ntkl key 123 AAA,AAB:o,BAA,BAB:ov :%ban1 ban2" + * "A8 B #test 87654321 +ntkAl key secret 123 A8AAG,A8AAC:v,A8AAA:0,A8AAF:2,A8AAD,A8AAB:v1,A8AAE:1 :%ban1 ban2" + * + * list example: + * + * "xxx,sss:v,ttt,aaa:123,bbb,ccc:2,ddd,kkk:v2,lll:2,mmm" + * + * means + * + * xxx // first modeless nicks + * sss +v // then opless nicks + * ttt +v // no ":": everything stays the same + * aaa -123 // first field with digit: absolute value + * bbb -123 + * ccc -125 // only digits, not first field: increment + * ddd -125 + * kkk -2 +v // field with a 'v': absolute value + * lll -4 +v // only digits: increment + * mmm -4 +v * * Anti net.ride code. * - * When the channel already exist, and its TS is larger then + * When the channel already exist, and its TS is larger than * the TS in the BURST message, then we cancel all existing modes. * If its is smaller then the received BURST message is ignored. * If it's equal, then the received modes are just added. @@ -190,7 +224,7 @@ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) switch (*parv[param]) { case '+': /* parameter introduces a mode string */ param += mode_parse(mbuf, cptr, sptr, chptr, parc - param, - parv + param, parse_flags); + parv + param, parse_flags, NULL); break; case '%': /* parameter contains bans */ @@ -266,8 +300,10 @@ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct Client *acptr; char *nicklist = parv[param], *p = 0, *nick, *ptr; - int default_mode = CHFL_DEOPPED | CHFL_BURST_JOINED; + int current_mode = CHFL_DEOPPED | CHFL_BURST_JOINED; int last_mode = CHFL_DEOPPED | CHFL_BURST_JOINED; + int oplevel = -1; /* Mark first field with digits: means the same as 'o' (but with level). */ + int last_oplevel = 0; for (nick = ircd_strtok(&p, nicklist, ","); nick; nick = ircd_strtok(&p, 0, ",")) { @@ -276,12 +312,44 @@ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) *ptr++ = '\0'; if (parse_flags & MODE_PARSE_SET) { - for (default_mode = CHFL_DEOPPED | CHFL_BURST_JOINED; *ptr; - ptr++) { - if (*ptr == 'o') /* has oper status */ - default_mode = (default_mode & ~CHFL_DEOPPED) | CHFL_CHANOP; - else if (*ptr == 'v') /* has voice status */ - default_mode |= CHFL_VOICE; + int current_mode_needs_reset; + for (current_mode_needs_reset = 1; *ptr; ptr++) { + if (*ptr == 'o') { /* has oper status */ + /* + * An 'o' is pre-oplevel protocol, so this is only for + * backwards compatibility. Give them an op-level of + * MAXOPLEVEL so everyone can deop them. + */ + oplevel = MAXOPLEVEL; + if (current_mode_needs_reset) { + current_mode = CHFL_DEOPPED | CHFL_BURST_JOINED; + current_mode_needs_reset = 0; + } + current_mode = (current_mode & ~CHFL_DEOPPED) | CHFL_CHANOP; + } + else if (*ptr == 'v') { /* has voice status */ + if (current_mode_needs_reset) { + current_mode = CHFL_DEOPPED | CHFL_BURST_JOINED; + current_mode_needs_reset = 0; + } + current_mode |= CHFL_VOICE; + oplevel = -1; /* subsequential digits are an absolute op-level value. */ + } + else if (isdigit(*ptr)) { + int level_increment = 0; + if (oplevel == -1) { /* op-level is absolute value? */ + if (current_mode_needs_reset) { + current_mode = CHFL_DEOPPED | CHFL_BURST_JOINED; + current_mode_needs_reset = 0; + } + oplevel = 0; + } + current_mode = (current_mode & ~CHFL_DEOPPED) | CHFL_CHANOP; + do { + level_increment = 10 * level_increment + *ptr++ - '0'; + } while(isdigit(*ptr)); + oplevel += level_increment; + } else /* I don't recognize that flag */ break; /* so stop processing */ } @@ -298,17 +366,22 @@ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) for (ptr = nick; *ptr; ptr++) /* store nick */ nickstr[nickpos++] = *ptr; - if (default_mode != last_mode) { /* if mode changed... */ - last_mode = default_mode; + if (current_mode != last_mode) { /* if mode changed... */ + last_mode = current_mode; + last_oplevel = oplevel; nickstr[nickpos++] = ':'; /* add a specifier */ - if (default_mode & CHFL_CHANOP) - nickstr[nickpos++] = 'o'; - if (default_mode & CHFL_VOICE) + if (current_mode & CHFL_VOICE) nickstr[nickpos++] = 'v'; + if (current_mode & CHFL_CHANOP) + nickpos += ircd_snprintf(0, nickstr + nickpos, sizeof(nickstr) - nickpos, "%u", oplevel); + } else if (current_mode & CHFL_CHANOP && oplevel != last_oplevel) { /* if just op level changed... */ + nickstr[nickpos++] = ':'; /* add a specifier */ + nickpos += ircd_snprintf(0, nickstr + nickpos, sizeof(nickstr) - nickpos, "%u", oplevel - last_oplevel); + last_oplevel = oplevel; } - add_user_to_channel(chptr, acptr, default_mode); + add_user_to_channel(chptr, acptr, current_mode, oplevel); sendcmdto_channel_butserv_butone(acptr, CMD_JOIN, chptr, NULL, "%H", chptr); } } diff --git a/ircd/m_endburst.c b/ircd/m_endburst.c index d13be04..68ac9e1 100644 --- a/ircd/m_endburst.c +++ b/ircd/m_endburst.c @@ -127,11 +127,8 @@ int ms_end_of_burst(struct Client* cptr, struct Client* sptr, int parc, char* pa next_chan = chan->next; if (!chan->members) { /* empty channel */ - if (!(chan->mode.mode & MODE_BURSTADDED)) - sendto_opmask_butone(0, SNO_OLDSNO, "Empty channel %H not added by " - "BURST!", chan); - - sub1_from_channel(chan); /* ok, nuke channel now */ + if ((chan->mode.mode & MODE_BURSTADDED)) + sub1_from_channel(chan); /* New empty channel, schedule it for removal. */ } chan->mode.mode &= ~MODE_BURSTADDED; diff --git a/ircd/m_join.c b/ircd/m_join.c index 9381d2d..e8f9beb 100644 --- a/ircd/m_join.c +++ b/ircd/m_join.c @@ -248,14 +248,15 @@ int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) send_reply(sptr, i, chptr->chname); continue; } - } /* else if ((i = can_join(sptr, chptr, keys))) { */ + } /* else if ((i = can_join(sptr, chptr, keys))) */ joinbuf_join(&join, chptr, flags); } else if (!(chptr = get_channel(sptr, name, CGT_CREATE))) continue; /* couldn't get channel */ else if (check_target_limit(sptr, chptr, chptr->chname, 1)) { /* Note: check_target_limit will only ever return 0 here */ - sub1_from_channel(chptr); /* created it... */ + chptr->members = 0; + destruct_channel(chptr); /* created it... */ continue; } else joinbuf_join(&create, chptr, flags); diff --git a/ircd/m_mode.c b/ircd/m_mode.c index f32ea25..fc77ac7 100644 --- a/ircd/m_mode.c +++ b/ircd/m_mode.c @@ -137,18 +137,19 @@ m_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) MODEBUF_DEST_HACK4)); /* Send HACK(4) notice */ mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, (MODE_PARSE_SET | /* Set the mode */ - MODE_PARSE_FORCE)); /* Force it to take */ + MODE_PARSE_FORCE), /* Force it to take */ + member); return modebuf_flush(&mbuf); } else mode_parse(0, cptr, sptr, chptr, parc - 2, parv + 2, - (member ? MODE_PARSE_NOTOPER : MODE_PARSE_NOTMEMBER)); + (member ? MODE_PARSE_NOTOPER : MODE_PARSE_NOTMEMBER), member); return 0; } modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_CHANNEL | /* Send mode to channel */ MODEBUF_DEST_SERVER)); /* Send mode to servers */ - mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, MODE_PARSE_SET); + mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, MODE_PARSE_SET, member); return modebuf_flush(&mbuf); } @@ -185,7 +186,8 @@ ms_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, (MODE_PARSE_SET | /* Set the mode */ MODE_PARSE_STRICT | /* Interpret it strictly */ - MODE_PARSE_FORCE)); /* And force it to be accepted */ + MODE_PARSE_FORCE), /* And force it to be accepted */ + NULL); } else { if (!(member = find_member_link(chptr, sptr)) || !IsChanOp(member)) { modebuf_init(&mbuf, sptr, cptr, chptr, @@ -195,7 +197,8 @@ ms_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) MODEBUF_DEST_BOUNCE)); /* And bounce the MODE */ mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, (MODE_PARSE_STRICT | /* Interpret it strictly */ - MODE_PARSE_BOUNCE)); /* And bounce the MODE */ + MODE_PARSE_BOUNCE), /* And bounce the MODE */ + member); } else { modebuf_init(&mbuf, sptr, cptr, chptr, (MODEBUF_DEST_CHANNEL | /* Send mode to clients */ @@ -203,7 +206,8 @@ ms_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, (MODE_PARSE_SET | /* Set the mode */ MODE_PARSE_STRICT | /* Interpret it strictly */ - MODE_PARSE_FORCE)); /* And force it to be accepted */ + MODE_PARSE_FORCE), /* And force it to be accepted */ + member); } } diff --git a/ircd/m_opmode.c b/ircd/m_opmode.c index 01db05a..ddfd734 100644 --- a/ircd/m_opmode.c +++ b/ircd/m_opmode.c @@ -123,7 +123,8 @@ int ms_opmode(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, (MODE_PARSE_SET | /* Set the modes on the channel */ MODE_PARSE_STRICT | /* Be strict about it */ - MODE_PARSE_FORCE)); /* And force them to be accepted */ + MODE_PARSE_FORCE), /* And force them to be accepted */ + NULL); modebuf_flush(&mbuf); /* flush the modes */ @@ -166,7 +167,8 @@ int mo_opmode(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, (MODE_PARSE_SET | /* set the modes on the channel */ - MODE_PARSE_FORCE)); /* And force them to be accepted */ + MODE_PARSE_FORCE), /* And force them to be accepted */ + NULL); modebuf_flush(&mbuf); /* flush the modes */ diff --git a/ircd/s_err.c b/ircd/s_err.c index 0fdcc6c..5ad955c 100644 --- a/ircd/s_err.c +++ b/ircd/s_err.c @@ -36,7 +36,7 @@ static Numeric replyTable[] = { /* 003 */ { RPL_CREATED, ":This server was created %s", "003" }, /* 004 */ - { RPL_MYINFO, "%s %s dioswkgx biklmnopstvr bklov", "004" }, + { RPL_MYINFO, "%s %s dioswkgx Abiklmnopstuvr Abklouv", "004" }, /* 005 */ { RPL_ISUPPORT, "%s :are supported by this server", "005" }, /* 006 */ @@ -1132,7 +1132,7 @@ static Numeric replyTable[] = { /* 549 */ { 0 }, /* 550 */ - { 0 }, + { ERR_NOTLOWEROPLEVEL, "%s %s %hu %hu :Cannot %s someone with %s op-level", "550" }, /* 551 */ { 0 }, /* 552 */ diff --git a/ircd/s_misc.c b/ircd/s_misc.c index 62a3372..1344f86 100644 --- a/ircd/s_misc.c +++ b/ircd/s_misc.c @@ -476,11 +476,11 @@ int exit_client(struct Client *cptr, /* Connection being handled by get_client_name(killer, HIDE_IP)); sendto_opmask_butone(0, SNO_NETWORK, "Net break: %C %C (%s)", cli_serv(victim)->up, victim, comment); - } #ifdef HEAD_IN_SAND_MAP - map_update(victim); + map_update(victim); #endif + } /* * First generate the needed protocol for the other server links -- 2.20.1