diff options
Diffstat (limited to 'src/protocol/inspircd12.cpp')
-rw-r--r-- | src/protocol/inspircd12.cpp | 181 |
1 files changed, 110 insertions, 71 deletions
diff --git a/src/protocol/inspircd12.cpp b/src/protocol/inspircd12.cpp index 9587f57a7..78d3a88fc 100644 --- a/src/protocol/inspircd12.cpp +++ b/src/protocol/inspircd12.cpp @@ -65,9 +65,6 @@ IRCDVar myIrcd[] = { NULL, /* CAPAB Chan Modes */ 0, /* We support inspircd TOKENS */ 0, /* TIME STAMPS are BASE64 */ - 0, /* SJOIN ban char */ - 0, /* SJOIN except char */ - 0, /* SJOIN invite char */ 0, /* Can remove User Channel Modes with SVSMODE */ 0, /* Sglines are not enforced until user reconnects */ 1, /* ts6 */ @@ -513,91 +510,133 @@ int anope_event_fmode(const char *source, int ac, const char **av) * * 0: name * 1: channel ts (when it was created, see protocol docs for more info) - * 2: channel modes + params (NOTEL this may definitely be more than one param!) + * 2: channel modes + params (NOTE: this may definitely be more than one param!) * last: users */ int anope_event_fjoin(const char *source, int ac, const char **av) { - const char *newav[30]; // hopefully 30 will do until the stupid ac/av stuff goes away. - - /* storing the current nick */ - char *curnick; - - /* these are used to generate the final string that is passed to ircservices' core */ - int nlen = 0; - char nicklist[514]; - - /* temporary buffer */ - char prefixandnick[60]; - - *nicklist = '\0'; - *prefixandnick = '\0'; + Channel *c = findchan(av[0]); + time_t ts = atol(av[1]); + bool was_created = false; + bool keep_their_modes = true; - if (ac <= 3) - return MOD_CONT; + if (!c) + { + c = new Channel(av[0], ts); + was_created = true; + } + /* Our creation time is newer than what the server gave us */ + else if (c->creation_time > ts) + { + c->creation_time = ts; - spacesepstream nicks(av[ac - 1]); - std::string nick; + /* Remove status from all of our users */ + for (struct c_userlist *cu = c->users; cu; cu = cu->next) + { + c->RemoveMode(NULL, CMODE_OWNER, cu->user->nick); + c->RemoveMode(NULL, CMODE_PROTECT, cu->user->nick); + c->RemoveMode(NULL, CMODE_OP, cu->user->nick); + c->RemoveMode(NULL, CMODE_HALFOP, cu->user->nick); + c->RemoveMode(NULL, CMODE_VOICE, cu->user->nick); + } + if (c->ci) + { + /* Rejoin the bot to fix the TS */ + if (c->ci->bi) + { + ircdproto->SendPart(c->ci->bi, c, "TS reop"); + bot_join(c->ci); + } + /* Reset mlock */ + check_modes(c); + } + } + /* Their TS is newer than ours, our modes > theirs, unset their modes if need be */ + else + keep_their_modes = false; + + /* Mark the channel as syncing */ + if (was_created) + c->SetFlag(CH_SYNCING); + + /* If we need to keep their modes, and this FJOIN string contains modes */ + if (keep_their_modes && ac >= 4) + { + /* Set the modes internally */ + ChanSetInternalModes(c, ac - 3, av + 2); + } - while (nicks.GetToken(nick)) + spacesepstream sep(av[ac - 1]); + std::string buf; + while (sep.GetToken(buf)) { - curnick = sstrdup(nick.c_str()); - char *curnick_real = curnick; - for (; *curnick; curnick++) + std::list<ChannelMode *> Status; + Status.clear(); + + /* Loop through prefixes and find modes for them */ + while (buf[0] != ',') { - /* XXX: bleagh! -- w00t */ - switch (*curnick) + ChannelMode *cm = ModeManager::FindChannelModeByChar(buf[0]); + buf.erase(buf.begin()); + if (!cm) { - case 'q': - prefixandnick[nlen++] = '~'; - break; - case 'a': - prefixandnick[nlen++] = '&'; - break; - case 'o': - prefixandnick[nlen++] = '@'; - break; - case 'h': - prefixandnick[nlen++] = '%'; - break; - case 'v': - prefixandnick[nlen++] = '+'; - break; - case ',': - curnick++; - strncpy(prefixandnick + nlen, curnick, sizeof(prefixandnick) - nlen); - goto endnick; - break; - default: - alog("fjoin: unrecognised prefix: %c", *curnick); - break; + alog("Recieved unknown mode prefix %c in FJOIN string", buf[0]); + continue; } + + Status.push_back(cm); } + buf.erase(buf.begin()); -// Much as I hate goto.. I can't `break 2' to get here.. XXX ugly -endnick: - strlcat(nicklist, prefixandnick, sizeof(nicklist)); - strlcat(nicklist, " ", sizeof(nicklist)); - delete [] curnick_real; - nlen = 0; - } + User *u = find_byuid(buf); + if (!u) + { + if (debug) + alog("debug: FJOIN for nonexistant user %s on %s", buf.c_str(), c->name.c_str()); + continue; + } - newav[0] = av[1]; /* timestamp */ - newav[1] = av[0]; /* channel name */ + EventReturn MOD_RESULT; + FOREACH_RESULT(I_OnPreJoinChannel, OnPreJoinChannel(u, c)); - int i; + /* Add the user to the channel */ + c->JoinUser(u); - /* We want to replace the last string with our newly formatted user string */ - for (i = 2; i != ac - 1; i++) - { - newav[i] = av[i]; - } + /* Update their status internally on the channel + * This will enforce secureops etc on the user + */ + for (std::list<ChannelMode *>::iterator it = Status.begin(); it != Status.end(); ++it) + { + c->SetModeInternal(*it, buf); + } - newav[i] = nicklist; - i++; + /* Now set whatever modes this user is allowed to have on the channel */ + chan_set_correct_modes(u, c, 1); - do_sjoin(source, i, newav); + /* Check to see if modules want the user to join, if they do + * check to see if they are allowed to join (CheckKick will kick/ban them) + * Don't trigger OnJoinChannel event then as the user will be destroyed + */ + if (MOD_RESULT != EVENT_STOP && c->ci && c->ci->CheckKick(u)) + continue; + FOREACH_MOD(I_OnJoinChannel, OnJoinChannel(u, c)); + } + + /* Channel is done syncing */ + if (was_created) + { + /* Unset the syncing flag */ + c->UnsetFlag(CH_SYNCING); + + /* If there are users in the channel they are allowed to be, set topic mlock etc */ + if (c->usercount) + c->Sync(); + /* If there are no users in the channel, there is a ChanServ timer set to part the service bot + * and destroy the channel soon + */ + } + return MOD_CONT; } @@ -1177,10 +1216,10 @@ void moduleAddIRCDMsgs() { m = createMessage("METADATA", anope_event_metadata); addCoreMessage(IRCD,m); } -bool ChannelModeFlood::IsValid(const char *value) +bool ChannelModeFlood::IsValid(const std::string &value) { char *dp, *end; - if (value && *value != ':' && strtoul((*value == '*' ? value + 1 : value), &dp, 10) > 0 && *dp == ':' && *(++dp) && strtoul(dp, &end, 10) > 0 && !*end) return 1; + if (!value.empty() && value[0] != ':' && strtoul((value[0] == '*' ? value.c_str() + 1 : value.c_str()), &dp, 10) > 0 && *dp == ':' && *(++dp) && strtoul(dp, &end, 10) > 0 && !*end) return 1; else return 0; } |