X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=ircd%2Fm_destruct.c;h=f5b7dd60cfc118cbda14667fcfbf4ea1909403e2;hb=refs%2Fheads%2Fupstream;hp=c05e41e2eee3ce79a68bd23ecc7491d125cd8028;hpb=80881d85337d93d70b67a505ae5178199b1b3155;p=ircu2.10.12-pk.git diff --git a/ircd/m_destruct.c b/ircd/m_destruct.c index c05e41e..f5b7dd6 100644 --- a/ircd/m_destruct.c +++ b/ircd/m_destruct.c @@ -1,7 +1,6 @@ /* * IRC - Internet Relay Chat, ircd/m_destruct.c - * Copyright (C) 1990 Jarkko Oikarinen and - * University of Oulu, Computing Center + * Copyright (C) 1997, 2005 Carlo Wood. * * See file AUTHORS in IRC package for additional names of * the programmers. @@ -23,97 +22,75 @@ * $Id$ */ -/* - * m_functions execute protocol messages on this server: - * - * cptr is always NON-NULL, pointing to a *LOCAL* client - * structure (with an open socket connected!). This - * identifies the physical socket where the message - * originated (or which caused the m_function to be - * executed--some m_functions may call others...). - * - * sptr is the source of the message, defined by the - * prefix part of the message if present. If not - * or prefix not found, then sptr==cptr. - * - * (!IsServer(cptr)) => (cptr == sptr), because - * prefixes are taken *only* from servers... - * - * (IsServer(cptr)) - * (sptr == cptr) => the message didn't - * have the prefix. - * - * (sptr != cptr && IsServer(sptr) means - * the prefix specified servername. (?) - * - * (sptr != cptr && !IsServer(sptr) means - * that message originated from a remote - * user (not local). - * - * combining - * - * (!IsServer(sptr)) means that, sptr can safely - * taken as defining the target structure of the - * message in this server. - * - * *Always* true (if 'parse' and others are working correct): - * - * 1) sptr->from == cptr (note: cptr->from == cptr) - * - * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr - * *cannot* be a local connection, unless it's - * actually cptr!). [MyConnect(x) should probably - * be defined as (x == x->from) --msa ] - * - * parc number of variable parameter strings (if zero, - * parv is allowed to be NULL) - * - * parv a NULL terminated list of parameter pointers, - * - * parv[0], sender (prefix string), if not present - * this points to an empty string. - * parv[1]...parv[parc-1] - * pointers to additional parameters - * parv[parc] == NULL, *always* - * - * note: it is guaranteed that parv[0]..parv[parc-1] are all - * non-NULL pointers. - */ -#if 0 -/* - * No need to include handlers.h here the signatures must match - * and we don't need to force a rebuild of all the handlers everytime - * we add a new one to the list. --Bleep - */ -#include "handlers.h" -#endif /* 0 */ +#include "config.h" + #include "client.h" #include "hash.h" #include "ircd.h" +#include "ircd_log.h" #include "ircd_reply.h" #include "ircd_string.h" #include "msg.h" #include "numeric.h" #include "numnicks.h" #include "send.h" +#include "channel.h" +#include "destruct_event.h" -#include +/* #include -- Now using assert in ircd_log.h */ #include /* * ms_destruct - server message handler * + * Added 1997 by Run, actually coded and used since 2002. + * * parv[0] = sender prefix * parv[1] = channel channelname * parv[2] = channel time stamp * - * This function does nothing, it does passes DESTRUCT to the other servers. - * In the future we will start to use this message. - * + * This message is intended to destruct _empty_ channels. + * + * The reason it is needed is to somehow add the notion + * "I destructed information" to the networks state + * (also messages that are still propagating are part + * of the global state). Without it the network could + * easily be desynced as a result of destructing a channel + * on only a part of the network while keeping the modes + * and creation time on others. + * There are three possible ways a DESTRUCT message is + * handled by remote servers: + * 1) The channel is empty and has the same timestamp + * as on the message. Conclusion: The channel has + * not been destructed and recreated in the meantime, + * this means that the normal synchronization rules + * account and we react as if we decided to destruct + * the channel ourselves: we destruct the channel and + * send a DESTRUCT in all directions. + * 2) The channel is not empty. In case we cannot remove + * it and do not propagate the DESTRUCT message. Instead + * a resynchronizing BURST message is sent upstream + * in order to restore the channel on that side (which + * will have a TS younger than the current channel if + * it was recreated and will thus be fully synced, just + * like in the case of a real net-junction). + * 3) The channel is empty, but the creation time of the + * channel is older than the timestamp on the message. + * This can happen when there is more than one minute + * lag and remotely a channel was created slightly + * after we created the channel, being abandoned again + * and staying empty for a minute without that our + * CREATE reached that remote server. The remote server + * then could have generated the DESTRUCT. In the meantime + * our user also left the channel. We can ignore the + * destruct because it comes from an 'area' that will + * be overridden by our own CREATE: the state that generated + * this DESTRUCT is 'history'. */ int ms_destruct(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { time_t chanTS; /* Creation time of the channel */ + struct Channel* chptr; assert(0 != cptr); assert(0 != sptr); @@ -122,58 +99,100 @@ int ms_destruct(struct Client* cptr, struct Client* sptr, int parc, char* parv[] if (parc < 3 || EmptyString(parv[2])) return need_more_params(sptr,"DESTRUCT"); - /* Don't pass on DESTRUCT messages for channels that exist */ - if (FindChannel(parv[1])) - return 0; - chanTS = atoi(parv[2]); - /* Pass on DESTRUCT message */ - sendcmdto_serv_butone(sptr, CMD_DESTRUCT, cptr, "%s %Tu", parv[1], chanTS); - - return 0; -} - -#if 0 -/* - * m_destruct - * - * parv[0] = sender prefix - * parv[1] = channel channelname - * parv[2] = channel time stamp - * - * This function does nothing, it does passes DESTRUCT to the other servers. - * In the future we will start to use this message. - * - */ -int m_destruct(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) -{ - time_t chanTS; /* Creation time of the channel */ + /* Ignore DESTRUCT messages for non-existing channels. */ + if (!(chptr = FindChannel(parv[1]))) + return 0; - if (parc < 3 || *parv[2] == '\0') + /* Ignore DESTRUCT when the channel is older than the + timestamp on the message. */ + if (chanTS > chptr->creationtime) return 0; -#ifdef GODMODE - /* Allow DESTRUCT from user */ - if (MyUser(sptr)) - sptr = &me; - else + /* 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 *member; + struct ModeBuf mbuf; + struct Ban *link; + + /* 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 JOINs for all members. */ + for (member = chptr->members; member; member = member->next_member) + 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)) + 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); #endif - /* sanity checks: Only accept DESTRUCT messages from servers */ - if (!IsServer(sptr)) return 0; + } - /* Don't pass on DESTRUCT messages for channels that exist */ - if (FindChannel(parv[1])) - return 0; + /* Pass on DESTRUCT message and ALSO bounce it back! */ + sendcmdto_serv_butone(&me, CMD_DESTRUCT, 0, "%s %Tu", parv[1], chanTS); - chanTS = atoi(parv[2]); - - /* Pass on DESTRUCT message */ - sendto_highprot_butone(cptr, 10, "%s DESTRUCT %s " TIME_T_FMT, /* XXX DEAD */ - NumServ(sptr), parv[1], chanTS); + /* Remove the empty channel. */ + if (chptr->destruct_event) + remove_destruct_event(chptr); + destruct_channel(chptr); return 0; } -#endif