From beae1b811daeae08b761c0ba2ef4f4d845645d5e Mon Sep 17 00:00:00 2001 From: "Kevin L. Mitchell" Date: Thu, 4 May 2000 15:33:36 +0000 Subject: [PATCH] Author: Kev Log message: reimplement BURST with empty channel processing in m_end_of_burst git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@233 c9e4aea6-c8fd-4c43-8297-357d70d61c8c --- ChangeLog | 22 ++++- include/channel.h | 4 + ircd/channel.c | 86 +++++++++++++++- ircd/m_burst.c | 242 +++++++++++++++++++++++++++++++++++++++++++++- ircd/m_endburst.c | 21 ++++ 5 files changed, 370 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index b042b7f..fd2e170 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,25 @@ +2000-05-04 Kevin L. Mitchell + + * ircd/m_burst.c (ms_burst): debugged ban processing; removed + debugging hooks + + * ircd/channel.c (modebuf_extract): remove debugging + sendto_opmask_butone calls + 2000-05-03 Kevin L. Mitchell + * ircd/channel.c: support a couple of new flags to support using + mode_parse; fix some bugs with 0 struct ModeBuf *; implementation + of modebuf_extract to extract added flags for use by ms_burst + + * include/channel.h: a couple of new flags to support using + mode_parse inside ms_burst + + * ircd/m_burst.c (ms_burst): brand new implementation of BURST + + * ircd/m_endburst.c: add loop to processing of end_of_burst to + free empty channels after the BURST is over. + * ircd/m_server.c: convert to use new send.c functions--I wanted to rewrite it from scratch, but the logic's pretty complex; I may still rewrite it, though... @@ -1096,7 +1116,7 @@ # # ChangeLog for ircu2.10.11 # -# $Id: ChangeLog,v 1.130 2000-05-03 14:50:32 kev Exp $ +# $Id: ChangeLog,v 1.131 2000-05-04 15:33:35 kev Exp $ # # Insert new changes at beginning of the change list. # diff --git a/include/channel.h b/include/channel.h index 3d2b729..b59b402 100644 --- a/include/channel.h +++ b/include/channel.h @@ -94,6 +94,7 @@ struct Client; #define MODE_LISTED 0x10000 #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 */ /* * mode flags which take another parameter (With PARAmeterS) */ @@ -356,6 +357,7 @@ extern void modebuf_mode_string(struct ModeBuf *mbuf, unsigned int mode, extern void modebuf_mode_client(struct ModeBuf *mbuf, unsigned int mode, struct Client *client); extern int modebuf_flush(struct ModeBuf *mbuf); +extern void modebuf_extract(struct ModeBuf *mbuf, char *buf); extern void mode_ban_invalidate(struct Channel *chan); extern void mode_invite_clear(struct Channel *chan); @@ -370,6 +372,8 @@ extern int mode_parse(struct ModeBuf *mbuf, struct Client *cptr, #define MODE_PARSE_BOUNCE 0x08 /* we will be bouncing the modes */ #define MODE_PARSE_NOTOPER 0x10 /* send "not chanop" to user */ #define MODE_PARSE_NOTMEMBER 0x20 /* send "not member" to user */ +#define MODE_PARSE_WIPEOUT 0x40 /* wipe out +k and +l during burst */ +#define MODE_PARSE_BURST 0x80 /* be even more strict w/extra args */ extern void joinbuf_init(struct JoinBuf *jbuf, struct Client *source, struct Client *connect, unsigned int type, diff --git a/ircd/channel.c b/ircd/channel.c index d110fe0..0e5bbb5 100644 --- a/ircd/channel.c +++ b/ircd/channel.c @@ -26,6 +26,7 @@ #include "ircd_alloc.h" #include "ircd_chattr.h" #include "ircd_reply.h" +#include "ircd_snprintf.h" #include "ircd_string.h" #include "list.h" #include "match.h" @@ -3069,6 +3070,70 @@ modebuf_flush(struct ModeBuf *mbuf) return modebuf_flush_int(mbuf, 1); } +/* + * This extracts the simple modes contained in mbuf + */ +void +modebuf_extract(struct ModeBuf *mbuf, char *buf) +{ + static int flags[] = { +/* MODE_CHANOP, 'o', */ +/* MODE_VOICE, 'v', */ + MODE_PRIVATE, 'p', + MODE_SECRET, 's', + MODE_MODERATED, 'm', + MODE_TOPICLIMIT, 't', + MODE_INVITEONLY, 'i', + MODE_NOPRIVMSGS, 'n', + MODE_KEY, 'k', +/* MODE_BAN, 'b', */ + MODE_LIMIT, 'l', + 0x0, 0x0 + }; + unsigned int add; + int i, bufpos = 0, len; + int *flag_p; + char *key = 0, limitbuf[20]; + + assert(0 != mbuf); + assert(0 != buf); + + buf[0] = '\0'; + + add = mbuf->mb_add; + + 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); + + 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), "%d", MB_UINT(mbuf, i)); + } + } + + if (!add) + return; + + buf[bufpos++] = '+'; /* start building buffer */ + + for (flag_p = flags; flag_p[0]; flag_p += 2) + if (*flag_p & add) + buf[bufpos++] = flag_p[1]; + + for (i = 0, len = bufpos; i < len; i++) { + if (buf[i] == 'k') + build_string(buf, &bufpos, key, 0, ' '); + else if (buf[i] == 'l') + build_string(buf, &bufpos, limitbuf, 0, ' '); + } + + buf[bufpos] = '\0'; + + return; +} + /* * Simple function to invalidate bans */ @@ -3156,7 +3221,8 @@ mode_parse_limit(struct ParseState *state, int *flag_p) state->parc--; state->max_args--; - if (!t_limit) /* if it was zero, ignore it */ + if (!(state->flags & MODE_PARSE_WIPEOUT) && + (!t_limit || t_limit == state->chptr->mode.limit)) return; } else t_limit = state->chptr->mode.limit; @@ -3243,6 +3309,10 @@ mode_parse_key(struct ParseState *state, int *flag_p) return; } + if (!(state->flags & MODE_PARSE_WIPEOUT) && state->dir == MODE_ADD && + !ircd_strcmp(state->chptr->mode.key, t_str)) + return; /* no key change */ + assert(0 != state->mbuf); if (state->flags & MODE_PARSE_BOUNCE) { @@ -3756,6 +3826,9 @@ mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr, } /* switch (*modestr) { */ } /* for (; *modestr; modestr++) { */ + if (state.flags & MODE_PARSE_BURST) + break; /* don't interpret any more arguments */ + if (state.parc > 0) { /* process next argument in string */ modestr = state.parv[state.args_used++]; state.parc--; @@ -3786,10 +3859,17 @@ mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr, * the rest of the function finishes building resultant MODEs; if the * origin isn't a member or an oper, skip it. */ - if (state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) + if (!state.mbuf || state.flags & (MODE_PARSE_NOTOPER | MODE_PARSE_NOTMEMBER)) return state.args_used; /* tell our parent how many args we gobbled */ - assert(0 != state.mbuf); + if (state.flags & MODE_PARSE_WIPEOUT) { + if (!(state.done & DONE_LIMIT)) /* remove the old limit */ + modebuf_mode_uint(state.mbuf, MODE_DEL | MODE_LIMIT, + state.chptr->mode.limit); + if (!(state.done & DONE_KEY)) /* remove the old key */ + modebuf_mode_string(state.mbuf, MODE_DEL | MODE_KEY, + state.chptr->mode.key, 0); + } if (state.done & DONE_BANCLEAN) /* process bans */ mode_process_bans(&state); diff --git a/ircd/m_burst.c b/ircd/m_burst.c index 8bdf174..55a00f2 100644 --- a/ircd/m_burst.c +++ b/ircd/m_burst.c @@ -95,6 +95,7 @@ #include "ircd_reply.h" #include "ircd_string.h" #include "list.h" +#include "match.h" #include "msg.h" #include "numeric.h" #include "numnicks.h" @@ -102,6 +103,7 @@ #include "s_misc.h" #include "send.h" #include "struct.h" +#include "support.h" #include #include @@ -137,6 +139,244 @@ * If its is smaller then the received BURST message is ignored. * If it's equal, then the received modes are just added. */ +int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) +{ + struct ModeBuf modebuf, *mbuf = 0; + struct Channel *chptr; + time_t timestamp; + struct Membership *member; + struct SLink *lp, **lp_p; + unsigned int parse_flags = (MODE_PARSE_FORCE | MODE_PARSE_BURST); + int param, nickpos = 0, banpos = 0; + char modestr[IRC_BUFSIZE], nickstr[IRC_BUFSIZE], banstr[IRC_BUFSIZE]; + + if (parc < 4) + return 0; + + if (!IsBurst(sptr)) /* don't allow BURST outside of burst */ + return exit_client_msg(cptr, cptr, &me, "HACK: BURST message outside " + "net.burst from %s", sptr->name); + + if (!(chptr = get_channel(sptr, parv[1], CGT_CREATE))) + return 0; /* can't create the channel? */ + + timestamp = atoi(parv[2]); + + /* turn off burst joined flag */ + for (member = chptr->members; member; member = member->next_member) + member->status &= ~CHFL_BURST_JOINED; + + if (!chptr->creationtime) /* mark channel as created during BURST */ + chptr->mode.mode |= MODE_BURSTADDED; + + /* new channel or an older one */ + if (!chptr->creationtime || chptr->creationtime > timestamp) { + chptr->creationtime = timestamp; + + modebuf_init(mbuf = &modebuf, sptr, cptr, chptr, MODEBUF_DEST_CHANNEL); + modebuf_mode(mbuf, MODE_DEL | chptr->mode.mode); /* wipeout modes */ + chptr->mode.mode &= ~(MODE_ADD | MODE_DEL | MODE_PRIVATE | MODE_SECRET | + MODE_MODERATED | MODE_TOPICLIMIT | MODE_INVITEONLY | + MODE_NOPRIVMSGS); + + parse_flags |= (MODE_PARSE_SET | MODE_PARSE_WIPEOUT); /* wipeout keys */ + + /* mark bans for wipeout */ + for (lp = chptr->banlist; lp; lp = lp->next) + lp->flags |= CHFL_BURST_BAN_WIPEOUT; + } else if (chptr->creationtime == timestamp) { + modebuf_init(mbuf = &modebuf, sptr, cptr, chptr, MODEBUF_DEST_CHANNEL); + + parse_flags |= MODE_PARSE_SET; /* set new modes */ + } + + param = 3; /* parse parameters */ + while (param < parc) { + switch (*parv[param]) { + case '+': /* parameter introduces a mode string */ + param += mode_parse(mbuf, cptr, sptr, chptr, parc - param, + parv + param, parse_flags); + break; + + case '%': /* parameter contains bans */ + if (parse_flags & MODE_PARSE_SET) { + char *banlist = parv[param] + 1, *p = 0, *ban, *ptr; + struct SLink *newban; + + for (ban = ircd_strtok(&p, banlist, " "); ban; + ban = ircd_strtok(&p, 0, " ")) { + ban = collapse(pretty_mask(ban)); + + /* + * Yeah, we should probably do this elsewhere, and make it better + * and more general; this will hold until we get there, though. + * I dislike the current add_banid API... -Kev + * + * I wish there were a better algo. for this than the n^2 one + * shown below *sigh* + */ + for (lp = chptr->banlist; lp; lp = lp->next) { + if (!ircd_strcmp(lp->value.ban.banstr, ban)) { + ban = 0; /* don't add ban */ + lp->flags &= ~CHFL_BURST_BAN_WIPEOUT; /* not wiping out */ + break; /* new ban already existed; don't even repropagate */ + } else if (!(lp->flags & CHFL_BURST_BAN_WIPEOUT) && + !mmatch(lp->value.ban.banstr, ban)) { + ban = 0; /* don't add ban unless wiping out bans */ + break; /* new ban is encompassed by an existing one; drop */ + } else if (!mmatch(ban, lp->value.ban.banstr)) + lp->flags |= CHFL_BAN_OVERLAPPED; /* remove overlapping ban */ + + if (!lp->next) + break; + } + + if (ban) { /* add the new ban to the end of the list */ + /* Build ban buffer */ + if (!banpos) { + banstr[banpos++] = ' '; + banstr[banpos++] = ':'; + banstr[banpos++] = '%'; + } else + banstr[banpos++] = ' '; + for (ptr = ban; *ptr; ptr++) /* add ban to buffer */ + banstr[banpos++] = *ptr; + + newban = make_link(); /* create new ban */ + + DupString(newban->value.ban.banstr, ban); + DupString(newban->value.ban.who, sptr->name); + newban->value.ban.when = TStime(); + + newban->flags = CHFL_BAN | CHFL_BURST_BAN; /* set flags */ + if ((ptr = strrchr(ban, '@')) && check_if_ipmask(ptr + 1)) + newban->flags |= CHFL_BAN_IPMASK; + + newban->next = 0; + if (lp) + lp->next = newban; /* link it in */ + else + chptr->banlist = newban; + } + } + } + param++; /* look at next param */ + break; + + default: /* parameter contains clients */ + { + struct Client *acptr; + char *nicklist = parv[param], *p = 0, *nick, *ptr; + int default_mode = CHFL_DEOPPED | CHFL_BURST_JOINED; + int last_mode = CHFL_DEOPPED | CHFL_BURST_JOINED; + + for (nick = ircd_strtok(&p, nicklist, ","); nick; + nick = ircd_strtok(&p, 0, " ")) { + + if ((ptr = strchr(nick, ':'))) { /* new flags; deal */ + *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; + else /* I don't recognize that flag */ + break; /* so stop processing */ + } + } + } + + if (!(acptr = findNUser(nick)) || acptr->from != cptr) + continue; /* ignore this client */ + + /* Build nick buffer */ + nickstr[nickpos] = nickpos ? ',' : ' '; /* first char */ + nickpos++; + + for (ptr = nick; *ptr; ptr++) /* store nick */ + nickstr[nickpos++] = *ptr; + + if (default_mode != last_mode) { /* if mode changed... */ + last_mode = default_mode; + + nickstr[nickpos++] = ':'; /* add a specifier */ + if (default_mode & CHFL_CHANOP) + nickstr[nickpos++] = 'o'; + if (default_mode & CHFL_VOICE) + nickstr[nickpos++] = 'v'; + } + + add_user_to_channel(chptr, acptr, default_mode); + sendcmdto_channel_butserv(acptr, CMD_JOIN, chptr, "%H", chptr); + } + } + param++; + break; + } /* switch (*parv[param]) { */ + } /* while (param < parc) { */ + + nickstr[nickpos] = '\0'; + banstr[banpos] = '\0'; + + if (parse_flags & MODE_PARSE_SET) { + modebuf_extract(mbuf, modestr + 1); /* for sending BURST onward */ + modestr[0] = modestr[1] ? ' ' : '\0'; + } else + modestr[0] = '\0'; + + sendcmdto_serv_butone(sptr, CMD_BURST, cptr, "%H %Tu%s%s%s", chptr, + chptr->creationtime, modestr, nickstr, banstr); + + if (parse_flags & MODE_PARSE_WIPEOUT || banpos) + mode_ban_invalidate(chptr); + + if (parse_flags & MODE_PARSE_SET) { /* any modes changed? */ + /* first deal with channel members */ + for (member = chptr->members; member; member = member->next_member) { + if (member->status & CHFL_BURST_JOINED) { /* joined during burst */ + if (member->status & CHFL_CHANOP) + modebuf_mode_client(mbuf, MODE_ADD | CHFL_CHANOP, member->user); + if (member->status & CHFL_VOICE) + modebuf_mode_client(mbuf, MODE_ADD | CHFL_VOICE, member->user); + } else if (parse_flags & MODE_PARSE_WIPEOUT) { /* wipeout old ops */ + if (member->status & CHFL_CHANOP) + modebuf_mode_client(mbuf, MODE_DEL | CHFL_CHANOP, member->user); + if (member->status & CHFL_VOICE) + modebuf_mode_client(mbuf, MODE_DEL | CHFL_VOICE, member->user); + member->status = ((member->status & ~(CHFL_CHANOP | CHFL_VOICE)) | + CHFL_DEOPPED); + } + } + + /* Now deal with channel bans */ + lp_p = &chptr->banlist; + while (*lp_p) { + lp = *lp_p; + + /* remove ban from channel */ + if (lp->flags & (CHFL_BAN_OVERLAPPED | CHFL_BURST_BAN_WIPEOUT)) { + modebuf_mode_string(mbuf, MODE_DEL | MODE_BAN, + lp->value.ban.banstr, 1); /* let it free banstr */ + + *lp_p = lp->next; /* clip out of list */ + MyFree(lp->value.ban.who); /* free who */ + free_link(lp); /* free ban */ + continue; + } else if (lp->flags & CHFL_BURST_BAN) /* add ban to channel */ + modebuf_mode_string(mbuf, MODE_ADD | MODE_BAN, + lp->value.ban.banstr, 0); /* don't free banstr */ + + lp->flags &= (CHFL_BAN | CHFL_BAN_IPMASK); /* reset the flag */ + lp_p = &(*lp_p)->next; + } + } + + return mbuf ? modebuf_flush(mbuf) : 0; +} +#if 0 int ms_burst(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { struct Channel* chptr; @@ -821,7 +1061,7 @@ int ms_burst(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) } return 0; } - +#endif #if 0 /* diff --git a/ircd/m_endburst.c b/ircd/m_endburst.c index 605a45c..ec42f72 100644 --- a/ircd/m_endburst.c +++ b/ircd/m_endburst.c @@ -87,6 +87,7 @@ */ #include "handlers.h" #endif /* 0 */ +#include "channel.h" #include "client.h" #include "hash.h" #include "ircd.h" @@ -107,10 +108,15 @@ * This the last message in a net.burst. * It clears a flag for the server sending the burst. * + * As of 10.11, to fix a bug in the way BURST is processed, it also + * makes sure empty channels are deleted + * * parv[0] - sender prefix */ int ms_end_of_burst(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { + struct Channel *chan, *next_chan; + assert(0 != cptr); assert(0 != sptr); if (!IsServer(sptr)) @@ -123,6 +129,21 @@ int ms_end_of_burst(struct Client* cptr, struct Client* sptr, int parc, char* pa if (MyConnect(sptr)) sendcmdto_one(&me, CMD_END_OF_BURST_ACK, sptr, ""); + /* Count through channels... */ + for (chan = GlobalChannelList; chan; chan = next_chan) { + 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 */ + } + + chan->mode.mode &= ~MODE_BURSTADDED; + } + return 0; } -- 2.20.1