diff --git a/include/bots.h b/include/bots.h index 7d2fa74f3..f6b8d2e14 100644 --- a/include/bots.h +++ b/include/bots.h @@ -71,8 +71,22 @@ class CoreExport BotInfo : public User, public Flags */ void UnAssign(User *u, ChannelInfo *ci); - void Join(Channel *c); - void Join(const Anope::string &chname); + /** Join this bot to a channel + * @param c The channel + * @param update_ts Assume we're updating the TS for this channel + */ + void Join(Channel *c, bool update_ts = false); + + /** Join this bot to a channel + * @param chname The channel name + * @param update_ts Assume we're updating the TS for this channel + */ + void Join(const Anope::string &chname, bool update_ts = false); + + /** Part this bot from a channel + * @param c The channel + * @param reason The reason we're parting + */ void Part(Channel *c, const Anope::string &reason = ""); }; diff --git a/include/channels.h b/include/channels.h index 845f8fc36..8c5d83c5d 100644 --- a/include/channels.h +++ b/include/channels.h @@ -44,7 +44,7 @@ struct UserContainer { User *user; UserData ud; - Flags *Status; + ChannelStatus *Status; UserContainer(User *u) : user(u) { } virtual ~UserContainer() { } @@ -104,6 +104,11 @@ class CoreExport Channel : public Extensible, public Flags int16 bouncy_modes; /* Did we fail to set modes here? */ int16 topic_sync; /* Is the topic in sync? */ + /** Call if we need to unset all modes and clear all user status (internally). + * Only useful if we get a SJOIN with a TS older than what we have here + */ + void Reset(); + /** Restore the channel topic, set mlock (key), set stickied bans, etc */ void Sync(); @@ -217,23 +222,27 @@ class CoreExport Channel : public Extensible, public Flags /** Clear all the modes from the channel * @param bi The client unsetting the modes + * @param internal Only remove the modes internally */ - void ClearModes(BotInfo *bi = NULL); + void ClearModes(BotInfo *bi = NULL, bool internal = false); /** Clear all the bans from the channel * @param bi The client unsetting the modes + * @param internal Only remove the modes internally */ - void ClearBans(BotInfo *bi = NULL); + void ClearBans(BotInfo *bi = NULL, bool internal = false); /** Clear all the excepts from the channel * @param bi The client unsetting the modes + * @param internal Only remove the modes internally */ - void ClearExcepts(BotInfo *bi = NULL); + void ClearExcepts(BotInfo *bi = NULL, bool internal = false); /** Clear all the invites from the channel * @param bi The client unsetting the modes + * @param internal Only remove the modes internally */ - void ClearInvites(BotInfo *bi = NULL); + void ClearInvites(BotInfo *bi = NULL, bool internal = false); /** Get a param from the channel * @param Name The mode @@ -268,6 +277,13 @@ class CoreExport Channel : public Extensible, public Flags * @return true if the kick was scucessful, false if a module blocked the kick */ bool Kick(BotInfo *bi, User *u, const char *reason = NULL, ...); + + /** Get a string of the modes set on this channel + * @param complete Include mode parameters + * @param plus If set to false (with complete), mode parameters will not be given for modes requring no parameters to be unset + * @return A mode string + */ + Anope::string GetModes(bool complete, bool plus); }; #endif // CHANNELS_H diff --git a/include/extern.h b/include/extern.h index b2dd30b79..4dc6cb4ba 100644 --- a/include/extern.h +++ b/include/extern.h @@ -66,8 +66,6 @@ E void ChanSetInternalModes(Channel *c, int ac, const char **av); E User *nc_on_chan(Channel *c, const NickCore *nc); -E Anope::string chan_get_modes(Channel *chan, int complete, int plus); - E int get_access_level(ChannelInfo *ci, NickAlias *na); E int get_access_level(ChannelInfo *ci, NickCore *nc); E Anope::string get_xop_level(int level); diff --git a/include/modes.h b/include/modes.h index 6447550ad..4d0706a9a 100644 --- a/include/modes.h +++ b/include/modes.h @@ -420,7 +420,7 @@ class CoreExport ModeManager public: /* List of all modes Anope knows about */ - static std::list Modes; + static std::map Modes; /* User modes */ static std::map UserModesByChar; @@ -468,6 +468,12 @@ class CoreExport ModeManager */ static UserMode *FindUserModeByName(UserModeName Name); + /** Find a mode by name + * @param name The mode name + * @return The mode + */ + static Mode *FindModeByName(const Anope::string &name); + /** Gets the channel mode char for a symbol (eg + returns v) * @param Value The symbol * @return The char diff --git a/include/services.h b/include/services.h index 15670c8ac..ca02d087e 100644 --- a/include/services.h +++ b/include/services.h @@ -730,13 +730,13 @@ struct LevelInfo /*************************************************************************/ -#include "users.h" -#include "bots.h" - /* This structure stocks ban data since it must not be removed when * user is kicked. */ +#include "users.h" +#include "bots.h" + struct BanData { BanData *next, *prev; @@ -973,7 +973,8 @@ class CoreExport IRCDProto virtual void SendQuit(const BotInfo *bi, const char *fmt, ...); virtual void SendPing(const Anope::string &servname, const Anope::string &who); virtual void SendPong(const Anope::string &servname, const Anope::string &who); - virtual void SendJoin(const BotInfo *bi, const Anope::string &, time_t) = 0; + virtual void SendJoin(const BotInfo *, const Anope::string &, time_t) = 0; + virtual void SendJoin(BotInfo *, const ChannelContainer *); virtual void SendSQLineDel(const XLine *x) = 0; virtual void SendInvite(const BotInfo *bi, const Anope::string &chan, const Anope::string &nick); virtual void SendPart(const BotInfo *bi, const Channel *chan, const char *fmt, ...); @@ -998,6 +999,7 @@ class CoreExport IRCDProto virtual void SendSVSJoin(const Anope::string &, const Anope::string &, const Anope::string &, const Anope::string &) { } virtual void SendSVSPart(const Anope::string &, const Anope::string &, const Anope::string &) { } virtual void SendSWhois(const Anope::string &, const Anope::string &, const Anope::string &) { } + virtual void SendBOB() { } virtual void SendEOB() { } virtual void SendServer(const Server *) = 0; virtual bool IsNickValid(const Anope::string &) { return true; } diff --git a/include/users.h b/include/users.h index 78d83c062..40e98b114 100644 --- a/include/users.h +++ b/include/users.h @@ -17,10 +17,17 @@ typedef unordered_map_namespace::unordered_map +{ + public: + Anope::string BuildCharPrefixList() const; + Anope::string BuildModePrefixList() const; +}; + struct ChannelContainer { Channel *chan; - Flags *Status; + ChannelStatus *Status; ChannelContainer(Channel *c) : chan(c) { } virtual ~ChannelContainer() { } diff --git a/modules/core/cs_set_persist.cpp b/modules/core/cs_set_persist.cpp index fe3c84242..955e2082f 100644 --- a/modules/core/cs_set_persist.cpp +++ b/modules/core/cs_set_persist.cpp @@ -33,6 +33,8 @@ class CommandCSSetPersist : public Command if (!ci->HasFlag(CI_PERSIST)) { ci->SetFlag(CI_PERSIST); + if (ci->c) + ci->c->SetFlag(CH_PERSIST); /* Channel doesn't exist, create it */ if (!ci->c) @@ -65,6 +67,8 @@ class CommandCSSetPersist : public Command if (ci->HasFlag(CI_PERSIST)) { ci->UnsetFlag(CI_PERSIST); + if (ci->c) + ci->c->UnsetFlag(CH_PERSIST); /* Unset perm mode */ if (cm && ci->c && ci->c->HasMode(CMODE_PERM)) diff --git a/modules/core/db_plain.cpp b/modules/core/db_plain.cpp index 7f90ad6f9..9c47306ca 100644 --- a/modules/core/db_plain.cpp +++ b/modules/core/db_plain.cpp @@ -1011,43 +1011,33 @@ class DBPlain : public Module if (ci->GetMLockCount(true)) { db << "MD MLOCK_ON"; - for (std::list::iterator it = ModeManager::Modes.begin(), it_end = ModeManager::Modes.end(); it != it_end; ++it) + for (std::map::iterator it = ModeManager::ChannelModesByChar.begin(), it_end = ModeManager::ChannelModesByChar.end(); it != it_end; ++it) { - if ((*it)->Class == MC_CHANNEL) - { - ChannelMode *cm = debug_cast(*it); - - if (ci->HasMLock(cm->Name, true)) - db << " " << cm->NameAsString; - } + ChannelMode *cm = it->second; + if (ci->HasMLock(cm->Name, true)) + db << " " << cm->NameAsString; } db << endl; } if (ci->GetMLockCount(false)) { db << "MD MLOCK_OFF"; - for (std::list::iterator it = ModeManager::Modes.begin(), it_end = ModeManager::Modes.end(); it != it_end; ++it) - { - if ((*it)->Class == MC_CHANNEL) - { - ChannelMode *cm = debug_cast(*it); - if (ci->HasMLock(cm->Name, false)) - db << " " << cm->NameAsString; - } + for (std::map::iterator it = ModeManager::ChannelModesByChar.begin(), it_end = ModeManager::ChannelModesByChar.end(); it != it_end; ++it) + { + ChannelMode *cm = it->second; + if (ci->HasMLock(cm->Name, false)) + db << " " << cm->NameAsString; } db << endl; } - for (std::list::iterator it = ModeManager::Modes.begin(), it_end = ModeManager::Modes.end(); it != it_end; ++it) + for (std::map::iterator it = ModeManager::ChannelModesByChar.begin(), it_end = ModeManager::ChannelModesByChar.end(); it != it_end; ++it) { - if ((*it)->Class == MC_CHANNEL) - { - ChannelMode *cm = debug_cast(*it); + ChannelMode *cm = it->second; + Anope::string Param; - Anope::string Param; - if (ci->GetParam(cm->Name, Param)) - db << "MD MLP " << cm->NameAsString << " " << Param << endl; - } + if (ci->GetParam(cm->Name, Param)) + db << "MD MLP " << cm->NameAsString << " " << Param << endl; } if (!ci->memos.memos.empty()) { diff --git a/modules/core/os_chanlist.cpp b/modules/core/os_chanlist.cpp index 8fcb1c397..87b3d736d 100644 --- a/modules/core/os_chanlist.cpp +++ b/modules/core/os_chanlist.cpp @@ -46,7 +46,7 @@ class CommandOSChanList : public Command if (!cc->chan->HasMode(*it)) continue; - notice_lang(Config->s_OperServ, u, OPER_CHANLIST_RECORD, cc->chan->name.c_str(), cc->chan->users.size(), chan_get_modes(cc->chan, 1, 1).c_str(), !cc->chan->topic.empty() ? cc->chan->topic.c_str() : ""); + notice_lang(Config->s_OperServ, u, OPER_CHANLIST_RECORD, cc->chan->name.c_str(), cc->chan->users.size(), cc->chan->GetModes(true, true).c_str(), !cc->chan->topic.empty() ? cc->chan->topic.c_str() : ""); } } else @@ -64,7 +64,7 @@ class CommandOSChanList : public Command if (!c->HasMode(*it)) continue; - notice_lang(Config->s_OperServ, u, OPER_CHANLIST_RECORD, c->name.c_str(), c->users.size(), chan_get_modes(c, 1, 1).c_str(), !c->topic.empty() ? c->topic.c_str() : ""); + notice_lang(Config->s_OperServ, u, OPER_CHANLIST_RECORD, c->name.c_str(), c->users.size(), c->GetModes(true, true).c_str(), !c->topic.empty() ? c->topic.c_str() : ""); } } diff --git a/modules/extra/db_mysql.cpp b/modules/extra/db_mysql.cpp index 27a1226d1..4aeac0322 100644 --- a/modules/extra/db_mysql.cpp +++ b/modules/extra/db_mysql.cpp @@ -199,15 +199,11 @@ static Anope::string MakeMLock(ChannelInfo *ci, bool status) { Anope::string ret; - for (std::list::iterator it = ModeManager::Modes.begin(), it_end = ModeManager::Modes.end(); it != it_end; ++it) + for (std::map::iterator it = ModeManager::ChannelModesByChar.begin(), it_end = ModeManager::ChannelModesByChar.end(); it != it_end; ++it) { - if ((*it)->Class == MC_CHANNEL) - { - ChannelMode *cm = debug_cast(*it); - - if (ci->HasMLock(cm->Name, status)) - ret += " " + cm->NameAsString; - } + ChannelMode *cm = it->second; + if (ci->HasMLock(cm->Name, status)) + ret += " " + cm->NameAsString; } if (!ret.empty()) @@ -230,16 +226,13 @@ static Anope::string GetMLockParams(ChannelInfo *ci) { Anope::string ret; - for (std::list::iterator it = ModeManager::Modes.begin(), it_end = ModeManager::Modes.end(); it != it_end; ++it) + for (std::map::iterator it = ModeManager::ChannelModesByChar.begin(), it_end = ModeManager::ChannelModesByChar.end(); it != it_end; ++it) { - if ((*it)->Class == MC_CHANNEL) - { - ChannelMode *cm = debug_cast(*it); + ChannelMode *cm = it->second; - Anope::string param; - if (ci->GetParam(cm->Name, param)) - ret += " " + cm->NameAsString + " " + param; - } + Anope::string param; + if (ci->GetParam(cm->Name, param)) + ret += " " + cm->NameAsString + " " + param; } if (!ret.empty()) diff --git a/modules/protocol/bahamut.cpp b/modules/protocol/bahamut.cpp index 572b91367..9c3e107a4 100644 --- a/modules/protocol/bahamut.cpp +++ b/modules/protocol/bahamut.cpp @@ -197,6 +197,19 @@ class BahamutIRCdProto : public IRCDProto send_cmd(user->nick, "SJOIN %ld %s", static_cast(chantime), channel.c_str()); } + void SendJoin(BotInfo *user, const ChannelContainer *cc) + { + SendJoin(user, cc->chan->name, cc->chan->creation_time); + for (std::map::iterator it = ModeManager::ChannelModesByChar.begin(), it_end = ModeManager::ChannelModesByChar.end(); it != it_end; ++it) + { + if (cc->Status->HasFlag(it->second->Name)) + { + cc->chan->SetMode(user, it->second, user->nick); + } + } + cc->chan->SetModes(user, false, "%s", cc->chan->GetModes(true, true).c_str()); + } + void SendAkill(const XLine *x) { // Calculate the time left before this would expire, capping it at 2 days @@ -226,6 +239,11 @@ class BahamutIRCdProto : public IRCDProto this->SendModeInternal(NULL, u, merge_args(ac, av)); } + void SendBOB() + { + send_cmd("", "BURST"); + } + void SendEOB() { send_cmd("", "BURST 0"); @@ -290,56 +308,26 @@ int anope_event_sjoin(const Anope::string &source, int ac, const char **av) { Channel *c = findchan(av[1]); time_t ts = Anope::string(av[0]).is_number_only() ? convertTo(av[0]) : 0; - bool was_created = false; bool keep_their_modes = false; if (!c) { c = new Channel(av[1], ts); - was_created = true; + c->SetFlag(CH_SYNCING); } /* Our creation time is newer than what the server gave us */ else if (c->creation_time > ts) { c->creation_time = ts; + c->Reset(); - /* Remove status from all of our users */ - for (std::list::const_iterator it = ModeManager::Modes.begin(), it_end = ModeManager::Modes.end(); it != it_end; ++it) - { - Mode *m = *it; - - if (m->Type != MODE_STATUS) - continue; - - ChannelMode *cm = debug_cast(m); - - for (CUserList::const_iterator uit = c->users.begin(), uit_end = c->users.end(); uit != uit_end; ++uit) - { - UserContainer *uc = *uit; - - c->RemoveMode(NULL, cm, uc->user->nick); - } - } - if (c->ci) - { - /* Rejoin the bot to fix the TS */ - if (c->ci->bi) - { - c->ci->bi->Part(c, "TS reop"); - c->ci->bi->Join(c); - } - /* Reset mlock */ - check_modes(c); - } + /* Reset mlock */ + check_modes(c); } /* Their TS is newer than ours, our modes > theirs, unset their modes if need be */ - else + else if (ts > c->creation_time) 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) { @@ -350,7 +338,7 @@ int anope_event_sjoin(const Anope::string &source, int ac, const char **av) /* 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) + if (!c->HasFlag(CH_SYNCING) && ac == 2) { User *u = finduser(source); if (!u) @@ -396,7 +384,8 @@ int anope_event_sjoin(const Anope::string &source, int ac, const char **av) continue; } - Status.push_back(cm); + if (keep_their_modes) + Status.push_back(cm); } User *u = finduser(buf); @@ -433,7 +422,7 @@ int anope_event_sjoin(const Anope::string &source, int ac, const char **av) } /* Channel is done syncing */ - if (was_created) + if (c->HasFlag(CH_SYNCING)) { /* Unset the syncing flag */ c->UnsetFlag(CH_SYNCING); diff --git a/modules/protocol/inspircd11.cpp b/modules/protocol/inspircd11.cpp index c06b74501..cc2c99fa6 100644 --- a/modules/protocol/inspircd11.cpp +++ b/modules/protocol/inspircd11.cpp @@ -185,6 +185,19 @@ class InspIRCdProto : public IRCDProto send_cmd(user->nick, "JOIN %s %ld", channel.c_str(), static_cast(chantime)); } + void SendJoin(BotInfo *user, const ChannelContainer *cc) + { + SendJoin(user, cc->chan->name, cc->chan->creation_time); + for (std::map::iterator it = ModeManager::ChannelModesByChar.begin(), it_end = ModeManager::ChannelModesByChar.end(); it != it_end; ++it) + { + if (cc->Status->HasFlag(it->second->Name)) + { + cc->chan->SetMode(user, it->second, user->nick); + } + } + cc->chan->SetModes(user, false, "%s", cc->chan->GetModes(true, true).c_str()); + } + /* UNSQLINE */ void SendSQLineDel(const XLine *x) { @@ -270,6 +283,11 @@ class InspIRCdProto : public IRCDProto send_cmd(source, "SVSPART %s %s", nick.c_str(), chan.c_str()); } + void SendBOB() + { + send_cmd("", "BURST %ld", time(NULL)); + } + void SendEOB() { send_cmd("", "ENDBURST"); @@ -386,56 +404,26 @@ int anope_event_fjoin(const Anope::string &source, int ac, const char **av) { Channel *c = findchan(av[0]); time_t ts = Anope::string(av[1]).is_number_only() ? convertTo(av[1]) : 0; - bool was_created = false; bool keep_their_modes = true; if (!c) { c = new Channel(av[0], ts); - was_created = true; + c->SetFlag(CH_SYNCING); } /* Our creation time is newer than what the server gave us */ else if (c->creation_time > ts) { c->creation_time = ts; + c->Reset(); - /* Remove status from all of our users */ - for (std::list::const_iterator it = ModeManager::Modes.begin(), it_end = ModeManager::Modes.end(); it != it_end; ++it) - { - Mode *m = *it; - - if (m->Type != MODE_STATUS) - continue; - - ChannelMode *cm = debug_cast(m); - - for (CUserList::const_iterator uit = c->users.begin(), uit_end = c->users.end(); uit != uit_end; ++uit) - { - UserContainer *uc = *uit; - - c->RemoveMode(NULL, cm, uc->user->nick); - } - } - if (c->ci) - { - /* Rejoin the bot to fix the TS */ - if (c->ci->bi) - { - c->ci->bi->Part(c, "TS reop"); - c->ci->bi->Join(c); - } - /* Reset mlock */ - check_modes(c); - } + /* Reset mlock */ + check_modes(c); } /* Their TS is newer than ours, our modes > theirs, unset their modes if need be */ - else + else if (ts > c->creation_time) keep_their_modes = false; - /* Mark the channel as syncing */ - if (was_created) - c->SetFlag(CH_SYNCING); - spacesepstream sep(av[ac - 1]); Anope::string buf; while (sep.GetToken(buf)) @@ -456,7 +444,8 @@ int anope_event_fjoin(const Anope::string &source, int ac, const char **av) } buf.erase(buf.begin()); - Status.push_back(cm); + if (keep_their_modes) + Status.push_back(cm); } User *u = finduser(buf); @@ -492,7 +481,7 @@ int anope_event_fjoin(const Anope::string &source, int ac, const char **av) } /* Channel is done syncing */ - if (was_created) + if (c->HasFlag(CH_SYNCING)) { /* Unset the syncing flag */ c->UnsetFlag(CH_SYNCING); diff --git a/modules/protocol/inspircd12.cpp b/modules/protocol/inspircd12.cpp index a78ead0a8..55a371700 100644 --- a/modules/protocol/inspircd12.cpp +++ b/modules/protocol/inspircd12.cpp @@ -185,6 +185,11 @@ class InspIRCdProto : public IRCDProto send_cmd(TS6SID, "FJOIN %s %ld + :,%s", channel.c_str(), static_cast(chantime), user->GetUID().c_str()); } + void SendJoin(BotInfo *user, const ChannelContainer *cc) + { + send_cmd(TS6SID, "FJOIN %s %ld +%s :%s,%s", cc->chan->name.c_str(), static_cast(cc->chan->creation_time), cc->chan->GetModes(true, true).c_str(), cc->Status->BuildCharPrefixList().c_str(), user->GetUID().c_str()); + } + /* UNSQLINE */ void SendSQLineDel(const XLine *x) { @@ -275,6 +280,11 @@ class InspIRCdProto : public IRCDProto send_cmd(TS6SID, "METADATA %s swhois :%s", u->GetUID().c_str(), mask.c_str()); } + void SendBOB() + { + send_cmd(TS6SID, "BURST %ld", time(NULL)); + } + void SendEOB() { send_cmd(TS6SID, "ENDBURST"); @@ -427,56 +437,26 @@ int anope_event_fjoin(const Anope::string &source, int ac, const char **av) { Channel *c = findchan(av[0]); time_t ts = Anope::string(av[1]).is_number_only() ? convertTo(av[1]) : 0; - bool was_created = false; bool keep_their_modes = true; if (!c) { c = new Channel(av[0], ts); - was_created = true; + c->SetFlag(CH_SYNCING); } /* Our creation time is newer than what the server gave us */ else if (c->creation_time > ts) { c->creation_time = ts; + c->Reset(); - /* Remove status from all of our users */ - for (std::list::const_iterator it = ModeManager::Modes.begin(), it_end = ModeManager::Modes.end(); it != it_end; ++it) - { - Mode *m = *it; - - if (m->Type != MODE_STATUS) - continue; - - ChannelMode *cm = debug_cast(m); - - for (CUserList::const_iterator uit = c->users.begin(), uit_end = c->users.end(); uit != uit_end; ++uit) - { - UserContainer *uc = *uit; - - c->RemoveMode(NULL, cm, uc->user->nick); - } - } - if (c->ci) - { - /* Rejoin the bot to fix the TS */ - if (c->ci->bi) - { - c->ci->bi->Part(c, "TS reop"); - c->ci->bi->Join(c); - } - /* Reset mlock */ - check_modes(c); - } + /* Reset mlock */ + check_modes(c); } /* Their TS is newer than ours, our modes > theirs, unset their modes if need be */ - else + else if (ts > c->creation_time) 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) { @@ -502,7 +482,8 @@ int anope_event_fjoin(const Anope::string &source, int ac, const char **av) } buf.erase(buf.begin()); - Status.push_back(cm); + if (keep_their_modes) + Status.push_back(cm); } buf.erase(buf.begin()); @@ -539,7 +520,7 @@ int anope_event_fjoin(const Anope::string &source, int ac, const char **av) } /* Channel is done syncing */ - if (was_created) + if (c->HasFlag(CH_SYNCING)) { /* Unset the syncing flag */ c->UnsetFlag(CH_SYNCING); diff --git a/modules/protocol/inspircd20.cpp b/modules/protocol/inspircd20.cpp index c55bc7020..8a8748d49 100644 --- a/modules/protocol/inspircd20.cpp +++ b/modules/protocol/inspircd20.cpp @@ -183,6 +183,11 @@ class InspIRCdProto : public IRCDProto send_cmd(TS6SID, "FJOIN %s %ld + :,%s", channel.c_str(), static_cast(chantime), user->GetUID().c_str()); } + void SendJoin(BotInfo *user, const ChannelContainer *cc) + { + send_cmd(TS6SID, "FJOIN %s %ld +%s :%s,%s", cc->chan->name.c_str(), static_cast(cc->chan->creation_time), cc->chan->GetModes(true, true).c_str(), cc->Status->BuildCharPrefixList().c_str(), user->GetUID().c_str()); + } + /* UNSQLINE */ void SendSQLineDel(const XLine *x) { @@ -276,6 +281,11 @@ class InspIRCdProto : public IRCDProto send_cmd(TS6SID, "METADATA %s swhois :%s", u->GetUID().c_str(), mask.c_str()); } + void SendBOB() + { + send_cmd(TS6SID, "BURST %ld", time(NULL)); + } + void SendEOB() { send_cmd(TS6SID, "ENDBURST"); @@ -425,56 +435,26 @@ int anope_event_fjoin(const Anope::string &source, int ac, const char **av) { Channel *c = findchan(av[0]); time_t ts = Anope::string(av[1]).is_number_only() ? convertTo(av[1]) : 0; - bool was_created = false; bool keep_their_modes = true; if (!c) { c = new Channel(av[0], ts); - was_created = true; + c->SetFlag(CH_SYNCING); } /* Our creation time is newer than what the server gave us */ else if (c->creation_time > ts) { c->creation_time = ts; + c->Reset(); - /* Remove status from all of our users */ - for (std::list::const_iterator it = ModeManager::Modes.begin(), it_end = ModeManager::Modes.end(); it != it_end; ++it) - { - Mode *m = *it; - - if (m->Type != MODE_STATUS) - continue; - - ChannelMode *cm = debug_cast(m); - - for (CUserList::const_iterator uit = c->users.begin(), uit_end = c->users.end(); uit != uit_end; ++uit) - { - UserContainer *uc = *uit; - - c->RemoveMode(NULL, cm, uc->user->nick); - } - } - if (c->ci) - { - /* Rejoin the bot to fix the TS */ - if (c->ci->bi) - { - c->ci->bi->Part(c, "TS reop"); - c->ci->bi->Join(c); - } - /* Reset mlock */ - check_modes(c); - } + /* Reset mlock */ + check_modes(c); } - /* Their TS is newer than ours, our modes > theirs, unset their modes if need be */ - else + /* Their TS is newer than ours, our modes > theirs, unset their modes */ + else if (ts > c->creation_time) 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) { @@ -500,7 +480,8 @@ int anope_event_fjoin(const Anope::string &source, int ac, const char **av) } buf.erase(buf.begin()); - Status.push_back(cm); + if (keep_their_modes) + Status.push_back(cm); } buf.erase(buf.begin()); @@ -537,7 +518,7 @@ int anope_event_fjoin(const Anope::string &source, int ac, const char **av) } /* Channel is done syncing */ - if (was_created) + if (c->HasFlag(CH_SYNCING)) { /* Unset the syncing flag */ c->UnsetFlag(CH_SYNCING); diff --git a/modules/protocol/ratbox.cpp b/modules/protocol/ratbox.cpp index 8db46a3d5..a26ee9598 100644 --- a/modules/protocol/ratbox.cpp +++ b/modules/protocol/ratbox.cpp @@ -145,6 +145,11 @@ class RatboxProto : public IRCDTS6Proto send_cmd("", "SJOIN %ld %s + :%s", static_cast(chantime), channel.c_str(), user->GetUID().c_str()); } + void SendJoin(const BotInfo *user, const ChannelContainer *cc) + { + send_cmd("", "SJOIN %ld %s +%s :%s%s", static_cast(cc->chan->creation_time), cc->chan->name.c_str(), cc->chan->GetModes(true, true).c_str(), cc->Status->BuildModePrefixList().c_str(), user->GetUID().c_str()); + } + void SendAkill(const XLine *x) { BotInfo *bi = OperServ; @@ -281,56 +286,26 @@ int anope_event_sjoin(const Anope::string &source, int ac, const char **av) { Channel *c = findchan(av[1]); time_t ts = Anope::string(av[0]).is_number_only() ? convertTo(av[0]) : 0; - bool was_created = false; bool keep_their_modes = true; if (!c) { c = new Channel(av[1], ts); - was_created = true; + c->SetFlag(CH_SYNCING); } /* Our creation time is newer than what the server gave us */ else if (c->creation_time > ts) { c->creation_time = ts; + c->Reset(); - /* Remove status from all of our users */ - for (std::list::const_iterator it = ModeManager::Modes.begin(), it_end = ModeManager::Modes.end(); it != it_end; ++it) - { - Mode *m = *it; - - if (m->Type != MODE_STATUS) - continue; - - ChannelMode *cm = debug_cast(m); - - for (CUserList::const_iterator uit = c->users.begin(), uit_end = c->users.end(); uit != uit_end; ++uit) - { - UserContainer *uc = *uit; - - c->RemoveMode(NULL, cm, uc->user->nick); - } - } - if (c->ci) - { - /* Rejoin the bot to fix the TS */ - if (c->ci->bi) - { - c->ci->bi->Part(c, "TS reop"); - c->ci->bi->Join(c); - } - /* Reset mlock */ - check_modes(c); - } + /* Reset mlock */ + check_modes(c); } /* Their TS is newer than ours, our modes > theirs, unset their modes if need be */ - else + else if (ts > c->creation_time) 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) { @@ -356,7 +331,8 @@ int anope_event_sjoin(const Anope::string &source, int ac, const char **av) continue; } - Status.push_back(cm); + if (keep_their_modes) + Status.push_back(cm); } User *u = finduser(buf); @@ -392,7 +368,7 @@ int anope_event_sjoin(const Anope::string &source, int ac, const char **av) } /* Channel is done syncing */ - if (was_created) + if (c->HasFlag(CH_SYNCING)) { /* Unset the syncing flag */ c->UnsetFlag(CH_SYNCING); diff --git a/modules/protocol/unreal32.cpp b/modules/protocol/unreal32.cpp index 1e18e92f9..ff04e87eb 100644 --- a/modules/protocol/unreal32.cpp +++ b/modules/protocol/unreal32.cpp @@ -214,6 +214,12 @@ class UnrealIRCdProto : public IRCDProto send_cmd(Config->ServerName, "~ %ld %s :%s", static_cast(chantime), channel.c_str(), user->nick.c_str()); } + void SendJoin(BotInfo *user, const ChannelContainer *cc) + { + send_cmd(Config->ServerName, "~ %ld %s :%s%s", static_cast(cc->chan->creation_time), cc->chan->name.c_str(), cc->Status->BuildModePrefixList().c_str(), user->nick.c_str()); + cc->chan->SetModes(user, false, "%s", cc->chan->GetModes(true, true).c_str()); + } + /* unsqline */ void SendSQLineDel(const XLine *x) @@ -988,54 +994,25 @@ int anope_event_sjoin(const Anope::string &source, int ac, const char **av) Channel *c = findchan(av[1]); time_t ts = Anope::string(av[0]).is_number_only() ? convertTo(av[0]) : 0; bool keep_their_modes = true; - bool was_created = false; if (!c) { c = new Channel(av[1], ts); - was_created = true; + c->SetFlag(CH_SYNCING); } /* Our creation time is newer than what the server gave us */ else if (c->creation_time > ts) { c->creation_time = ts; + c->Reset(); - for (std::list::const_iterator it =ModeManager::Modes.begin(), it_end = ModeManager::Modes.end(); it != it_end; ++it) - { - Mode *m = *it; - - if (m->Type != MODE_STATUS) - continue; - - ChannelMode *cm = debug_cast(m); - - for (CUserList::const_iterator uit = c->users.begin(), uit_end = c->users.end(); uit != uit_end; ++uit) - { - UserContainer *uc = *uit; - - c->RemoveMode(NULL, cm, uc->user->nick); - } - } - if (c->ci) - { - /* Rejoin the bot to fix the TS */ - if (c->ci->bi) - { - c->ci->bi->Part(c, "TS reop"); - c->ci->bi->Join(c); - } - /* Reset mlock */ - check_modes(c); - } + /* Reset mlock */ + check_modes(c); } /* Their TS is newer than ours, our modes > theirs, unset their modes if need be */ - else + else if (ts > c->creation_time) 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) { @@ -1090,7 +1067,8 @@ int anope_event_sjoin(const Anope::string &source, int ac, const char **av) continue; } - Status.push_back(cm); + if (keep_their_modes) + Status.push_back(cm); } User *u = finduser(buf); @@ -1127,7 +1105,7 @@ int anope_event_sjoin(const Anope::string &source, int ac, const char **av) } /* Channel is done syncing */ - if (was_created) + if (c->HasFlag(CH_SYNCING)) { /* Unset the syncing flag */ c->UnsetFlag(CH_SYNCING); diff --git a/src/bots.cpp b/src/bots.cpp index cb7a370c1..d63f6787f 100644 --- a/src/bots.cpp +++ b/src/bots.cpp @@ -49,7 +49,7 @@ BotInfo::BotInfo(const Anope::string &nnick, const Anope::string &nuser, const A if (!this->uid.empty()) BotListByUID[this->uid] = this; - // If we're synchronised with the uplink already, call introduce_user() for this bot. + // If we're synchronised with the uplink already, send the bot. if (Me && !Me->GetLinks().empty() && Me->GetLinks().front()->IsSynced()) { ircdproto->SendClientIntroduction(this->nick, this->GetIdent(), this->host, this->realname, ircd->pseudoclient_mode, this->uid); @@ -136,7 +136,7 @@ void BotInfo::UnAssign(User *u, ChannelInfo *ci) ci->bi = NULL; } -void BotInfo::Join(Channel *c) +void BotInfo::Join(Channel *c, bool update_ts) { if (Config->BSSmartJoin) { @@ -162,19 +162,39 @@ void BotInfo::Join(Channel *c) if (c->HasMode(CMODE_INVITE) || (limit && c->users.size() >= limit)) ircdproto->SendNoticeChanops(this, c, "%s invited %s into the channel.", this->nick.c_str(), this->nick.c_str()); } + + ModeManager::ProcessModes(); } - ircdproto->SendJoin(this, c->name, c->creation_time); - for (std::list::iterator it = BotModes.begin(), it_end = BotModes.end(); it != it_end; ++it) - c->SetMode(this, *it, this->nick, false); c->JoinUser(this); + ChannelContainer *cc = this->FindChannel(c); + for (std::list::iterator it = BotModes.begin(), it_end = BotModes.end(); it != it_end; ++it) + { + if (!update_ts) + { + c->SetMode(this, *it, this->nick, false); + } + else + { + cc->Status->SetFlag((*it)->Name); + c->SetModeInternal(*it, this->nick, false); + } + } + if (!update_ts) + ircdproto->SendJoin(this, c->name, c->creation_time); + else + { + ircdproto->SendJoin(this, cc); + + c->Reset(); + } FOREACH_MOD(I_OnBotJoin, OnBotJoin(c->ci, this)); } -void BotInfo::Join(const Anope::string &chname) +void BotInfo::Join(const Anope::string &chname, bool update_ts) { Channel *c = findchan(chname); - return this->Join(c ? c : new Channel(chname)); + return this->Join(c ? c : new Channel(chname), update_ts); } void BotInfo::Part(Channel *c, const Anope::string &reason) diff --git a/src/channels.cpp b/src/channels.cpp index a10a4e675..709d9cf01 100644 --- a/src/channels.cpp +++ b/src/channels.cpp @@ -75,6 +75,28 @@ Channel::~Channel() ChannelList.erase(this->name); } +void Channel::Reset() +{ + this->ClearModes(NULL, false); + this->ClearBans(NULL, false); + this->ClearExcepts(NULL, false); + this->ClearInvites(NULL, false); + + for (CUserList::const_iterator it = this->users.begin(), it_end = this->users.end(); it != it_end; ++it) + { + UserContainer *uc = *it; + + if (findbot(uc->user->nick)) + continue; + + uc->Status->ClearFlags(); + } + + check_modes(this); + for (CUserList::const_iterator it = this->users.begin(), it_end = this->users.end(); it != it_end; ++it) + chan_set_correct_modes((*it)->user, this, 1); +} + void Channel::Sync() { if (this->users.empty() || (this->users.size() == 1 && this->ci && this->ci->bi == this->users.front()->user)) @@ -84,7 +106,6 @@ void Channel::Sync() if (this->ci) { check_modes(this); - stick_all(this->ci); } if (Me && Me->IsSynced() && !this->topic_sync) @@ -95,7 +116,7 @@ void Channel::JoinUser(User *user) { Alog(LOG_DEBUG) << user->nick << " joins " << this->name; - Flags *Status = new Flags; + ChannelStatus *Status = new ChannelStatus(); ChannelContainer *cc = new ChannelContainer(this); cc->Status = Status; user->chans.push_back(cc); @@ -104,6 +125,14 @@ void Channel::JoinUser(User *user) uc->Status = Status; this->users.push_back(uc); + bool update_ts = false; + if (this->ci && this->ci->HasFlag(CI_PERSIST) && this->creation_time > this->ci->time_registered) + { + Alog(LOG_DEBUG) << "Changing TS of " << this->name << " from " << this->creation_time << " to " << this->ci->time_registered; + this->creation_time = this->ci->time_registered; + update_ts = true; + } + if (!get_ignore(user->nick)) { if (this->ci && check_access(user, this->ci, CA_MEMO) && this->ci->memos.memos.size() > 0) @@ -126,11 +155,9 @@ void Channel::JoinUser(User *user) * and the ignored user doesnt just leave, the bot will never * make it into the channel, leaving the channel botless even for * legit users - Rob - * But don't join the bot if the channel is persistant - Adam - * But join persistant channels when syncing with our uplink- DP **/ - if ((!Me->IsSynced() || !this->ci->HasFlag(CI_PERSIST)) && this->users.size() >= Config->BSMinUsers && !this->FindUser(this->ci->bi)) - this->ci->bi->Join(this); + if (this->users.size() >= Config->BSMinUsers && !this->FindUser(this->ci->bi)) + this->ci->bi->Join(this, update_ts); /* Only display the greet if the main uplink we're connected * to has synced, or we'll get greet-floods when the net * recovers from a netsplit. -GD @@ -141,6 +168,16 @@ void Channel::JoinUser(User *user) this->ci->bi->lastmsg = time(NULL); } } + + if (update_ts) + { + /* Send the updated TS */ + if (!this->ci->bi || !this->FindUser(this->ci->bi)) + { + whosends(this->ci)->Join(this, update_ts); + whosends(this->ci)->Part(this); + } + } } /** Remove a user internally from the channel @@ -296,7 +333,8 @@ void Channel::SetModeInternal(ChannelMode *cm, const Anope::string ¶m, bool cc->Status->SetFlag(cm->Name); /* Enforce secureops, etc */ - chan_set_correct_modes(u, this, 0); + if (EnforceMLock) + chan_set_correct_modes(u, this, 0); return; } /* Setting b/e/I etc */ @@ -654,24 +692,31 @@ bool Channel::HasParam(ChannelModeName Name) const /** Clear all the modes from the channel * @param bi The client setting the modes + * @param internal Only remove the modes internally */ -void Channel::ClearModes(BotInfo *bi) +void Channel::ClearModes(BotInfo *bi, bool internal) { - ChannelMode *cm; - for (size_t n = CMODE_BEGIN + 1; n != CMODE_END; ++n) { - cm = ModeManager::FindChannelModeByName(static_cast(n)); + ChannelMode *cm = ModeManager::FindChannelModeByName(static_cast(n)); if (cm && this->HasMode(cm->Name)) { if (cm->Type == MODE_REGULAR) - this->RemoveMode(NULL, cm); + { + if (!internal) + this->RemoveMode(NULL, cm); + else + this->RemoveModeInternal(cm); + } else if (cm->Type == MODE_PARAM) { Anope::string param; this->GetParam(cm->Name, param); - this->RemoveMode(NULL, cm, param); + if (!internal) + this->RemoveMode(NULL, cm, param); + else + this->RemoveModeInternal(cm, param); } } } @@ -681,58 +726,67 @@ void Channel::ClearModes(BotInfo *bi) /** Clear all the bans from the channel * @param bi The client setting the modes + * @param internal Only remove the modes internally */ -void Channel::ClearBans(BotInfo *bi) +void Channel::ClearBans(BotInfo *bi, bool internal) { Entry *entry, *nexte; - ChannelModeList *cml; - cml = debug_cast(ModeManager::FindChannelModeByName(CMODE_BAN)); + ChannelModeList *cml = debug_cast(ModeManager::FindChannelModeByName(CMODE_BAN)); if (cml && this->bans && this->bans->count) for (entry = this->bans->entries; entry; entry = nexte) { nexte = entry->next; - this->RemoveMode(bi, CMODE_BAN, entry->mask); + if (!internal) + this->RemoveMode(bi, cml, entry->mask); + else + this->RemoveModeInternal(cml, entry->mask); } } /** Clear all the excepts from the channel * @param bi The client setting the modes + * @param internal Only remove the modes internally */ -void Channel::ClearExcepts(BotInfo *bi) +void Channel::ClearExcepts(BotInfo *bi, bool internal) { Entry *entry, *nexte; - ChannelModeList *cml; - cml = debug_cast(ModeManager::FindChannelModeByName(CMODE_EXCEPT)); + ChannelModeList *cml = debug_cast(ModeManager::FindChannelModeByName(CMODE_EXCEPT)); if (cml && this->excepts && this->excepts->count) for (entry = this->excepts->entries; entry; entry = nexte) { nexte = entry->next; - this->RemoveMode(bi, CMODE_EXCEPT, entry->mask); + if (!internal) + this->RemoveMode(bi, cml, entry->mask); + else + this->RemoveModeInternal(cml, entry->mask); } } /** Clear all the invites from the channel * @param bi The client setting the modes + * @param internal Only remove the modes internally */ -void Channel::ClearInvites(BotInfo *bi) +void Channel::ClearInvites(BotInfo *bi, bool internal) { Entry *entry, *nexte; - ChannelModeList *cml; - cml = debug_cast(ModeManager::FindChannelModeByName(CMODE_INVITEOVERRIDE)); + ChannelModeList *cml = debug_cast(ModeManager::FindChannelModeByName(CMODE_INVITEOVERRIDE)); if (cml && this->invites && this->invites->count) for (entry = this->invites->entries; entry; entry = nexte) { nexte = entry->next; - this->RemoveMode(bi, CMODE_INVITEOVERRIDE, entry->mask); + if (!internal) + this->RemoveMode(bi, cml, entry->mask); + else + this->RemoveModeInternal(cml, entry->mask); } } @@ -922,24 +976,21 @@ bool Channel::Kick(BotInfo *bi, User *u, const char *reason, ...) return true; } -/* Returns a fully featured binary modes string. If complete is 0, the - * eventual parameters won't be added to the string. - */ - -Anope::string chan_get_modes(Channel *chan, int complete, int plus) +Anope::string Channel::GetModes(bool complete, bool plus) { - Anope::string res, params, param; + Anope::string res; - if (chan->HasModes()) + if (this->HasModes()) { - for (std::list::iterator it = ModeManager::Modes.begin(), it_end = ModeManager::Modes.end(); it != it_end; ++it) + Anope::string params; + for (std::map::const_iterator it = ModeManager::Modes.begin(), it_end = ModeManager::Modes.end(); it != it_end; ++it) { - if ((*it)->Class != MC_CHANNEL) + if (it->second->Class != MC_CHANNEL) continue; - ChannelMode *cm = debug_cast(*it); + ChannelMode *cm = debug_cast(it->second); - if (chan->HasMode(cm->Name)) + if (this->HasMode(cm->Name)) { res += cm->ModeChar; @@ -951,7 +1002,8 @@ Anope::string chan_get_modes(Channel *chan, int complete, int plus) if (plus || !cmp->MinusNoArg) { - chan->GetParam(cmp->Name, param); + Anope::string param; + this->GetParam(cmp->Name, param); if (!param.empty()) params += " " + param; @@ -1056,7 +1108,6 @@ User *nc_on_chan(Channel *c, const NickCore *nc) void do_join(const Anope::string &source, int ac, const char **av) { User *user; - Channel *chan; time_t ctime = time(NULL); user = finduser(source); @@ -1085,7 +1136,7 @@ void do_join(const Anope::string &source, int ac, const char **av) continue; } - chan = findchan(buf); + Channel *chan = findchan(buf); /* Channel doesn't exist, create it */ if (!chan) @@ -1099,19 +1150,10 @@ void do_join(const Anope::string &source, int ac, const char **av) /* Their time is older, we lose */ if (chan->creation_time > ts) { - Alog(LOG_DEBUG) << "recieved a new TS for JOIN: " << ts; + Alog(LOG_DEBUG) << "Recieved an older TS " << chan->name << " in JOIN, changing from " << chan->creation_time << " to " << ts; + chan->creation_time = ts; - if (chan->ci) - { - /* Cycle the bot to fix ts */ - if (chan->ci->bi) - { - chan->ci->bi->Part(chan, "TS reop"); - chan->ci->bi->Join(chan); - } - /* Be sure to set mlock again, else we could be -r etc.. */ - check_modes(chan); - } + chan->Reset(); } } diff --git a/src/chanserv.cpp b/src/chanserv.cpp index 03760b9b6..c80de4c75 100644 --- a/src/chanserv.cpp +++ b/src/chanserv.cpp @@ -290,8 +290,6 @@ void check_modes(Channel *c) /* If this channel does not have the mode and the mode is mlocked */ if (cm->Type == MODE_REGULAR && !c->HasMode(cm->Name) && ci->HasMLock(cm->Name, true)) { - c->SetMode(NULL, cm); - /* Add the eventual parameter and modify the Channel structure */ if (cm->Type == MODE_PARAM) { @@ -335,6 +333,8 @@ void check_modes(Channel *c) c->RemoveMode(NULL, cm); } } + + stick_all(ci); } /*************************************************************************/ diff --git a/src/init.cpp b/src/init.cpp index 35407ec81..d3476a490 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -22,16 +22,16 @@ extern void moduleAddIRCDMsgs(); void introduce_user(const Anope::string &user) { /* Watch out for infinite loops... */ -#define LTSIZE 20 - static int lasttimes[LTSIZE]; - if (lasttimes[0] >= time(NULL) - 3) - fatal("introduce_user() loop detected"); - memmove(lasttimes, lasttimes + 1, sizeof(lasttimes) - sizeof(int)); - lasttimes[LTSIZE - 1] = time(NULL); -#undef LTSIZE - /* We make the bots go online */ + time_t now = time(NULL); + static time_t lasttime = now - 4; + if (lasttime >= now - 3) + fatal("introduce_user loop detected"); + lasttime = now; - /* XXX: it might be nice to have this inside BotInfo's constructor, or something? */ + if (user.empty()) + ircdproto->SendBOB(); + + /* We make the bots go online */ for (botinfo_map::const_iterator it = BotListByNick.begin(), it_end = BotListByNick.end(); it != it_end; ++it) { BotInfo *bi = it->second; @@ -41,8 +41,20 @@ void introduce_user(const Anope::string &user) ircdproto->SendClientIntroduction(bi->nick, bi->GetIdent(), bi->host, bi->realname, ircd->pseudoclient_mode, bi->GetUID()); XLine x(bi->nick, "Reserved for services"); ircdproto->SendSQLine(&x); + + for (UChannelList::const_iterator cit = bi->chans.begin(), cit_end = bi->chans.end(); cit != cit_end; ++cit) + { + ircdproto->SendJoin(bi, *cit); + } } } + + if (user.empty()) + { + /* Load MLock from the database now that we know what modes exist */ + for (registered_channel_map::iterator it = RegisteredChannelList.begin(), it_end = RegisteredChannelList.end(); it != it_end; ++it) + it->second->LoadMLock(); + } } /*************************************************************************/ @@ -66,16 +78,14 @@ static int set_group() if (gr) { setgid(gr->gr_gid); - return 0; } else { - Alog() << "Unknown group `" << RUNGROUP << "'"; + Alog() << "Unknown run group '" << RUNGROUP << "'"; return -1; } -#else - return 0; #endif + return 0; } /*************************************************************************/ diff --git a/src/main.cpp b/src/main.cpp index df7c61c63..bcb67b6fa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -553,15 +553,6 @@ int main(int ac, char **av, char **envp) delete u; } - /* Nuke all channels */ - for (channel_map::const_iterator it = ChannelList.begin(); it != ChannelList.end();) - { - Channel *c = it->second; - ++it; - - delete c; - } - Me->SetFlag(SERVER_SYNCING); Me->ClearLinks(); diff --git a/src/modes.cpp b/src/modes.cpp index 624023e66..ce34e461c 100644 --- a/src/modes.cpp +++ b/src/modes.cpp @@ -13,7 +13,7 @@ std::list > ModeManager::StackerObjects; /* List of all modes Anope knows about */ -std::list ModeManager::Modes; +std::map ModeManager::Modes; /* User modes */ std::map ModeManager::UserModesByChar; @@ -91,6 +91,37 @@ void SetDefaultMLock(ServerConfig *config) } } +Anope::string ChannelStatus::BuildCharPrefixList() const +{ + Anope::string ret; + + for (std::map::const_iterator it = ModeManager::ChannelModesByChar.begin(), it_end = ModeManager::ChannelModesByChar.end(); it != it_end; ++it) + { + if (this->HasFlag(it->second->Name)) + { + ret += it->second->ModeChar; + } + } + + return ret; +} + +Anope::string ChannelStatus::BuildModePrefixList() const +{ + Anope::string ret; + + for (std::map::const_iterator it = ModeManager::ChannelModesByChar.begin(), it_end = ModeManager::ChannelModesByChar.end(); it != it_end; ++it) + { + if (this->HasFlag(it->second->Name)) + { + ChannelModeStatus *cm = debug_cast(it->second); + ret += cm->Symbol; + } + } + + return ret; +} + /** Default constructor * @param mClass The type of mode this is * @param mNameAsString The mode name as a string @@ -607,7 +638,7 @@ bool ModeManager::AddUserMode(UserMode *um) Alog() << "ModeManager: Added generic support for user mode " << um->ModeChar; } ModeManager::UserModesByName.insert(std::make_pair(um->Name, um)); - ModeManager::Modes.push_back(um); + ModeManager::Modes.insert(std::make_pair(um->NameAsString, um)); FOREACH_MOD(I_OnUserModeAdd, OnUserModeAdd(um)); @@ -631,7 +662,7 @@ bool ModeManager::AddChannelMode(ChannelMode *cm) Alog() << "ModeManager: Added generic support for channel mode " << cm->ModeChar; } ModeManager::ChannelModesByName.insert(std::make_pair(cm->Name, cm)); - ModeManager::Modes.push_back(cm); + ModeManager::Modes.insert(std::make_pair(cm->NameAsString, cm)); /* Apply this mode to the new default mlock if its used */ SetDefaultMLock(Config); @@ -671,6 +702,20 @@ UserMode *ModeManager::FindUserModeByChar(char Mode) return NULL; } +/** Find a mode by name + * @param name The mode name + * @return The mode + */ +Mode *ModeManager::FindModeByName(const Anope::string &name) +{ + std::map::const_iterator it = ModeManager::Modes.find(name); + + if (it != ModeManager::Modes.end()) + return it->second; + + return NULL; +} + /** Find a channel mode * @param Mode The modename * @return The mode class diff --git a/src/protocol.cpp b/src/protocol.cpp index d0cfef071..dfa7d2b3d 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -197,6 +197,11 @@ void IRCDProto::SendPong(const Anope::string &servname, const Anope::string &who send_cmd(ircd->ts6 ? TS6SID : Config->ServerName, "PONG %s %s", servname.c_str(), who.c_str()); } +void IRCDProto::SendJoin(BotInfo *bi, const ChannelContainer *cc) +{ + SendJoin(bi, cc->chan->name, cc->chan->creation_time); +} + void IRCDProto::SendInvite(const BotInfo *bi, const Anope::string &chan, const Anope::string &nick) { send_cmd(ircd->ts6 ? bi->GetUID() : bi->nick, "INVITE %s %s", nick.c_str(), chan.c_str()); diff --git a/src/regchannel.cpp b/src/regchannel.cpp index d055a632b..393054acf 100644 --- a/src/regchannel.cpp +++ b/src/regchannel.cpp @@ -343,65 +343,60 @@ void ChannelInfo::ClearBadWords() */ void ChannelInfo::LoadMLock() { - std::vector modenames; + std::vector modenames_on, modenames_off; - if (this->GetExtRegular("db_mlock_modes_on", modenames)) + // Force +r + this->SetMLock(CMODE_REGISTERED, true); + this->GetExtRegular("db_mlock_modes_on", modenames_on); + this->GetExtRegular("db_mlock_modes_off", modenames_off); + + if (!modenames_on.empty() || !modenames_off.empty()) { - for (std::vector::iterator it = modenames.begin(), it_end = modenames.end(); it != it_end; ++it) + for (std::vector::iterator it = modenames_on.begin(), it_end = modenames_on.end(); it != it_end; ++it) { - for (std::list::iterator mit = ModeManager::Modes.begin(), mit_end = ModeManager::Modes.end(); mit != mit_end; ++mit) - { - if ((*mit)->Class == MC_CHANNEL) - { - ChannelMode *cm = debug_cast(*mit); + Mode *m = ModeManager::FindModeByName(*it); - if (cm->NameAsString.equals_ci(*it)) - this->SetMLock(cm->Name, true); - } + if (m && m->NameAsString.equals_cs(*it)) + { + ChannelMode *cm = debug_cast(m); + this->SetMLock(cm->Name, true); } } - - this->Shrink("db_mlock_modes_on"); - } - - if (this->GetExtRegular("db_mlock_modes_off", modenames)) - { - for (std::vector::iterator it = modenames.begin(), it_end = modenames.end(); it != it_end; ++it) + for (std::vector::iterator it = modenames_off.begin(), it_end = modenames_off.end(); it != it_end; ++it) { - for (std::list::iterator mit = ModeManager::Modes.begin(), mit_end = ModeManager::Modes.end(); mit != mit_end; ++mit) - { - if ((*mit)->Class == MC_CHANNEL) - { - ChannelMode *cm = debug_cast(*mit); + Mode *m = ModeManager::FindModeByName(*it); - if (cm->NameAsString.equals_ci(*it)) - this->SetMLock(cm->Name, false); - } + if (m && m->NameAsString.equals_cs(*it)) + { + ChannelMode *cm = debug_cast(m); + this->SetMLock(cm->Name, false); } } - - this->Shrink("db_mlock_modes_off"); } std::vector > params; - if (this->GetExtRegular("db_mlp", params)) { for (std::vector >::iterator it = params.begin(), it_end = params.end(); it != it_end; ++it) { - for (std::list::iterator mit = ModeManager::Modes.begin(), mit_end = ModeManager::Modes.end(); mit != mit_end; ++mit) + Mode *m = ModeManager::FindModeByName(it->first); + if (m && m->Class == MC_CHANNEL) { - if ((*mit)->Class == MC_CHANNEL) - { - ChannelMode *cm = debug_cast(*mit); - - if (cm->NameAsString.equals_ci(it->first)) - this->SetMLock(cm->Name, true, it->second); - } + ChannelMode *cm = debug_cast(m); + this->SetMLock(cm->Name, true, it->second); } } + } - this->Shrink("db_mlp"); + /* Create perm channel */ + if (this->HasFlag(CI_PERSIST) && !this->c) + { + this->c = new Channel(this->name, this->time_registered); + if (!this->bi) + ChanServ->Assign(NULL, this); + this->bi->Join(c); + check_modes(this->c); + restore_topic(this->name); } } diff --git a/src/servers.cpp b/src/servers.cpp index 7668cebbf..520cf5f36 100644 --- a/src/servers.cpp +++ b/src/servers.cpp @@ -413,14 +413,6 @@ void CapabParse(int ac, const char **av) } } } - - /* Apply MLock now that we know what modes exist (capab is parsed after modes are added to Anope) */ - for (registered_channel_map::iterator it = RegisteredChannelList.begin(), it_end = RegisteredChannelList.end(); it != it_end; ++it) - { - ChannelInfo *ci = it->second; - - ci->LoadMLock(); - } } /*************************************************************************/