diff options
Diffstat (limited to 'modules/database/db_sql_live_read.cpp')
-rw-r--r-- | modules/database/db_sql_live_read.cpp | 434 |
1 files changed, 434 insertions, 0 deletions
diff --git a/modules/database/db_sql_live_read.cpp b/modules/database/db_sql_live_read.cpp new file mode 100644 index 000000000..1159e41fc --- /dev/null +++ b/modules/database/db_sql_live_read.cpp @@ -0,0 +1,434 @@ +#include "module.h" +#include "../extra/sql.h" +#include "../commands/os_session.h" + +class MySQLInterface : public SQLInterface +{ + public: + MySQLInterface(Module *o) : SQLInterface(o) { } + + void OnResult(const SQLResult &r) + { + Log(LOG_DEBUG) << "SQL successfully executed query: " << r.finished_query; + } + + void OnError(const SQLResult &r) + { + if (!r.GetQuery().query.empty()) + Log(LOG_DEBUG) << "Error executing query " << r.finished_query << ": " << r.GetError(); + else + Log(LOG_DEBUG) << "Error executing query: " << r.GetError(); + } +}; + +class DBMySQL : public Module +{ + private: + MySQLInterface sqlinterface; + service_reference<SQLProvider, Base> SQL; + std::set<Anope::string> tables; + + void RunQuery(const SQLQuery &query) + { + if (SQL) + { + if (readonly && this->ro) + { + readonly = this->ro = false; + BotInfo *bi = findbot(Config->OperServ); + if (bi) + ircdproto->SendGlobops(bi, "Found SQL again, going out of readonly mode..."); + } + + SQL->Run(&sqlinterface, query); + } + else + { + if (Anope::CurTime - Config->UpdateTimeout > lastwarn) + { + BotInfo *bi = findbot(Config->OperServ); + if (bi) + ircdproto->SendGlobops(bi, "Unable to locate SQL reference, going to readonly..."); + readonly = this->ro = true; + this->lastwarn = Anope::CurTime; + } + } + } + + void Insert(const Anope::string &table, const SerializableBase::serialized_data &data) + { + if (tables.count(table) == 0 && SQL) + { + this->RunQuery(this->SQL->CreateTable(table, data)); + tables.insert(table); + } + + Anope::string query_text = "INSERT INTO `" + table + "` ("; + for (SerializableBase::serialized_data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it) + query_text += "`" + it->first + "`,"; + query_text.erase(query_text.end() - 1); + query_text += ") VALUES ("; + for (SerializableBase::serialized_data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it) + query_text += "@" + it->first + "@,"; + query_text.erase(query_text.end() - 1); + query_text += ") ON DUPLICATE KEY UPDATE "; + for (SerializableBase::serialized_data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it) + query_text += it->first + "=VALUES(" + it->first + "),"; + query_text.erase(query_text.end() - 1); + + SQLQuery query(query_text); + for (SerializableBase::serialized_data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it) + query.setValue(it->first, it->second.astr()); + + this->RunQuery(query); + } + + void Delete(const Anope::string &table, const SerializableBase::serialized_data &data) + { + Anope::string query_text = "DELETE FROM `" + table + "` WHERE "; + for (SerializableBase::serialized_data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it) + query_text += "`" + it->first + "` = @" + it->first + "@"; + + SQLQuery query(query_text); + for (SerializableBase::serialized_data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it) + query.setValue(it->first, it->second.astr()); + + this->RunQuery(query); + } + + public: + time_t lastwarn; + bool ro; + + DBMySQL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE), sqlinterface(this), SQL("") + { + this->lastwarn = 0; + this->ro = false; + + Implementation i[] = { I_OnReload, I_OnServerConnect }; + ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); + + OnReload(); + + if (CurrentUplink) + OnServerConnect(); + } + + void OnReload() + { + ConfigReader config; + Anope::string engine = config.ReadValue("db_sql", "engine", "", 0); + this->SQL = engine; + } + + void OnServerConnect() + { + Implementation i[] = { + /* Misc */ + I_OnPostCommand, + /* NickServ */ + I_OnNickAddAccess, I_OnNickEraseAccess, I_OnNickClearAccess, + I_OnDelCore, I_OnNickForbidden, I_OnNickGroup, + I_OnNickRegister, I_OnChangeCoreDisplay, + I_OnNickSuspended, I_OnDelNick, + /* ChanServ */ + I_OnAccessAdd, I_OnAccessDel, I_OnAccessClear, I_OnLevelChange, + I_OnDelChan, I_OnChanRegistered, I_OnChanSuspend, + I_OnAkickAdd, I_OnAkickDel, I_OnMLock, I_OnUnMLock, + /* BotServ */ + I_OnBotCreate, I_OnBotChange, I_OnBotDelete, + I_OnBotAssign, I_OnBotUnAssign, + I_OnBadWordAdd, I_OnBadWordDel, + /* MemoServ */ + I_OnMemoSend, I_OnMemoDel, + /* OperServ */ + I_OnExceptionAdd, I_OnExceptionDel, + I_OnAddXLine, I_OnDelXLine, + /* HostServ */ + I_OnSetVhost, I_OnDeleteVhost + }; + ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); + } + + void OnPostCommand(CommandSource &source, Command *command, const std::vector<Anope::string> ¶ms) + { + User *u = source.u; + + if (command->name.find("nickserv/set/") == 0) + { + NickAlias *na = findnick(source.u->nick); + if (!na) + this->Insert(na->nc->serialize_name(), na->nc->serialize()); + + } + else if (command->name.find("nickserv/saset/") == 0) + { + NickAlias *na = findnick(params[1]); + if (!na) + this->Insert(na->nc->serialize_name(), na->nc->serialize()); + } + else if (command->name.find("chanserv/set") == 0 || command->name.find("chanserv/saset") == 0) + { + ChannelInfo *ci = params.size() > 0 ? cs_findchan(params[0]) : NULL; + if (!ci) + this->Insert(ci->serialize_name(), ci->serialize()); + } + else if (command->name == "botserv/kick" && params.size() > 2) + { + ChannelInfo *ci = cs_findchan(params[0]); + if (!ci) + return; + if (!ci->AccessFor(u).HasPriv("SET") && !u->HasPriv("botserv/administration")) + return; + this->Insert(ci->serialize_name(), ci->serialize()); + } + else if (command->name == "botserv/set" && params.size() > 1) + { + ChannelInfo *ci = cs_findchan(params[0]); + BotInfo *bi = NULL; + if (!ci) + bi = findbot(params[0]); + if (bi && params[1].equals_ci("PRIVATE") && u->HasPriv("botserv/set/private")) + this->Insert(bi->serialize_name(), bi->serialize()); + else if (ci && !ci->AccessFor(u).HasPriv("SET") && !u->HasPriv("botserv/administration")) + this->Insert(ci->serialize_name(), ci->serialize()); + } + else if (command->name == "memoserv/ignore" && params.size() > 0) + { + Anope::string target = params[0]; + if (target[0] != '#') + { + NickCore *nc = u->Account(); + if (nc) + this->Insert(nc->serialize_name(), nc->serialize()); + } + else + { + ChannelInfo *ci = cs_findchan(target); + if (ci && ci->AccessFor(u).HasPriv("MEMO")) + this->Insert(ci->serialize_name(), ci->serialize()); + } + } + } + + void OnNickAddAccess(NickCore *nc, const Anope::string &entry) + { + this->Insert(nc->serialize_name(), nc->serialize()); + } + + void OnNickEraseAccess(NickCore *nc, const Anope::string &entry) + { + this->Insert(nc->serialize_name(), nc->serialize()); + } + + void OnNickClearAccess(NickCore *nc) + { + this->Insert(nc->serialize_name(), nc->serialize()); + } + + void OnDelCore(NickCore *nc) + { + this->Delete(nc->serialize_name(), nc->serialize()); + } + + void OnNickForbidden(NickAlias *na) + { + this->Insert(na->serialize_name(), na->serialize()); + } + + void OnNickGroup(User *u, NickAlias *) + { + OnNickRegister(findnick(u->nick)); + } + + void InsertAlias(NickAlias *na) + { + this->Insert(na->serialize_name(), na->serialize()); + } + + void InsertCore(NickCore *nc) + { + this->Insert(nc->serialize_name(), nc->serialize()); + } + + void OnNickRegister(NickAlias *na) + { + this->InsertCore(na->nc); + this->InsertAlias(na); + } + + void OnChangeCoreDisplay(NickCore *nc, const Anope::string &newdisplay) + { + SerializableBase::serialized_data data = nc->serialize(); + this->Delete(nc->serialize_name(), data); + data.erase("display"); + data["display"] << newdisplay; + this->Insert(nc->serialize_name(), data); + + for (std::list<NickAlias *>::iterator it = nc->aliases.begin(), it_end = nc->aliases.end(); it != it_end; ++it) + { + NickAlias *na = *it; + data = na->serialize(); + + this->Delete(na->serialize_name(), data); + data.erase("nc"); + data["nc"] << newdisplay; + this->Insert(na->serialize_name(), data); + } + } + + void OnNickSuspend(NickAlias *na) + { + this->Insert(na->serialize_name(), na->serialize()); + } + + void OnDelNick(NickAlias *na) + { + this->Delete(na->serialize_name(), na->serialize()); + } + + void OnAccessAdd(ChannelInfo *ci, User *, ChanAccess *access) + { + this->Insert(access->serialize_name(), access->serialize()); + } + + void OnAccessDel(ChannelInfo *ci, User *u, ChanAccess *access) + { + this->Delete(access->serialize_name(), access->serialize()); + } + + void OnAccessClear(ChannelInfo *ci, User *u) + { + for (unsigned i = 0; i < ci->GetAccessCount(); ++i) + this->OnAccessDel(ci, NULL, ci->GetAccess(i)); + } + + void OnLevelChange(User *u, ChannelInfo *ci, const Anope::string &priv, int16 what) + { + this->Insert(ci->serialize_name(), ci->serialize()); + } + + void OnDelChan(ChannelInfo *ci) + { + this->Delete(ci->serialize_name(), ci->serialize()); + } + + void OnChanRegistered(ChannelInfo *ci) + { + this->Insert(ci->serialize_name(), ci->serialize()); + } + + void OnChanSuspend(ChannelInfo *ci) + { + this->Insert(ci->serialize_name(), ci->serialize()); + } + + void OnAkickAdd(ChannelInfo *ci, AutoKick *ak) + { + this->Insert(ak->serialize_name(), ak->serialize()); + } + + void OnAkickDel(ChannelInfo *ci, AutoKick *ak) + { + this->Delete(ak->serialize_name(), ak->serialize()); + } + + EventReturn OnMLock(ChannelInfo *ci, ModeLock *lock) + { + this->Insert(lock->serialize_name(), lock->serialize()); + return EVENT_CONTINUE; + } + + EventReturn OnUnMLock(ChannelInfo *ci, ModeLock *lock) + { + this->Delete(lock->serialize_name(), lock->serialize()); + return EVENT_CONTINUE; + } + + void OnBotCreate(BotInfo *bi) + { + this->Insert(bi->serialize_name(), bi->serialize()); + } + + void OnBotChange(BotInfo *bi) + { + OnBotCreate(bi); + } + + void OnBotDelete(BotInfo *bi) + { + this->Delete(bi->serialize_name(), bi->serialize()); + } + + EventReturn OnBotAssign(User *sender, ChannelInfo *ci, BotInfo *bi) + { + this->Insert(ci->serialize_name(), ci->serialize()); + return EVENT_CONTINUE; + } + + EventReturn OnBotUnAssign(User *sender, ChannelInfo *ci) + { + this->Insert(ci->serialize_name(), ci->serialize()); + return EVENT_CONTINUE; + } + + void OnBadWordAdd(ChannelInfo *ci, BadWord *bw) + { + this->Insert(bw->serialize_name(), bw->serialize()); + } + + void OnBadWordDel(ChannelInfo *ci, BadWord *bw) + { + this->Delete(bw->serialize_name(), bw->serialize()); + } + + void OnMemoSend(const Anope::string &source, const Anope::string &target, MemoInfo *mi, Memo *m) + { + this->Insert(m->serialize_name(), m->serialize()); + } + + void OnMemoDel(const NickCore *nc, MemoInfo *mi, Memo *m) + { + this->Delete(m->serialize_name(), m->serialize()); + } + + void OnMemoDel(ChannelInfo *ci, MemoInfo *mi, Memo *m) + { + this->Delete(m->serialize_name(), m->serialize()); + } + + EventReturn OnExceptionAdd(Exception *ex) + { + this->Insert(ex->serialize_name(), ex->serialize()); + return EVENT_CONTINUE; + } + + void OnExceptionDel(User *, Exception *ex) + { + this->Delete(ex->serialize_name(), ex->serialize()); + } + + EventReturn OnAddXLine(XLine *x, XLineManager *xlm) + { + this->Insert(x->serialize_name(), x->serialize()); + return EVENT_CONTINUE; + } + + void OnDelXLine(User *, XLine *x, XLineManager *xlm) + { + this->Delete(x->serialize_name(), x->serialize()); + } + + void OnDeleteVhost(NickAlias *na) + { + this->Insert(na->serialize_name(), na->serialize()); + } + + void OnSetVhost(NickAlias *na) + { + this->Insert(na->serialize_name(), na->serialize()); + } +}; + +MODULE_INIT(DBMySQL) + |