X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=ircd%2Fm_join.c;h=e0049667ca8a1eb691f603312e453ad0bb8688b6;hb=refs%2Fheads%2Fupstream;hp=9056c077837cb09dde7a6d3d4e964c3976b35320;hpb=534a8b34c9ece2d6aa4d003394b397ed48aa4ea9;p=ircu2.10.12-pk.git diff --git a/ircd/m_join.c b/ircd/m_join.c index 9056c07..e004966 100644 --- a/ircd/m_join.c +++ b/ircd/m_join.c @@ -158,7 +158,7 @@ int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) if (!(chptr = FindChannel(name))) { if (((name[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS)) - || strlen(name) >= IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) { + || strlen(name) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) { send_reply(sptr, ERR_NOSUCHCHANNEL, name); continue; } @@ -167,7 +167,7 @@ int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) continue; /* Try to add the new channel as a recent target for the user. */ - if (check_target_limit(sptr, chptr, chptr->chname, 1)) { + if (check_target_limit(sptr, chptr, chptr->chname, 0)) { chptr->members = 0; destruct_channel(chptr); continue; @@ -239,16 +239,30 @@ int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) /* Is there some reason the user may not join? */ if (err) { - send_reply(sptr, err, chptr->chname); + switch(err) { + case ERR_NEEDREGGEDNICK: + send_reply(sptr, + ERR_NEEDREGGEDNICK, + chptr->chname, + feature_str(FEAT_URLREG)); + break; + default: + send_reply(sptr, err, chptr->chname); + break; + } continue; } joinbuf_join(&join, chptr, flags); if (flags & CHFL_CHANOP) { - /* Send a MODE to the other servers. If the user used the A/U pass, - * let his server op him, otherwise let him op himself. */ struct ModeBuf mbuf; - modebuf_init(&mbuf, chptr->mode.apass[0] ? &me : sptr, cptr, chptr, MODEBUF_DEST_SERVER); + /* Always let the server op him: this is needed on a net with older servers + because they 'destruct' channels immediately when they become empty without + sending out a DESTRUCT message. As a result, they would always bounce a mode + (as HACK(2)) when the user ops himself. + (There is also no particularly good reason to have the user op himself.) + */ + modebuf_init(&mbuf, &me, cptr, chptr, MODEBUF_DEST_SERVER); modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr, chptr->mode.apass[0] ? ((flags & CHFL_CHANNEL_MANAGER) ? 0 : 1) : MAXOPLEVEL); modebuf_flush(&mbuf); @@ -332,8 +346,7 @@ int ms_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) } flags |= HasFlag(sptr, FLAG_TS8) ? CHFL_SERVOPOK : 0; - /* when the network is 2.10.11+ then remove MAGIC_REMOTE_JOIN_TS */ - chptr->creationtime = creation ? creation : MAGIC_REMOTE_JOIN_TS; + chptr->creationtime = creation; } else { /* We have a valid channel? */ if ((member = find_member_link(chptr, sptr))) @@ -355,9 +368,64 @@ int ms_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) by one when someone joins an existing, but empty, channel. However, this is only necessary when the channel is still empty (also here) and when this channel doesn't have +A set. + + To prevent this from allowing net-rides on the channel, we + clear all modes from the channel. + + (Scenario for a net ride: c1 - s1 - s2 - c2, with c1 the only + user in the channel; c1 parts and rejoins, gaining ops. + Before s2 sees c1's part, c2 joins the channel and parts + immediately. s1 sees c1 part, c1 create, c2 join, c2 part; + c2's join resets the timestamp. s2 sees c2 join, c2 part, c1 + part, c1 create; but since s2 sees the channel as a zannel or + non-existent, it does not bounce the create with the newer + timestamp.) */ - if (creation && creation - ((!chptr->mode.apass[0] && chptr->users == 0) ? 1 : 0) <= chptr->creationtime) + if (creation && (creation < chptr->creationtime || + (!chptr->mode.apass[0] && chptr->users == 0))) { + struct Membership *member; + struct ModeBuf mbuf; + chptr->creationtime = creation; + /* Wipe out the current modes on the channel. */ + modebuf_init(&mbuf, sptr, cptr, chptr, MODEBUF_DEST_CHANNEL | MODEBUF_DEST_HACK3); + + modebuf_mode(&mbuf, MODE_DEL | chptr->mode.mode); + chptr->mode.mode &= MODE_BURSTADDED | MODE_WASDELJOINS; + + if (chptr->mode.limit) { + modebuf_mode_uint(&mbuf, MODE_DEL | MODE_LIMIT, chptr->mode.limit); + chptr->mode.limit = 0; + } + + if (chptr->mode.key[0]) { + modebuf_mode_string(&mbuf, MODE_DEL | MODE_KEY, chptr->mode.key, 0); + chptr->mode.key[0] = '\0'; + } + + if (chptr->mode.upass[0]) { + modebuf_mode_string(&mbuf, MODE_DEL | MODE_UPASS, chptr->mode.upass, 0); + chptr->mode.upass[0] = '\0'; + } + + if (chptr->mode.apass[0]) { + modebuf_mode_string(&mbuf, MODE_DEL | MODE_APASS, chptr->mode.apass, 0); + chptr->mode.apass[0] = '\0'; + } + + for (member = chptr->members; member; member = member->next_member) + { + if (IsChanOp(member)) { + modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, member->user, OpLevel(member)); + member->status &= ~CHFL_CHANOP; + } + if (HasVoice(member)) { + modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, member->user, OpLevel(member)); + member->status &= ~CHFL_VOICE; + } + } + modebuf_flush(&mbuf); + } } joinbuf_join(&join, chptr, flags);