diff options
Diffstat (limited to 'src/protocol')
| -rw-r--r-- | src/protocol/bahamut.c | 166 | ||||
| -rw-r--r-- | src/protocol/inspircd11.c | 157 | ||||
| -rw-r--r-- | src/protocol/inspircd12.cpp | 181 | ||||
| -rw-r--r-- | src/protocol/ratbox.c | 130 | ||||
| -rw-r--r-- | src/protocol/unreal32.c | 158 |
5 files changed, 655 insertions, 137 deletions
diff --git a/src/protocol/bahamut.c b/src/protocol/bahamut.c index bd5a323dc..ac0647d41 100644 --- a/src/protocol/bahamut.c +++ b/src/protocol/bahamut.c @@ -48,9 +48,6 @@ IRCDVar myIrcd[] = { NULL, /* CAPAB Chan Modes */ 0, /* We support 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 */ 0, /* ts6 */ @@ -350,7 +347,163 @@ class BahamutIRCdProto : public IRCDProto /* EVENT: SJOIN */ int anope_event_sjoin(const char *source, int ac, const char **av) { - do_sjoin(source, ac, av); + Channel *c = findchan(av[1]); + time_t ts = atol(av[0]); + bool was_created = false; + bool keep_their_modes = false; + + if (!c) + { + c = new Channel(av[1], 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; + + /* 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 SJOIN string contains modes */ + if (keep_their_modes && ac >= 4) + { + /* Set the modes internally */ + ChanSetInternalModes(c, ac - 3, av + 2); + } + + /* For a reason unknown to me, bahamut will send a SJOIN from the user joining a channel + * if the channel already existed + */ + if (!was_created && ac == 2) + { + User *u = finduser(source); + if (!u) + { + if (debug) + alog("debug: SJOIN for nonexistant user %s on %s", source, c->name.c_str()); + } + else + { + EventReturn MOD_RESULT; + FOREACH_RESULT(I_OnPreJoinChannel, OnPreJoinChannel(u, c)); + + /* Add the user to the channel */ + c->JoinUser(u); + + /* Now set whatever modes this user is allowed to have on the channel */ + chan_set_correct_modes(u, c, 1); + + /* 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))) + { + FOREACH_MOD(I_OnJoinChannel, OnJoinChannel(u, c)); + } + } + } + else + { + spacesepstream sep(av[ac - 1]); + std::string buf; + while (sep.GetToken(buf)) + { + std::list<ChannelMode *> Status; + Status.clear(); + char ch; + + /* Get prefixes from the nick */ + while ((ch = ModeManager::GetStatusChar(buf[0]))) + { + buf.erase(buf.begin()); + ChannelMode *cm = ModeManager::FindChannelModeByChar(ch); + if (!cm) + { + alog("Recieved unknown mode prefix %c in SJOIN string", buf[0]); + continue; + } + + Status.push_back(cm); + } + + User *u = finduser(buf); + if (!u) + { + if (debug) + alog("debug: SJOIN for nonexistant user %s on %s", buf.c_str(), c->name.c_str()); + continue; + } + + EventReturn MOD_RESULT; + FOREACH_RESULT(I_OnPreJoinChannel, OnPreJoinChannel(u, c)); + + /* Add the user to the channel */ + c->JoinUser(u); + + /* 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); + } + + /* Now set whatever modes this user is allowed to have on the channel */ + chan_set_correct_modes(u, c, 1); + + /* 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; } @@ -614,11 +767,11 @@ int anope_event_burst(const char *source, int ac, const char **av) return MOD_CONT; } -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) + 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 true; return false; @@ -707,6 +860,7 @@ class ProtoBahamut : public Module pmodule_ircd_var(myIrcd); pmodule_ircd_useTSMode(0); + moduleAddIRCDMsgs(); moduleAddModes(); pmodule_ircd_proto(&ircd_proto); diff --git a/src/protocol/inspircd11.c b/src/protocol/inspircd11.c index 55f0858e3..91b400e9b 100644 --- a/src/protocol/inspircd11.c +++ b/src/protocol/inspircd11.c @@ -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 */ 0, /* ts6 */ @@ -460,59 +457,121 @@ int anope_event_fmode(const char *source, int ac, const char **av) int anope_event_fjoin(const char *source, int ac, const char **av) { - const char *newav[10]; - - /* 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]; + Channel *c = findchan(av[0]); + time_t ts = atol(av[1]); + bool was_created = false; + bool keep_their_modes = true; - /* temporary buffer */ - char prefixandnick[60]; + 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; - *nicklist = '\0'; - *prefixandnick = '\0'; + /* 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); + + spacesepstream sep(av[ac - 1]); + std::string buf; + while (sep.GetToken(buf)) + { + std::list<ChannelMode *> Status; + Status.clear(); + char ch; - if (ac < 3) - return MOD_CONT; + /* Loop through prefixes */ + while ((ch = ModeManager::GetStatusChar(buf[0]))) + { + buf.erase(buf.begin()); + ChannelMode *cm = ModeManager::FindChannelModeByChar(ch); - spacesepstream nicks(av[2]); - std::string nick; - - while (nicks.GetToken(nick)) { - curnick = sstrdup(nick.c_str()); - char *curnick_real = curnick; - for (; *curnick; curnick++) { - /* I bet theres a better way to do this... */ - if ((*curnick == '&') || - (*curnick == '~') || (*curnick == '@') || (*curnick == '%') - || (*curnick == '+')) { - prefixandnick[nlen++] = *curnick; + if (cm) + { + alog("Recieved unknown mode prefix %c in FJOIN string", buf[0]); continue; - } else { - if (*curnick == ',') { - curnick++; - strncpy(prefixandnick + nlen, curnick, - sizeof(prefixandnick) - nlen); - break; - } else { - alog("fjoin: unrecognised prefix: %c", *curnick); - } } + + Status.push_back(cm); } - strlcat(nicklist, prefixandnick, sizeof(nicklist)); - strlcat(nicklist, " ", sizeof(nicklist)); - delete [] curnick_real; - nlen = 0; + + User *u = finduser(buf); + if (!u) + { + if (debug) + alog("debug: FJOIN for nonexistant user %s on %s", buf.c_str(), c->name.c_str()); + continue; + } + + EventReturn MOD_RESULT; + FOREACH_RESULT(I_OnPreJoinChannel, OnPreJoinChannel(u, c)); + + /* Add the user to the channel */ + c->JoinUser(u); + + /* 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); + } + + /* Now set whatever modes this user is allowed to have on the channel */ + chan_set_correct_modes(u, c, 1); + + /* 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)); } - newav[0] = av[1]; /* timestamp */ - newav[1] = av[0]; /* channel name */ - newav[2] = "+"; /* channel modes */ - newav[3] = nicklist; - do_sjoin(source, 4, newav); + /* 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; } @@ -972,11 +1031,11 @@ void moduleAddIRCDMsgs() { m = createMessage("IDLE", anope_event_idle); 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) + 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 true; return false; 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; } diff --git a/src/protocol/ratbox.c b/src/protocol/ratbox.c index e605a922a..40ed33634 100644 --- a/src/protocol/ratbox.c +++ b/src/protocol/ratbox.c @@ -46,9 +46,6 @@ IRCDVar myIrcd[] = { NULL, /* CAPAB Chan Modes */ 0, /* We support 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 */ @@ -335,7 +332,7 @@ class RatboxProto : public IRCDTS6Proto snprintf(svidbuf, sizeof(svidbuf), "%ld", static_cast<long>(u->timestamp)); u->nc->Shrink("authenticationtoken"); - u->nc->Extend("authenticationtoken", new ExtensibleItemPointerArray<char>(svidbuf)); + u->nc->Extend("authenticationtoken", new ExtensibleItemPointerArray<char>(sstrdup(svidbuf))); } } ircd_proto; @@ -345,7 +342,128 @@ class RatboxProto : public IRCDTS6Proto int anope_event_sjoin(const char *source, int ac, const char **av) { - do_sjoin(source, ac, av); + Channel *c = findchan(av[1]); + time_t ts = atol(av[0]); + bool was_created = false; + bool keep_their_modes = true; + + if (!c) + { + c = new Channel(av[1], 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; + + /* 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 SJOIN string contains modes */ + if (keep_their_modes && ac >= 4) + { + /* Set the modes internally */ + ChanSetInternalModes(c, ac - 3, av + 2); + } + + spacesepstream sep(av[ac - 1]); + std::string buf; + while (sep.GetToken(buf)) + { + std::list<ChannelMode *> Status; + Status.clear(); + char ch; + + /* Get prefixes from the nick */ + while ((ch = ModeManager::GetStatusChar(buf[0]))) + { + buf.erase(buf.begin()); + ChannelMode *cm = ModeManager::FindChannelModeByChar(ch); + if (!cm) + { + alog("Recieved unknown mode prefix %c in SJOIN string", buf[0]); + continue; + } + + Status.push_back(cm); + } + + User *u = find_byuid(buf); + if (!u) + { + if (debug) + alog("debug: SJOIN for nonexistant user %s on %s", buf.c_str(), c->name.c_str()); + continue; + } + + EventReturn MOD_RESULT; + FOREACH_RESULT(I_OnPreJoinChannel, OnPreJoinChannel(u, c)); + + /* Add the user to the channel */ + c->JoinUser(u); + + /* 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); + } + + /* Now set whatever modes this user is allowed to have on the channel */ + chan_set_correct_modes(u, c, 1); + + /* 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; } @@ -541,7 +659,7 @@ int anope_event_kick(const char *source, int ac, const char **av) int anope_event_join(const char *source, int ac, const char **av) { if (ac != 1) { - do_sjoin(source, ac, av); + anope_event_sjoin(source, ac, av); return MOD_CONT; } else { do_join(source, ac, av); diff --git a/src/protocol/unreal32.c b/src/protocol/unreal32.c index 8f5d70fe8..7b924ff52 100644 --- a/src/protocol/unreal32.c +++ b/src/protocol/unreal32.c @@ -48,9 +48,6 @@ IRCDVar myIrcd[] = { NULL, /* CAPAB Chan Modes */ 1, /* We support Unreal TOKENS */ 1, /* TIME STAMPS are BASE64 */ - '&', /* SJOIN ban char */ - '\"', /* SJOIN except char */ - '\'', /* SJOIN invite char */ 1, /* Can remove User Channel Modes with SVSMODE */ 0, /* Sglines are not enforced until user reconnects */ 0, /* ts6 */ @@ -970,7 +967,157 @@ int anope_event_userhost(const char *source, int ac, const char **av) int anope_event_sjoin(const char *source, int ac, const char **av) { - do_sjoin(source, ac, av); + Channel *c = findchan(av[1]); + time_t ts = base64dects(av[0]); + bool keep_their_modes = true; + bool was_created = false; + + if (!c) + { + c = new Channel(av[1], 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; + + /* 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 SJOIN string contains modes */ + if (keep_their_modes && ac >= 4) + { + /* Set the modes internally */ + ChanSetInternalModes(c, ac - 3, av + 2); + } + + spacesepstream sep(av[ac - 1]); + std::string buf; + while (sep.GetToken(buf)) + { + /* Ban */ + if (keep_their_modes && buf[0] == '&') + { + buf.erase(buf.begin()); + ChannelModeList *cml = dynamic_cast<ChannelModeList *>(ModeManager::FindChannelModeByName(CMODE_BAN)); + if (cml->IsValid(buf)) + cml->AddMask(c, buf.c_str()); + } + /* Except */ + else if (keep_their_modes && buf[0] == '"') + { + buf.erase(buf.begin()); + ChannelModeList *cml = dynamic_cast<ChannelModeList *>(ModeManager::FindChannelModeByName(CMODE_EXCEPT)); + + if (cml->IsValid(buf)) + cml->AddMask(c, buf.c_str()); + } + /* Invex */ + else if (keep_their_modes && buf[0] == '\'') + { + buf.erase(buf.begin()); + ChannelModeList *cml = dynamic_cast<ChannelModeList *>(ModeManager::FindChannelModeByName(CMODE_INVITEOVERRIDE)); + + if (cml->IsValid(buf)) + cml->AddMask(c, buf.c_str()); + } + else + { + std::list<ChannelMode *> Status; + Status.clear(); + char ch; + + /* Get prefixes from the nick */ + while ((ch = ModeManager::GetStatusChar(buf[0]))) + { + buf.erase(buf.begin()); + ChannelMode *cm = ModeManager::FindChannelModeByChar(ch); + if (!cm) + { + alog("Recieved unknown mode prefix %c in SJOIN string", buf[0]); + continue; + } + + Status.push_back(cm); + } + + User *u = finduser(buf); + if (!u) + { + if (debug) + alog("debug: SJOIN for nonexistant user %s on %s", buf.c_str(), c->name.c_str()); + continue; + } + + EventReturn MOD_RESULT; + FOREACH_RESULT(I_OnPreJoinChannel, OnPreJoinChannel(u, c)); + + /* Add the user to the channel */ + c->JoinUser(u); + + /* 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); + } + + /* Now set whatever modes this user is allowed to have on the channel */ + chan_set_correct_modes(u, c, 1); + + /* 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; } @@ -1047,8 +1194,9 @@ void moduleAddIRCDMsgs() { } /* Borrowed part of this check from UnrealIRCd */ -bool ChannelModeFlood::IsValid(const char *value) +bool ChannelModeFlood::IsValid(const std::string &value2) { + const char *value = value2.c_str(); char *dp, *end; /* NEW +F */ char xbuf[256], *p, *p2, *x = xbuf + 1; |
