aboutsummaryrefslogtreecommitdiffstats
path: root/src/modules/m_flatfile_channels.cpp
diff options
context:
space:
mode:
authorGravatar Jackmcbarn2010-09-06 13:47:36 -0400
committerGravatar Jackmcbarn2010-09-06 13:51:06 -0400
commitbed2cd84f2a3f34763cea677baf5ab7e073c41b2 (patch)
tree8cfdec30b06e3261848012a926de900a5480832d /src/modules/m_flatfile_channels.cpp
parentChange 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/m_flatfile_channels.cpp')
-rw-r--r--src/modules/m_flatfile_channels.cpp174
1 files changed, 83 insertions, 91 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()