diff options
| author | 2010-09-06 13:47:36 -0400 | |
|---|---|---|
| committer | 2010-09-06 13:51:06 -0400 | |
| commit | bed2cd84f2a3f34763cea677baf5ab7e073c41b2 (patch) | |
| tree | 8cfdec30b06e3261848012a926de900a5480832d /src/modules | |
| parent | Change m_passforward to use PopulateInfoMap (diff) | |
Update m_flatfile_channels to be more robust
Enable storage of registered channels without permanent channels, or vice versa
Only set the dirty bit if a channel that is written to the database gets its mode or topic changed, rather than any channel or user
Move NukeChannel to core and put announcets back in options
Allow sending mode merges via the protocol interface
Diffstat (limited to 'src/modules')
| -rw-r--r-- | src/modules/m_flatfile_channels.cpp | 174 | ||||
| -rw-r--r-- | src/modules/m_spanningtree/commands.h | 3 | ||||
| -rw-r--r-- | src/modules/m_spanningtree/fjoin.cpp | 55 | ||||
| -rw-r--r-- | src/modules/m_spanningtree/protocolinterface.cpp | 3 | ||||
| -rw-r--r-- | src/modules/m_spanningtree/protocolinterface.h | 2 | ||||
| -rw-r--r-- | src/modules/m_spanningtree/utils.cpp | 1 | ||||
| -rw-r--r-- | src/modules/m_spanningtree/utils.h | 3 |
7 files changed, 87 insertions, 154 deletions
diff --git a/src/modules/m_flatfile_channels.cpp b/src/modules/m_flatfile_channels.cpp index 2e05a41aa..01f8045a7 100644 --- a/src/modules/m_flatfile_channels.cpp +++ b/src/modules/m_flatfile_channels.cpp @@ -21,7 +21,7 @@ /* structure for single entry */ struct EntryDescriptor { - std::string name, ts, topicset, topicsetby, topic, modes, registrant; + std::string name, ts, topicset, topicsetby, topic, modes; }; /** reads the channel database and returns structure with it */ class DatabaseReader @@ -55,7 +55,6 @@ class DatabaseReader /* clear data */ entry.name = ""; entry.ts = ""; - entry.registrant = ""; entry.topicset = ""; entry.topicsetby = ""; entry.modes = ""; @@ -74,37 +73,23 @@ class DatabaseReader std::string token; irc::spacesepstream sep(str); /* get first one */ - bool res = sep.GetToken (token); /* malformed if it is not chaninfo */ - if (token != "chaninfo" || !res) + if (!sep.GetToken (token) || token != "chaninfo") { ServerInstance->Logs->Log ("MODULE", DEFAULT, "malformed channel database"); return 0; } /* okay, read channel name */ - res = sep.GetToken (token); /* name was get, but if it's the last token, database is malformed */ - if (!res) + if (!sep.GetToken (token)) { ServerInstance->Logs->Log ("MODULE", DEFAULT, "malformed channel database"); return 0; } /* save name */ entry.name = token; - /* get next token, if it's the last one, db is malformed */ - res = sep.GetToken (token); - if (!res) - { - ServerInstance->Logs->Log ("MODULE", DEFAULT, "malformed channel database"); - return 0; - } /* set channel timestamp */ - entry.ts = token; - /* get the last token */ - res = sep.GetToken (token); - /* this time we ignore things after this token */ - /* set registrant */ - entry.registrant = token; + sep.GetToken (entry.ts); /* initial entry read, read next lines in a loop until end, eof means malformed database again */ while (1) { @@ -130,7 +115,7 @@ class DatabaseReader ServerInstance->Logs->Log ("MODULE", DEFAULT, "malformed channel database"); return 0; } - res = sep2.GetToken (token); + sep2.GetToken (token); /* break the loop if token is "end" */ if (token == "end") break; /* it is not, so the large if statement there */ @@ -142,18 +127,16 @@ class DatabaseReader ServerInstance->Logs->Log ("MODULE", DEFAULT, "malformed topic declaration in channel database for channel %s", entry.name.c_str ( )); } /* if not, then read topic set time */ - res = sep2.GetToken (token); /* if end then malformed */ - if (!res) + if (!sep2.GetToken (token)) { ServerInstance->Logs->Log ("MODULE", DEFAULT, "malformed topic declaration in channel database for channel %s", entry.name.c_str ( )); } /* save that */ entry.topicset = token; /* get next token */ - res = sep2.GetToken (token); /* if last then malformed */ - if (!res) + if (!sep2.GetToken (token)) { ServerInstance->Logs->Log ("MODULE", DEFAULT, "malformed topic declaration in channel database for channel %s", entry.name.c_str ( )); } @@ -257,6 +240,13 @@ class FlatFileChannelDB : public Module private: std::string filedb; bool dirty; // filedb needs to be flushed to disk + bool storeregistered, storepermanent; + + /** Whether or not to store a channel to the database */ + bool ShouldStoreChannel(Channel* c) + { + return (storeregistered && c->IsModeSet("registered")) || (storepermanent && c->IsModeSet("permanent")); + } void WriteFileDatabase ( ) { @@ -264,7 +254,7 @@ class FlatFileChannelDB : public Module DatabaseWriter db (filedb); for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++) { - if (i->second->IsModeSet("permanent") || i->second->IsModeSet("registered")) + if (ShouldStoreChannel(i->second)) db.next(i->second); } } @@ -288,77 +278,77 @@ class FlatFileChannelDB : public Module /* entry is valid */ /* try to find the channel */ Channel *chan = ServerInstance->FindChan (entry->name); + time_t ourTS = atol (entry->ts.c_str ( )); /* now, things that will be done depends on if channel was found or not */ - if (chan) - { - /* if it was found, then channel timestamp becomes not important, only things needing to be set is the registrant status, do it */ - /* create the mode stacker */ - irc::modestacker ms; - /* we need to push the mode change */ - ms.push (irc::modechange ("registered", entry->registrant)); - /* make the server process and apply the mode change */ - ServerInstance->Modes->Process (ServerInstance->FakeClient, chan, ms); - /* we don't do it below because channel doesn't exist then */ - /* but in this situation, channel exists and there are users on it, they must know that mode has been changed */ - /* send that info to them */ - ServerInstance->Modes->Send (ServerInstance->FakeClient, chan, ms); - } - else + if (!chan) { /* channel does not exist, allocate it, it will be constructed and added to the network as an empty channel */ - chan = new Channel (entry->name, atol (entry->ts.c_str ( ))); + chan = new Channel (entry->name, ourTS); /* empty modeless channel added and allocated */ - /* so, channel exists in the network, then if topic is not empty, set data */ - if (!entry->topic.empty ( )) - { - chan->topic = entry->topic; - chan->topicset = atol (entry->topicset.c_str ( )); - chan->setby = entry->topicsetby; - } - /* if modestring is not empty, then set all modes in it */ - if (!entry->modes.empty ( )) + } + else if(chan->age > ourTS) + { + chan = Channel::Nuke(chan, entry->name, ourTS); + } + else if(chan->age < ourTS) + { + continue; // there's a channel older than the one we want to load, so we don't load it + } + /* so, channel exists in the network, then if our topic is newer than the current, set data + * if no topic was ever set, topicset is 0 */ + time_t topicTS = atol (entry->topicset.c_str ( )); + if (topicTS && topicTS >= chan->topicset) + { + chan->topic = entry->topic; + chan->topicset = atol (entry->topicset.c_str ( )); + chan->setby = entry->topicsetby; + chan->WriteChannelWithServ(chan->setby, "TOPIC %s :%s", chan->name.c_str(), chan->topic.c_str()); + } + /* if modestring is not empty, then set all modes in it */ + if (!entry->modes.empty ( )) + { + /* create sepstream */ + irc::spacesepstream sep(entry->modes); + /* create modestacker for stacking all mode changes */ + irc::modestacker ms; + /* spacesepstream is used to iterate through all modes that were saved for a channel */ + /* modestacker ms is used to stack them */ + /* iterate through the mode list */ + while (!sep.StreamEnd ( )) { - /* create sepstream */ - irc::spacesepstream sep(entry->modes); - /* create modestacker for stacking all mode changes */ - irc::modestacker ms; - /* spacesepstream is used to iterate through all modes that were saved for a channel */ - /* modestacker ms is used to stack them */ - /* iterate through the mode list */ - while (!sep.StreamEnd ( )) + /* get the mode to be applied */ + std::string token, name, value; + sep.GetToken (token); + /* the mode looks like name=value unless it doesn't have any value then it's just name */ + /* find the position of = sign */ + size_t namepos = token.find ('='); + /* if we didn't find anything, set name to the token because mode is... valueless */ + if (namepos == std::string::npos) name = token; + /* if it found that = sign, we have both name and value */ + else + { + /* it found it, name is string before the character, value is the string after it */ + name = token.substr (0, namepos); + value = token.substr (namepos + 1); + } + /* mode name and value found, we can now add it to the modestacker */ + /* hmm, or we can't, reason is that letters are separate in user and channel modes, but mode names are not, so what if this thing we're setting is + an user mode? */ + /* to check that, we must find the mode */ + ModeHandler *mc = ServerInstance->Modes->FindMode (name); + /* those actions will be taken only if mode was found and if it's the channel mode */ + if (mc && mc->GetModeType ( ) == MODETYPE_CHANNEL) { - /* get the mode to be applied */ - std::string token, name, value; - sep.GetToken (token); - /* the mode looks like name=value unless it doesn't have any value then it's just name */ - /* find the position of = sign */ - size_t namepos = token.find ('='); - /* if we didn't find anything, set name to the token because mode is... valueless */ - if (namepos == std::string::npos) name = token; - /* if it found that = sign, we have both name and value */ - else - { - /* it found it, name is string before the character, value is the string after it */ - name = token.substr (0, namepos); - value = token.substr (namepos + 1); - } - /* mode name and value found, we can now add it to the modestacker */ - /* hmm, or we can't, reason is that letters are separate in user and channel modes, but mode names are not, so what if this thing we're setting is - an user mode? */ - /* to check that, we must find the mode */ - ModeHandler *mc = ServerInstance->Modes->FindMode (name); - /* those actions will be taken only if mode was found and if it's the channel mode */ - if (mc && mc->GetModeType ( ) == MODETYPE_CHANNEL) - { - /* mode was found and is not an user mode but a channel mode, push it to the modestacker, we use id instead of name for quicker push because we - have the mode handler now */ - ms.push (irc::modechange (mc->id, value)); - } + /* mode was found and is not an user mode but a channel mode, push it to the modestacker, we use id instead of name for quicker push because we + have the mode handler now */ + ms.push (irc::modechange (mc->id, value)); } - /* okay, all modes were pushed, modestacker can now produce the mode line */ - /* so, process all mode changes and apply them on a channel */ - ServerInstance->Modes->Process (ServerInstance->FakeClient, chan, ms); } + /* okay, all modes were pushed, modestacker can now produce the mode line */ + /* so, process all mode changes and apply them on a channel as a merge */ + ServerInstance->Modes->Process (ServerInstance->FakeClient, chan, ms, true); + ServerInstance->Modes->Send (ServerInstance->FakeClient, chan, ms); + ServerInstance->PI->SendMode (ServerInstance->FakeClient, chan, ms, true); } } } @@ -387,8 +377,9 @@ class FlatFileChannelDB : public Module void ReadConfig(ConfigReadStatus& status) { ConfigTag *tag = ServerInstance->Config->GetTag ("chandb"); - filedb = tag->getString ("dbfile"); + storeregistered = tag->getBool("storeregistered", true); + storepermanent = tag->getBool("storepermanent", false); } /* called on background timer to write all channels to disk if they were changed */ void OnBackgroundTimer (time_t cur) @@ -404,12 +395,13 @@ class FlatFileChannelDB : public Module /* after the topic has been changed, call this to check if channel was registered */ void OnPostTopicChange (User *user, Channel *chan, const std::string &topic) { - dirty = true; + if (ShouldStoreChannel(chan)) dirty = true; } /* this event is called after each modechange */ void OnMode (User *user, Extensible *target, const irc::modestacker &modes) { - dirty = true; + Channel* chan = IS_CHANNEL(target); + if (chan && ShouldStoreChannel(chan)) dirty = true; } void Prioritize() diff --git a/src/modules/m_spanningtree/commands.h b/src/modules/m_spanningtree/commands.h index 0b4f9853d..daacd3766 100644 --- a/src/modules/m_spanningtree/commands.h +++ b/src/modules/m_spanningtree/commands.h @@ -85,9 +85,6 @@ class CommandFJoin : public Command CommandFJoin(Module* Creator) : Command(Creator, "FJOIN", 3) { flags_needed = FLAG_SERVERONLY; } CmdResult Handle (const std::vector<std::string>& parameters, User *user); RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_BROADCAST; } - /** Recreate a channel, remove modes, send TS change information - */ - Channel* NukeChannel(Channel* old, const std::string& name, time_t ts); }; class CommandFMode : public Command { diff --git a/src/modules/m_spanningtree/fjoin.cpp b/src/modules/m_spanningtree/fjoin.cpp index df11aa091..41a860915 100644 --- a/src/modules/m_spanningtree/fjoin.cpp +++ b/src/modules/m_spanningtree/fjoin.cpp @@ -94,7 +94,7 @@ CmdResult CommandFJoin::Handle(const std::vector<std::string>& params, User *src } else if (ourTS > TS) { - chan = NukeChannel(chan, channel, TS); + chan = Channel::Nuke(chan, channel, TS); if (incremental) { ServerInstance->SNO->WriteToSnoMask('d', "Incremental merge FJOIN recieved for %s", chan->name.c_str()); @@ -162,56 +162,3 @@ CmdResult CommandFJoin::Handle(const std::vector<std::string>& params, User *src } return CMD_SUCCESS; } - -Channel* CommandFJoin::NukeChannel(Channel* old, const std::string& channel, time_t newTS) -{ - time_t oldTS = old->age; - ServerInstance->SNO->WriteToSnoMask('d', "Recreating channel"); - if (((ModuleSpanningTree*)(Module*)creator)->Utils->AnnounceTSChange) - old->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :TS for %s changed from %lu to %lu", - old->name.c_str(), channel.c_str(), (unsigned long) oldTS, (unsigned long) newTS); - - // prepare a mode change that removes all modes on the channel - irc::modestacker stack; - for (ModeIDIter id; id; id++) - { - ModeHandler* mh = ServerInstance->Modes->FindMode(id); - - /* Passing a pointer to a modestacker here causes the mode to be put onto the mode stack, - * rather than applied immediately. Module unloads require this to be done immediately, - * for this function we require tidyness instead. Fixes bug #493 - */ - if (mh && mh->GetModeType() == MODETYPE_CHANNEL) - mh->RemoveMode(old, &stack); - } - - // don't process the change, just send it to clients - ServerInstance->Modes->Send(ServerInstance->FakeClient, old, stack); - - // unhook the old channel - chan_hash::iterator iter = ServerInstance->chanlist->find(old->name); - ServerInstance->chanlist->erase(iter); - - // create the new channel (which inserts itself in chanlist) - Channel* chan = new Channel(channel, newTS); - - // migrate all the users to the new channel - // This has the side effect of dropping their permissions (op/voice/etc) - for(UserMembIter i = old->userlist.begin(); i != old->userlist.end(); i++) - { - User* u = i->first; - Membership* memb = i->second; - u->chans.erase(memb); - memb->cull(); - delete memb; - memb = chan->AddUser(u); - u->chans.insert(memb); - } - // nuke the old channel - old->userlist.clear(); - old->cull(); - delete old; - - return chan; -} - diff --git a/src/modules/m_spanningtree/protocolinterface.cpp b/src/modules/m_spanningtree/protocolinterface.cpp index f262ac0d8..5bc26014b 100644 --- a/src/modules/m_spanningtree/protocolinterface.cpp +++ b/src/modules/m_spanningtree/protocolinterface.cpp @@ -97,7 +97,7 @@ void SpanningTreeProtocolInterface::SendTopic(Channel* channel, std::string &top Utils->DoOneToMany(ServerInstance->Config->GetSID(),"FTOPIC", params); } -void SpanningTreeProtocolInterface::SendMode(User* src, Extensible* dest, irc::modestacker& cmodes) +void SpanningTreeProtocolInterface::SendMode(User* src, Extensible* dest, irc::modestacker& cmodes, bool merge) { irc::modestacker modes(cmodes); parameterlist outlist; @@ -122,6 +122,7 @@ void SpanningTreeProtocolInterface::SendMode(User* src, Extensible* dest, irc::m while (!modes.empty()) { outlist[2] = modes.popModeLine(FORMAT_NETWORK); + if(merge) outlist[2][0] = '='; Utils->DoOneToMany(src->uuid,"FMODE",outlist); } } diff --git a/src/modules/m_spanningtree/protocolinterface.h b/src/modules/m_spanningtree/protocolinterface.h index 4fba4f793..a155b4db9 100644 --- a/src/modules/m_spanningtree/protocolinterface.h +++ b/src/modules/m_spanningtree/protocolinterface.h @@ -16,7 +16,7 @@ class SpanningTreeProtocolInterface : public ProtocolInterface virtual bool SendEncapsulatedData(const parameterlist &encap); virtual void SendMetaData(Extensible* target, const std::string &key, const std::string &data); virtual void SendTopic(Channel* channel, std::string &topic); - virtual void SendMode(User*, Extensible*, irc::modestacker&); + virtual void SendMode(User*, Extensible*, irc::modestacker&, bool = false); virtual void SendSNONotice(const std::string &snomask, const std::string &text); virtual void PushToClient(User* target, const std::string &rawline); virtual void SendChannelPrivmsg(Channel* target, char status, const std::string &text); diff --git a/src/modules/m_spanningtree/utils.cpp b/src/modules/m_spanningtree/utils.cpp index 6ba998b32..2eb068d2f 100644 --- a/src/modules/m_spanningtree/utils.cpp +++ b/src/modules/m_spanningtree/utils.cpp @@ -340,7 +340,6 @@ void SpanningTreeUtilities::ReadConfiguration() ConfigTag* tag = status.GetTag("spanningtree"); FlatLinks = tag->getBool("flatlinks"); HideULines = tag->getBool("hideulines"); - AnnounceTSChange = tag->getBool("announcets"); AllowOptCommon = tag->getBool("allowmismatch"); ChallengeResponse = !tag->getBool("disablehmac"); quiet_bursts = tag->getBool("quietbursts"); diff --git a/src/modules/m_spanningtree/utils.h b/src/modules/m_spanningtree/utils.h index 5281c7580..6c4f0a687 100644 --- a/src/modules/m_spanningtree/utils.h +++ b/src/modules/m_spanningtree/utils.h @@ -55,9 +55,6 @@ class SpanningTreeUtilities : public classbase /** Hide U-Lined servers in /MAP and /LINKS */ bool HideULines; - /** Announce TS changes to channels on merge - */ - bool AnnounceTSChange; /** Allow modules marked as VF_OPTCOMMON to be mismatched when linking */ |
