From e54ec73c9572a6d6351e333225bb8f00d805b9e9 Mon Sep 17 00:00:00 2001 From: Michael Poole Date: Tue, 15 Nov 2005 03:13:22 +0000 Subject: [PATCH] Make DESTRUCT crossing CREATE or BURST not send a BURST. git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/branches/u2_10_12_branch@1553 c9e4aea6-c8fd-4c43-8297-357d70d61c8c --- ChangeLog | 9 +++++ ircd/channel.c | 4 +-- ircd/m_destruct.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 98 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5979a74..5ea102d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2005-11-14 Carlo Wood + + * ircd/channel.c (modebuf_flush_int): Fix test for limitdel. + (modebuf_mode_uint): Make sure the limit is included as an + argument when necessary (and only when necessary) in a bounce. + + * ircd/m_destruct.c (ms_destruct): Generate a mode bounce instead + of burst to resynchronize a non-empty destructed channel. + 2005-11-14 Michael Poole * ircd/channel.c (find_no_nickchange_channel): Disallow nick diff --git a/ircd/channel.c b/ircd/channel.c index 57839aa..ae27dae 100644 --- a/ircd/channel.c +++ b/ircd/channel.c @@ -1771,7 +1771,7 @@ modebuf_flush_int(struct ModeBuf *mbuf, int all) * limit is supressed if we're removing it; we have to figure out which * direction is the direction for it to be removed, though... */ - limitdel |= (mbuf->mb_dest & MODEBUF_DEST_HACK2) ? MODE_DEL : MODE_ADD; + limitdel |= (mbuf->mb_dest & MODEBUF_DEST_BOUNCE) ? MODE_DEL : MODE_ADD; for (i = 0; i < mbuf->mb_count; i++) { if (MB_TYPE(mbuf, i) & MODE_SAVE) @@ -1968,7 +1968,7 @@ modebuf_mode_uint(struct ModeBuf *mbuf, unsigned int mode, unsigned int uint) assert(0 != mbuf); assert(0 != (mode & (MODE_ADD | MODE_DEL))); - if (mode == (MODE_LIMIT | MODE_DEL)) { + if (mode == (MODE_LIMIT | ((mbuf->mb_dest & MODEBUF_DEST_BOUNCE) ? MODE_ADD : MODE_DEL))) { mbuf->mb_rem |= mode; return; } diff --git a/ircd/m_destruct.c b/ircd/m_destruct.c index 632e27a..cafbb6e 100644 --- a/ircd/m_destruct.c +++ b/ircd/m_destruct.c @@ -1,6 +1,6 @@ /* * IRC - Internet Relay Chat, ircd/m_destruct.c - * Copyright (C) 1997 Carlo Wood. + * Copyright (C) 1997, 2005 Carlo Wood. * * See file AUTHORS in IRC package for additional names of * the programmers. @@ -113,7 +113,93 @@ int ms_destruct(struct Client* cptr, struct Client* sptr, int parc, char* parv[] /* Don't pass on DESTRUCT messages for channels that are not empty, but instead send a BURST msg upstream. */ if (chptr->users > 0) { +#if 0 /* Once all servers are 2.10.12, this can be used too. + Until then we have to use CREATE and MODE to + get the message accross, because older server do + not accept a BURST outside the net.burst. */ send_channel_modes(cptr, chptr); +#else + /* This happens when a JOIN and DESTRUCT crossed, ie: + + server1 ----------------- server2 + DESTRUCT--> <-- JOIN,MODE + + Where the JOIN and MODE are the result of joining + the zannel before it expired on server2, or in the + case of simulateous expiration, a DESTRUCT crossing + with another DESTRUCT (that will be ignored) and + a CREATE of a user joining right after that: + + server1 ----------------- server2 + DESTRUCT--> <-- DESTRUCT <-- CREATE + + in both cases, when the DESTRUCT arrives on + server2 we need to send synchronizing messages + upstream (to server1). Since sending two CREATEs + or JOINs for the same user after another is a + protocol violation, we first have to send PARTs + (we can't send a DESTRUCT because 2.10.11 ignores + DESTRUCT messages (just passes them on) and has + a bug that causes two JOIN's for the same user to + result in that user being on the channel twice). */ + + struct Membership *chanop; + struct Membership *member; + int is_real_chanop; + struct ModeBuf mbuf; + struct Ban *link; + + /* First find a channel op, if any. */ + for (chanop = chptr->members; chanop && !IsChanOp(chanop); chanop = chanop->next_member); + /* Now chanop is either a channel op, or NULL. */ + is_real_chanop = chanop ? 1 : 0; + + /* Next, send all PARTs upstream. */ + for (member = chptr->members; member; member = member->next_member) + sendcmdto_one(member->user, CMD_PART, cptr, "%H", chptr); + + /* Next, send a CREATE. If we don't have a chanop, just use the first member. */ + if (!chanop) + chanop = chptr->members; + sendcmdto_one(chanop->user, CMD_CREATE, cptr, "%H %Tu", chptr, chanTS); + + /* Next, send JOINs for possible other members. */ + for (member = chptr->members; member; member = member->next_member) + if (member != chanop) + sendcmdto_one(member->user, CMD_JOIN, cptr, "%H", chptr); + + /* Build MODE strings. We use MODEBUF_DEST_BOUNCE with MODE_DEL to assure + that the resulting MODEs are only sent upstream. */ + modebuf_init(&mbuf, sptr, cptr, chptr, MODEBUF_DEST_SERVER | MODEBUF_DEST_BOUNCE); + + /* Op/voice the users as appropriate. We use MODE_DEL because we fake a bounce. */ + for (member = chptr->members; member; member = member->next_member) + { + if (IsChanOp(member) && member != chanop) + modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, member->user, OpLevel(member)); + if (HasVoice(member)) + modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, member->user, MAXOPLEVEL + 1); + } + + /* Send other MODEs. */ + modebuf_mode(&mbuf, MODE_DEL | chptr->mode.mode); + if (*chptr->mode.key) + modebuf_mode_string(&mbuf, MODE_DEL | MODE_KEY, chptr->mode.key, 0); + if (chptr->mode.limit) + modebuf_mode_uint(&mbuf, MODE_DEL | MODE_LIMIT, chptr->mode.limit); + if (*chptr->mode.upass) + modebuf_mode_string(&mbuf, MODE_DEL | MODE_UPASS, chptr->mode.upass, 0); + if (*chptr->mode.apass) + modebuf_mode_string(&mbuf, MODE_DEL | MODE_APASS, chptr->mode.apass, 0); + for (link = chptr->banlist; link; link = link->next) + modebuf_mode_string(&mbuf, MODE_DEL | MODE_BAN, link->banstr, 0); + modebuf_flush(&mbuf); + + /* When chanop wasn't really a chanop, let him deop himself. */ + if (!is_real_chanop) + sendcmdto_one(chanop->user, CMD_MODE, cptr, "%H -o %C", chptr, chanop->user); +#endif + return 0; } -- 2.20.1