summaryrefslogtreecommitdiffstats
path: root/src/modules/m_sql_channels.cpp
diff options
context:
space:
mode:
authorGravatar Daniel De Graaf2010-09-05 12:43:13 -0400
committerGravatar Daniel De Graaf2010-09-05 12:43:13 -0400
commit10ade1e23da96dee972be77d7cd3fe6d0f107a4d (patch)
treef50e76b65126da47e5e6bf9d01f9e63ee440ec99 /src/modules/m_sql_channels.cpp
parentReport location with config errors in m_cloaking (diff)
downloadinspircd++-10ade1e23da96dee972be77d7cd3fe6d0f107a4d.tar.gz
inspircd++-10ade1e23da96dee972be77d7cd3fe6d0f107a4d.tar.bz2
inspircd++-10ade1e23da96dee972be77d7cd3fe6d0f107a4d.zip
Break channel database read/write out of m_chanregister
Diffstat (limited to 'src/modules/m_sql_channels.cpp')
-rw-r--r--src/modules/m_sql_channels.cpp192
1 files changed, 192 insertions, 0 deletions
diff --git a/src/modules/m_sql_channels.cpp b/src/modules/m_sql_channels.cpp
new file mode 100644
index 000000000..e00e6c53b
--- /dev/null
+++ b/src/modules/m_sql_channels.cpp
@@ -0,0 +1,192 @@
+/* +------------------------------------+
+ * | Inspire Internet Relay Chat Daemon |
+ * +------------------------------------+
+ *
+ * InspIRCd: (C) 2002-2010 InspIRCd Development Team
+ * See: http://wiki.inspircd.org/Credits
+ *
+ * This program is free but copyrighted software; see
+ * the file COPYING for details.
+ *
+ * ---------------------------------------------------
+ */
+
+
+#include "inspircd.h"
+#include "sql.h"
+
+/* $ModDesc: Provides channel mode +r for channel registration */
+
+static bool reading = false;
+
+class DatabaseReadQuery : public SQLQuery
+{
+ public:
+ LocalIntExt& InDB;
+ DatabaseReadQuery(Module* me, LocalIntExt& indb) : SQLQuery(me), InDB(indb)
+ {
+ }
+
+ void OnResult(SQLResult& res)
+ {
+ SQLEntries row;
+ reading = true;
+ while (res.GetRow(row))
+ {
+ std::string channame = row[0];
+ Channel* chan = ServerInstance->FindChan(channame);
+ if (!chan)
+ {
+ time_t ts = atol(row[1].value.c_str());
+ if (!ts)
+ ts = ServerInstance->Time();
+ chan = new Channel(channame, ts);
+ }
+ InDB.set(chan, 1);
+ if (!row[2].nul)
+ {
+ irc::spacesepstream modes(row[2]);
+ std::string mode;
+ irc::modestacker ms;
+ while (modes.GetToken(mode))
+ {
+ std::string::size_type eq = mode.find('=');
+ std::string name = mode.substr(0, eq);
+ std::string value;
+ if (eq != std::string::npos)
+ value = mode.substr(eq + 1);
+ ModeHandler *mh = ServerInstance->Modes->FindMode(name);
+ if (!mh)
+ continue;
+ ms.push(irc::modechange(mh->id, value, true));
+ }
+ ServerInstance->Modes->Process(ServerInstance->FakeClient, chan, ms);
+ }
+ if (!row[3].nul)
+ {
+ chan->topic = row[3];
+ chan->setby = row[4];
+ chan->topicset = atol(row[5].value.c_str());
+ }
+ }
+ reading = false;
+ }
+};
+class DiscardQuery : public SQLQuery
+{
+ public:
+ DiscardQuery(Module* me) : SQLQuery(me) {}
+ void OnResult(SQLResult& res) {}
+ void OnError(SQLerror& e)
+ {
+ ServerInstance->Logs->Log("m_chanregister", DEFAULT, "SQL update returned error: %s", e.str.c_str());
+ }
+};
+
+class ChanSQLDB : public Module
+{
+ private:
+ std::string tablename;
+ dynamic_reference<SQLProvider> sqldb;
+ LocalIntExt InDB;
+
+ public:
+ ChanSQLDB() : sqldb("SQL"), InDB("in_sql_chans", this)
+ {
+ }
+ Version GetVersion()
+ {
+ return Version("Provides channel state updates to an SQL databse", VF_VENDOR);
+ }
+ void init()
+ {
+ Implementation eventlist[] = {
+ I_OnMode, I_OnPostTopicChange
+ };
+
+ ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
+
+ ParamL n;
+ n.push_back(tablename);
+ // just dump the entire thing back to us, please
+ sqldb->submit(new DatabaseReadQuery(this, InDB),
+ "SELECT (name, ts, modes, topic, topicset, topicts) FROM ?", n);
+ }
+ void ReadConfig(ConfigReadStatus& status)
+ {
+ ConfigTag *tag = ServerInstance->Config->GetTag ("chandb");
+
+ tablename = tag->getString("sqltable");
+ std::string dbid = tag->getString("dbid");
+ if (dbid.empty())
+ sqldb.SetProvider("SQL");
+ else
+ sqldb.SetProvider("SQL/" + dbid);
+ if (!sqldb)
+ status.ReportError(tag, "SQL database not found!");
+ }
+ void OnPostTopicChange (User *user, Channel *chan, const std::string &topic)
+ {
+ if (reading || !InDB.get(chan))
+ return;
+ ParamL n;
+ n.push_back(tablename);
+ n.push_back(chan->topic);
+ n.push_back(chan->setby);
+ n.push_back(ConvToStr(chan->topicset));
+ n.push_back(chan->name);
+ sqldb->submit(new DiscardQuery(this),
+ "UPDATE ? SET (topic, topicset, topicts) = ('?', '?', '?') WHERE name = '?'", n);
+ }
+
+ void OnMode (User *user, Extensible *target, const irc::modestacker &modes)
+ {
+ Channel *chan = IS_CHANNEL(target);
+ if (reading || !chan)
+ return;
+ if (!InDB.get(chan))
+ {
+ AddToDB(chan);
+ return;
+ }
+ irc::modestacker ms;
+ chan->ChanModes(ms, MODELIST_FULL);
+ ParamL n;
+ n.push_back(tablename);
+ n.push_back(ms.popModeLine(FORMAT_PERSIST, INT_MAX, INT_MAX));
+ n.push_back(chan->name);
+ sqldb->submit(new DiscardQuery(this),
+ "UPDATE ? SET modes = '?' WHERE name = '?'", n);
+ }
+
+ void AddToDB(Channel* chan)
+ {
+ irc::modestacker ms;
+ chan->ChanModes(ms, MODELIST_FULL);
+ ParamL n;
+ n.push_back(tablename);
+ n.push_back(chan->name);
+ n.push_back(ConvToStr(chan->age));
+ n.push_back(ms.popModeLine(FORMAT_PERSIST, INT_MAX, INT_MAX));
+ if (chan->topic.empty())
+ {
+ sqldb->submit(new DiscardQuery(this),
+ "INSERT INTO ? (name, ts, modes) VALUES ('?', '?', '?')", n);
+ }
+ else
+ {
+ n.push_back(chan->topic);
+ n.push_back(chan->setby);
+ n.push_back(ConvToStr(chan->topicset));
+ sqldb->submit(new DiscardQuery(this),
+ "INSERT INTO ? (name, ts, modes, topic, topicset, topicts) VALUES ('?', '?', '?', '?', '?', '?')", n);
+ }
+ }
+
+ void Prioritize()
+ {
+ // database reading may depend on channel modes being loaded
+ ServerInstance->Modules->SetPriority(this, I_ModuleInit, PRIORITY_LAST);
+ }
+};
+MODULE_INIT(ChanSQLDB)