diff options
Diffstat (limited to 'modules')
42 files changed, 3314 insertions, 2697 deletions
diff --git a/modules/commands/bs_kick.cpp b/modules/commands/bs_kick.cpp index 74ccaf05c..2c41b4b90 100644 --- a/modules/commands/bs_kick.cpp +++ b/modules/commands/bs_kick.cpp @@ -577,26 +577,60 @@ class CommandBSKick : public Command } }; -struct BanData +struct BanData : public ExtensibleItem { - Anope::string mask; - time_t last_use; - int16 ttb[TTB_SIZE]; + struct Data + { + Anope::string mask; + time_t last_use; + int16 ttb[TTB_SIZE]; + + Data() + { + this->Clear(); + } + + void Clear() + { + last_use = 0; + for (int i = 0; i < TTB_SIZE; ++i) + this->ttb[i] = 0; + } + }; + + private: + typedef std::map<Anope::string, Data, std::less<ci::string> > data_type; + data_type data_map; - BanData() + public: + Data &get(const Anope::string &key) { - this->Clear(); + return this->data_map[key]; } - void Clear() + bool empty() const + { + return this->data_map.empty(); + } + + void purge() { - last_use = 0; - for (int i = 0; i < TTB_SIZE; ++i) - this->ttb[i] = 0; + for (data_type::iterator it = data_map.begin(), it_end = data_map.end(); it != it_end;) + { + const Anope::string &user = it->first; + Data &bd = it->second; + ++it; + + if (Anope::CurTime - bd.last_use > Config->BSKeepData) + { + data_map.erase(user); + continue; + } + } } }; -struct UserData +struct UserData : public ExtensibleItem { UserData() { @@ -621,6 +655,11 @@ struct UserData Anope::string lastline; Anope::string lasttarget; int16 times; + + void OnDelete() + { + delete this; + } }; @@ -637,23 +676,11 @@ class BanDataPurger : public CallBack { Channel *c = it->second; - std::map<Anope::string, BanData> bandata; - if (c->GetExtRegular("bs_main_bandata", bandata)) + BanData *bd = c->GetExt<BanData *>("bs_main_bandata"); + if (bd != NULL) { - for (std::map<Anope::string, BanData>::iterator it2 = bandata.begin(), it2_end = bandata.end(); it2 != it2_end;) - { - const Anope::string &user = it2->first; - BanData *bd = &it2->second; - ++it2; - - if (Anope::CurTime - bd->last_use > Config->BSKeepData) - { - bandata.erase(user); - continue; - } - } - - if (bandata.empty()) + bd->purge(); + if (bd->empty()) c->Shrink("bs_main_bandata"); } } @@ -665,30 +692,32 @@ class BSKick : public Module CommandBSKick commandbskick; BanDataPurger purger; - BanData *GetBanData(User *u, Channel *c) + BanData::Data &GetBanData(User *u, Channel *c) { - std::map<Anope::string, BanData> bandatamap; - if (!c->GetExtRegular("bs_main_bandata", bandatamap)); - c->Extend("bs_main_bandata", new ExtensibleItemRegular<std::map<Anope::string, BanData> >(bandatamap)); - c->GetExtRegular("bs_main_bandata", bandatamap); - - BanData *bd = &bandatamap[u->GetMask()]; - if (bd->last_use && Anope::CurTime - bd->last_use > Config->BSKeepData) - bd->Clear(); - bd->last_use = Anope::CurTime; - return bd; + BanData *bd = c->GetExt<BanData *>("bs_main_bandata"); + if (bd == NULL) + { + bd = new BanData(); + c->Extend("bs_main_bandata", bd); + } + + return bd->get(u->GetMask()); } UserData *GetUserData(User *u, Channel *c) { - UserData *ud = NULL; UserContainer *uc = c->FindUser(u); - if (uc != NULL && !uc->GetExtPointer("bs_main_userdata", ud)) + if (uc == NULL) + return NULL; + + UserData *ud = uc->GetExt<UserData *>("bs_main_userdata"); + if (ud == NULL) { ud = new UserData(); - uc->Extend("bs_main_userdata", new ExtensibleItemPointer<UserData>(ud)); + uc->Extend("bs_main_userdata", ud); } - return ud; + + return ud; } void check_ban(ChannelInfo *ci, User *u, int ttbtype) @@ -697,17 +726,17 @@ class BSKick : public Module if (u->server->IsULined()) return; - BanData *bd = this->GetBanData(u, ci->c); + BanData::Data &bd = this->GetBanData(u, ci->c); - ++bd->ttb[ttbtype]; - if (ci->ttb[ttbtype] && bd->ttb[ttbtype] >= ci->ttb[ttbtype]) + ++bd.ttb[ttbtype]; + if (ci->ttb[ttbtype] && bd.ttb[ttbtype] >= ci->ttb[ttbtype]) { - /* Should not use == here because bd->ttb[ttbtype] could possibly be > ci->ttb[ttbtype] + /* Should not use == here because bd.ttb[ttbtype] could possibly be > ci->ttb[ttbtype] * if the TTB was changed after it was not set (0) before and the user had already been * kicked a few times. Bug #1056 - Adam */ Anope::string mask; - bd->ttb[ttbtype] = 0; + bd.ttb[ttbtype] = 0; get_idealban(ci, u, mask); diff --git a/modules/commands/cs_access.cpp b/modules/commands/cs_access.cpp index 2821ba5c3..3e737b709 100644 --- a/modules/commands/cs_access.cpp +++ b/modules/commands/cs_access.cpp @@ -28,7 +28,7 @@ static void reset_levels(ChannelInfo *ci) ci->SetLevel(it->first, it->second); } -class AccessChanAccess : public ChanAccess +class AccessChanAccess : public ChanAccess, public Serializable<AccessChanAccess> { public: int level; @@ -86,6 +86,41 @@ class AccessChanAccess : public ChanAccess return highest; } } + + Anope::string serialize_name() { return "AccessChanAccess"; } + serialized_data serialize() + { + serialized_data data; + + data["provider"] << this->provider->name; + data["ci"] << this->ci->name; + data["mask"] << this->mask; + data["creator"] << this->creator; + data["last_seen"].setType(Serialize::DT_INT) << this->last_seen; + data["created"].setType(Serialize::DT_INT) << this->created; + data["level"].setType(Serialize::DT_INT) << this->level; + + return data; + } + + static void unserialize(SerializableBase::serialized_data &data) + { + service_reference<AccessProvider> aprovider(data["provider"].astr()); + ChannelInfo *ci = cs_findchan(data["ci"].astr()); + if (!aprovider || !ci) + return; + + AccessChanAccess *access = new AccessChanAccess(aprovider); + access->provider = aprovider; + access->ci = ci; + data["mask"] >> access->mask; + data["creator"] >> access->creator; + data["last_seen"] >> access->last_seen; + data["created"] >> access->created; + data["level"] >> access->level; + + ci->AddAccess(access); + } }; class AccessAccessProvider : public AccessProvider @@ -459,10 +494,10 @@ class CommandCSAccess : public Command source.Reply(ACCESS_DENIED); else { - ci->ClearAccess(); - FOREACH_MOD(I_OnAccessClear, OnAccessClear(ci, u)); + ci->ClearAccess(); + source.Reply(_("Channel %s access list has been cleared."), ci->name.c_str()); bool override = !IsFounder(u, ci); @@ -833,6 +868,7 @@ class CSAccess : public Module { this->SetAuthor("Anope"); + Serializable<AccessChanAccess>::Alloc.Register("AccessChanAccess"); Implementation i[] = { I_OnReload, I_OnCreateChan, I_OnGroupCheckPriv }; ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); diff --git a/modules/commands/cs_entrymsg.cpp b/modules/commands/cs_entrymsg.cpp index 05b97e027..6fa8d5dd3 100644 --- a/modules/commands/cs_entrymsg.cpp +++ b/modules/commands/cs_entrymsg.cpp @@ -13,34 +13,70 @@ #include "module.h" -struct EntryMsg +struct EntryMsg : Serializable<EntryMsg> { - static unsigned MaxEntries; + ChannelInfo *ci; + Anope::string creator; + Anope::string message; + time_t when; - EntryMsg(const Anope::string &cname, const Anope::string &cmessage, time_t ct = Anope::CurTime) + EntryMsg(ChannelInfo *c, const Anope::string &cname, const Anope::string &cmessage, time_t ct = Anope::CurTime) { + + this->ci = c; this->creator = cname; this->message = cmessage; this->when = ct; } - Anope::string creator; - Anope::string message; - time_t when; + serialized_data serialize() + { + serialized_data data; + + data["ci"] << this->ci->name; + data["creator"] << this->creator; + data["message"] << this->message; + data["when"].setType(Serialize::DT_INT) << this->when; + + return data; + } + + static void unserialize(serialized_data &data); }; -unsigned EntryMsg::MaxEntries = 0; + +static unsigned MaxEntries = 0; + +struct EntryMessageList : std::vector<EntryMsg>, ExtensibleItem +{ +}; + +void EntryMsg::unserialize(serialized_data &data) +{ + ChannelInfo *ci = cs_findchan(data["ci"].astr()); + if (!ci) + return; + + EntryMessageList *messages = ci->GetExt<EntryMessageList *>("cs_entrymsg"); + if (messages == NULL) + { + messages = new EntryMessageList(); + ci->Extend("cs_entrymsg", messages); + } + + messages->push_back(EntryMsg(ci, data["creator"].astr(), data["message"].astr())); +} class CommandEntryMessage : public Command { private: void DoList(CommandSource &source, ChannelInfo *ci) { - std::vector<EntryMsg> messages; - if (ci->GetExtRegular("cs_entrymsg", messages)) + EntryMessageList *messages = ci->GetExt<EntryMessageList *>("cs_entrymsg"); + if (messages == NULL) { source.Reply(_("Entry message list for \2%s\2:"), ci->name.c_str()); - for (unsigned i = 0; i < messages.size(); ++i) - source.Reply(CHAN_LIST_ENTRY, i + 1, messages[i].message.c_str(), messages[i].creator.c_str(), do_strftime(messages[i].when).c_str()); + for (unsigned i = 0; i < messages->size(); ++i) + source.Reply(CHAN_LIST_ENTRY, i + 1, (*messages)[i].message.c_str(), (*messages)[i].creator.c_str(), do_strftime((*messages)[i].when).c_str()); source.Reply(_("End of entry message list.")); } else @@ -49,35 +85,36 @@ class CommandEntryMessage : public Command void DoAdd(CommandSource &source, ChannelInfo *ci, const Anope::string &message) { - std::vector<EntryMsg> messages; - ci->GetExtRegular("cs_entrymsg", messages); + EntryMessageList *messages = ci->GetExt<EntryMessageList *>("cs_entrymsg"); + if (messages == NULL) + { + messages = new EntryMessageList(); + ci->Extend("cs_entrymsg", messages); + } - if (EntryMsg::MaxEntries && messages.size() >= EntryMsg::MaxEntries) + if (MaxEntries && messages->size() >= MaxEntries) source.Reply(_("The entry message list for \2%s\2 is full."), ci->name.c_str()); else { - messages.push_back(EntryMsg(source.u->nick, message)); - ci->Extend("cs_entrymsg", new ExtensibleItemRegular<std::vector<EntryMsg> >(messages)); + messages->push_back(EntryMsg(ci, source.u->nick, message)); source.Reply(_("Entry message added to \2%s\2"), ci->name.c_str()); } } void DoDel(CommandSource &source, ChannelInfo *ci, const Anope::string &message) { - std::vector<EntryMsg> messages; + EntryMessageList *messages = ci->GetExt<EntryMessageList *>("cs_entrymsg"); if (!message.is_pos_number_only()) source.Reply(("Entry message \002%s\002 not found on channel \002%s\002."), message.c_str(), ci->name.c_str()); - else if (ci->GetExtRegular("cs_entrymsg", messages)) + else if (messages != NULL) { try { unsigned i = convertTo<unsigned>(message); - if (i > 0 && i <= messages.size()) + if (i > 0 && i <= messages->size()) { - messages.erase(messages.begin() + i - 1); - if (!messages.empty()) - ci->Extend("cs_entrymsg", new ExtensibleItemRegular<std::vector<EntryMsg> >(messages)); - else + messages->erase(messages->begin() + i - 1); + if (messages->empty()) ci->Shrink("cs_entrymsg"); source.Reply(_("Entry message \2%i\2 for \2%s\2 deleted."), i, ci->name.c_str()); } @@ -165,58 +202,27 @@ class CSEntryMessage : public Module { this->SetAuthor("Anope"); - Implementation i[] = { I_OnJoinChannel, I_OnReload, I_OnDatabaseReadMetadata, I_OnDatabaseWriteMetadata }; - ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); - - this->OnReload(); + + Serializable<EntryMsg>::Alloc.Register("EntryMsg"); } void OnJoinChannel(User *u, Channel *c) { if (u && c && c->ci && u->server->IsSynced()) { - std::vector<EntryMsg> messages; + EntryMessageList *messages = c->ci->GetExt<EntryMessageList *>("cs_entrymsg"); - if (c->ci->GetExtRegular("cs_entrymsg", messages)) - for (unsigned i = 0; i < messages.size(); ++i) - u->SendMessage(c->ci->WhoSends(), "[%s] %s", c->ci->name.c_str(), messages[i].message.c_str()); + if (messages != NULL) + for (unsigned i = 0; i < messages->size(); ++i) + u->SendMessage(c->ci->WhoSends(), "[%s] %s", c->ci->name.c_str(), (*messages)[i].message.c_str()); } } void OnReload() { ConfigReader config; - EntryMsg::MaxEntries = config.ReadInteger("cs_entrymsg", "maxentries", "5", 0, true); - } - - EventReturn OnDatabaseReadMetadata(ChannelInfo *ci, const Anope::string &key, const std::vector<Anope::string> ¶ms) - { - if (key.find("CS_ENTRYMSG_") == 0 && params.size() > 2) - { - Anope::string creator = params[0]; - time_t t = params[1].is_pos_number_only() ? convertTo<time_t>(params[1]) : Anope::CurTime; - Anope::string message = params[2]; - for (unsigned j = 3; j < params.size(); ++j) - message += " " + params[j]; - - std::vector<EntryMsg> messages; - ci->GetExtRegular("cs_entrymsg", messages); - messages.push_back(EntryMsg(creator, message, t)); - ci->Extend("cs_entrymsg", new ExtensibleItemRegular<std::vector<EntryMsg> >(messages)); - - return EVENT_STOP; - } - - return EVENT_CONTINUE; - } - - void OnDatabaseWriteMetadata(void (*WriteMetadata)(const Anope::string &, const Anope::string &), ChannelInfo *ci) - { - std::vector<EntryMsg> messages; - if (ci->GetExtRegular("cs_entrymsg", messages)) - for (unsigned i = 0; i < messages.size(); ++i) - WriteMetadata("CS_ENTRYMSG_" + stringify(i), messages[i].creator + " " + stringify(messages[i].when) + " " + messages[i].message); + MaxEntries = config.ReadInteger("cs_entrymsg", "maxentries", "5", 0, true); } }; diff --git a/modules/commands/cs_flags.cpp b/modules/commands/cs_flags.cpp index 5ead6f2d9..1b790b5f1 100644 --- a/modules/commands/cs_flags.cpp +++ b/modules/commands/cs_flags.cpp @@ -15,7 +15,7 @@ static std::map<Anope::string, char> defaultFlags; -class FlagsChanAccess : public ChanAccess +class FlagsChanAccess : public ChanAccess, public Serializable<FlagsChanAccess> { public: std::set<char> flags; @@ -65,6 +65,41 @@ class FlagsChanAccess : public ChanAccess return Anope::string(buffer.begin(), buffer.end()); } + + Anope::string serialize_name() { return "FlagsChanAccess"; } + serialized_data serialize() + { + serialized_data data; + + data["provider"] << this->provider->name; + data["ci"] << this->ci->name; + data["mask"] << this->mask; + data["creator"] << this->creator; + data["last_seen"].setType(Serialize::DT_INT) << this->last_seen; + data["created"].setType(Serialize::DT_INT) << this->created; + data["flags"] << this->Serialize(); + + return data; + } + + static void unserialize(SerializableBase::serialized_data &data) + { + service_reference<AccessProvider> aprovider(data["provider"].astr()); + ChannelInfo *ci = cs_findchan(data["ci"].astr()); + if (!aprovider || !ci) + return; + + FlagsChanAccess *access = new FlagsChanAccess(aprovider); + access->provider = aprovider; + access->ci = ci; + data["mask"] >> access->mask; + data["creator"] >> access->creator; + data["last_seen"] >> access->last_seen; + data["created"] >> access->created; + access->Unserialize(data["flags"].astr()); + + ci->AddAccess(access); + } }; class FlagsAccessProvider : public AccessProvider @@ -385,6 +420,8 @@ class CSFlags : public Module ModuleManager::Attach(i, this, 1); this->OnReload(); + + Serializable<FlagsChanAccess>::Alloc.Register("FlagsChanAccess"); } void OnReload() diff --git a/modules/commands/cs_info.cpp b/modules/commands/cs_info.cpp index 5fc85666a..e7c8e039e 100644 --- a/modules/commands/cs_info.cpp +++ b/modules/commands/cs_info.cpp @@ -100,10 +100,9 @@ class CommandCSInfo : public Command } if (ci->HasFlag(CI_SUSPENDED)) { - Anope::string by, reason; - ci->GetExtRegular("suspend_by", by); - ci->GetExtRegular("suspend_reason", reason); - source.Reply(_(" Suspended: [%s] %s"), by.c_str(), !reason.empty() ? reason.c_str() : NO_REASON); + Anope::string *by = ci->GetExt<Anope::string *>("suspend_by"), *reason = ci->GetExt<Anope::string *>("suspend_reason"); + if (by != NULL) + source.Reply(_(" Suspended: [%s] %s"), by->c_str(), (reason && !reason->empty() ? reason->c_str() : NO_REASON)); } FOREACH_MOD(I_OnChanInfo, OnChanInfo(source, ci, show_all)); diff --git a/modules/commands/cs_seen.cpp b/modules/commands/cs_seen.cpp index d466acca4..f828e181d 100644 --- a/modules/commands/cs_seen.cpp +++ b/modules/commands/cs_seen.cpp @@ -19,26 +19,55 @@ enum TypeInfo NEW, NICK_TO, NICK_FROM, JOIN, PART, QUIT, KICK }; -struct SeenInfo +struct SeenInfo; +typedef Anope::insensitive_map<SeenInfo *> database_map; +database_map database; + +struct SeenInfo : Serializable<SeenInfo> { + Anope::string nick; Anope::string vhost; TypeInfo type; Anope::string nick2; // for nickchanges and kicks Anope::string channel; // for join/part/kick Anope::string message; // for part/kick/quit time_t last; // the time when the user was last seen -}; -class ModuleConfigClass -{ - public: - time_t purgetime; - time_t expiretimeout; + serialized_data serialize() + { + serialized_data data; + + data["nick"] << nick; + data["vhost"] << vhost; + data["type"] << type; + data["nick2"] << nick2; + data["channel"] << channel; + data["message"] << message; + data["last"].setType(Serialize::DT_INT) << last; + + return data; + } + + static void unserialize(serialized_data &data) + { + SeenInfo *s = new SeenInfo(); + + data["nick"] >> s->nick; + data["vhost"] >> s->vhost; + unsigned int n; + data["type"] >> n; + s->type = static_cast<TypeInfo>(n); + data["nick2"] >> s->nick2; + data["channel"] >> s->channel; + data["message"] >> s->message; + data["last"] >> s->last; + + database[s->nick] = s; + } }; -ModuleConfigClass ModuleConfig; -typedef Anope::insensitive_map<SeenInfo *> database_map; -database_map database; +static time_t purgetime; +static time_t expiretimeout; static SeenInfo *FindInfo(const Anope::string &nick) { @@ -262,7 +291,7 @@ class DataBasePurger : public CallBack database_map::iterator cur = it; ++it; - if ((Anope::CurTime - cur->second->last) > ModuleConfig.purgetime) + if ((Anope::CurTime - cur->second->last) > purgetime) { Log(LOG_DEBUG) << cur->first << " was last seen " << do_strftime(cur->second->last) << ", purging entry"; delete cur->second; @@ -289,48 +318,55 @@ class CSSeen : public Module I_OnUserQuit, I_OnJoinChannel, I_OnPartChannel, - I_OnUserKicked, - I_OnDatabaseRead, - I_OnDatabaseWrite }; + I_OnUserKicked }; ModuleManager::Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - OnReload(); + + Serializable<SeenInfo>::Alloc.Register("SeenInfo"); } + void OnReload() { ConfigReader config; - ModuleConfig.purgetime = dotime(config.ReadValue("cs_seen", "purgetime", "30d", 0)); - ModuleConfig.expiretimeout = dotime(config.ReadValue("cs_seen", "expiretimeout", "1d", 0)); + purgetime = dotime(config.ReadValue("cs_seen", "purgetime", "30d", 0)); + expiretimeout = dotime(config.ReadValue("cs_seen", "expiretimeout", "1d", 0)); - if (purger.GetSecs() != ModuleConfig.expiretimeout) - purger.SetSecs(ModuleConfig.expiretimeout); + if (purger.GetSecs() != expiretimeout) + purger.SetSecs(expiretimeout); } + void OnUserConnect(User *u) { UpdateUser(u, NEW, u->nick, "", "", ""); } + void OnUserNickChange(User *u, const Anope::string &oldnick) { UpdateUser(u, NICK_TO, oldnick, u->nick, "", ""); UpdateUser(u, NICK_FROM, u->nick, oldnick, "", ""); } + void OnUserQuit(User *u, const Anope::string &msg) { UpdateUser(u, QUIT, u->nick, "", "", msg); } + void OnJoinChannel(User *u, Channel *c) { UpdateUser(u, JOIN, u->nick, "", c->name, ""); } + void OnPartChannel(User *u, Channel *c, const Anope::string &channel, const Anope::string &msg) { UpdateUser(u, PART, u->nick, "", channel, msg); } + void OnUserKicked(Channel *c, User *target, const Anope::string &source, const Anope::string &msg) { UpdateUser(target, KICK, target->nick, source, c->name, msg); } + void UpdateUser(const User *u, const TypeInfo Type, const Anope::string &nick, const Anope::string &nick2, const Anope::string &channel, const Anope::string &message) { SeenInfo *info = FindInfo(nick); @@ -339,6 +375,7 @@ class CSSeen : public Module info = new SeenInfo; database.insert(std::pair<Anope::string, SeenInfo *>(nick, info)); } + info->nick = nick; info->vhost = u->GetVIdent() + "@" + u->GetDisplayedHost(); info->type = Type; info->last = Anope::CurTime; @@ -346,82 +383,6 @@ class CSSeen : public Module info->channel = channel; info->message = message; } - - EventReturn OnDatabaseRead(const std::vector<Anope::string> ¶ms) - { - if (params[0].equals_ci("SEEN") && (params.size() >= 5)) - { - SeenInfo *info = new SeenInfo; - database.insert(std::pair<Anope::string, SeenInfo *>(params[1], info)); - info->vhost = params[2]; - info->last = params[3].is_pos_number_only() ? convertTo<time_t>(params[3]) : 0 ; - if (params[4].equals_ci("NEW")) - { - info->type = NEW; - } - else if (params[4].equals_ci("NICK_TO") && params.size() == 6) - { - info->type = NICK_TO; - info->nick2 = params[5]; - } - else if (params[4].equals_ci("NICK_FROM") && params.size() == 6) - { - info->type = NICK_FROM; - info->nick2 = params[5]; - } - else if (params[4].equals_ci("JOIN") && params.size() == 6) - { - info->type = JOIN; - info->channel = params[5]; - } - else if (params[4].equals_ci("PART") && params.size() == 7) - { - info->type = PART; - info->channel = params[5]; - info->message = params[6]; - } - else if (params[4].equals_ci("QUIT") && params.size() == 6) - { - info->type = QUIT; - info->message = params[5]; - } - else if (params[4].equals_ci("KICK") && params.size() == 8) - { - info->type = KICK; - info->nick2 = params[5]; - info->channel = params[6]; - info->message = params[7]; - } - return EVENT_STOP; - } - return EVENT_CONTINUE; - } - void OnDatabaseWrite(void (*Write)(const Anope::string &)) - { - for (database_map::iterator it = database.begin(), it_end = database.end(); it != it_end; ++it) - { - std::stringstream buf; - buf << "SEEN " << it->first.c_str() << " " << it->second->vhost << " " << it->second->last << " "; - switch (it->second->type) - { - case NEW: - buf << "NEW"; break; - case NICK_TO: - buf << "NICK_TO " << it->second->nick2; break; - case NICK_FROM: - buf << "NICK_FROM " << it->second->nick2; break; - case JOIN: - buf << "JOIN " << it->second->channel; break; - case PART: - buf << "PART " << it->second->channel << " :" << it->second->message; break; - case QUIT: - buf << "QUIT :" << it->second->message; break; - case KICK: - buf << "KICK " << it->second->nick2 << " " << it->second->channel << " :" << it->second->message; break; - } - Write(buf.str()); - } - } }; MODULE_INIT(CSSeen) diff --git a/modules/commands/cs_set_misc.cpp b/modules/commands/cs_set_misc.cpp index 61c8c163b..0757e965b 100644 --- a/modules/commands/cs_set_misc.cpp +++ b/modules/commands/cs_set_misc.cpp @@ -12,6 +12,37 @@ #include "module.h" +struct MiscData : Anope::string, ExtensibleItem, Serializable<MiscData> +{ + ChannelInfo *ci; + Anope::string name; + Anope::string data; + + MiscData(ChannelInfo *c, const Anope::string &n, const Anope::string &d) : ci(c), name(n), data(d) + { + } + + serialized_data serialize() + { + serialized_data sdata; + + sdata["ci"] << this->ci->name; + sdata["name"] << this->name; + sdata["data"] << this->data; + + return sdata; + } + + static void unserialize(serialized_data &data) + { + ChannelInfo *ci = cs_findchan(data["ci"].astr()); + if (ci == NULL) + return; + + ci->Extend(data["name"].astr(), new MiscData(ci, data["name"].astr(), data["data"].astr())); + } +}; + class CommandCSSetMisc : public Command { public: @@ -34,10 +65,11 @@ class CommandCSSetMisc : public Command return; } - ci->Shrink("cs_set_misc:" + source.command.replace_all_cs(" ", "_")); + Anope::string key = "cs_set_misc:" + source.command.replace_all_cs(" ", "_"); + ci->Shrink(key); if (params.size() > 1) { - ci->Extend("cs_set_misc:" + source.command.replace_all_cs(" ", "_"), new ExtensibleItemRegular<Anope::string>(params[1])); + ci->Extend(key, new MiscData(ci, key, params[1])); source.Reply(CHAN_SETTING_CHANGED, source.command.c_str(), ci->name.c_str(), params[1].c_str()); } else @@ -64,9 +96,10 @@ class CSSetMisc : public Module { this->SetAuthor("Anope"); - Implementation i[] = { I_OnChanInfo, I_OnDatabaseWriteMetadata, I_OnDatabaseReadMetadata }; + Implementation i[] = { I_OnChanInfo }; ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); + Serializable<MiscData>::Alloc.Register("CSMisc"); } void OnChanInfo(CommandSource &source, ChannelInfo *ci, bool ShowHidden) @@ -79,35 +112,11 @@ class CSSetMisc : public Module if (list[i].find("cs_set_misc:") != 0) continue; - Anope::string value; - if (ci->GetExtRegular(list[i], value)) - source.Reply(" %s: %s", list[i].substr(12).replace_all_cs("_", " ").c_str(), value.c_str()); + MiscData *data = ci->GetExt<MiscData *>(list[i]); + if (data != NULL) + source.Reply(" %s: %s", list[i].substr(12).replace_all_cs("_", " ").c_str(), data->data.c_str()); } } - - void OnDatabaseWriteMetadata(void (*WriteMetadata)(const Anope::string &, const Anope::string &), ChannelInfo *ci) - { - std::deque<Anope::string> list; - ci->GetExtList(list); - - for (unsigned i = 0; i < list.size(); ++i) - { - if (list[i].find("cs_set_misc:") != 0) - continue; - - Anope::string value; - if (ci->GetExtRegular(list[i], value)) - WriteMetadata(list[i], ":" + value); - } - } - - EventReturn OnDatabaseReadMetadata(ChannelInfo *ci, const Anope::string &key, const std::vector<Anope::string> ¶ms) - { - if (key.find("cs_set_misc:") == 0) - ci->Extend(key, new ExtensibleItemRegular<Anope::string>(params[0])); - - return EVENT_CONTINUE; - } }; MODULE_INIT(CSSetMisc) diff --git a/modules/commands/cs_suspend.cpp b/modules/commands/cs_suspend.cpp index d9f846d71..d59931b45 100644 --- a/modules/commands/cs_suspend.cpp +++ b/modules/commands/cs_suspend.cpp @@ -45,9 +45,9 @@ class CommandCSSuspend : public Command } ci->SetFlag(CI_SUSPENDED); - ci->Extend("suspend_by", new ExtensibleItemRegular<Anope::string>(u->nick)); + ci->Extend("suspend_by", new ExtensibleString(u->nick)); if (!reason.empty()) - ci->Extend("suspend_reason", new ExtensibleItemRegular<Anope::string>(reason)); + ci->Extend("suspend_reason", new ExtensibleString(reason)); if (ci->c) { @@ -113,10 +113,9 @@ class CommandCSUnSuspend : public Command return; } - Anope::string by, reason; - ci->GetExtRegular("suspend_by", by); - ci->GetExtRegular("suspend_reason", reason); - Log(LOG_ADMIN, u, this, ci) << " which was suspended by " << by << " for: " << (!reason.empty() ? reason : "No reason"); + Anope::string *by = ci->GetExt<Anope::string *>("suspend_by"), *reason = ci->GetExt<Anope::string *>("suspend_reason"); + if (by != NULL) + Log(LOG_ADMIN, u, this, ci) << " which was suspended by " << *by << " for: " << (reason && !reason->empty() ? *reason : "No reason"); ci->UnsetFlag(CI_SUSPENDED); ci->Shrink("suspend_by"); diff --git a/modules/commands/cs_xop.cpp b/modules/commands/cs_xop.cpp index b2aaffde6..e132f19f5 100644 --- a/modules/commands/cs_xop.cpp +++ b/modules/commands/cs_xop.cpp @@ -90,7 +90,7 @@ static struct XOPAccess } }; -class XOPChanAccess : public ChanAccess +class XOPChanAccess : public ChanAccess, public Serializable<XOPChanAccess> { public: XOPType type; @@ -188,6 +188,41 @@ class XOPChanAccess : public ChanAccess return max; } } + + Anope::string serialize_name() { return "XOPChanAccess"; } + serialized_data serialize() + { + serialized_data data; + + data["provider"] << this->provider->name; + data["ci"] << this->ci->name; + data["mask"] << this->mask; + data["creator"] << this->creator; + data["last_seen"] << this->last_seen; + data["created"] << this->created; + data["type"] << this->Serialize(); + + return data; + } + + static void unserialize(SerializableBase::serialized_data &data) + { + service_reference<AccessProvider> aprovider(data["provider"].astr()); + ChannelInfo *ci = cs_findchan(data["ci"].astr()); + if (!aprovider || !ci) + return; + + XOPChanAccess *access = new XOPChanAccess(aprovider); + access->provider = aprovider; + access->ci = ci; + data["mask"] >> access->mask; + data["creator"] >> access->creator; + data["last_seen"] >> access->last_seen; + data["created"] >> access->created; + access->Unserialize(data["type"].astr()); + + ci->AddAccess(access); + } }; class XOPAccessProvider : public AccessProvider @@ -868,6 +903,7 @@ class CSXOP : public Module { this->SetAuthor("Anope"); + Serializable<XOPChanAccess>::Alloc.Register("XOPChanAccess"); } }; diff --git a/modules/commands/hs_request.cpp b/modules/commands/hs_request.cpp index 3d330bc2a..82bba1bbc 100644 --- a/modules/commands/hs_request.cpp +++ b/modules/commands/hs_request.cpp @@ -21,18 +21,42 @@ static bool HSRequestMemoUser = false; static bool HSRequestMemoOper = false; -void my_add_host_request(const Anope::string &nick, const Anope::string &vIdent, const Anope::string &vhost, const Anope::string &creator, time_t tmp_time); void req_send_memos(CommandSource &source, const Anope::string &vIdent, const Anope::string &vHost); -struct HostRequest +struct HostRequest : ExtensibleItem, Serializable<HostRequest> { + Anope::string nick; Anope::string ident; Anope::string host; time_t time; -}; -typedef std::map<Anope::string, HostRequest *, std::less<ci::string> > RequestMap; -RequestMap Requests; + serialized_data serialize() + { + serialized_data data; + + data["nick"] << this->nick; + data["ident"] << this->ident; + data["host"] << this->host; + data["time"].setType(Serialize::DT_INT) << this->time; + + return data; + } + + static void unserialize(serialized_data &data) + { + NickAlias *na = findnick(data["nick"].astr()); + if (na == NULL) + return; + + HostRequest *req = new HostRequest; + req->nick = na->nick; + data["ident"] >> req->ident; + data["host"] >> req->host; + data["time"] >> req->time; + + na->Extend("hs_request", req); + } +}; class CommandHSRequest : public Command { @@ -54,6 +78,12 @@ class CommandHSRequest : public Command { User *u = source.u; + NickAlias *na = findnick(u->nick); + if (na == NULL) + na = findnick(u->Account()->display); + if (!na) + return; + Anope::string rawhostmask = params[0]; Anope::string user, host; @@ -111,7 +141,14 @@ class CommandHSRequest : public Command u->lastmemosend = Anope::CurTime; return; } - my_add_host_request(u->nick, user, host, u->nick, Anope::CurTime); + + + HostRequest *req = new HostRequest; + req->nick = u->nick; + req->ident = user; + req->host = host; + req->time = Anope::CurTime; + na->Extend("hs_request", req); source.Reply(_("Your vHost has been requested")); req_send_memos(source, user, host); @@ -147,29 +184,21 @@ class CommandHSActivate : public Command const Anope::string &nick = params[0]; NickAlias *na = findnick(nick); - if (na) + HostRequest *req = na ? na->GetExt<HostRequest *>("hs_request") : NULL; + if (req) { - RequestMap::iterator it = Requests.find(na->nick); - if (it != Requests.end()) - { - na->hostinfo.SetVhost(it->second->ident, it->second->host, u->nick, it->second->time); - FOREACH_MOD(I_OnSetVhost, OnSetVhost(na)); + na->hostinfo.SetVhost(req->ident, req->host, u->nick, req->time); + FOREACH_MOD(I_OnSetVhost, OnSetVhost(na)); - if (HSRequestMemoUser && memoserv) - memoserv->Send(Config->HostServ, na->nick, _("[auto memo] Your requested vHost has been approved."), true); + if (HSRequestMemoUser && memoserv) + memoserv->Send(Config->HostServ, na->nick, _("[auto memo] Your requested vHost has been approved."), true); - source.Reply(_("vHost for %s has been activated"), na->nick.c_str()); - Log(LOG_COMMAND, u, this, NULL) << "for " << na->nick << " for vhost " << (!it->second->ident.empty() ? it->second->ident + "@" : "") << it->second->host; - delete it->second; - Requests.erase(it); - } - else - source.Reply(_("No request for nick %s found."), nick.c_str()); + source.Reply(_("vHost for %s has been activated"), na->nick.c_str()); + Log(LOG_COMMAND, u, this, NULL) << "for " << na->nick << " for vhost " << (!req->ident.empty() ? req->ident + "@" : "") << req->host; + na->Shrink("hs_request"); } else - source.Reply(NICK_X_NOT_REGISTERED, nick.c_str()); - - return; + source.Reply(_("No request for nick %s found."), nick.c_str()); } bool OnHelp(CommandSource &source, const Anope::string &subcommand) @@ -199,11 +228,11 @@ class CommandHSReject : public Command const Anope::string &nick = params[0]; const Anope::string &reason = params.size() > 1 ? params[1] : ""; - RequestMap::iterator it = Requests.find(nick); - if (it != Requests.end()) + NickAlias *na = findnick(nick); + HostRequest *req = na ? na->GetExt<HostRequest *>("hs_request") : NULL; + if (req) { - delete it->second; - Requests.erase(it); + na->Shrink("hs_request"); if (HSRequestMemoUser && memoserv) { @@ -246,9 +275,13 @@ class HSListBase : public Command int from = 0, to = 0; unsigned display_counter = 0; - for (RequestMap::iterator it = Requests.begin(), it_end = Requests.end(); it != it_end; ++it) + for (nickalias_map::const_iterator it = NickAliasList.begin(), it_end = NickAliasList.end(); it != it_end; ++it) { - HostRequest *hr = it->second; + NickAlias *na = it->second; + HostRequest *hr = na->GetExt<HostRequest *>("hs_request"); + if (!hr) + continue; + if (((counter >= from && counter <= to) || (!from && !to)) && display_counter < Config->NSListMax) { ++display_counter; @@ -260,8 +293,6 @@ class HSListBase : public Command ++counter; } source.Reply(_("Displayed all records (Count: \002%d\002)"), display_counter); - - return; } public: HSListBase(Module *creator, const Anope::string &cmd, int min, int max) : Command(creator, cmd, min, max) @@ -306,8 +337,7 @@ class HSRequest : public Module { this->SetAuthor("Anope"); - - Implementation i[] = { I_OnDelNick, I_OnDatabaseRead, I_OnDatabaseWrite, I_OnReload }; + Implementation i[] = { I_OnReload }; ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); this->OnReload(); @@ -315,47 +345,8 @@ class HSRequest : public Module ~HSRequest() { - /* Clean up all open host requests */ - while (!Requests.empty()) - { - delete Requests.begin()->second; - Requests.erase(Requests.begin()); - } - } - - void OnDelNick(NickAlias *na) - { - RequestMap::iterator it = Requests.find(na->nick); - - if (it != Requests.end()) - { - delete it->second; - Requests.erase(it); - } - } - - EventReturn OnDatabaseRead(const std::vector<Anope::string> ¶ms) - { - if (params[0].equals_ci("HS_REQUEST") && params.size() >= 5) - { - Anope::string vident = params[2].equals_ci("(null)") ? "" : params[2]; - my_add_host_request(params[1], vident, params[3], params[1], params[4].is_pos_number_only() ? convertTo<time_t>(params[4]) : 0); - - return EVENT_STOP; - } - - return EVENT_CONTINUE; - } - - void OnDatabaseWrite(void (*Write)(const Anope::string &)) - { - for (RequestMap::iterator it = Requests.begin(), it_end = Requests.end(); it != it_end; ++it) - { - HostRequest *hr = it->second; - std::stringstream buf; - buf << "HS_REQUEST " << it->first << " " << (hr->ident.empty() ? "(null)" : hr->ident) << " " << hr->host << " " << hr->time; - Write(buf.str()); - } + for (nickalias_map::const_iterator it = NickAliasList.begin(), it_end = NickAliasList.end(); it != it_end; ++it) + it->second->Shrink("hs_request"); } void OnReload() @@ -393,28 +384,4 @@ void req_send_memos(CommandSource &source, const Anope::string &vIdent, const An } } -void my_add_host_request(const Anope::string &nick, const Anope::string &vIdent, const Anope::string &vhost, const Anope::string &creator, time_t tmp_time) -{ - HostRequest *hr = new HostRequest; - hr->ident = vIdent; - hr->host = vhost; - hr->time = tmp_time; - RequestMap::iterator it = Requests.find(nick); - if (it != Requests.end()) - { - delete it->second; - Requests.erase(it); - } - Requests.insert(std::make_pair(nick, hr)); -} - -void my_load_config() -{ - ConfigReader config; - HSRequestMemoUser = config.ReadFlag("hs_request", "memouser", "no", 0); - HSRequestMemoOper = config.ReadFlag("hs_request", "memooper", "no", 0); - - Log(LOG_DEBUG) << "[hs_request] Set config vars: MemoUser=" << HSRequestMemoUser << " MemoOper=" << HSRequestMemoOper; -} - MODULE_INIT(HSRequest) diff --git a/modules/commands/ns_ajoin.cpp b/modules/commands/ns_ajoin.cpp index bed0442d7..d7bde685e 100644 --- a/modules/commands/ns_ajoin.cpp +++ b/modules/commands/ns_ajoin.cpp @@ -13,66 +13,113 @@ #include "module.h" +struct AJoinList : std::vector<std::pair<Anope::string, Anope::string> >, ExtensibleItem, Serializable<AJoinList> +{ + NickCore *nc; + + AJoinList(NickCore *n) : nc(n) { } + + serialized_data serialize() + { + serialized_data sd; + + sd["nc"] << this->nc->display; + Anope::string channels; + for (unsigned i = 0; i < this->size(); ++i) + channels += this->at(i).first + "," + this->at(i).second; + sd["channels"] << channels; + + return sd; + } + + static void unserialize(serialized_data &sd) + { + NickCore *nc = findcore(sd["nc"].astr()); + if (nc == NULL) + return; + + AJoinList *aj = new AJoinList(nc); + nc->Extend("ns_ajoin_channels", aj); + + Anope::string token; + spacesepstream ssep(sd["channels"].astr()); + while (ssep.GetToken(token)) + { + size_t c = token.find(','); + Anope::string chan, key; + if (c == Anope::string::npos) + chan = token; + else + { + chan = token.substr(0, c); + key = token.substr(c + 1); + } + + aj->push_back(std::make_pair(chan, key)); + } + } +}; + class CommandNSAJoin : public Command { void DoList(CommandSource &source, const std::vector<Anope::string> ¶ms) { - std::vector<std::pair<Anope::string, Anope::string> > channels; - source.u->Account()->GetExtRegular("ns_ajoin_channels", channels); + AJoinList *channels = source.u->Account()->GetExt<AJoinList *>("ns_ajoin_channels"); - if (channels.empty()) + if (channels == NULL || channels->empty()) source.Reply(_("Your auto join list is empty.")); else { source.Reply(_("Your auto join list:\n" " Num Channel Key")); - for (unsigned i = 0; i < channels.size(); ++i) - source.Reply(" %3d %-12s %s", i + 1, channels[i].first.c_str(), channels[i].second.c_str()); + for (unsigned i = 0; i < channels->size(); ++i) + source.Reply(" %3d %-12s %s", i + 1, channels->at(i).first.c_str(), channels->at(i).second.c_str()); } } void DoAdd(CommandSource &source, const std::vector<Anope::string> ¶ms) { - std::vector<std::pair<Anope::string, Anope::string> > channels; - source.u->Account()->GetExtRegular("ns_ajoin_channels", channels); + AJoinList *channels = source.u->Account()->GetExt<AJoinList *>("ns_ajoin_channels"); + if (channels == NULL) + { + channels = new AJoinList(source.u->Account()); + source.u->Account()->Extend("ns_ajoin_channels", channels); + } - unsigned i; - for (i = 0; i < channels.size(); ++i) - if (channels[i].first.equals_ci(params[1])) - break; + unsigned i = 0; + if (channels != NULL) + for (; i < channels->size(); ++i) + if (channels->at(i).first.equals_ci(params[1])) + break; - if (channels.size() >= Config->AJoinMax) + if (channels->size() >= Config->AJoinMax) source.Reply(_("Your auto join list is full.")); - else if (i != channels.size()) + else if (i != channels->size()) source.Reply(_("%s is already on your auto join list."), params[1].c_str()); else if (ircdproto->IsChannelValid(params[1]) == false) source.Reply(CHAN_X_INVALID, params[1].c_str()); else { - channels.push_back(std::make_pair(params[1], params.size() > 2 ? params[2] : "")); + channels->push_back(std::make_pair(params[1], params.size() > 2 ? params[2] : "")); source.Reply(_("Added %s to your auto join list."), params[1].c_str()); - source.u->Account()->Extend("ns_ajoin_channels", new ExtensibleItemRegular<std::vector< - std::pair<Anope::string, Anope::string> > >(channels)); } } void DoDel(CommandSource &source, const std::vector<Anope::string> ¶ms) { - std::vector<std::pair<Anope::string, Anope::string> > channels; - source.u->Account()->GetExtRegular("ns_ajoin_channels", channels); + AJoinList *channels = source.u->Account()->GetExt<AJoinList *>("ns_ajoin_channels"); - unsigned i; - for (i = 0; i < channels.size(); ++i) - if (channels[i].first.equals_ci(params[1])) - break; + unsigned i = 0; + if (channels != NULL) + for (; i < channels->size(); ++i) + if (channels->at(i).first.equals_ci(params[1])) + break; - if (i == channels.size()) + if (channels == NULL || i == channels->size()) source.Reply(_("%s was not found on your auto join list."), params[1].c_str()); else { - channels.erase(channels.begin() + i); - source.u->Account()->Extend("ns_ajoin_channels", new ExtensibleItemRegular<std::vector< - std::pair<Anope::string, Anope::string> > >(channels)); + channels->erase(channels->begin() + i); source.Reply(_("%s was removed from your auto join list."), params[1].c_str()); } } @@ -120,25 +167,28 @@ class NSAJoin : public Module { this->SetAuthor("Anope"); - - Implementation i[] = { I_OnNickIdentify, I_OnDatabaseWriteMetadata, I_OnDatabaseReadMetadata }; + Implementation i[] = { I_OnNickIdentify }; ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); + + Serializable<AJoinList>::Alloc.Register("AJoinList"); } void OnNickIdentify(User *u) { - std::vector<std::pair<Anope::string, Anope::string> > channels; - u->Account()->GetExtRegular("ns_ajoin_channels", channels); + AJoinList *channels = u->Account()->GetExt<AJoinList *>("ns_ajoin_channels"); + + if (channels == NULL) + return; - for (unsigned i = 0; i < channels.size(); ++i) + for (unsigned i = 0; i < channels->size(); ++i) { - Channel *c = findchan(channels[i].first); - ChannelInfo *ci = c != NULL ? c->ci : cs_findchan(channels[i].first); + Channel *c = findchan(channels->at(i).first); + ChannelInfo *ci = c != NULL ? c->ci : cs_findchan(channels->at(i).first); if (c == NULL && ci != NULL) c = ci->c; bool need_invite = false; - Anope::string key = channels[i].second; + Anope::string key = channels->at(i).second; if (ci != NULL) { @@ -192,54 +242,12 @@ class NSAJoin : public Module BotInfo *bi = findbot(Config->NickServ); if (!bi || !ci->AccessFor(u).HasPriv("INVITE")) continue; - ircdproto->SendInvite(bi, channels[i].first, u->nick); + ircdproto->SendInvite(bi, channels->at(i).first, u->nick); } - ircdproto->SendSVSJoin(Config->NickServ, u->nick, channels[i].first, key); + ircdproto->SendSVSJoin(Config->NickServ, u->nick, channels->at(i).first, key); } } - - void OnDatabaseWriteMetadata(void (*WriteMetadata)(const Anope::string &, const Anope::string &), NickCore *nc) - { - std::vector<std::pair<Anope::string, Anope::string> > channels; - nc->GetExtRegular("ns_ajoin_channels", channels); - - Anope::string chans; - for (unsigned i = 0; i < channels.size(); ++i) - chans += " " + channels[i].first + "," + channels[i].second; - - if (!chans.empty()) - { - chans.erase(chans.begin()); - WriteMetadata("NS_AJOIN", chans); - } - } - - EventReturn OnDatabaseReadMetadata(NickCore *nc, const Anope::string &key, const std::vector<Anope::string> ¶ms) - { - if (key == "NS_AJOIN") - { - std::vector<std::pair<Anope::string, Anope::string> > channels; - nc->GetExtRegular("ns_ajoin_channels", channels); - - for (unsigned i = 0; i < params.size(); ++i) - { - Anope::string chan, chankey; - commasepstream sep(params[i]); - sep.GetToken(chan); - sep.GetToken(chankey); - - channels.push_back(std::make_pair(chan, chankey)); - } - - nc->Extend("ns_ajoin_channels", new ExtensibleItemRegular<std::vector< - std::pair<Anope::string, Anope::string> > >(channels)); - - return EVENT_STOP; - } - - return EVENT_CONTINUE; - } }; MODULE_INIT(NSAJoin) diff --git a/modules/commands/ns_register.cpp b/modules/commands/ns_register.cpp index aced3046e..acfcd2acd 100644 --- a/modules/commands/ns_register.cpp +++ b/modules/commands/ns_register.cpp @@ -46,8 +46,8 @@ class CommandNSConfirm : public Command } else if (u->Account()) { - Anope::string code; - if (u->Account()->GetExtRegular<Anope::string>("ns_register_passcode", code) && code == passcode) + Anope::string *code = u->Account()->GetExt<Anope::string *>("ns_register_passcode"); + if (code != NULL && *code == passcode) { u->Account()->Shrink("ns_register_passcode"); Log(LOG_COMMAND, u, this) << "to confirm their email"; @@ -320,8 +320,9 @@ class NSRegister : public Module static bool SendRegmail(User *u, NickAlias *na, BotInfo *bi) { - Anope::string code; - if (na->nc->GetExtRegular<Anope::string>("ns_register_passcode", code) == false) + Anope::string *code = na->nc->GetExt<Anope::string *>("ns_register_passcode"); + Anope::string codebuf; + if (code == NULL) { int chars[] = { ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', @@ -332,20 +333,22 @@ static bool SendRegmail(User *u, NickAlias *na, BotInfo *bi) }; int idx, min = 1, max = 62; for (idx = 0; idx < 9; ++idx) - code += chars[1 + static_cast<int>((static_cast<float>(max - min)) * getrandom16() / 65536.0) + min]; - na->nc->Extend("ns_register_passcode", new ExtensibleItemRegular<Anope::string>(code)); + codebuf += chars[1 + static_cast<int>((static_cast<float>(max - min)) * getrandom16() / 65536.0) + min]; + na->nc->Extend("ns_register_passcode", new ExtensibleString(codebuf)); } + else + codebuf = *code; Anope::string subject = translate(na->nc, Config->MailRegistrationSubject.c_str()); Anope::string message = translate(na->nc, Config->MailRegistrationMessage.c_str()); subject = subject.replace_all_cs("%n", na->nick); subject = subject.replace_all_cs("%N", Config->NetworkName); - subject = subject.replace_all_cs("%c", code); + subject = subject.replace_all_cs("%c", codebuf); message = message.replace_all_cs("%n", na->nick); message = message.replace_all_cs("%N", Config->NetworkName); - message = message.replace_all_cs("%c", code); + message = message.replace_all_cs("%c", codebuf); return Mail(u, na->nc, bi, subject, message); } diff --git a/modules/commands/ns_resetpass.cpp b/modules/commands/ns_resetpass.cpp index 153691cdf..3cced2de2 100644 --- a/modules/commands/ns_resetpass.cpp +++ b/modules/commands/ns_resetpass.cpp @@ -56,6 +56,12 @@ class CommandNSResetPass : public Command } }; +struct ResetInfo : ExtensibleItem +{ + Anope::string code; + time_t time; +}; + class NSResetPass : public Module { CommandNSResetPass commandnsresetpass; @@ -80,28 +86,25 @@ class NSResetPass : public Module User *u = source.u; NickAlias *na = findnick(params[0]); - time_t t; - Anope::string c; - if (na && na->nc->GetExtRegular("ns_resetpass_code", c) && na->nc->GetExtRegular("ns_resetpass_time", t)) + ResetInfo *ri = na ? na->nc->GetExt<ResetInfo *>("ns_resetpass") : NULL; + if (na && ri) { const Anope::string &passcode = params[1]; - if (t < Anope::CurTime - 3600) + if (ri->time < Anope::CurTime - 3600) { - na->nc->Shrink("ns_resetpass_code"); - na->nc->Shrink("ns_resetpass_time"); + na->nc->Shrink("ns_resetpass"); source.Reply(_("Your password reset request has expired.")); } - else if (passcode.equals_cs(c)) + else if (passcode.equals_cs(ri->code)) { - na->nc->Shrink("ns_resetpass_code"); - na->nc->Shrink("ns_resetpass_time"); + na->nc->Shrink("ns_resetpass"); Log(LOG_COMMAND, u, &commandnsresetpass) << "confirmed RESETPASS to forcefully identify to " << na->nick; na->nc->UnsetFlag(NI_UNCONFIRMED); u->Identify(na); - source.Reply(_("You are now identified for your nick. Change your passwor now.")); + source.Reply(_("You are now identified for your nick. Change your password now.")); } else @@ -142,8 +145,10 @@ static bool SendResetEmail(User *u, NickAlias *na, BotInfo *bi) message = message.replace_all_cs("%N", Config->NetworkName); message = message.replace_all_cs("%c", passcode); - na->nc->Extend("ns_resetpass_code", new ExtensibleItemRegular<Anope::string>(passcode)); - na->nc->Extend("ns_resetpass_time", new ExtensibleItemRegular<time_t>(Anope::CurTime)); + ResetInfo *ri = new ResetInfo; + ri->code = passcode; + ri->time = Anope::CurTime; + na->nc->Extend("ns_resetpass", ri); return Mail(u, na->nc, bi, subject, message); } diff --git a/modules/commands/ns_set_email.cpp b/modules/commands/ns_set_email.cpp index 175ed5b9e..e86338075 100644 --- a/modules/commands/ns_set_email.cpp +++ b/modules/commands/ns_set_email.cpp @@ -26,7 +26,7 @@ static bool SendConfirmMail(User *u, BotInfo *bi) Anope::string code; for (idx = 0; idx < 9; ++idx) code += chars[1 + static_cast<int>((static_cast<float>(max - min)) * getrandom16() / 65536.0) + min]; - u->Account()->Extend("ns_set_email_passcode", new ExtensibleItemRegular<Anope::string>(code)); + u->Account()->Extend("ns_set_email_passcode", new ExtensibleString(code)); Anope::string subject = Config->MailEmailchangeSubject; Anope::string message = Config->MailEmailchangeMessage; @@ -80,7 +80,7 @@ class CommandNSSetEmail : public Command if (!param.empty() && Config->NSConfirmEmailChanges && !u->IsServicesOper()) { - u->Account()->Extend("ns_set_email", new ExtensibleItemRegular<Anope::string>(param)); + u->Account()->Extend("ns_set_email", new ExtensibleString(param)); Anope::string old = u->Account()->email; u->Account()->email = param; if (SendConfirmMail(u, source.owner)) @@ -163,12 +163,12 @@ class NSSetEmail : public Module User *u = source.u; if (command->name == "nickserv/confirm" && !params.empty() && u->IsIdentified()) { - Anope::string new_email, passcode; - if (u->Account()->GetExtRegular("ns_set_email", new_email) && u->Account()->GetExtRegular("ns_set_email_passcode", passcode)) + Anope::string *new_email = u->Account()->GetExt<Anope::string *>("ns_set_email"), *passcode = u->Account()->GetExt<Anope::string *>("ns_set_email_passcode"); + if (new_email && passcode) { - if (params[0] == passcode) + if (params[0] == *passcode) { - u->Account()->email = new_email; + u->Account()->email = *new_email; Log(LOG_COMMAND, u, command) << "to confirm their email address change to " << u->Account()->email; source.Reply(_("Your email address has been changed to \002%s\002."), u->Account()->email.c_str()); u->Account()->Shrink("ns_set_email"); diff --git a/modules/commands/ns_set_misc.cpp b/modules/commands/ns_set_misc.cpp index c511159d2..a9b93083d 100644 --- a/modules/commands/ns_set_misc.cpp +++ b/modules/commands/ns_set_misc.cpp @@ -13,6 +13,38 @@ #include "module.h" +struct MiscData : Anope::string, ExtensibleItem, Serializable<MiscData> +{ + NickCore *nc; + Anope::string name; + Anope::string data; + + MiscData(NickCore *ncore, const Anope::string &n, const Anope::string &d) : nc(ncore), name(n), data(d) + { + } + + serialized_data serialize() + { + serialized_data sdata; + + sdata["nc"] << this->nc->display; + sdata["name"] << this->name; + sdata["data"] << this->data; + + return sdata; + } + + static void unserialize(serialized_data &data) + { + NickCore *nc = findcore(data["nc"].astr()); + if (nc == NULL) + return; + + nc->Extend(data["name"].astr(), new MiscData(nc, data["name"].astr(), data["data"].astr())); + } +}; + + class CommandNSSetMisc : public Command { public: @@ -31,10 +63,11 @@ class CommandNSSetMisc : public Command } NickCore *nc = na->nc; - nc->Shrink("ns_set_misc:" + source.command.replace_all_cs(" ", "_")); + Anope::string key = "ns_set_misc:" + source.command.replace_all_cs(" ", "_"); + nc->Shrink(key); if (!param.empty()) { - nc->Extend("ns_set_misc:" + source.command.replace_all_cs(" ", "_"), new ExtensibleItemRegular<Anope::string>(param)); + nc->Extend(key, new MiscData(nc, key, param)); source.Reply(CHAN_SETTING_CHANGED, source.command.c_str(), nc->display.c_str(), param.c_str()); } else @@ -75,9 +108,10 @@ class NSSetMisc : public Module { this->SetAuthor("Anope"); - Implementation i[] = { I_OnNickInfo, I_OnDatabaseWriteMetadata, I_OnDatabaseReadMetadata }; + Implementation i[] = { I_OnNickInfo }; ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); + Serializable<MiscData>::Alloc.Register("NSMisc"); } void OnNickInfo(CommandSource &source, NickAlias *na, bool ShowHidden) @@ -90,35 +124,11 @@ class NSSetMisc : public Module if (list[i].find("ns_set_misc:") != 0) continue; - Anope::string value; - if (na->nc->GetExtRegular(list[i], value)) - source.Reply(" %s: %s", list[i].substr(12).replace_all_cs("_", " ").c_str(), value.c_str()); - } - } - - void OnDatabaseWriteMetadata(void (*WriteMetadata)(const Anope::string &, const Anope::string &), NickCore *nc) - { - std::deque<Anope::string> list; - nc->GetExtList(list); - - for (unsigned i = 0; i < list.size(); ++i) - { - if (list[i].find("ns_set_misc:") != 0) - continue; - - Anope::string value; - if (nc->GetExtRegular(list[i], value)) - WriteMetadata(list[i], ":" + value); + MiscData *data = na->nc->GetExt<MiscData *>(list[i]); + if (data) + source.Reply(" %s: %s", list[i].substr(12).replace_all_cs("_", " ").c_str(), data->data.c_str()); } } - - EventReturn OnDatabaseReadMetadata(NickCore *nc, const Anope::string &key, const std::vector<Anope::string> ¶ms) - { - if (key.find("ns_set_misc:") == 0) - nc->Extend(key, new ExtensibleItemRegular<Anope::string>(params[0])); - - return EVENT_CONTINUE; - } }; MODULE_INIT(NSSetMisc) diff --git a/modules/commands/os_forbid.cpp b/modules/commands/os_forbid.cpp index ef591923c..00731f703 100644 --- a/modules/commands/os_forbid.cpp +++ b/modules/commands/os_forbid.cpp @@ -214,10 +214,11 @@ class OSForbid : public Module { this->SetAuthor("Anope"); - Implementation i[] = { I_OnUserConnect, I_OnUserNickChange, I_OnJoinChannel, I_OnPreCommand, I_OnDatabaseWrite, I_OnDatabaseRead }; + Implementation i[] = { I_OnUserConnect, I_OnUserNickChange, I_OnJoinChannel, I_OnPreCommand }; ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); + Serializable<ForbidData>::Alloc.Register("Forbid"); } void OnUserConnect(dynamic_reference<User> &u, bool &exempt) @@ -301,48 +302,6 @@ class OSForbid : public Module return EVENT_CONTINUE; } - - void OnDatabaseWrite(void (*Write)(const Anope::string &)) - { - std::vector<ForbidData *> forbids = this->forbidService.GetForbids(); - for (unsigned i = 0; i < forbids.size(); ++i) - { - ForbidData *f = forbids[i]; - Anope::string ftype; - if (f->type == FT_NICK) - ftype = "NICK"; - else if (f->type == FT_CHAN) - ftype = "CHAN"; - else if (f->type == FT_EMAIL) - ftype = "EMAIL"; - Write("FORBID " + f->mask + " " + f->creator + " " + stringify(f->created) + " " + stringify(f->expires) + " " + ftype + " " + f->reason); - } - } - - EventReturn OnDatabaseRead(const std::vector<Anope::string> ¶ms) - { - if (params.size() > 5 && params[0] == "FORBID") - { - ForbidData *f = new ForbidData(); - f->mask = params[1]; - f->creator = params[2]; - f->created = convertTo<time_t>(params[3]); - f->expires = convertTo<time_t>(params[4]); - if (params[5] == "NICK") - f->type = FT_NICK; - else if (params[5] == "CHAN") - f->type = FT_CHAN; - else if (params[5] == "EMAIL") - f->type = FT_EMAIL; - else - f->type = FT_NONE; - f->reason = params.size() > 6 ? params[6] : ""; - - this->forbidService.AddForbid(f); - } - - return EVENT_CONTINUE; - } }; MODULE_INIT(OSForbid) diff --git a/modules/commands/os_forbid.h b/modules/commands/os_forbid.h index 06a936645..1aac412a3 100644 --- a/modules/commands/os_forbid.h +++ b/modules/commands/os_forbid.h @@ -9,7 +9,7 @@ enum ForbidType FT_EMAIL }; -struct ForbidData +struct ForbidData : Serializable<ForbidData> { Anope::string mask; Anope::string creator; @@ -17,6 +17,9 @@ struct ForbidData time_t created; time_t expires; ForbidType type; + + serialized_data serialize(); + static void unserialize(serialized_data &data); }; class ForbidService : public Service<Base> @@ -33,5 +36,40 @@ class ForbidService : public Service<Base> virtual const std::vector<ForbidData *> &GetForbids() = 0; }; +static service_reference<ForbidService, Base> forbid_service("forbid"); + +SerializableBase::serialized_data ForbidData::serialize() +{ + serialized_data data; + + data["mask"] << this->mask; + data["creator"] << this->creator; + data["reason"] << this->reason; + data["created"] << this->created; + data["expires"] << this->expires; + data["type"] << this->type; + + return data; +} + +void ForbidData::unserialize(SerializableBase::serialized_data &data) +{ + if (!forbid_service) + return; + + ForbidData *fb = new ForbidData; + + data["mask"] >> fb->mask; + data["creator"] >> fb->creator; + data["reason"] >> fb->reason; + data["created"] >> fb->created; + data["expires"] >> fb->expires; + unsigned int t; + data["type"] >> t; + fb->type = static_cast<ForbidType>(t); + + forbid_service->AddForbid(fb); +} + #endif diff --git a/modules/commands/os_ignore.cpp b/modules/commands/os_ignore.cpp index 5f2cbb195..6462284f5 100644 --- a/modules/commands/os_ignore.cpp +++ b/modules/commands/os_ignore.cpp @@ -17,7 +17,7 @@ class OSIgnoreService : public IgnoreService { public: - OSIgnoreService(Module *o, const Anope::string &n) : IgnoreService(o, n) { } + OSIgnoreService(Module *o) : IgnoreService(o) { } void AddIgnore(const Anope::string &mask, const Anope::string &creator, const Anope::string &reason, time_t delta = Anope::CurTime) { @@ -124,7 +124,7 @@ class OSIgnoreService : public IgnoreService } /* Check whether the entry has timed out */ - if (ign != ign_end)// && (*ign)->time && (*ign)->time <= Anope::CurTime) + if (ign != ign_end) { IgnoreData &id = *ign; @@ -146,7 +146,6 @@ class CommandOSIgnore : public Command private: void DoAdd(CommandSource &source, const std::vector<Anope::string> ¶ms) { - service_reference<IgnoreService, Base> ignore_service("ignore"); if (!ignore_service) return; @@ -181,7 +180,6 @@ class CommandOSIgnore : public Command void DoList(CommandSource &source) { - service_reference<IgnoreService, Base> ignore_service("ignore"); if (!ignore_service) return; @@ -205,7 +203,6 @@ class CommandOSIgnore : public Command void DoDel(CommandSource &source, const std::vector<Anope::string> ¶ms) { - service_reference<IgnoreService, Base> ignore_service("ignore"); if (!ignore_service) return; @@ -222,7 +219,6 @@ class CommandOSIgnore : public Command void DoClear(CommandSource &source) { - service_reference<IgnoreService, Base> ignore_service("ignore"); if (!ignore_service) return; @@ -287,53 +283,15 @@ class OSIgnore : public Module public: OSIgnore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE), - osignoreservice(this, "ignore"), commandosignore(this) + osignoreservice(this), commandosignore(this) { this->SetAuthor("Anope"); - Implementation i[] = { I_OnDatabaseRead, I_OnDatabaseWrite, I_OnBotPrivmsg }; + Implementation i[] = { I_OnBotPrivmsg }; ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); - } - - EventReturn OnDatabaseRead(const std::vector<Anope::string> ¶ms) - { - if (params.size() >= 4 && params[0].equals_ci("OS") && params[1].equals_ci("IGNORE")) - { - service_reference<IgnoreService, Base> ignore_service("ignore"); - if (ignore_service) - { - const Anope::string &mask = params[2]; - time_t time = params[3].is_pos_number_only() ? convertTo<time_t>(params[3]) : 0; - const Anope::string &creator = params.size() > 4 ? params[4] : ""; - const Anope::string &reason = params.size() > 5 ? params[5] : ""; - ignore_service->AddIgnore(mask, creator, reason, time - Anope::CurTime); - - return EVENT_STOP; - } - } - - return EVENT_CONTINUE; - } - - void OnDatabaseWrite(void (*Write)(const Anope::string &)) - { - for (std::list<IgnoreData>::iterator ign = this->osignoreservice.GetIgnores().begin(), ign_end = this->osignoreservice.GetIgnores().end(); ign != ign_end; ) - { - if (ign->time && ign->time <= Anope::CurTime) - { - Log(LOG_DEBUG) << "[os_ignore] Expiring ignore entry " << ign->mask; - ign = this->osignoreservice.GetIgnores().erase(ign); - } - else - { - std::stringstream buf; - buf << "OS IGNORE " << ign->mask << " " << ign->time << " " << ign->creator << " :" << ign->reason; - Write(buf.str()); - ++ign; - } - } + Serializable<IgnoreData>::Alloc.Register("Ignore"); } EventReturn OnBotPrivmsg(User *u, BotInfo *bi, Anope::string &message) diff --git a/modules/commands/os_ignore.h b/modules/commands/os_ignore.h index b00f427dd..753a4cfaf 100644 --- a/modules/commands/os_ignore.h +++ b/modules/commands/os_ignore.h @@ -10,12 +10,15 @@ */ -struct IgnoreData +struct IgnoreData : Serializable<IgnoreData> { Anope::string mask; Anope::string creator; Anope::string reason; time_t time; /* When do we stop ignoring them? */ + + serialized_data serialize(); + static void unserialize(serialized_data &data); }; class IgnoreService : public Service<Base> @@ -23,7 +26,7 @@ class IgnoreService : public Service<Base> protected: std::list<IgnoreData> ignores; - IgnoreService(Module *c, const Anope::string &n) : Service<Base>(c, n) { } + IgnoreService(Module *c) : Service<Base>(c, "ignore") { } public: virtual void AddIgnore(const Anope::string &mask, const Anope::string &creator, const Anope::string &reason, time_t delta = Anope::CurTime) = 0; @@ -37,3 +40,28 @@ class IgnoreService : public Service<Base> inline std::list<IgnoreData> &GetIgnores() { return this->ignores; } }; +static service_reference<IgnoreService, Base> ignore_service("ignore"); + +SerializableBase::serialized_data IgnoreData::serialize() +{ + serialized_data data; + + data["mask"] << this->mask; + data["creator"] << this->creator; + data["reason"] << this->reason; + data["time"] << this->time; + + return data; +} + +void IgnoreData::unserialize(SerializableBase::serialized_data &data) +{ + if (!ignore_service) + return; + + time_t t; + data["time"] >> t; + + ignore_service->AddIgnore(data["mask"].astr(), data["creator"].astr(), data["reason"].astr(), t); +} + diff --git a/modules/commands/os_login.cpp b/modules/commands/os_login.cpp index 57c172f7f..d08310424 100644 --- a/modules/commands/os_login.cpp +++ b/modules/commands/os_login.cpp @@ -32,7 +32,7 @@ class CommandOSLogin : public Command source.Reply(_("No oper block for your nick.")); else if (o->password.empty()) source.Reply(_("Your oper block doesn't require logging in.")); - else if (source.u->GetExt("os_login_password_correct")) + else if (source.u->HasExt("os_login_password_correct")) source.Reply(_("You are already identified.")); else if (o->password != password) { @@ -42,7 +42,7 @@ class CommandOSLogin : public Command else { Log(LOG_ADMIN, source.u, this) << "and successfully identified to " << source.owner->nick; - source.u->Extend("os_login_password_correct"); + source.u->Extend("os_login_password_correct", NULL); source.Reply(_("Password accepted.")); } @@ -84,7 +84,7 @@ class OSLogin : public Module { if (!u->Account()->o->password.empty()) { - if (u->GetExt("os_login_password_correct")) + if (u->HasExt("os_login_password_correct")) return EVENT_ALLOW; return EVENT_STOP; } diff --git a/modules/commands/os_module.cpp b/modules/commands/os_module.cpp index 7f9f1d990..36fe570cd 100644 --- a/modules/commands/os_module.cpp +++ b/modules/commands/os_module.cpp @@ -32,13 +32,6 @@ class CommandOSModLoad : public Command { ircdproto->SendGlobops(source.owner, "%s loaded module %s", u->nick.c_str(), mname.c_str()); source.Reply(_("Module \002%s\002 loaded"), mname.c_str()); - - /* If a user is loading this module, then the core databases have already been loaded - * so trigger the event manually - */ - Module *m = ModuleManager::FindModule(mname); - if (m) - m->OnPostLoadDatabases(); } else if (status == MOD_ERR_EXISTS) source.Reply(_("Module \002%s\002 is already loaded."), mname.c_str()); @@ -100,13 +93,6 @@ class CommandOSModReLoad : public Command { ircdproto->SendGlobops(source.owner, "%s reloaded module %s", u->nick.c_str(), mname.c_str()); source.Reply(_("Module \002%s\002 reloaded"), mname.c_str()); - - /* If a user is loading this module, then the core databases have already been loaded - * so trigger the event manually - */ - m = ModuleManager::FindModule(mname); - if (m) - m->OnPostLoadDatabases(); } else { diff --git a/modules/commands/os_news.cpp b/modules/commands/os_news.cpp index 6a959ee47..b2537bbc9 100644 --- a/modules/commands/os_news.cpp +++ b/modules/commands/os_news.cpp @@ -377,9 +377,10 @@ class OSNews : public Module this->SetAuthor("Anope"); - Implementation i[] = { I_OnUserModeSet, I_OnUserConnect, I_OnDatabaseRead, I_OnDatabaseWrite }; + Implementation i[] = { I_OnUserModeSet, I_OnUserConnect }; ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); + Serializable<NewsItem>::Alloc.Register("NewsItem"); } void OnUserModeSet(User *u, UserModeName Name) @@ -396,51 +397,6 @@ class OSNews : public Module DisplayNews(user, NEWS_LOGON); DisplayNews(user, NEWS_RANDOM); } - - EventReturn OnDatabaseRead(const std::vector<Anope::string> ¶ms) - { - if (params[0].equals_ci("OS") && params.size() >= 7 && params[1].equals_ci("NEWS")) - { - NewsItem *n = new NewsItem(); - // params[2] was news number - n->time = params[3].is_number_only() ? convertTo<time_t>(params[3]) : 0; - n->who = params[4]; - if (params[5].equals_ci("LOGON")) - n->type = NEWS_LOGON; - else if (params[5].equals_ci("RANDOM")) - n->type = NEWS_RANDOM; - else if (params[5].equals_ci("OPER")) - n->type = NEWS_OPER; - n->text = params[6]; - - this->newsservice.AddNewsItem(n); - - return EVENT_STOP; - } - - return EVENT_CONTINUE; - } - - void OnDatabaseWrite(void (*Write)(const Anope::string &)) - { - for (unsigned i = 0; i < 3; ++i) - { - std::vector<NewsItem *> &list = this->newsservice.GetNewsList(static_cast<NewsType>(i)); - for (std::vector<NewsItem *>::iterator it = list.begin(); it != list.end(); ++it) - { - NewsItem *n = *it; - Anope::string ntype; - if (n->type == NEWS_LOGON) - ntype = "LOGON"; - else if (n->type == NEWS_RANDOM) - ntype = "RANDOM"; - else if (n->type == NEWS_OPER) - ntype = "OPER"; - Anope::string buf = "OS NEWS 0 " + stringify(n->time) + " " + n->who + " " + ntype + " :" + n->text; - Write(buf); - } - } - } }; MODULE_INIT(OSNews) diff --git a/modules/commands/os_news.h b/modules/commands/os_news.h index 436cadcb4..9e41173d7 100644 --- a/modules/commands/os_news.h +++ b/modules/commands/os_news.h @@ -15,12 +15,15 @@ struct NewsMessages const char *msgs[10]; }; -struct NewsItem +struct NewsItem : Serializable<NewsItem> { NewsType type; Anope::string text; Anope::string who; time_t time; + + serialized_data serialize(); + static void unserialize(serialized_data &data); }; class NewsService : public Service<Base> @@ -35,5 +38,36 @@ class NewsService : public Service<Base> virtual std::vector<NewsItem *> &GetNewsList(NewsType t) = 0; }; +static service_reference<NewsService, Base> news_service("news"); + +SerializableBase::serialized_data NewsItem::serialize() +{ + serialized_data data; + + data["type"] << this->type; + data["text"] << this->text; + data["who"] << this->who; + data["time"] << this->time; + + return data; +} + +void NewsItem::unserialize(SerializableBase::serialized_data &data) +{ + if (!news_service) + return; + + NewsItem *ni = new NewsItem(); + + unsigned int t; + data["type"] >> t; + ni->type = static_cast<NewsType>(t); + data["text"] >> ni->text; + data["who"] >> ni->who; + data["time"] >> ni->time; + + news_service->AddNewsItem(ni); +} + #endif // OS_NEWS diff --git a/modules/commands/os_oper.cpp b/modules/commands/os_oper.cpp index db300f1ce..1d38a0279 100644 --- a/modules/commands/os_oper.cpp +++ b/modules/commands/os_oper.cpp @@ -13,6 +13,34 @@ #include "module.h" +struct MyOper : Oper, Serializable<MyOper> +{ + MyOper(const Anope::string &n, OperType *o) : Oper(n, o) { } + + serialized_data serialize() + { + serialized_data data; + + data["name"] << this->name; + data["type"] << this->ot->GetName(); + + return data; + } + + static void unserialize(serialized_data &data) + { + OperType *ot = OperType::Find(data["type"].astr()); + if (ot == NULL) + return; + NickCore *nc = findcore(data["name"].astr()); + if (nc == NULL) + return; + + nc->o = new MyOper(nc->display, ot); + Log(LOG_NORMAL, "operserv/oper") << "Tied oper " << nc->display << " to type " << ot->GetName(); + } +}; + class CommandOSOper : public Command { public: @@ -46,8 +74,7 @@ class CommandOSOper : public Command source.Reply(_("Oper type \2%s\2 has not been configured."), type.c_str()); else { - delete na->nc->o; - na->nc->o = new Oper(na->nc->display, ot); + na->nc->o = new MyOper(na->nc->display, ot); Log(LOG_ADMIN, source.u, this) << "ADD " << na->nick << " as type " << ot->GetName(); source.Reply("%s (%s) added to the \2%s\2 list.", na->nick.c_str(), na->nc->display.c_str(), ot->GetName().c_str()); @@ -177,43 +204,18 @@ class OSOper : public Module { this->SetAuthor("Anope"); - Implementation i[] = { I_OnDatabaseWrite, I_OnDatabaseRead }; - ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); - + Serializable<MyOper>::Alloc.Register("Oper"); } - void OnDatabaseWrite(void (*Write)(const Anope::string &)) + ~OSOper() { for (nickcore_map::const_iterator it = NickCoreList.begin(), it_end = NickCoreList.end(); it != it_end; ++it) { NickCore *nc = it->second; - if (!nc->o) - continue; - bool found = false; - for (std::list<NickAlias *>::const_iterator it2 = nc->aliases.begin(), it2_end = nc->aliases.end(); it2 != it2_end; ++it2) - if (Oper::Find((*it2)->nick) != NULL) - found = true; - if (found == false) - { - Write("OPER " + nc->display + " :" + nc->o->ot->GetName()); - } - } - } - EventReturn OnDatabaseRead(const std::vector<Anope::string> ¶ms) - { - if (params[0] == "OPER" && params.size() > 2) - { - NickCore *nc = findcore(params[1]); - if (!nc || nc->o) - return EVENT_CONTINUE; - OperType *ot = OperType::Find(params[2]); - if (ot == NULL) - return EVENT_CONTINUE; - nc->o = new Oper(nc->display, ot); - Log(LOG_NORMAL, "operserv/oper") << "Tied oper " << nc->display << " to type " << ot->GetName(); + if (nc->o && !nc->o->config) + delete nc->o; } - return EVENT_CONTINUE; } }; diff --git a/modules/commands/os_session.cpp b/modules/commands/os_session.cpp index 8b174f333..a6a2d2396 100644 --- a/modules/commands/os_session.cpp +++ b/modules/commands/os_session.cpp @@ -14,8 +14,6 @@ #include "module.h" #include "os_session.h" -static service_reference<SessionService, Base> sessionservice("session"); - class MySessionService : public SessionService { SessionMap Sessions; @@ -94,18 +92,18 @@ class ExpireTimer : public Timer void Tick(time_t) { - if (!sessionservice) + if (!session_service) return; - for (unsigned i = sessionservice->GetExceptions().size(); i > 0; --i) + for (unsigned i = session_service->GetExceptions().size(); i > 0; --i) { - Exception *e = sessionservice->GetExceptions()[i - 1]; + Exception *e = session_service->GetExceptions()[i - 1]; if (!e->expires || e->expires > Anope::CurTime) continue; BotInfo *bi = findbot(Config->OperServ); if (Config->WallExceptionExpire && bi) ircdproto->SendGlobops(bi, "Session exception for %s has expired.", e->mask.c_str()); - sessionservice->DelException(e); + session_service->DelException(e); delete e; } } @@ -133,7 +131,7 @@ class ExceptionDelCallback : public NumberList virtual void HandleNumber(unsigned Number) { - if (!Number || Number > sessionservice->GetExceptions().size()) + if (!Number || Number > session_service->GetExceptions().size()) return; ++Deleted; @@ -143,10 +141,10 @@ class ExceptionDelCallback : public NumberList static void DoDel(CommandSource &source, unsigned index) { - Exception *e = sessionservice->GetExceptions()[index]; + Exception *e = session_service->GetExceptions()[index]; FOREACH_MOD(I_OnExceptionDel, OnExceptionDel(source.u, e)); - sessionservice->DelException(e); + session_service->DelException(e); delete e; } }; @@ -163,7 +161,7 @@ class ExceptionListCallback : public NumberList virtual void HandleNumber(unsigned Number) { - if (!Number || Number > sessionservice->GetExceptions().size()) + if (!Number || Number > session_service->GetExceptions().size()) return; if (!SentHeader) @@ -178,10 +176,10 @@ class ExceptionListCallback : public NumberList static void DoList(CommandSource &source, unsigned index) { - if (index >= sessionservice->GetExceptions().size()) + if (index >= session_service->GetExceptions().size()) return; - source.Reply(_("%3d %4d %s"), index + 1, sessionservice->GetExceptions()[index]->limit, sessionservice->GetExceptions()[index]->mask.c_str()); + source.Reply(_("%3d %4d %s"), index + 1, session_service->GetExceptions()[index]->limit, session_service->GetExceptions()[index]->mask.c_str()); } }; @@ -194,7 +192,7 @@ class ExceptionViewCallback : public ExceptionListCallback void HandleNumber(unsigned Number) { - if (!Number || Number > sessionservice->GetExceptions().size()) + if (!Number || Number > session_service->GetExceptions().size()) return; if (!SentHeader) @@ -208,12 +206,12 @@ class ExceptionViewCallback : public ExceptionListCallback static void DoList(CommandSource &source, unsigned index) { - if (index >= sessionservice->GetExceptions().size()) + if (index >= session_service->GetExceptions().size()) return; - Anope::string expirebuf = expire_left(source.u->Account(), sessionservice->GetExceptions()[index]->expires); + Anope::string expirebuf = expire_left(source.u->Account(), session_service->GetExceptions()[index]->expires); - source.Reply(_("%3d. %s (by %s on %s; %s)\n " " Limit: %-4d - %s"), index + 1, sessionservice->GetExceptions()[index]->mask.c_str(), !sessionservice->GetExceptions()[index]->who.empty() ? sessionservice->GetExceptions()[index]->who.c_str() : "<unknown>", do_strftime((sessionservice->GetExceptions()[index]->time ? sessionservice->GetExceptions()[index]->time : Anope::CurTime)).c_str(), expirebuf.c_str(), sessionservice->GetExceptions()[index]->limit, sessionservice->GetExceptions()[index]->reason.c_str()); + source.Reply(_("%3d. %s (by %s on %s; %s)\n " " Limit: %-4d - %s"), index + 1, session_service->GetExceptions()[index]->mask.c_str(), !session_service->GetExceptions()[index]->who.empty() ? session_service->GetExceptions()[index]->who.c_str() : "<unknown>", do_strftime((session_service->GetExceptions()[index]->time ? session_service->GetExceptions()[index]->time : Anope::CurTime)).c_str(), expirebuf.c_str(), session_service->GetExceptions()[index]->limit, session_service->GetExceptions()[index]->reason.c_str()); } }; @@ -238,7 +236,7 @@ class CommandOSSession : public Command source.Reply(_("Hosts with at least \002%d\002 sessions:"), mincount); source.Reply(_("Sessions Host")); - for (SessionService::SessionMap::iterator it = sessionservice->GetSessions().begin(), it_end = sessionservice->GetSessions().end(); it != it_end; ++it) + for (SessionService::SessionMap::iterator it = session_service->GetSessions().begin(), it_end = session_service->GetSessions().end(); it != it_end; ++it) { Session *session = it->second; @@ -253,13 +251,13 @@ class CommandOSSession : public Command void DoView(CommandSource &source, const std::vector<Anope::string> ¶ms) { Anope::string param = params[1]; - Session *session = sessionservice->FindSession(param); + Session *session = session_service->FindSession(param); if (!session) source.Reply(_("\002%s\002 not found on session list."), param.c_str()); else { - Exception *exception = sessionservice->FindException(param); + Exception *exception = session_service->FindException(param); source.Reply(_("The host \002%s\002 currently has \002%d\002 sessions with a limit of \002%d\002."), param.c_str(), session->count, exception ? exception-> limit : Config->DefSessionLimit); } @@ -375,7 +373,7 @@ class CommandOSException : public Command return; } - for (std::vector<Exception *>::iterator it = sessionservice->GetExceptions().begin(), it_end = sessionservice->GetExceptions().end(); it != it_end; ++it) + for (std::vector<Exception *>::iterator it = session_service->GetExceptions().begin(), it_end = session_service->GetExceptions().end(); it != it_end; ++it) { Exception *e = *it; if (e->mask.equals_ci(mask)) @@ -405,7 +403,7 @@ class CommandOSException : public Command delete exception; else { - sessionservice->AddException(exception); + session_service->AddException(exception); source.Reply(_("Session limit for \002%s\002 set to \002%d\002."), mask.c_str(), limit); if (readonly) source.Reply(READ_ONLY_MODE); @@ -432,9 +430,9 @@ class CommandOSException : public Command } else { - unsigned i = 0, end = sessionservice->GetExceptions().size(); + unsigned i = 0, end = session_service->GetExceptions().size(); for (; i < end; ++i) - if (mask.equals_ci(sessionservice->GetExceptions()[i]->mask)) + if (mask.equals_ci(session_service->GetExceptions()[i]->mask)) { ExceptionDelCallback::DoDel(source, i); source.Reply(_("\002%s\002 deleted from session-limit exception list."), mask.c_str()); @@ -470,13 +468,13 @@ class CommandOSException : public Command } catch (const ConvertException &) { } - if (n1 >= 0 && n1 < sessionservice->GetExceptions().size() && n2 >= 0 && n2 < sessionservice->GetExceptions().size() && n1 != n2) + if (n1 >= 0 && n1 < session_service->GetExceptions().size() && n2 >= 0 && n2 < session_service->GetExceptions().size() && n1 != n2) { - Exception *temp = sessionservice->GetExceptions()[n1]; - sessionservice->GetExceptions()[n1] = sessionservice->GetExceptions()[n2]; - sessionservice->GetExceptions()[n2] = temp; + Exception *temp = session_service->GetExceptions()[n1]; + session_service->GetExceptions()[n1] = session_service->GetExceptions()[n2]; + session_service->GetExceptions()[n2] = temp; - source.Reply(_("Exception for \002%s\002 (#%d) moved to position \002%d\002."), sessionservice->GetExceptions()[n1]->mask.c_str(), n1 + 1, n2 + 1); + source.Reply(_("Exception for \002%s\002 (#%d) moved to position \002%d\002."), session_service->GetExceptions()[n1]->mask.c_str(), n1 + 1, n2 + 1); if (readonly) source.Reply(READ_ONLY_MODE); @@ -500,8 +498,8 @@ class CommandOSException : public Command { bool SentHeader = false; - for (unsigned i = 0, end = sessionservice->GetExceptions().size(); i < end; ++i) - if (mask.empty() || Anope::Match(sessionservice->GetExceptions()[i]->mask, mask)) + for (unsigned i = 0, end = session_service->GetExceptions().size(); i < end; ++i) + if (mask.empty() || Anope::Match(session_service->GetExceptions()[i]->mask, mask)) { if (!SentHeader) { @@ -533,8 +531,8 @@ class CommandOSException : public Command { bool SentHeader = false; - for (unsigned i = 0, end = sessionservice->GetExceptions().size(); i < end; ++i) - if (mask.empty() || Anope::Match(sessionservice->GetExceptions()[i]->mask, mask)) + for (unsigned i = 0, end = session_service->GetExceptions().size(); i < end; ++i) + if (mask.empty() || Anope::Match(session_service->GetExceptions()[i]->mask, mask)) { if (!SentHeader) { @@ -614,10 +612,10 @@ class CommandOSException : public Command "the format of the optional \037expiry\037 parameter.\n" "\002EXCEPTION DEL\002 removes the given mask from the exception list.\n" "\002EXCEPTION MOVE\002 moves exception \037num\037 to \037position\037. The\n" - "sessionservice->GetExceptions() inbetween will be shifted up or down to fill the gap.\n" + "sessions inbetween will be shifted up or down to fill the gap.\n" "\002EXCEPTION LIST\002 and \002EXCEPTION VIEW\002 show all current\n" - "sessionservice->GetExceptions(); if the optional mask is given, the list is limited\n" - "to those sessionservice->GetExceptions() matching the mask. The difference is that\n" + "sessions if the optional mask is given, the list is limited\n" + "to those sessions matching the mask. The difference is that\n" "\002EXCEPTION VIEW\002 is more verbose, displaying the name of the\n" "person who added the exception, its session limit, reason, \n" "host mask and the expiry date and time.\n" @@ -728,7 +726,7 @@ class OSSession : public Module ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); ModuleManager::SetPriority(this, PRIORITY_FIRST); - + Serializable<Exception>::Alloc.Register("Exception"); } void OnUserConnect(dynamic_reference<User> &user, bool &exempt) diff --git a/modules/commands/os_session.h b/modules/commands/os_session.h index d406a7154..8a839318d 100644 --- a/modules/commands/os_session.h +++ b/modules/commands/os_session.h @@ -1,6 +1,20 @@ #ifndef OS_SESSION_H #define OS_SESSION_H +struct Exception : Serializable<Exception> +{ + Anope::string mask; /* Hosts to which this exception applies */ + unsigned limit; /* Session limit for exception */ + Anope::string who; /* Nick of person who added the exception */ + Anope::string reason; /* Reason for exception's addition */ + time_t time; /* When this exception was added */ + time_t expires; /* Time when it expires. 0 == no expiry */ + + serialized_data serialize(); + static void unserialize(serialized_data &data); +}; + + class SessionService : public Service<Base> { public: @@ -28,5 +42,37 @@ class SessionService : public Service<Base> virtual SessionMap &GetSessions() = 0; }; +static service_reference<SessionService, Base> session_service("session"); + +SerializableBase::serialized_data Exception::serialize() +{ + serialized_data data; + + data["mask"] << this->mask; + data["limit"] << this->limit; + data["who"] << this->who; + data["reason"] << this->reason; + data["time"] << this->time; + data["expires"] << this->expires; + + return data; +} + +void Exception::unserialize(SerializableBase::serialized_data &data) +{ + if (!session_service) + return; + + Exception *ex = new Exception; + data["mask"] >> ex->mask; + data["limit"] >> ex->limit; + data["who"] >> ex->who; + data["reason"] >> ex->reason; + data["time"] >> ex->time; + data["expires"] >> ex->expires; + + session_service->AddException(ex); +} + #endif diff --git a/modules/commands/os_shutdown.cpp b/modules/commands/os_shutdown.cpp index efc55c0be..c43be2d51 100644 --- a/modules/commands/os_shutdown.cpp +++ b/modules/commands/os_shutdown.cpp @@ -55,8 +55,8 @@ class CommandOSRestart : public Command { User *u = source.u; quitmsg = "RESTART command received from " + u->nick; - save_databases(); quitting = restarting = true; + save_databases(); return; } @@ -82,8 +82,8 @@ class CommandOSShutdown : public Command { User *u = source.u; quitmsg = source.command + " command received from " + u->nick; - save_databases(); quitting = true; + save_databases(); return; } diff --git a/modules/database/db_flatfile.cpp b/modules/database/db_flatfile.cpp new file mode 100644 index 000000000..f17ed6fd1 --- /dev/null +++ b/modules/database/db_flatfile.cpp @@ -0,0 +1,191 @@ +/* + * (C) 2003-2011 Anope Team + * Contact us at team@anope.org + * + * Please read COPYING and README for further details. + * + * Based on the original code of Epona by Lara. + * Based on the original code of Services by Andy Church. + */ + +/*************************************************************************/ + +#include "module.h" + +Anope::string DatabaseFile; + +class DBFlatFile : public Module +{ + /* Day the last backup was on */ + int LastDay; + /* Backup file names */ + std::list<Anope::string> Backups; + + SerializableBase *find(const Anope::string &sname) + { + for (unsigned i = 0; i < serialized_types.size(); ++i) + if (serialized_types[i]->serialize_name() == sname) + return serialized_types[i]; + return NULL; + } + + public: + DBFlatFile(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE) + { + this->SetAuthor("Anope"); + + Implementation i[] = { I_OnReload, I_OnLoadDatabase, I_OnSaveDatabase }; + ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); + + OnReload(); + + LastDay = 0; + } + + void BackupDatabase() + { + /* Do not backup a database that doesn't exist */ + if (!IsFile(DatabaseFile)) + return; + + time_t now = Anope::CurTime; + tm *tm = localtime(&now); + + if (tm->tm_mday != LastDay) + { + LastDay = tm->tm_mday; + Anope::string newname = "backups/" + DatabaseFile + "." + stringify(tm->tm_year) + stringify(tm->tm_mon) + stringify(tm->tm_mday); + + /* Backup already exists */ + if (IsFile(newname)) + return; + + Log(LOG_DEBUG) << "db_flatfile: Attemping to rename " << DatabaseFile << " to " << newname; + if (rename(DatabaseFile.c_str(), newname.c_str())) + { + Log() << "Unable to back up database!"; + + if (!Config->NoBackupOkay) + quitting = true; + + return; + } + + Backups.push_back(newname); + + if (Config->KeepBackups > 0 && Backups.size() > static_cast<unsigned>(Config->KeepBackups)) + { + DeleteFile(Backups.front().c_str()); + Backups.pop_front(); + } + } + } + + void OnReload() + { + ConfigReader config; + DatabaseFile = config.ReadValue("flatfile", "database", "anope.db", 0); + } + + EventReturn OnLoadDatabase() + { + std::fstream db; + db.open(DatabaseFile.c_str(), std::ios_base::in); + + if (!db.is_open()) + { + Log() << "Unable to open " << DatabaseFile << " for reading!"; + return EVENT_CONTINUE; + } + + SerializableBase *sb = NULL; + SerializableBase::serialized_data data; + std::multimap<SerializableBase *, SerializableBase::serialized_data> objects; + for (Anope::string buf, token; std::getline(db, buf.str());) + { + spacesepstream sep(buf); + + if (!sep.GetToken(token)) + continue; + + if (token == "OBJECT" && sep.GetToken(token)) + { + sb = this->find(token); + data.clear(); + } + else if (token == "DATA" && sb != NULL && sep.GetToken(token)) + data[token] << sep.GetRemaining(); + else if (token == "END" && sb != NULL) + { + objects.insert(std::make_pair(sb, data)); + + sb = NULL; + data.clear(); + } + } + + for (unsigned i = 0; i < serialized_types.size(); ++i) + { + SerializableBase *stype = serialized_types[i]; + + std::multimap<SerializableBase *, SerializableBase::serialized_data>::iterator it = objects.find(stype), it_end = objects.upper_bound(stype); + if (it == objects.end()) + continue; + for (; it != it_end; ++it) + it->first->alloc(it->second); + } + + db.close(); + + return EVENT_STOP; + } + + + EventReturn OnSaveDatabase() + { + BackupDatabase(); + + Anope::string tmp_db = DatabaseFile + ".tmp"; + if (IsFile(DatabaseFile)) + rename(DatabaseFile.c_str(), tmp_db.c_str()); + + std::fstream db(DatabaseFile.c_str(), std::ios_base::out | std::ios_base::trunc); + if (!db.is_open()) + { + Log() << "Unable to open " << DatabaseFile << " for writing"; + if (IsFile(tmp_db)) + rename(tmp_db.c_str(), DatabaseFile.c_str()); + return EVENT_CONTINUE; + } + + for (std::list<SerializableBase *>::iterator it = serialized_items.begin(), it_end = serialized_items.end(); it != it_end; ++it) + { + SerializableBase *base = *it; + SerializableBase::serialized_data data = base->serialize(); + + db << "OBJECT " << base->serialize_name() << "\n"; + for (SerializableBase::serialized_data::iterator dit = data.begin(), dit_end = data.end(); dit != dit_end; ++dit) + db << "DATA " << dit->first << " " << dit->second.astr() << "\n"; + db << "END\n"; + } + + db.close(); + + if (db.good() == false) + { + Log() << "Unable to write database"; + if (!Config->NoBackupOkay) + quitting = true; + if (IsFile(tmp_db)) + rename(tmp_db.c_str(), DatabaseFile.c_str()); + } + else + DeleteFile(tmp_db.c_str()); + + return EVENT_CONTINUE; + } +}; + +MODULE_INIT(DBFlatFile) + + diff --git a/modules/database/db_mysql.cpp b/modules/database/db_mysql.cpp deleted file mode 100644 index e03c89d16..000000000 --- a/modules/database/db_mysql.cpp +++ /dev/null @@ -1,1568 +0,0 @@ -#include "module.h" -#include "../extra/sql.h" -#include "../commands/os_session.h" - -static Anope::string ToString(const std::vector<Anope::string> &strings) -{ - Anope::string ret; - - for (unsigned i = 0; i < strings.size(); ++i) - ret += " " + strings[i]; - - if (!ret.empty()) - ret.erase(ret.begin()); - - return ret; -} - -static std::vector<Anope::string> MakeVector(const Anope::string &buf) -{ - Anope::string s; - spacesepstream sep(buf); - std::vector<Anope::string> params; - - while (sep.GetToken(s)) - { - if (s[0] == ':') - { - s.erase(s.begin()); - if (!s.empty() && !sep.StreamEnd()) - params.push_back(s + " " + sep.GetRemaining()); - else if (!s.empty()) - params.push_back(s); - } - else - params.push_back(s); - } - - return params; -} - -static NickAlias *CurNick = NULL; -static NickCore *CurCore = NULL; -static ChannelInfo *CurChannel = NULL; -static BotInfo *CurBot = NULL; - -static void Write(const Anope::string &data); -static void WriteNickMetadata(const Anope::string &key, const Anope::string &data); -static void WriteCoreMetadata(const Anope::string &key, const Anope::string &data); -static void WriteChannelMetadata(const Anope::string &key, const Anope::string &data); -static void WriteBotMetadata(const Anope::string &key, const Anope::string &data); - -class CommandSQLSync : public Command -{ - public: - CommandSQLSync(Module *creator) : Command(creator, "operserv/sqlsync", 0, 0) - { - this->SetDesc(_("Import your databases to SQL")); - this->SetSyntax(""); - } - - void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms); - - bool OnHelp(CommandSource &source, const Anope::string &subcommand) - { - this->SendSyntax(source); - source.Reply(" "); - source.Reply(_("This command syncs your databases with SQL. You should\n" - "only have to execute this command once, when you initially\n" - "import your databases into SQL.")); - return true; - } -}; - -class MySQLInterface : public SQLInterface -{ - public: - MySQLInterface(Module *o) : SQLInterface(o) { } - - void OnResult(const SQLResult &r); - - void OnError(const SQLResult &r); -}; - -class DBMySQL; -static DBMySQL *me; -class DBMySQL : public Module -{ - private: - CommandSQLSync commandsqlsync; - MySQLInterface sqlinterface; - service_reference<SQLProvider, Base> SQL; - - public: - service_reference<SessionService, Base> SessionInterface; - time_t lastwarn; - bool ro; - - 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, is m_mysql loaded? Going to readonly..."); - readonly = this->ro = true; - this->lastwarn = Anope::CurTime; - } - } - } - - DBMySQL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE), commandsqlsync(this), sqlinterface(this), SQL("mysql/main"), SessionInterface("session") - { - me = this; - - this->lastwarn = 0; - this->ro = false; - - Implementation i[] = { - I_OnLoadDatabase, I_OnServerConnect - }; - ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); - - if (CurrentUplink) - OnServerConnect(); - } - - void OnServerConnect() - { - Implementation i[] = { - /* Misc */ - I_OnSaveDatabase, 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_OnChanForbidden, 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)); - } - - EventReturn OnLoadDatabase() - { - if (!SQL) - { - Log() << "Error, unable to find service reference for SQL, is m_mysql loaded and configured properly?"; - return EVENT_CONTINUE; - } - - SQLQuery query; - - query = "SELECT * FROM `anope_ns_core`"; - SQLResult r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - NickCore *nc = new NickCore(r.Get(i, "display")); - nc->pass = r.Get(i, "pass"); - nc->email = r.Get(i, "email"); - nc->greet = r.Get(i, "greet"); - - spacesepstream sep(r.Get(i, "flags")); - Anope::string buf; - std::vector<Anope::string> flags; - while (sep.GetToken(buf)) - flags.push_back(buf); - nc->FromString(flags); - - nc->language = r.Get(i, "language"); - nc->memos.memomax = r.Get(i, "memomax").is_number_only() ? convertTo<int16>(r.Get(i, "memomax")) : 20; - } - - query = "SELECT * FROM `anope_ns_access`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - NickCore *nc = findcore(r.Get(i, "display")); - if (!nc) - { - Log() << "MySQL: Got NickCore access entry for nonexistant core " << r.Get(i, "display"); - continue; - } - - nc->AddAccess(r.Get(i, "access")); - } - - query = "SELECT * FROM `anope_ns_core_metadata`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - NickCore *nc = findcore(r.Get(i, "display")); - if (!nc) - { - Log() << "MySQL: Got NickCore access entry for nonexistant core " << r.Get(i, "display"); - continue; - } - - EventReturn MOD_RESULT;; - std::vector<Anope::string> Params = MakeVector(r.Get(i, "value")); - FOREACH_RESULT(I_OnDatabaseReadMetadata, OnDatabaseReadMetadata(nc, r.Get(i, "name"), Params)); - } - - query = "SELECT * FROM `anope_ns_alias`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - NickCore *nc = findcore(r.Get(i, "display")); - if (!nc) - { - Log() << "MySQL: Got NickAlias for nick " << r.Get(i, "nick") << " with nonexistant core " << r.Get(i, "display"); - continue; - } - - NickAlias *na = new NickAlias(r.Get(i, "nick"), nc); - na->last_quit = r.Get(i, "last_quit"); - na->last_realname = r.Get(i, "last_realname"); - na->last_usermask = r.Get(i, "last_usermask"); - na->last_realhost = r.Get(i, "last_realhost"); - na->time_registered = r.Get(i, "time_registered").is_pos_number_only() ? convertTo<time_t>(r.Get(i, "time_registered")) : Anope::CurTime; - na->last_seen = r.Get(i, "last_seen").is_pos_number_only() ? convertTo<time_t>(r.Get(i, "last_seen")) : Anope::CurTime; - - spacesepstream sep(r.Get(i, "flags")); - Anope::string buf; - std::vector<Anope::string> flags; - while (sep.GetToken(buf)) - flags.push_back(buf); - - na->FromString(flags); - } - - query = "SELECT * FROM `anope_ns_alias_metadata`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - NickAlias *na = findnick(r.Get(i, "nick")); - if (!na) - { - Log() << "MySQL: Got metadata for nonexistant nick " << r.Get(i, "nick"); - continue; - } - - EventReturn MOD_RESULT; - std::vector<Anope::string> Params = MakeVector(r.Get(i, "value")); - FOREACH_RESULT(I_OnDatabaseReadMetadata, OnDatabaseReadMetadata(na, r.Get(i, "name"), Params)); - } - - query = "SELECT * FROM `anope_hs_core`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - NickAlias *na = findnick(r.Get(i, "nick")); - if (!na) - { - Log() << "MySQL: Got vhost entry for nonexistant nick " << r.Get(i, "nick"); - continue; - } - - time_t creation = r.Get(i, "time").is_pos_number_only() ? convertTo<time_t>(r.Get(i, "time")) : Anope::CurTime; - na->hostinfo.SetVhost(r.Get(i, "vident"), r.Get(i, "vhost"), r.Get(i, "creator"), creation); - } - - query = "SELECT * FROM `anope_bs_core`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - BotInfo *bi = findbot(r.Get(i, "nick")); - if (!bi) - bi = new BotInfo(r.Get(i, "nick"), r.Get(i, "user"), r.Get(i, "host")); - bi->realname = r.Get(i, "rname"); - bi->created = r.Get(i, "created").is_pos_number_only() ? convertTo<time_t>(r.Get(i, "created")) : Anope::CurTime; - - spacesepstream sep(r.Get(i, "flags")); - Anope::string buf; - std::vector<Anope::string> flags; - while (sep.GetToken(buf)) - flags.push_back(buf); - - bi->FromString(flags); - } - - query = "SELECT * FROM `anope_bs_info_metadata`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - BotInfo *bi = findbot(r.Get(i, "botname")); - if (!bi) - { - Log() << "MySQL: BotInfo metadata for nonexistant bot " << r.Get(i, "botname"); - continue; - } - - EventReturn MOD_RESULT; - std::vector<Anope::string> Params = MakeVector(r.Get(i, "value")); - FOREACH_RESULT(I_OnDatabaseReadMetadata, OnDatabaseReadMetadata(bi, r.Get(i, "name"), Params)); - } - - query = "SELECT * FROM `anope_cs_info`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - NickCore *nc = NULL; - - if (!r.Get(i, "founder").empty()) - { - nc = findcore(r.Get(i, "founder")); - if (!nc) - { - Log() << "MySQL: Channel " << r.Get(i, "name") << " with nonexistant founder " << r.Get(i, "founder"); - continue; - } - - ChannelInfo *ci = new ChannelInfo(r.Get(i, "name")); - ci->SetFounder(nc); - if (!r.Get(i, "successor").empty()) - ci->successor = findcore(r.Get(i, "successor")); - ci->desc = r.Get(i, "descr"); - ci->time_registered = r.Get(i, "time_registered").is_pos_number_only() ? convertTo<time_t>(r.Get(i, "time_registered")) : Anope::CurTime; - ci->last_used = r.Get(i, "last_used").is_pos_number_only() ? convertTo<time_t>(r.Get(i, "last_used")) : Anope::CurTime; - ci->last_topic = r.Get(i, "last_topic"); - ci->last_topic_setter = r.Get(i, "last_topic_setter"); - ci->last_topic_time = r.Get(i, "last_topic_time").is_number_only() ? convertTo<int>(r.Get(i, "last_topic_time")) : Anope::CurTime; - ci->bantype = r.Get(i, "bantype").is_number_only() ? convertTo<int>(r.Get(i, "bantype")) : 2; - ci->memos.memomax = r.Get(i, "memomax").is_number_only() ? convertTo<int16>(r.Get(i, "memomax")) : 20; - ci->capsmin = r.Get(i, "capsmin").is_number_only() ? convertTo<int>(r.Get(i, "capsmin")) : 0; - ci->capspercent = r.Get(i, "capspercent").is_number_only() ? convertTo<int>(r.Get(i, "capspercent")) : 0; - ci->floodlines = r.Get(i, "floodlines").is_number_only() ? convertTo<int>(r.Get(i, "floodlines")) : 0; - ci->floodsecs = r.Get(i, "floodsecs").is_number_only() ? convertTo<int>(r.Get(i, "floodsecs")) : 0; - ci->repeattimes = r.Get(i, "repeattimes").is_number_only() ? convertTo<int>(r.Get(i, "repeattimes")) : 0; - ci->bi = findbot(r.Get(i, "botnick")); - if (ci->bi && !r.Get(i, "botflags").empty()) - { - spacesepstream sep(r.Get(i, "botflags")); - Anope::string buf; - std::vector<Anope::string> flags; - while (sep.GetToken(buf)) - flags.push_back(buf); - - ci->botflags.FromString(flags); - } - - if (!r.Get(i, "flags").empty()) - { - spacesepstream sep(r.Get(i, "flags")); - Anope::string buf; - std::vector<Anope::string> flags; - while (sep.GetToken(buf)) - flags.push_back(buf); - - ci->FromString(flags); - } - } - } - - query = "SELECT * FROM `anope_cs_ttb`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - ChannelInfo *ci = cs_findchan(r.Get(i, "channel")); - if (!ci) - { - Log() << "MySQL: Channel ttb for nonexistant channel " << r.Get(i, "channel"); - continue; - } - - ci->ttb[atoi(r.Get(i, "ttb_id").c_str())] = atoi(r.Get(i, "value").c_str()); - } - - query = "SELECT * FROM `anope_bs_badwords`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - ChannelInfo *ci = cs_findchan(r.Get(i, "channel")); - if (!ci) - { - Log() << "MySQL: Channel badwords entry for nonexistant channel " << r.Get(i, "channel"); - continue; - } - - BadWordType BWTYPE = BW_ANY; - if (r.Get(i, "type").equals_cs("SINGLE")) - BWTYPE = BW_SINGLE; - else if (r.Get(i, "type").equals_cs("START")) - BWTYPE = BW_START; - else if (r.Get(i, "type").equals_cs("END")) - BWTYPE = BW_END; - ci->AddBadWord(r.Get(i, "word"), BWTYPE); - } - - query = "SELECT * FROM `anope_cs_access`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - ChannelInfo *ci = cs_findchan(r.Get(i, "channel")); - if (!ci) - { - Log() << "MySQL: Channel access entry for nonexistant channel " << r.Get(i, "channel"); - continue; - } - - const Anope::string &provider = r.Get(i, "provider"), &data = r.Get(i, "data"); - service_reference<AccessProvider> ap(provider); - if (!ap) - { - Log() << "MySQL: Access entry for " << ci->name << " using nonexistant provider " << provider; - continue; - } - - ChanAccess *access = ap->Create(); - access->ci = ci; - access->mask = r.Get(i, "mask"); - access->creator = r.Get(i, "creator"); - access->last_seen = r.Get(i, "last_seen").is_pos_number_only() ? convertTo<time_t>(r.Get(i, "last_seen")) : Anope::CurTime; - access->created = r.Get(i, "created").is_pos_number_only() ? convertTo<time_t>(r.Get(i, "created")) : Anope::CurTime; - access->Unserialize(data); - ci->AddAccess(access); - } - - query = "SELECT * FROM `anope_cs_akick`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - ChannelInfo *ci = cs_findchan(r.Get(i, "channel")); - if (!ci) - { - Log() << "MySQL: Channel access entry for nonexistant channel " << r.Get(i, "channel"); - continue; - } - - NickCore *nc = NULL; - spacesepstream sep(r.Get(i, "flags")); - Anope::string flag, mask; - while (sep.GetToken(flag)) - { - if (flag.equals_cs("ISNICK")) - nc = findcore(r.Get(i, "mask")); - - AutoKick *ak; - if (nc) - ak = ci->AddAkick(r.Get(i, "creator"), nc, r.Get(i, "reason"), atol(r.Get(i, "created").c_str()), atol(r.Get(i, "last_used").c_str())); - else - ak = ci->AddAkick(r.Get(i, "creator"), r.Get(i, "mask"), r.Get(i, "reason"), atol(r.Get(i, "created").c_str()), atol(r.Get(i, "last_used").c_str())); - if (nc) - ak->SetFlag(AK_ISNICK); - } - } - - query = "SELECT * FROM `anope_cs_levels`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - ChannelInfo *ci = cs_findchan(r.Get(i, "channel")); - if (!ci) - { - Log() << "MySQL: Channel level entry for nonexistant channel " << r.Get(i, "channel"); - continue; - } - - ci->SetLevel(r.Get(i, "name"), atoi(r.Get(i, "level").c_str())); - } - - query = "SELECT * FROM `anope_cs_info_metadata`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - ChannelInfo *ci = cs_findchan(r.Get(i, "channel")); - if (!ci) - { - Log() << "MySQL: Channel metadata for nonexistant channel " << r.Get(i, "channel"); - continue; - } - - EventReturn MOD_RESULT; - std::vector<Anope::string> Params = MakeVector(r.Get(i, "value")); - FOREACH_RESULT(I_OnDatabaseReadMetadata, OnDatabaseReadMetadata(ci, r.Get(i, "name"), Params)); - } - - query = "SELECT * FROM `anope_cs_mlock`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - ChannelInfo *ci = cs_findchan(r.Get(i, "channel")); - if (!ci) - { - Log() << "MySQL: Channel mlock for nonexistant channel " << r.Get(i, "channel"); - continue; - } - - Anope::string mode_name = r.Get(i, "mode"); - bool set = r.Get(i, "status") == "1" ? true : false; - Anope::string setter = r.Get(i, "setter"); - time_t mcreated = r.Get(i, "created").is_pos_number_only() ? convertTo<time_t>(r.Get(i, "created")) : Anope::CurTime; - Anope::string param = r.Get(i, "param"); - - for (size_t j = CMODE_BEGIN + 1; j < CMODE_END; ++j) - if (ChannelModeNameStrings[j] == mode_name) - { - ChannelModeName n = static_cast<ChannelModeName>(j); - ci->mode_locks.insert(std::make_pair(n, ModeLock(set, n, param, setter, mcreated))); - break; - } - } - - query = "SELECT * FROM `anope_ms_info`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - MemoInfo *mi = NULL; - if (r.Get(i, "serv").equals_cs("NICK")) - { - NickCore *nc = findcore(r.Get(i, "receiver")); - if (nc) - mi = &nc->memos; - } - else if (r.Get(i, "serv").equals_cs("CHAN")) - { - ChannelInfo *ci = cs_findchan(r.Get(i, "receiver")); - if (ci) - mi = &ci->memos; - } - if (mi) - { - Memo *m = new Memo(); - mi->memos.push_back(m); - m->sender = r.Get(i, "sender"); - m->time = r.Get(i, "time").is_pos_number_only() ? convertTo<time_t>(r.Get(i, "time")) : Anope::CurTime; - m->text = r.Get(i, "text"); - - if (!r.Get(i, "flags").empty()) - { - spacesepstream sep(r.Get(i, "flags")); - Anope::string buf; - std::vector<Anope::string> flags; - while (sep.GetToken(buf)) - flags.push_back(buf); - - m->FromString(flags); - } - } - } - - for (std::list<XLineManager *>::iterator it = XLineManager::XLineManagers.begin(), it_end = XLineManager::XLineManagers.end(); it != it_end; ++it) - { - XLineManager *xm = *it; - - query = "SELECT * FROM `anope_os_xlines` WHERE `type` = @type"; - query.setValue("type", Anope::string(xm->Type())); - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - Anope::string user = r.Get(i, "user"); - Anope::string host = r.Get(i, "host"); - Anope::string by = r.Get(i, "xby"); - Anope::string reason = r.Get(i, "reason"); - time_t seton = r.Get(i, "seton").is_pos_number_only() ? convertTo<time_t>(r.Get(i, "seton")) : Anope::CurTime; - time_t expires = r.Get(i, "expires").is_pos_number_only() ? convertTo<time_t>(r.Get(i, "expires")) : Anope::CurTime; - - XLine *x = xm->Add(user + "@" + host, by, expires, reason); - if (x) - x->Created = seton; - } - } - - query = "SELECT * FROM `anope_os_exceptions`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - Anope::string mask = r.Get(i, "mask"); - unsigned limit = convertTo<unsigned>(r.Get(i, "slimit")); - Anope::string creator = r.Get(i, "who"); - Anope::string reason = r.Get(i, "reason"); - time_t expires = convertTo<time_t>(r.Get(i, "expires")); - - if (SessionInterface) - { - Exception *e = new Exception(); - e->mask = mask; - e->limit = limit; - e->who = creator; - e->reason = reason; - e->time = expires; - SessionInterface->AddException(e); - } - } - - query = "SELECT * FROM `anope_extra`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - std::vector<Anope::string> params = MakeVector(r.Get(i, "data")); - EventReturn MOD_RESULT; - FOREACH_RESULT(I_OnDatabaseRead, OnDatabaseRead(params)); - } - - query = "SELECT * FROM `anope_ns_core_metadata`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - NickCore *nc = findcore(r.Get(i, "nick")); - if (!nc) - continue; - if (r.Get(i, "name") == "MEMO_IGNORE") - nc->memos.ignores.push_back(r.Get(i, "value").ci_str()); - } - - query = "SELECT * FROM `anope_cs_info_metadata`"; - r = SQL->RunQuery(query); - for (int i = 0; i < r.Rows(); ++i) - { - ChannelInfo *ci = cs_findchan(r.Get(i, "channel")); - if (!ci) - continue; - if (r.Get(i, "name") == "MEMO_IGNORE") - ci->memos.ignores.push_back(r.Get(i, "value").ci_str()); - } - - return EVENT_STOP; - } - - EventReturn OnSaveDatabase() - { - SQLQuery query; - - query = "TRUNCATE TABLE `anope_os_core`"; - this->RunQuery(query); - - query = "INSERT INTO `anope_os_core` (maxusercnt, maxusertime) VALUES(@maxusercnt, @maxusertime)"; - query.setValue("maxusercnt", maxusercnt); - query.setValue("maxusertime", maxusertime); - this->RunQuery(query); - - for (nickcore_map::const_iterator it = NickCoreList.begin(), it_end = NickCoreList.end(); it != it_end; ++it) - { - CurCore = it->second; - FOREACH_MOD(I_OnDatabaseWriteMetadata, OnDatabaseWriteMetadata(WriteCoreMetadata, CurCore)); - } - - for (nickalias_map::const_iterator it = NickAliasList.begin(), it_end = NickAliasList.end(); it != it_end; ++it) - { - CurNick = it->second; - FOREACH_MOD(I_OnDatabaseWriteMetadata, OnDatabaseWriteMetadata(WriteNickMetadata, CurNick)); - } - - for (registered_channel_map::const_iterator it = RegisteredChannelList.begin(), it_end = RegisteredChannelList.end(); it != it_end; ++it) - { - CurChannel = it->second; - FOREACH_MOD(I_OnDatabaseWriteMetadata, OnDatabaseWriteMetadata(WriteChannelMetadata, CurChannel)); - } - - for (Anope::insensitive_map<BotInfo *>::const_iterator it = BotListByNick.begin(), it_end = BotListByNick.end(); it != it_end; ++it) - { - if (it->second->HasFlag(BI_CONF)) - continue; - - CurBot = it->second; - FOREACH_MOD(I_OnDatabaseWriteMetadata, OnDatabaseWriteMetadata(WriteBotMetadata, CurBot)); - - query = "INSERT INTO `anope_bs_core` (nick, user, host, rname, flags, created, chancount) VALUES(@nick, @user, @host, @rname, @flags, @created, @chancount) ON DUPLICATE KEY UPDATE nick=VALUES(nick), user=VALUES(user), host=VALUES(host), rname=VALUES(rname), flags=VALUES(flags), created=VALUES(created), chancount=VALUES(chancount)"; - query.setValue("nick", CurBot->nick); - query.setValue("user", CurBot->GetIdent()); - query.setValue("host", CurBot->host); - query.setValue("rname", CurBot->realname); - query.setValue("flags", ToString(CurBot->ToString())); - query.setValue("created", CurBot->created); - query.setValue("chancount", CurBot->chancount); - this->RunQuery(query); - } - - query = "TRUNCATE TABLE `anope_extra`"; - this->RunQuery(query); - FOREACH_MOD(I_OnDatabaseWrite, OnDatabaseWrite(Write)); - - return EVENT_CONTINUE; - } - - void OnPostCommand(CommandSource &source, Command *command, const std::vector<Anope::string> ¶ms) - { - User *u = source.u; - - if (command->name.find("nickserv/set/") == 0 || command->name.find("nickserv/saset/") == 0) - { - NickAlias *na = findnick(command->name.find("nickserv/set/") == 0 ? source.u->nick : params[1]); - if (!na) - return; - - if (command->name == "nickserv/set/password" || command->name == "nickserv/saset/password") - { - SQLQuery query("UPDATE `anope_ns_core` SET `pass` = @pass WHERE `display` = @display"); - query.setValue("pass", na->nc->pass); - query.setValue("display", na->nc->display); - this->RunQuery(query); - } - else if (command->name == "nickserv/set/language" || command->name == "nickserv/saset/language") - { - SQLQuery query("UPDATE `anope_ns_core` SET `language` = @language WHERE `display` = @display"); - query.setValue("language", na->nc->language); - query.setValue("display", na->nc->display); - this->RunQuery(query); - } - else if (command->name == "nickserv/set/email" || command->name == "nickserv/saset/email") - { - SQLQuery query("UPDATE `anope_ns_core` SET `email` = @email WHERE `display` = @display"); - query.setValue("email", na->nc->email); - query.setValue("display", na->nc->display); - this->RunQuery(query); - } - else if (command->name == "nickserv/set/greet" || command->name == "nickserv/saset/greet") - { - SQLQuery query("UPDATE `anope_ns_core` SET `greet` = @greet WHERE `display` = @display"); - query.setValue("greet", na->nc->greet); - query.setValue("display", na->nc->display); - this->RunQuery(query); - } - else - { - SQLQuery query("UPDATE `anope_ns_core` SET `flags` = @flags WHERE `display` = @display"); - query.setValue("flags", ToString(na->nc->ToString())); - query.setValue("display", na->nc->display); - this->RunQuery(query); - } - } - 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) - return; - - if (command->name == "chanserv/set/founder" || command->name == "chanserv/saset/founder") - { - SQLQuery query("UPDATE `anope_cs_info` SET `founder` = @founder WHERE `name` = @name"); - query.setValue("founder", ci->GetFounder() ? ci->GetFounder()->display : ""); - query.setValue("name", ci->name); - this->RunQuery(query); - } - else if (command->name == "chanserv/set/successor" || command->name == "chanserv/saset/successor") - { - SQLQuery query("UPDATE `anope_cs_info` SET `successor` = @successor WHERE `name` = @name"); - query.setValue("successor", ci->successor ? ci->successor->display : ""); - query.setValue("name", ci->name); - this->RunQuery(query); - } - else if (command->name == "chanserv/set/desc" || command->name == "chanserv/saset/desc") - { - SQLQuery query("UPDATE `anope_cs_info` SET `descr` = @descr WHERE `name` = @name"); - query.setValue("descr", ci->desc); - query.setValue("name", ci->name); - this->RunQuery(query); - } - else if (command->name == "chanserv/set/bantype" || command->name == "chanserv/saset/bantype") - { - SQLQuery query("UPDATE `anope_cs_info` SET `bantype` = @bantype WHERE `name` = @name"); - query.setValue("bantype", ci->bantype); - query.setValue("name", ci->name); - this->RunQuery(query); - } - else - { - SQLQuery query("UPDATE `anope_cs_info` SET `flags` = @flags WHERE `name` = @name"); - query.setValue("flags", ToString(ci->ToString())); - query.setValue("name", ci->name); - this->RunQuery(query); - } - } - 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; - if (params[1].equals_ci("BADWORDS") || params[1].equals_ci("BOLDS") || params[1].equals_ci("CAPS") || params[1].equals_ci("COLORS") || params[1].equals_ci("FLOOD") || params[1].equals_ci("REPEAT") || params[1].equals_ci("REVERSES") || params[1].equals_ci("UNDERLINES")) - { - if (params[2].equals_ci("ON") || params[2].equals_ci("OFF")) - { - for (int i = 0; i < TTB_SIZE; ++i) - { - SQLQuery query("INSERT INTO `anope_cs_ttb` (channel, ttb_id, value) VALUES(@channel, @ttb_id, @value) ON DUPLICATE KEY UPDATE channel=VALUES(channel), ttb_id=VALUES(ttb_id), value=VALUES(value)"); - query.setValue("channel", ci->name); - query.setValue("ttb_id", i); - query.setValue("value", ci->ttb[i]); - this->RunQuery(query); - } - - { - SQLQuery query("UPDATE `anope_cs_info` SET `botflags` = @botflags WHERE `name` = @name"); - query.setValue("botflags", ToString(ci->botflags.ToString())); - query.setValue("name", ci->name); - this->RunQuery(query); - } - - if (params[1].equals_ci("CAPS")) - { - SQLQuery query("UPDATE `anope_cs_info` SET `capsmin` = @capsmin, `capspercent` = @capspercent WHERE `name` = @name"); - query.setValue("capsmin", ci->capsmin); - query.setValue("capspercent", ci->capspercent); - query.setValue("name", ci->name); - this->RunQuery(query); - } - else if (params[1].equals_ci("FLOOD")) - { - SQLQuery query("UPDATE `anope_cs_info` SET `floodlines` = @floodlines, `floodsecs` = @floodsecs WHERE `name` = @name"); - query.setValue("floodlines", ci->floodlines); - query.setValue("floodsecs", ci->floodsecs); - query.setValue("name", ci->name); - this->RunQuery(query); - } - else if (params[1].equals_ci("REPEAT")) - { - SQLQuery query("UPDATE `anope_cs_info` SET `repeattimes` = @ WHERE `name` = @"); - query.setValue("repeattimes", ci->repeattimes); - query.setValue("name", ci->name); - this->RunQuery(query); - } - } - } - } - else if (command->name == "botserv/set" && params.size() > 1) - { - ChannelInfo *ci = cs_findchan(params[0]); - if (ci && !ci->AccessFor(u).HasPriv("SET") && !u->HasPriv("botserv/administration")) - return; - BotInfo *bi = NULL; - if (!ci) - bi = findbot(params[0]); - if (bi && params[1].equals_ci("PRIVATE") && u->HasPriv("botserv/set/private")) - { - SQLQuery query("UPDATE `anope_bs_core` SET `flags` = @ WHERE `nick` = @"); - query.setValue("flags", ToString(bi->ToString())); - query.setValue("nick", bi->nick); - this->RunQuery(query); - } - else if (!ci) - return; - else if (params[1].equals_ci("DONTKICKOPS") || params[1].equals_ci("DONTKICKVOICES") || params[1].equals_ci("FANTASY") || params[1].equals_ci("GREET") || params[1].equals_ci("SYMBIOSIS") || params[1].equals_ci("NOBOT")) - { - SQLQuery query("UPDATE `anope_cs_info` SET `botflags` = @ WHERE `name` = @"); - query.setValue("botflags", ToString(ci->botflags.ToString())); - query.setValue("name", ci->name); - this->RunQuery(query); - } - } - else if (command->name == "memoserv/ignore" && params.size() > 0) - { - Anope::string target = params[0]; - NickCore *nc = NULL; - ChannelInfo *ci = NULL; - if (target[0] != '#') - { - target = u->nick; - nc = u->Account(); - if (!nc) - return; - } - else - { - ci = cs_findchan(target); - if (!ci || !ci->AccessFor(u).HasPriv("MEMO")) - return; - } - - MemoInfo *mi = ci ? &ci->memos : &nc->memos; - Anope::string table = ci ? "anope_cs_info_metadata" : "anope_ns_core_metadata"; - Anope::string ename = ci ? "channel" : "nick"; - - SQLQuery query("DELETE FROM `" + table + "` WHERE `" + ename + "` = @target AND `name` = 'MEMO_IGNORE'"); - query.setValue("target", target); - this->RunQuery(query); - - query = "INSERT INTO `" + table + "` VALUES(" + ename + ", name, value) (@target, 'MEMO_IGNORE, @ignore)"; - query.setValue("target", target); - for (unsigned j = 0; j < mi->ignores.size(); ++j) - { - query.setValue("ignore", mi->ignores[j]); - this->RunQuery(query); - } - } - } - - void OnNickAddAccess(NickCore *nc, const Anope::string &entry) - { - SQLQuery query("INSERT INTO `anope_ns_access` (display, access) VALUES(@display, @access)"); - query.setValue("display", nc->display); - query.setValue("access", entry); - this->RunQuery(query); - } - - void OnNickEraseAccess(NickCore *nc, const Anope::string &entry) - { - SQLQuery query("DELETE FROM `anope_ns_access` WHERE `display` = @display AND `access` = @access"); - query.setValue("display", nc->display); - query.setValue("access", entry); - this->RunQuery(query); - } - - void OnNickClearAccess(NickCore *nc) - { - SQLQuery query("DELETE FROM `anope_ns_access` WHERE `display` = @display"); - query.setValue("display", nc->display); - this->RunQuery(query); - } - - void OnDelCore(NickCore *nc) - { - SQLQuery query("DELETE FROM `anope_ns_core` WHERE `display` = @display"); - query.setValue("display", nc->display); - this->RunQuery(query); - } - - void OnNickForbidden(NickAlias *na) - { - SQLQuery query("UPDATE `anope_ns_alias` SET `flags` = @flags WHERE `nick` = @nick"); - query.setValue("flags", ToString(na->ToString())); - query.setValue("nick", na->nick); - this->RunQuery(query); - } - - void OnNickGroup(User *u, NickAlias *) - { - OnNickRegister(findnick(u->nick)); - } - - void InsertAlias(NickAlias *na) - { - SQLQuery query("INSERT INTO `anope_ns_alias` (nick, last_quit, last_realname, last_usermask, last_realhost, time_registered, last_seen, flags, display) VALUES(@nick, @last_quit, @last_realname, @last_usermask, @last_realhost, @time_registered, @last_seen, @flags, @display) ON DUPLICATE KEY UPDATE last_quit=VALUES(last_quit), last_realname=VALUES(last_realname), last_usermask=VALUES(last_usermask), last_realhost=VALUES(last_realhost), time_registered=VALUES(time_registered), last_seen=VALUES(last_seen), flags=VALUES(flags), display=VALUES(display)"); - query.setValue("nick", na->nick); - query.setValue("last_quit", na->last_quit); - query.setValue("last_realname", na->last_realname); - query.setValue("last_usermask", na->last_usermask); - query.setValue("last_realhost", na->last_realhost); - query.setValue("time_registered", na->time_registered); - query.setValue("last_seen", na->last_seen); - query.setValue("flags", ToString(na->ToString())); - query.setValue("display", na->nc->display); - this->RunQuery(query); - } - - void InsertCore(NickCore *nc) - { - SQLQuery query("INSERT INTO `anope_ns_core` (display, pass, email, greet, flags, language, memomax) VALUES(@display, @pass, @email, @greet, @flags, @language, @memomax) ON DUPLICATE KEY UPDATE pass=VALUES(pass), email=VALUES(email), greet=VALUES(greet), flags=VALUES(flags), language=VALUES(language), memomax=VALUES(memomax)"); - query.setValue("display", nc->display); - query.setValue("pass", nc->pass); - query.setValue("email", nc->email); - query.setValue("greet", nc->greet); - query.setValue("flags", ToString(nc->ToString())); - query.setValue("language", nc->language); - query.setValue("memomax", nc->memos.memomax); - this->RunQuery(query); - } - - void OnNickRegister(NickAlias *na) - { - this->InsertCore(na->nc); - this->InsertAlias(na); - } - - void OnChangeCoreDisplay(NickCore *nc, const Anope::string &newdisplay) - { - SQLQuery query("UPDATE `anope_ns_core` SET `display` = @newdisplay WHERE `display` = @olddisplay"); - query.setValue("newdisplay", newdisplay); - query.setValue("olddisplay", nc->display); - this->RunQuery(query); - } - - void OnNickSuspend(NickAlias *na) - { - SQLQuery query("UPDATE `anope_ns_core` SET `flags` = @flags WHERE `display` = @display"); - query.setValue("flags", ToString(na->nc->ToString())); - query.setValue("display", na->nc->display); - this->RunQuery(query); - } - - void OnDelNick(NickAlias *na) - { - SQLQuery query("DELETE FROM `anope_ns_alias` WHERE `nick` = @nick"); - query.setValue("nick", na->nick); - this->RunQuery(query); - } - - void OnAccessAdd(ChannelInfo *ci, User *, ChanAccess *access) - { - SQLQuery query("INSERT INTO `anope_cs_access` (provider, data, mask, channel, last_seen, creator) VALUES (@provider, @data, @mask, @channel, @last_seen, @creator) ON DUPLICATE KEY UPDATE level=VALUES(level), display=VALUES(display), channel=VALUES(channel), last_seen=VALUES(last_seen), creator=VALUES(creator)"); - query.setValue("provider", access->provider->name); - query.setValue("data", access->Serialize()); - query.setValue("mask", access->mask); - query.setValue("channel", ci->name); - query.setValue("last_seen", access->last_seen); - query.setValue("creator", access->creator); - this->RunQuery(query); - } - - void OnAccessDel(ChannelInfo *ci, User *u, ChanAccess *access) - { - SQLQuery query("DELETE FROM `anope_cs_access` WHERE `mask` = @mask AND `channel` = @channel"); - query.setValue("mask", access->mask); - query.setValue("channel", ci->name); - this->RunQuery(query); - } - - void OnAccessClear(ChannelInfo *ci, User *u) - { - SQLQuery query("DELETE FROM `anope_cs_access` WHERE `channel` = @channel"); - query.setValue("channel", ci->name); - this->RunQuery(query); - } - - void OnLevelChange(User *u, ChannelInfo *ci, const Anope::string &priv, int16 what) - { - SQLQuery query("UPDATE `anope_cs_levels` SET `level` = @level WHERE `channel` = @channel AND `name` = @name ON DUPLICATE KEY UPDATE level=VALUES(level), name=VALUES(name)"); - query.setValue("channel", ci->name); - if (priv == "ALL") - { - const std::vector<Privilege> &privs = PrivilegeManager::GetPrivileges(); - for (unsigned i = 0; i < privs.size(); ++i) - { - const Privilege &p = privs[i]; - query.setValue("level", ci->GetLevel(p.name)); - query.setValue("name", p.name); - this->RunQuery(query); - } - } - else - { - query.setValue("level", what); - query.setValue("name", name); - this->RunQuery(query); - } - } - - void OnChanForbidden(ChannelInfo *ci) - { - SQLQuery query("INSERT INTO `anope_cs_info` (name, time_registered, last_used, flags) VALUES (@name, @time_registered, @last_used, @flags)"); - query.setValue("name", ci->name); - query.setValue("time_registered", ci->time_registered); - query.setValue("last_used", ci->last_used); - query.setValue("flags", ToString(ci->ToString())); - this->RunQuery(query); - } - - void OnDelChan(ChannelInfo *ci) - { - SQLQuery query("DELETE FROM `anope_cs_info` WHERE `name` = @name"); - query.setValue("name", ci->name); - this->RunQuery(query); - } - - void OnChanRegistered(ChannelInfo *ci) - { - SQLQuery query("INSERT INTO `anope_cs_info` (name, founder, successor, descr, time_registered, last_used, last_topic, last_topic_setter, last_topic_time, flags, bantype, memomax, botnick, botflags, capsmin, capspercent, floodlines, floodsecs, repeattimes) VALUES(@name, @founder, @successor, @descr, @time_registered, @last_used, @last_topic_text, @last_topic_setter, @last_topic_time, @flags, @bantype, @memomax, @botnick, @botflags, @capsmin, @capspercent, @floodlines, @floodsecs, @repeattimes) ON DUPLICATE KEY UPDATE founder=VALUES(founder), successor=VALUES(successor), descr=VALUES(descr), time_registered=VALUES(time_registered), last_used=VALUES(last_used), last_topic=VALUES(last_topic), last_topic_setter=VALUES(last_topic_setter), last_topic_time=VALUES(last_topic_time), flags=VALUES(flags), bantype=VALUES(bantype), memomax=VALUES(memomax), botnick=VALUES(botnick), botflags=VALUES(botflags), capsmin=VALUES(capsmin), capspercent=VALUES(capspercent), floodlines=VALUES(floodlines), floodsecs=VALUES(floodsecs), repeattimes=VALUES(repeattimes)"); - query.setValue("name", ci->name); - query.setValue("founder", ci->GetFounder() ? ci->GetFounder()->display : ""); - query.setValue("successor", ci->successor ? ci->successor->display : ""); - query.setValue("descr", ci->desc); - query.setValue("time_registered", ci->time_registered); - query.setValue("last_used", ci->last_used); - query.setValue("last_topic_text", ci->last_topic); - query.setValue("last_topic_setter", ci->last_topic_setter); - query.setValue("last_topic_time", ci->last_topic_time); - query.setValue("flags", ToString(ci->ToString())); - query.setValue("bantype", ci->bantype); - query.setValue("memomax", ci->memos.memomax); - query.setValue("botnick", ci->bi ? ci->bi->nick : ""); - query.setValue("botflags", ToString(ci->botflags.ToString())); - query.setValue("capsmin", ci->capsmin); - query.setValue("capspercent", ci->capspercent); - query.setValue("floodlines", ci->floodlines); - query.setValue("floodsecs", ci->floodsecs); - query.setValue("repeattimes", ci->repeattimes); - this->RunQuery(query); - - for (std::multimap<ChannelModeName, ModeLock>::const_iterator it = ci->GetMLock().begin(), it_end = ci->GetMLock().end(); it != it_end; ++it) - { - const ModeLock &ml = it->second; - ChannelMode *cm = ModeManager::FindChannelModeByName(ml.name); - - if (cm != NULL) - { - query = "INSERT INTO `anope_cs_mlock` (channel, mode, status, setter, created, param) VALUES(@channel, @mode, @status, @setter, @created, @param) ON DUPLICATE KEY UPDATE channel=VALUES(channel), mode=VALUES(mode), status=VALUES(status), setter=VALUES(setter), created=VALUES(created), param=VALUES(param)"; - query.setValue("channel", ci->name); - query.setValue("mode", cm->NameAsString()); - query.setValue("status", ml.set ? 1 : 0); - query.setValue("setter", ml.setter); - query.setValue("created", ml.created); - query.setValue("param", ml.param); - this->RunQuery(query); - } - } - } - - void OnChanSuspend(ChannelInfo *ci) - { - SQLQuery query("UPDATE `anope_cs_info` SET `flags` = @flags WHERE `name` = @name"); - query.setValue("flags", ToString(ci->ToString())); - query.setValue("name", ci->name); - this->RunQuery(query); - } - - void OnAkickAdd(ChannelInfo *ci, AutoKick *ak) - { - SQLQuery query("INSERT INTO `anope_cs_akick` (channel, flags, mask, reason, creator, created, last_used) VALUES(@channel, @flags, @mask, @reason, @creator, @created, @last_used)"); - query.setValue("channel", ci->name); - query.setValue("flags", ak->HasFlag(AK_ISNICK) ? "ISNICK" : ""); - query.setValue("mask", ak->HasFlag(AK_ISNICK) ? ak->nc->display : ak->mask); - query.setValue("reason", ak->reason); - query.setValue("creator", ak->creator); - query.setValue("created", ak->addtime); - query.setValue("last_used", ak->last_used); - this->RunQuery(query); - } - - void OnAkickDel(ChannelInfo *ci, AutoKick *ak) - { - SQLQuery query("DELETE FROM `anope_cs_akick` WHERE `channel`= @mask AND `mask` = @mask"); - query.setValue("channel", ci->name); - query.setValue("mask", ak->HasFlag(AK_ISNICK) ? ak->nc->display : ak->mask); - this->RunQuery(query); - } - - EventReturn OnMLock(ChannelInfo *ci, ModeLock *lock) - { - ChannelMode *cm = ModeManager::FindChannelModeByName(lock->name); - if (cm != NULL) - { - SQLQuery query("INSERT INTO `anope_cs_mlock` (channel, mode, status, setter, created, param) VALUES(@channel, @mode, @status, @setter, @created, @param) ON DUPLICATE KEY UPDATE channel=VALUES(channel), mode=VALUES(mode), status=VALUES(status), setter=VALUES(setter), created=VALUES(created), param=VALUES(param)"); - query.setValue("channel", ci->name); - query.setValue("mode", cm->NameAsString()); - query.setValue("status", lock->set ? 1 : 0); - query.setValue("setter", lock->setter); - query.setValue("created", lock->created); - query.setValue("param", lock->param); - this->RunQuery(query); - } - return EVENT_CONTINUE; - } - - EventReturn OnUnMLock(ChannelInfo *ci, ChannelMode *mode, const Anope::string ¶m) - { - ChannelMode *cm = ModeManager::FindChannelModeByName(mode->Name); - if (cm != NULL) - { - SQLQuery query("DELETE FROM `anope_cs_mlock` WHERE `channel` = @channel AND `mode` = @mode AND `param` = @param"); - query.setValue("channel", ci->name); - query.setValue("mode", mode->NameAsString()); - query.setValue("param", param); - this->RunQuery(query); - } - return EVENT_CONTINUE; - } - - void OnBotCreate(BotInfo *bi) - { - SQLQuery query("INSERT INTO `anope_bs_core` (nick, user, host, rname, flags, created, chancount) VALUES(@nick, @user, @host, @rname, @flags, @created, @chancount) ON DUPLICATE KEY UPDATE nick=VALUES(nick), user=VALUES(user), host=VALUES(host), rname=VALUES(rname), flags=VALUES(flags), created=VALUES(created), chancount=VALUES(chancount)"); - query.setValue("nick", bi->nick); - query.setValue("user", bi->GetIdent()); - query.setValue("host", bi->host); - query.setValue("rname", bi->realname); - query.setValue("flags", ToString(bi->ToString())); - query.setValue("created", bi->created); - query.setValue("chancount", bi->chancount); - this->RunQuery(query); - } - - void OnBotChange(BotInfo *bi) - { - OnBotCreate(bi); - } - - void OnBotDelete(BotInfo *bi) - { - SQLQuery query("UPDATE `anope_cs_info` SET `botnick` = '' WHERE `botnick` = @botnick"); - query.setValue("botnick", bi->nick); - this->RunQuery(query); - } - - EventReturn OnBotAssign(User *sender, ChannelInfo *ci, BotInfo *bi) - { - SQLQuery query("UPDATE `anope_cs_info` SET `botnick` = @botnick WHERE `name` = @channel"); - query.setValue("botnick", bi->nick); - query.setValue("channel", ci->name); - this->RunQuery(query); - return EVENT_CONTINUE; - } - - EventReturn OnBotUnAssign(User *sender, ChannelInfo *ci) - { - SQLQuery query("UPDATE `anope_cs_info` SET `botnick` = '' WHERE `name` = @channel"); - query.setValue("channel", ci->name); - this->RunQuery(query); - return EVENT_CONTINUE; - } - - void OnBadWordAdd(ChannelInfo *ci, BadWord *bw) - { - SQLQuery query("INSERT INTO `anope_bs_badwords` (channel, word, type) VALUES(@channel, @word, @type) ON DUPLICATE KEY UPDATE channel=VALUES(channel), word=VALUES(word), type=VALUES(type)"); - query.setValue("channel", ci->name); - query.setValue("word", bw->word); - switch (bw->type) - { - case BW_SINGLE: - query.setValue("type", "SINGLE"); - break; - case BW_START: - query.setValue("type", "START"); - break; - case BW_END: - query.setValue("type", "END"); - break; - default: - query.setValue("type", "ANY"); - } - this->RunQuery(query); - } - - void OnBadWordDel(ChannelInfo *ci, BadWord *bw) - { - SQLQuery query("DELETE FROM `anope_bs_badwords` WHERE `channel` = @channel AND `word` = @word AND `type` = @type"); - query.setValue("channel", ci->name); - query.setValue("word", bw->word); - switch (bw->type) - { - case BW_SINGLE: - query.setValue("type", "SINGLE"); - break; - case BW_START: - query.setValue("type", "START"); - break; - case BW_END: - query.setValue("type", "END"); - break; - default: - query.setValue("type", "ANY"); - } - this->RunQuery(query); - } - - void OnMemoSend(const Anope::string &source, const Anope::string &target, MemoInfo *mi, Memo *m) - { - const Anope::string &mtype = (!target.empty() && target[0] == '#' ? "CHAN" : "NICK"); - SQLQuery query("INSERT INTO `anope_ms_info` (receiver, flags, time, sender, text, serv) VALUES(@receiver, @flags, @time, @sender, @text, @serv)"); - query.setValue("receiver", target); - query.setValue("flags", ToString(m->ToString())); - query.setValue("time", m->time); - query.setValue("sender", source); - query.setValue("text", m->text); - query.setValue("serv", mtype); - this->RunQuery(query); - } - - void OnMemoDel(const NickCore *nc, MemoInfo *mi, Memo *m) - { - SQLQuery query; - - if (m) - { - query = "DELETE FROM `anope_ms_info` WHERE `receiver` = @receiver AND `time` = @time"; - query.setValue("receiver", nc->display); - query.setValue("time", m->time); - } - else - { - query = "DELETE FROM `anope_ms_info` WHERE `receiver` = @receiver"; - query.setValue("receiver", nc->display); - } - - this->RunQuery(query); - } - - void OnMemoDel(ChannelInfo *ci, MemoInfo *mi, Memo *m) - { - SQLQuery query; - - if (m) - { - query = "DELETE FROM `anope_ms_info` WHERE `receiver` = @receiver AND `time` = @time"; - query.setValue("receiver", ci->name); - query.setValue("time", m->time); - } - else - { - query = "DELETE FROM `anope_ms_info` WHERE `receiver` = @receiver"; - query.setValue("receiver", ci->name); - } - - this->RunQuery(query); - } - - EventReturn OnExceptionAdd(Exception *ex) - { - SQLQuery query("INSERT INTO `anope_os_exceptions` (mask, slimit, who, reason, time, expires) VALUES(@mask, @slimit, @who, @reason, @time, @expires)"); - query.setValue("mask", ex->mask); - query.setValue("slimit", ex->limit); - query.setValue("who", ex->who); - query.setValue("reason", ex->reason); - query.setValue("time", ex->time); - query.setValue("expires", ex->expires); - return EVENT_CONTINUE; - } - - void OnExceptionDel(User *, Exception *ex) - { - SQLQuery query("DELETE FROM `anope_os_exceptions` WHERE `mask` = @mask"); - query.setValue("mask", ex->mask); - this->RunQuery(query); - } - - EventReturn OnAddXLine(XLine *x, XLineManager *xlm) - { - SQLQuery query("INSERT INTO `anope_os_xlines` (type, mask, xby, reason, seton, expire) VALUES(@type, @mask, @xby, @reason, @seton, @expire)"); - query.setValue("type", Anope::string(xlm->Type())); - query.setValue("mask", x->Mask); - query.setValue("xby", x->By); - query.setValue("reason", x->Reason); - query.setValue("seton", x->Created); - query.setValue("expire", x->Expires); - this->RunQuery(query); - return EVENT_CONTINUE; - } - - void OnDelXLine(User *, XLine *x, XLineManager *xlm) - { - SQLQuery query; - - if (x) - { - query = "DELETE FROM `anope_os_xlines` WHERE `mask` = @mask AND `type` = @type"; - query.setValue("mask", x->Mask); - query.setValue("type", Anope::string(xlm->Type())); - } - else - { - query = "DELETE FROM `anope_os_xlines` WHERE `type` = @type"; - query.setValue("type", Anope::string(xlm->Type())); - } - - this->RunQuery(query); - } - - void OnDeleteVhost(NickAlias *na) - { - SQLQuery query("DELETE FROM `anope_hs_core` WHERE `nick` = @nick"); - query.setValue("nick", na->nick); - this->RunQuery(query); - } - - void OnSetVhost(NickAlias *na) - { - SQLQuery query("INSERT INTO `anope_hs_core` (nick, vident, vhost, creator, time) VALUES(@nick, @vident, @vhost, @creator, @time)"); - query.setValue("nick", na->nick); - query.setValue("vident", na->hostinfo.GetIdent()); - query.setValue("vhost", na->hostinfo.GetHost()); - query.setValue("creator", na->hostinfo.GetCreator()); - query.setValue("time", na->hostinfo.GetTime()); - this->RunQuery(query); - } -}; - -void MySQLInterface::OnResult(const SQLResult &r) -{ - Log(LOG_DEBUG) << "MySQL successfully executed query: " << r.finished_query; -} - -void MySQLInterface::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(); -} - - -static void Write(const Anope::string &data) -{ - SQLQuery query("INSERT INTO `anope_extra` (data) VALUES(@data)"); - query.setValue("data", data); - me->RunQuery(query); -} - -static void WriteNickMetadata(const Anope::string &key, const Anope::string &data) -{ - if (!CurNick) - throw CoreException("WriteNickMetadata without a nick to write"); - - SQLQuery query("INSERT INTO `anope_ns_alias_metadata` (nick, name, value) VALUES(@nick, @name, @value)"); - query.setValue("nick", CurNick->nick); - query.setValue("name", key); - query.setValue("value", data); - me->RunQuery(query); -} - -static void WriteCoreMetadata(const Anope::string &key, const Anope::string &data) -{ - if (!CurCore) - throw CoreException("WritCoreMetadata without a core to write"); - - SQLQuery query("INSERT INTO `anope_ns_core_metadata` (nick, name, value) VALUES(@nick, @name, @value)"); - query.setValue("nick", CurCore->display); - query.setValue("name", key); - query.setValue("value", data); - me->RunQuery(query); -} - -static void WriteChannelMetadata(const Anope::string &key, const Anope::string &data) -{ - if (!CurChannel) - throw CoreException("WriteChannelMetadata without a channel to write"); - - SQLQuery query("INSERT INTO `anope_cs_info_metadata` (channel, name, value) VALUES(@channel, @name, @value)"); - query.setValue("channel", CurChannel->name); - query.setValue("name", key); - query.setValue("value", data); - me->RunQuery(query); -} - -static void WriteBotMetadata(const Anope::string &key, const Anope::string &data) -{ - if (!CurBot) - throw CoreException("WriteBotMetadata without a bot to write"); - - SQLQuery query("INSERT INTO `anope_bs_info_metadata` (botname, name, value) VALUES(@botname, @name, @value)"); - query.setValue("botname", CurBot->nick); - query.setValue("name", key); - query.setValue("value", data); - me->RunQuery(query); -} - -static void SaveDatabases() -{ - SQLQuery query; - - query = "TRUNCATE TABLE `anope_ns_core`"; - me->RunQuery(query); - - query = "TRUNCATE TABLE `anope_ms_info`"; - me->RunQuery(query); - - query = "TRUNCATE TABLE `anope_ns_alias`"; - me->RunQuery(query); - - for (nickcore_map::const_iterator nit = NickCoreList.begin(), nit_end = NickCoreList.end(); nit != nit_end; ++nit) - { - NickCore *nc = nit->second; - - me->InsertCore(nc); - - for (std::list<NickAlias *>::iterator it = nc->aliases.begin(), it_end = nc->aliases.end(); it != it_end; ++it) - { - me->InsertAlias(*it); - if ((*it)->hostinfo.HasVhost()) - me->OnSetVhost(*it); - } - - for (std::vector<Anope::string>::iterator it = nc->access.begin(), it_end = nc->access.end(); it != it_end; ++it) - { - query = "INSERT INTO `anope_ns_access` (display, access) VALUES(@display, @access)"; - query.setValue("display", nc->display); - query.setValue("access", *it); - me->RunQuery(query); - } - - for (unsigned j = 0, end = nc->memos.memos.size(); j < end; ++j) - { - Memo *m = nc->memos.memos[j]; - - me->OnMemoSend(m->sender, nc->display, &nc->memos, m); - } - } - - query = "TRUNCATE TABLE `anope_bs_core`"; - me->RunQuery(query); - - for (Anope::insensitive_map<BotInfo *>::const_iterator it = BotListByNick.begin(), it_end = BotListByNick.end(); it != it_end; ++it) - me->OnBotCreate(it->second); - - query = "TRUNCATE TABLE `anope_cs_info`"; - me->RunQuery(query); - - query = "TRUNCATE TABLE `anope_bs_badwords`"; - me->RunQuery(query); - - query = "TRUNCATE TABLE `anope_cs_access`"; - me->RunQuery(query); - - query = "TRUNCATE TABLE `anope_cs_akick`"; - me->RunQuery(query); - - query = "TRUNCATE TABLE `anope_cs_levels`"; - me->RunQuery(query); - - for (registered_channel_map::const_iterator it = RegisteredChannelList.begin(), it_end = RegisteredChannelList.end(); it != it_end; ++it) - { - ChannelInfo *ci = it->second; - - me->OnChanRegistered(ci); - - for (unsigned j = 0, end = ci->GetBadWordCount(); j < end; ++j) - { - BadWord *bw = ci->GetBadWord(j); - - me->OnBadWordAdd(ci, bw); - } - - for (unsigned j = 0, end = ci->GetAccessCount(); j < end; ++j) - { - ChanAccess *access = ci->GetAccess(j); - - me->OnAccessAdd(ci, NULL, access); - } - - for (unsigned j = 0, end = ci->GetAkickCount(); j < end; ++j) - { - AutoKick *ak = ci->GetAkick(j); - - me->OnAkickAdd(ci, ak); - } - - me->OnLevelChange(NULL, ci, "ALL", -1); - - for (unsigned j = 0, end = ci->memos.memos.size(); j < end; ++j) - { - Memo *m = ci->memos.memos[j]; - - me->OnMemoSend(m->sender, ci->name, &ci->memos, m); - } - } - - for (std::list<XLineManager *>::iterator it = XLineManager::XLineManagers.begin(), it_end = XLineManager::XLineManagers.end(); it != it_end; ++it) - for (unsigned i = 0, end = (*it)->GetCount(); i < end; ++i) - me->OnAddXLine((*it)->GetEntry(i), *it); - - if (me->SessionInterface) - for (SessionService::ExceptionVector::iterator it = me->SessionInterface->GetExceptions().begin(); it != me->SessionInterface->GetExceptions().end(); ++it) - me->OnExceptionAdd(*it); -} - -void CommandSQLSync::Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) -{ - SaveDatabases(); - source.Reply(_("Updating MySQL.")); - return; -} - -MODULE_INIT(DBMySQL) - diff --git a/modules/database/db_old.cpp b/modules/database/db_old.cpp new file mode 100644 index 000000000..55956da78 --- /dev/null +++ b/modules/database/db_old.cpp @@ -0,0 +1,1021 @@ +/* + * (C) 2003-2011 Anope Team + * Contact us at team@anope.org + * + * Please read COPYING and README for further details. + * + * Based on the original code of Epona by Lara. + * Based on the original code of Services by Andy Church. + */ + +/*************************************************************************/ + +#include "module.h" + +#define READ(x) \ +if (true) \ +{ \ + if ((x) < 0) \ + printf("Error, the database is broken, line %d, trying to continue... no guarantee.\n", __LINE__); \ +} \ +else \ + static_cast<void>(0) + +#define getc_db(f) (fgetc((f)->fp)) +#define read_db(f, buf, len) (fread((buf), 1, (len), (f)->fp)) +#define read_buffer(buf, f) (read_db((f), (buf), sizeof(buf)) == sizeof(buf)) + +#define OLD_BI_PRIVATE 0x0001 + +#define OLD_NI_KILLPROTECT 0x00000001 /* Kill others who take this nick */ +#define OLD_NI_SECURE 0x00000002 /* Don't recognize unless IDENTIFY'd */ +#define OLD_NI_MSG 0x00000004 /* Use PRIVMSGs instead of NOTICEs */ +#define OLD_NI_MEMO_HARDMAX 0x00000008 /* Don't allow user to change memo limit */ +#define OLD_NI_MEMO_SIGNON 0x00000010 /* Notify of memos at signon and un-away */ +#define OLD_NI_MEMO_RECEIVE 0x00000020 /* Notify of new memos when sent */ +#define OLD_NI_PRIVATE 0x00000040 /* Don't show in LIST to non-servadmins */ +#define OLD_NI_HIDE_EMAIL 0x00000080 /* Don't show E-mail in INFO */ +#define OLD_NI_HIDE_MASK 0x00000100 /* Don't show last seen address in INFO */ +#define OLD_NI_HIDE_QUIT 0x00000200 /* Don't show last quit message in INFO */ +#define OLD_NI_KILL_QUICK 0x00000400 /* Kill in 20 seconds instead of 60 */ +#define OLD_NI_KILL_IMMED 0x00000800 /* Kill immediately instead of in 60 sec */ +#define OLD_NI_MEMO_MAIL 0x00010000 /* User gets email on memo */ +#define OLD_NI_HIDE_STATUS 0x00020000 /* Don't show services access status */ +#define OLD_NI_SUSPENDED 0x00040000 /* Nickname is suspended */ +#define OLD_NI_AUTOOP 0x00080000 /* Autoop nickname in channels */ +#define OLD_NI_NOEXPIRE 0x00100000 /* nicks in this group won't expire */ + +#define OLD_CI_KEEPTOPIC 0x00000001 +#define OLD_CI_SECUREOPS 0x00000002 +#define OLD_CI_PRIVATE 0x00000004 +#define OLD_CI_TOPICLOCK 0x00000008 +#define OLD_CI_RESTRICTED 0x00000010 +#define OLD_CI_PEACE 0x00000020 +#define OLD_CI_SECURE 0x00000040 +#define OLD_CI_FORBIDDEN 0x00000080 +#define OLD_CI_ENCRYPTEDPW 0x00000100 +#define OLD_CI_NO_EXPIRE 0x00000200 +#define OLD_CI_MEMO_HARDMAX 0x00000400 +#define OLD_CI_OPNOTICE 0x00000800 +#define OLD_CI_SECUREFOUNDER 0x00001000 +#define OLD_CI_SIGNKICK 0x00002000 +#define OLD_CI_SIGNKICK_LEVEL 0x00004000 +#define OLD_CI_XOP 0x00008000 +#define OLD_CI_SUSPENDED 0x00010000 + +/* BotServ SET flags */ +#define OLD_BS_DONTKICKOPS 0x00000001 +#define OLD_BS_DONTKICKVOICES 0x00000002 +#define OLD_BS_FANTASY 0x00000004 +#define OLD_BS_SYMBIOSIS 0x00000008 +#define OLD_BS_GREET 0x00000010 +#define OLD_BS_NOBOT 0x00000020 + +/* BotServ Kickers flags */ +#define OLD_BS_KICK_BOLDS 0x80000000 +#define OLD_BS_KICK_COLORS 0x40000000 +#define OLD_BS_KICK_REVERSES 0x20000000 +#define OLD_BS_KICK_UNDERLINES 0x10000000 +#define OLD_BS_KICK_BADWORDS 0x08000000 +#define OLD_BS_KICK_CAPS 0x04000000 +#define OLD_BS_KICK_FLOOD 0x02000000 +#define OLD_BS_KICK_REPEAT 0x01000000 + +static Anope::string hashm; + +enum +{ + LANG_EN_US, /* United States English */ + LANG_JA_JIS, /* Japanese (JIS encoding) */ + LANG_JA_EUC, /* Japanese (EUC encoding) */ + LANG_JA_SJIS, /* Japanese (SJIS encoding) */ + LANG_ES, /* Spanish */ + LANG_PT, /* Portugese */ + LANG_FR, /* French */ + LANG_TR, /* Turkish */ + LANG_IT, /* Italian */ + LANG_DE, /* German */ + LANG_CAT, /* Catalan */ + LANG_GR, /* Greek */ + LANG_NL, /* Dutch */ + LANG_RU, /* Russian */ + LANG_HUN, /* Hungarian */ + LANG_PL /* Polish */ +}; + +static const char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char Pad64 = '='; + +static void my_b64_encode(const Anope::string &src, Anope::string &target) +{ + size_t src_pos = 0, src_len = src.length(); + unsigned char input[3]; + + target.clear(); + + while (src_len - src_pos > 2) + { + input[0] = src[src_pos++]; + input[1] = src[src_pos++]; + input[2] = src[src_pos++]; + + target += Base64[input[0] >> 2]; + target += Base64[((input[0] & 0x03) << 4) + (input[1] >> 4)]; + target += Base64[((input[1] & 0x0f) << 2) + (input[2] >> 6)]; + target += Base64[input[2] & 0x3f]; + } + + /* Now we worry about padding */ + if (src_pos != src_len) + { + input[0] = input[1] = input[2] = 0; + for (size_t i = 0; i < src_len - src_pos; ++i) + input[i] = src[src_pos + i]; + + target += Base64[input[0] >> 2]; + target += Base64[((input[0] & 0x03) << 4) + (input[1] >> 4)]; + if (src_pos == src_len - 1) + target += Pad64; + else + target += Base64[((input[1] & 0x0f) << 2) + (input[2] >> 6)]; + target += Pad64; + } +} + +static Anope::string Hex(const std::string &data) +{ + const char hextable[] = "0123456789abcdef"; + + size_t l = data.length(); + std::string rv; + for (size_t i = 0; i < l; ++i) + { + unsigned char c = data[i]; + rv += hextable[c >> 4]; + rv += hextable[c & 0xF]; + } + return rv; +} + +static Anope::string GetLevelName(int level) +{ + switch (level) + { + case 0: + return "INVITE"; + case 1: + return "AKICK"; + case 2: + return "SET"; + case 3: + return "UNBAN"; + case 4: + return "AUTOOP"; + case 5: + return "AUTODEOP"; + case 6: + return "AUTOVOICE"; + case 7: + return "OPDEOP"; + case 8: + return "LIST"; + case 9: + return "CLEAR"; + case 10: + return "NOJOIN"; + case 11: + return "CHANGE"; + case 12: + return "MEMO"; + case 13: + return "ASSIGN"; + case 14: + return "BADWORDS"; + case 15: + return "NOKICK"; + case 16: + return "FANTASIA"; + case 17: + return "SAY"; + case 18: + return "GREET"; + case 19: + return "VOICEME"; + case 20: + return "VOICE"; + case 21: + return "GETKEY"; + case 22: + return "AUTOHALFOP"; + case 23: + return "AUTOPROTECT"; + case 24: + return "OPDEOPME"; + case 25: + return "HALFOPME"; + case 26: + return "HALFOP"; + case 27: + return "PROTECTME"; + case 28: + return "PROTECT"; + case 29: + return "KICKME"; + case 30: + return "KICK"; + case 31: + return "SIGNKICK"; + case 32: + return "BANME"; + case 33: + return "BAN"; + case 34: + return "TOPIC"; + case 35: + return "INFO"; + default: + return "INVALID"; + } +} + +static char *strscpy(char *d, const char *s, size_t len) +{ + char *d_orig = d; + + if (!len) + return d; + while (--len && (*d++ = *s++)); + *d = '\0'; + return d_orig; +} + +struct dbFILE +{ + int mode; /* 'r' for reading, 'w' for writing */ + FILE *fp; /* The normal file descriptor */ + char filename[1024]; /* Name of the database file */ +}; + +static dbFILE *open_db_read(const char *service, const char *filename, int version) +{ + dbFILE *f; + FILE *fp; + int myversion; + + f = new dbFILE; + strscpy(f->filename, filename, sizeof(f->filename)); + f->mode = 'r'; + fp = fopen(f->filename, "rb"); + if (!fp) + { + Log() << "Can't read " << service << " database " << f->filename; + delete f; + return NULL; + } + f->fp = fp; + myversion = fgetc(fp) << 24 | fgetc(fp) << 16 | fgetc(fp) << 8 | fgetc(fp); + if (feof(fp)) + { + Log() << "Error reading version number on " << f->filename << ": End of file detected."; + delete f; + return NULL; + } + else if (myversion < version) + { + Log() << "Unsuported database version (" << myversion << ") on " << f->filename << "."; + delete f; + return NULL; + } + return f; +} + +void close_db(dbFILE *f) +{ + fclose(f->fp); + delete f; +} + +static int read_int16(int16 *ret, dbFILE *f) +{ + int c1, c2; + + *ret = 0; + + c1 = fgetc(f->fp); + c2 = fgetc(f->fp); + if (c1 == EOF || c2 == EOF) + return -1; + *ret = c1 << 8 | c2; + return 0; +} + +static int read_uint16(uint16 *ret, dbFILE *f) +{ + int c1, c2; + + *ret = 0; + + c1 = fgetc(f->fp); + c2 = fgetc(f->fp); + if (c1 == EOF || c2 == EOF) + return -1; + *ret = c1 << 8 | c2; + return 0; +} + +static int read_string(Anope::string &str, dbFILE *f) +{ + str.clear(); + uint16 len; + + if (read_uint16(&len, f) < 0) + return -1; + if (len == 0) + return 0; + char *s = new char[len]; + if (len != fread(s, 1, len, f->fp)) + { + delete [] s; + return -1; + } + str = s; + delete [] s; + return 0; +} + +static int read_uint32(uint32 *ret, dbFILE *f) +{ + int c1, c2, c3, c4; + + *ret = 0; + + c1 = fgetc(f->fp); + c2 = fgetc(f->fp); + c3 = fgetc(f->fp); + c4 = fgetc(f->fp); + if (c1 == EOF || c2 == EOF || c3 == EOF || c4 == EOF) + return -1; + *ret = c1 << 24 | c2 << 16 | c3 << 8 | c4; + return 0; +} + +int read_int32(int32 *ret, dbFILE *f) +{ + int c1, c2, c3, c4; + + *ret = 0; + + c1 = fgetc(f->fp); + c2 = fgetc(f->fp); + c3 = fgetc(f->fp); + c4 = fgetc(f->fp); + if (c1 == EOF || c2 == EOF || c3 == EOF || c4 == EOF) + return -1; + *ret = c1 << 24 | c2 << 16 | c3 << 8 | c4; + return 0; +} + +static void LoadNicks() +{ + dbFILE *f = open_db_read("NickServ", "nick.db", 14); + if (f == NULL) + return; + for (int i = 0; i < 1024; ++i) + for (int c; (c = getc_db(f)) == 1;) + { + Anope::string buffer; + + READ(read_string(buffer, f)); + NickCore *nc = new NickCore(buffer); + + char pwbuf[32]; + READ(read_buffer(pwbuf, f)); + if (hashm == "plain") + my_b64_encode(pwbuf, nc->pass); + else + nc->pass = Hex(pwbuf); + nc->pass = hashm + ":" + nc->pass; + + READ(read_string(buffer, f)); + nc->email = buffer; + + READ(read_string(buffer, f)); + nc->greet = buffer; + + uint32 uint; + READ(read_uint32(&uint, f)); + //nc->icq = uint; + + READ(read_string(buffer, f)); + //nc->url = buffer; + + READ(read_uint32(&uint, f)); + if (uint & OLD_NI_KILLPROTECT) + nc->SetFlag(NI_KILLPROTECT); + if (uint & OLD_NI_SECURE) + nc->SetFlag(NI_SECURE); + if (uint & OLD_NI_MSG) + nc->SetFlag(NI_MSG); + if (uint & OLD_NI_MEMO_HARDMAX) + nc->SetFlag(NI_MEMO_HARDMAX); + if (uint & OLD_NI_MEMO_SIGNON) + nc->SetFlag(NI_MEMO_SIGNON); + if (uint & OLD_NI_MEMO_RECEIVE) + nc->SetFlag(NI_MEMO_RECEIVE); + if (uint & OLD_NI_PRIVATE) + nc->SetFlag(NI_PRIVATE); + if (uint & OLD_NI_HIDE_EMAIL) + nc->SetFlag(NI_HIDE_EMAIL); + if (uint & OLD_NI_HIDE_MASK) + nc->SetFlag(NI_HIDE_MASK); + if (uint & OLD_NI_HIDE_QUIT) + nc->SetFlag(NI_HIDE_QUIT); + if (uint & OLD_NI_KILL_QUICK) + nc->SetFlag(NI_KILL_QUICK); + if (uint & OLD_NI_KILL_IMMED) + nc->SetFlag(NI_KILL_IMMED); + if (uint & OLD_NI_MEMO_MAIL) + nc->SetFlag(NI_MEMO_MAIL); + if (uint & OLD_NI_HIDE_STATUS) + nc->SetFlag(NI_HIDE_STATUS); + if (uint & OLD_NI_SUSPENDED) + nc->SetFlag(NI_SUSPENDED); + if (!(uint & OLD_NI_AUTOOP)) + nc->SetFlag(NI_AUTOOP); + if (uint & OLD_NI_NOEXPIRE) + nc->Extend("noexpire", NULL); + + uint16 u16; + READ(read_uint16(&u16, f)); + switch (u16) + { + case LANG_ES: + nc->language = "es_ES"; + break; + case LANG_PT: + nc->language = "pt_PT"; + break; + case LANG_FR: + nc->language = "fr_FR"; + break; + case LANG_TR: + nc->language = "tr_TR"; + break; + case LANG_IT: + nc->language = "it_IT"; + break; + case LANG_DE: + nc->language = "de_DE"; + break; + case LANG_CAT: + nc->language = "ca_ES"; // yes, iso639 defines catalan as CA + break; + case LANG_GR: + nc->language = "el_GR"; + break; + case LANG_NL: + nc->language = "nl_NL"; + break; + case LANG_RU: + nc->language = "ru_RU"; + break; + case LANG_HUN: + nc->language = "hu_HU"; + break; + case LANG_PL: + nc->language = "pl_PL"; + break; + case LANG_EN_US: + case LANG_JA_JIS: + case LANG_JA_EUC: + case LANG_JA_SJIS: // these seem to be unused + default: + nc->language = "en_US"; + } + + READ(read_uint16(&u16, f)); + for (uint16 j = 0; j < u16; ++j) + { + READ(read_string(buffer, f)); + nc->access.push_back(buffer); + } + + int16 i16; + READ(read_int16(&i16, f)); + READ(read_int16(&nc->memos.memomax, f)); + for (int16 j = 0; j < i16; ++j) + { + Memo *m = new Memo; + READ(read_uint32(&uint, f)); + uint16 flags; + READ(read_uint16(&flags, f)); + int32 tmp32; + READ(read_int32(&tmp32, f)); + m->time = tmp32; + char sbuf[32]; + READ(read_buffer(sbuf, f)); + m->sender = sbuf; + READ(read_string(m->text, f)); + nc->memos.memos.push_back(m); + } + READ(read_uint16(&u16, f)); + READ(read_int16(&i16, f)); + + Log(LOG_DEBUG) << "Loaded NickCore " << nc->display; + } + + for (int i = 0; i < 1024; ++i) + for (int c; (c = getc_db(f)) == 1;) + { + Anope::string nick, last_usermask, last_realname, last_quit; + time_t time_registered, last_seen; + + READ(read_string(nick, f)); + READ(read_string(last_usermask, f)); + READ(read_string(last_realname, f)); + READ(read_string(last_quit, f)); + + int32 tmp32; + READ(read_int32(&tmp32, f)); + time_registered = tmp32; + READ(read_int32(&tmp32, f)); + last_seen = tmp32; + + uint16 tmpu16; + READ(read_uint16(&tmpu16, f)); + Anope::string core; + READ(read_string(core, f)); + NickCore *nc = findcore(core); + if (nc == NULL) + { + Log() << "Skipping coreless nick " << nick << " with core " << core; + continue; + } + NickAlias *na = new NickAlias(nick, nc); + na->last_usermask = last_usermask; + na->last_realname = last_realname; + na->last_quit = last_quit; + na->time_registered = time_registered; + na->last_seen = last_seen; + + if (na->nc->HasExt("noexpire")) + na->SetFlag(NS_NO_EXPIRE); + + Log(LOG_DEBUG) << "Loaded NickAlias " << na->nick; + } + + close_db(f); /* End of section Ia */ +} + +static void LoadVHosts() +{ + dbFILE *f = open_db_read("HostServ", "hosts.db", 3); + if (f == NULL) + return; + + for (int c; (c = getc_db(f)) == 1;) + { + Anope::string nick, ident, host, creator; + int32 vtime; + + READ(read_string(nick, f)); + READ(read_string(ident, f)); + READ(read_string(host, f)); + READ(read_string(creator, f)); + READ(read_int32(&vtime, f)); + + NickAlias *na = findnick(nick); + if (na == NULL) + { + Log() << "Removing vhost for nonexistant nick " << nick; + continue; + } + + na->hostinfo.SetVhost(ident, host, creator, vtime); + + Log() << "Loaded vhost for " << na->nick; + } + + close_db(f); +} + +static void LoadBots() +{ + dbFILE *f = open_db_read("Botserv", "bot.db", 10); + if (f == NULL) + return; + + for (int c; (c = getc_db(f)) == 1;) + { + Anope::string nick, user, host, real; + int16 flags, chancount; + int32 created; + + READ(read_string(nick, f)); + READ(read_string(user, f)); + READ(read_string(host, f)); + READ(read_string(real, f)); + READ(read_int16(&flags, f)); + READ(read_int32(&created, f)); + READ(read_int16(&chancount, f)); + + BotInfo *bi = new BotInfo(nick, user, host, real); + bi->created = created; + bi->chancount = chancount; + + if (flags & OLD_BI_PRIVATE) + bi->SetFlag(BI_PRIVATE); + + Log(LOG_DEBUG) << "Loaded bot " << bi->nick; + } + + close_db(f); +} + +static void LoadChannels() +{ + dbFILE *f = open_db_read("ChanServ", "chan.db", 16); + if (f == NULL) + return; + + for (int i = 0; i < 256; ++i) + for (int c; (c = getc_db(f)) == 1;) + { + Anope::string buffer; + char namebuf[64]; + READ(read_buffer(namebuf, f)); + ChannelInfo *ci = new ChannelInfo(namebuf); + + READ(read_string(buffer, f)); + ci->SetFounder(findcore(buffer)); + + READ(read_string(buffer, f)); + ci->successor = findcore(buffer); + + char pwbuf[32]; + READ(read_buffer(pwbuf, f)); + + READ(read_string(ci->desc, f)); + READ(read_string(buffer, f)); + READ(read_string(buffer, f)); + + int32 tmp32; + READ(read_int32(&tmp32, f)); + ci->time_registered = tmp32; + + READ(read_int32(&tmp32, f)); + ci->last_used = tmp32; + + READ(read_string(ci->last_topic, f)); + + READ(read_buffer(pwbuf, f)); + ci->last_topic_setter = pwbuf; + + READ(read_int32(&tmp32, f)); + ci->last_topic_time = tmp32; + + uint32 tmpu32; + READ(read_uint32(&tmpu32, f)); + // Temporary flags cleanup + tmpu32 &= ~0x80000000; + if (tmpu32 & OLD_CI_KEEPTOPIC) + ci->SetFlag(CI_KEEPTOPIC); + if (tmpu32 & OLD_CI_SECUREOPS) + ci->SetFlag(CI_SECUREOPS); + if (tmpu32 & OLD_CI_PRIVATE) + ci->SetFlag(CI_PRIVATE); + if (tmpu32 & OLD_CI_TOPICLOCK) + ci->SetFlag(CI_TOPICLOCK); + if (tmpu32 & OLD_CI_RESTRICTED) + ci->SetFlag(CI_RESTRICTED); + if (tmpu32 & OLD_CI_PEACE) + ci->SetFlag(CI_PEACE); + if (tmpu32 & OLD_CI_SECURE) + ci->SetFlag(CI_SECURE); + if (tmpu32 & OLD_CI_NO_EXPIRE) + ci->SetFlag(CI_NO_EXPIRE); + if (tmpu32 & OLD_CI_MEMO_HARDMAX) + ci->SetFlag(CI_MEMO_HARDMAX); + if (tmpu32 & OLD_CI_SECUREFOUNDER) + ci->SetFlag(CI_SECUREFOUNDER); + if (tmpu32 & OLD_CI_SIGNKICK) + ci->SetFlag(CI_SIGNKICK); + if (tmpu32 & OLD_CI_SIGNKICK_LEVEL) + ci->SetFlag(CI_SIGNKICK_LEVEL); + if (tmpu32 & OLD_CI_SUSPENDED) + ci->SetFlag(CI_SUSPENDED); + + READ(read_string(buffer, f)); + READ(read_string(buffer, f)); + + int16 tmp16; + READ(read_int16(&tmp16, f)); + ci->bantype = tmp16; + + READ(read_int16(&tmp16, f)); + if (tmp16 > 36) + tmp16 = 36; + for (int16 j = 0; j < tmp16; ++j) + { + int16 level; + READ(read_int16(&level, f)); + + ci->SetLevel(GetLevelName(j), level); + } + + uint16 tmpu16; + READ(read_uint16(&tmpu16, f)); + for (uint16 j = 0; j < tmpu16; ++j) + { + uint16 in_use; + READ(read_uint16(&in_use, f)); + if (in_use) + { + service_reference<AccessProvider> provider("access/access"); + if (!provider) + break; + + ChanAccess *access = provider->Create(); + access->ci = ci; + + int16 level; + READ(read_int16(&level, f)); + access->Unserialize(stringify(level)); + + Anope::string mask; + READ(read_string(mask, f)); + access->mask = mask; + + READ(read_int32(&tmp32, f)); + access->last_seen = tmp32; + access->creator = "Unknown"; + access->created = Anope::CurTime; + + ci->AddAccess(access); + } + } + + READ(read_uint16(&tmpu16, f)); + for (uint16 j = 0; j < tmpu16; ++j) + { + uint16 flags; + READ(read_uint16(&flags, f)); + if (flags & 0x0001) + { + Anope::string mask, reason, creator; + READ(read_string(mask, f)); + READ(read_string(reason, f)); + READ(read_string(creator, f)); + READ(read_int32(&tmp32, f)); + + ci->AddAkick(creator, mask, reason, tmp32); + } + } + + READ(read_uint32(&tmpu32, f)); // mlock on + READ(read_uint32(&tmpu32, f)); // mlock off + READ(read_uint32(&tmpu32, f)); // mlock limit + READ(read_string(buffer, f)); + READ(read_string(buffer, f)); + READ(read_string(buffer, f)); + + READ(read_int16(&tmp16, f)); + READ(read_int16(&ci->memos.memomax, f)); + for (int16 j = 0; j < tmp16; ++j) + { + READ(read_uint32(&tmpu32, f)); + READ(read_uint16(&tmpu16, f)); + Memo *m = new Memo; + READ(read_int32(&tmp32, f)); + m->time = tmp32; + char sbuf[32]; + READ(read_buffer(sbuf, f)); + m->sender = sbuf; + READ(read_string(m->text, f)); + ci->memos.memos.push_back(m); + } + + READ(read_string(buffer, f)); + + READ(read_string(buffer, f)); + ci->bi = findbot(buffer); + + READ(read_int32(&tmp32, f)); + if (tmp32 & OLD_BS_DONTKICKOPS) + ci->botflags.SetFlag(BS_DONTKICKOPS); + if (tmp32 & OLD_BS_DONTKICKVOICES) + ci->botflags.SetFlag(BS_DONTKICKVOICES); + if (tmp32 & OLD_BS_FANTASY) + ci->botflags.SetFlag(BS_FANTASY); + if (tmp32 & OLD_BS_GREET) + ci->botflags.SetFlag(BS_GREET); + if (tmp32 & OLD_BS_NOBOT) + ci->botflags.SetFlag(BS_NOBOT); + if (tmp32 & OLD_BS_KICK_BOLDS) + ci->botflags.SetFlag(BS_KICK_BOLDS); + if (tmp32 & OLD_BS_KICK_COLORS) + ci->botflags.SetFlag(BS_KICK_COLORS); + if (tmp32 & OLD_BS_KICK_REVERSES) + ci->botflags.SetFlag(BS_KICK_REVERSES); + if (tmp32 & OLD_BS_KICK_UNDERLINES) + ci->botflags.SetFlag(BS_KICK_UNDERLINES); + if (tmp32 & OLD_BS_KICK_BADWORDS) + ci->botflags.SetFlag(BS_KICK_BADWORDS); + if (tmp32 & OLD_BS_KICK_CAPS) + ci->botflags.SetFlag(BS_KICK_CAPS); + if (tmp32 & OLD_BS_KICK_FLOOD) + ci->botflags.SetFlag(BS_KICK_FLOOD); + if (tmp32 & OLD_BS_KICK_REPEAT) + ci->botflags.SetFlag(BS_KICK_REPEAT); + + READ(read_int16(&tmp16, f)); + for (int16 j = 0; j < tmp16; ++j) + { + int16 ttb; + READ(read_int16(&ttb, f)); + if (j < TTB_SIZE) + ci->ttb[j] = ttb; + } + + READ(read_int16(&tmp16, f)); + ci->capsmin = tmp16; + READ(read_int16(&tmp16, f)); + ci->capspercent = tmp16; + READ(read_int16(&tmp16, f)); + ci->floodlines = tmp16; + READ(read_int16(&tmp16, f)); + ci->floodsecs = tmp16; + READ(read_int16(&tmp16, f)); + ci->repeattimes = tmp16; + + READ(read_uint16(&tmpu16, f)); + for (uint16 j = 0; j < tmpu16; ++j) + { + uint16 in_use; + READ(read_uint16(&in_use, f)); + if (in_use) + { + READ(read_string(buffer, f)); + uint16 type; + READ(read_uint16(&type, f)); + + BadWordType bwtype = BW_ANY; + if (type == 1) + bwtype = BW_SINGLE; + else if (type == 2) + bwtype = BW_START; + else if (type == 3) + bwtype = BW_END; + + ci->AddBadWord(buffer, bwtype); + } + } + + Log(LOG_DEBUG) << "Loaded channel " << ci->name; + } + + close_db(f); +} + +static void LoadOper() +{ + dbFILE *f = open_db_read("OperServ", "oper.db", 13); + if (f == NULL) + return; + + XLineManager *akill, *sqline, *snline, *szline; + akill = sqline = snline = szline = NULL; + + for (std::list<XLineManager *>::iterator it = XLineManager::XLineManagers.begin(), it_end = XLineManager::XLineManagers.end(); it != it_end; ++it) + { + XLineManager *xl = *it; + if (xl->Type() == 'G') + akill = xl; + else if (xl->Type() == 'Q') + sqline = xl; + else if (xl->Type() == 'N') + snline = xl; + else if (xl->Type() == 'Z') + szline = xl; + } + + int32 tmp32; + READ(read_int32(&tmp32, f)); + READ(read_int32(&tmp32, f)); + + int16 capacity; + read_int16(&capacity, f); // AKill count + for (int16 i = 0; i < capacity; ++i) + { + Anope::string user, host, by, reason; + int32 seton, expires; + + READ(read_string(user, f)); + READ(read_string(host, f)); + READ(read_string(by, f)); + READ(read_string(reason, f)); + READ(read_int32(&seton, f)); + READ(read_int32(&expires, f)); + + if (!akill) + continue; + + XLine *x = akill->Add(user + "@" + host, by, expires, reason); + if (x) + x->Created = seton; + } + + read_int16(&capacity, f); // SNLines + for (int16 i = 0; i < capacity; ++i) + { + Anope::string mask, by, reason; + int32 seton, expires; + + READ(read_string(mask, f)); + READ(read_string(by, f)); + READ(read_string(reason, f)); + READ(read_int32(&seton, f)); + READ(read_int32(&expires, f)); + + if (!snline) + continue; + + XLine *x = snline->Add(mask, by, expires, reason); + if (x) + x->Created = seton; + } + + read_int16(&capacity, f); // SQLines + for (int16 i = 0; i < capacity; ++i) + { + Anope::string mask, by, reason; + int32 seton, expires; + + READ(read_string(mask, f)); + READ(read_string(by, f)); + READ(read_string(reason, f)); + READ(read_int32(&seton, f)); + READ(read_int32(&expires, f)); + + if (!sqline) + continue; + + XLine *x = sqline->Add(mask, by, expires, reason); + if (x) + x->Created = seton; + } + + read_int16(&capacity, f); // SZLines + for (int16 i = 0; i < capacity; ++i) + { + Anope::string mask, by, reason; + int32 seton, expires; + + READ(read_string(mask, f)); + READ(read_string(by, f)); + READ(read_string(reason, f)); + READ(read_int32(&seton, f)); + READ(read_int32(&expires, f)); + + if (!szline) + continue; + + XLine *x = szline->Add(mask, by, expires, reason); + if (x) + x->Created = seton; + } + + close_db(f); +} + +class DBOld : public Module +{ + public: + DBOld(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE) + { + this->SetAuthor("Anope"); + + Implementation i[] = { I_OnLoadDatabase }; + ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); + + ConfigReader conf; + hashm = conf.ReadValue("db_old", "hash", "", 0); + + if (hashm != "md5" && hashm != "oldmd5" && hashm == "sha1" && hashm == "plain") + throw ModuleException("Invalid hash method"); + } + + EventReturn OnLoadDatabase() + { + LoadNicks(); + LoadVHosts(); + LoadBots(); + LoadChannels(); + LoadOper(); + + return EVENT_STOP; + } +}; + +MODULE_INIT(DBOld) + diff --git a/modules/database/db_plain.cpp b/modules/database/db_plain.cpp index bf0b05e3d..711434336 100644 --- a/modules/database/db_plain.cpp +++ b/modules/database/db_plain.cpp @@ -15,7 +15,14 @@ Anope::string DatabaseFile; std::stringstream db_buffer; -service_reference<SessionService, Base> SessionInterface("session"); + +class DatabaseException : public CoreException +{ + public: + DatabaseException(const Anope::string &reason = "") : CoreException(reason) { } + + virtual ~DatabaseException() throw() { } +}; /** Enum used for what METADATA type we are reading */ @@ -28,6 +35,300 @@ enum MDType MD_CH }; +static void LoadNickCore(const std::vector<Anope::string> ¶ms); +static void LoadNickAlias(const std::vector<Anope::string> ¶ms); +static void LoadBotInfo(const std::vector<Anope::string> ¶ms); +static void LoadChanInfo(const std::vector<Anope::string> ¶ms); +static void LoadOperInfo(const std::vector<Anope::string> ¶ms); + +EventReturn OnDatabaseRead(const std::vector<Anope::string> ¶ms) +{ + Anope::string key = params[0]; + std::vector<Anope::string> otherparams = params; + otherparams.erase(otherparams.begin()); + + if (key.equals_ci("NC")) + LoadNickCore(otherparams); + else if (key.equals_ci("NA")) + LoadNickAlias(otherparams); + else if (key.equals_ci("BI")) + LoadBotInfo(otherparams); + else if (key.equals_ci("CH")) + LoadChanInfo(otherparams); + else if (key.equals_ci("OS")) + LoadOperInfo(otherparams); + + return EVENT_CONTINUE; + } + +EventReturn OnDatabaseReadMetadata(NickCore *nc, const Anope::string &key, const std::vector<Anope::string> ¶ms) +{ + try + { + if (key.equals_ci("LANGUAGE")) + nc->language = params[0]; + else if (key.equals_ci("MEMOMAX")) + nc->memos.memomax = params[0].is_pos_number_only() ? convertTo<int16>(params[0]) : -1; + else if (key.equals_ci("EMAIL")) + nc->email = params[0]; + else if (key.equals_ci("GREET")) + nc->greet = params[0]; + else if (key.equals_ci("ACCESS")) + nc->AddAccess(params[0]); + else if (key.equals_ci("CERT")) + nc->AddCert(params[0]); + else if (key.equals_ci("FLAGS")) + nc->FromVector(params); + else if (key.equals_ci("MI")) + { + Memo *m = new Memo; + m->time = params[0].is_pos_number_only() ? convertTo<time_t>(params[0]) : 0; + m->sender = params[1]; + for (unsigned j = 2; params[j].equals_ci("UNREAD") || params[j].equals_ci("RECEIPT"); ++j) + { + if (params[j].equals_ci("UNREAD")) + m->SetFlag(MF_UNREAD); + else if (params[j].equals_ci("RECEIPT")) + m->SetFlag(MF_RECEIPT); + } + m->text = params[params.size() - 1]; + nc->memos.memos.push_back(m); + } + else if (key.equals_ci("MIG")) + nc->memos.ignores.push_back(params[0].ci_str()); + } + catch (const ConvertException &ex) + { + throw DatabaseException(ex.GetReason()); + } + return EVENT_CONTINUE; +} + +EventReturn OnDatabaseReadMetadata(NickAlias *na, const Anope::string &key, const std::vector<Anope::string> ¶ms) +{ + if (key.equals_ci("LAST_USERMASK")) + na->last_usermask = params[0]; + else if (key.equals_ci("LAST_REALHOST")) + na->last_realhost = params[0]; + else if (key.equals_ci("LAST_REALNAME")) + na->last_realname = params[0]; + else if (key.equals_ci("LAST_QUIT")) + na->last_quit = params[0]; + else if (key.equals_ci("FLAGS")) + na->FromVector(params); + else if (key.equals_ci("VHOST")) + na->hostinfo.SetVhost(params.size() > 3 ? params[3] : "", params[2], params[0], params[1].is_pos_number_only() ? convertTo<time_t>(params[1]) : 0); + return EVENT_CONTINUE; +} + +EventReturn OnDatabaseReadMetadata(BotInfo *bi, const Anope::string &key, const std::vector<Anope::string> ¶ms) +{ + if (key.equals_ci("FLAGS")) + bi->FromVector(params); + + return EVENT_CONTINUE; +} + +EventReturn OnDatabaseReadMetadata(ChannelInfo *ci, const Anope::string &key, const std::vector<Anope::string> ¶ms) +{ + try + { + if (key.equals_ci("BANTYPE")) + ci->bantype = params[0].is_pos_number_only() ? convertTo<int16>(params[0]) : Config->CSDefBantype; + else if (key.equals_ci("MEMOMAX")) + ci->memos.memomax = params[0].is_pos_number_only() ? convertTo<int16>(params[0]) : -1; + else if (key.equals_ci("FOUNDER")) + ci->SetFounder(findcore(params[0])); + else if (key.equals_ci("SUCCESSOR")) + ci->successor = findcore(params[0]); + else if (key.equals_ci("LEVELS")) + { + for (unsigned j = 0, end = params.size(); j < end; j += 2) + { + Privilege *p = PrivilegeManager::FindPrivilege(params[j]); + if (p == NULL) + continue; + ci->SetLevel(p->name, params[j + 1].is_number_only() ? convertTo<int16>(params[j + 1]) : 0); + } + } + else if (key.equals_ci("FLAGS")) + ci->FromVector(params); + else if (key.equals_ci("DESC")) + ci->desc = params[0]; + else if (key.equals_ci("TOPIC")) + { + ci->last_topic_setter = params[0]; + ci->last_topic_time = params[1].is_pos_number_only() ? convertTo<time_t>(params[1]) : 0; + ci->last_topic = params[2]; + } + else if (key.equals_ci("SUSPEND")) + { + ci->Extend("suspend_by", new ExtensibleString(params[0])); + ci->Extend("suspend_reason", new ExtensibleString(params[1])); + } + else if (key.equals_ci("ACCESS")) // Older access system, from Anope 1.9.4. + { + service_reference<AccessProvider> provider("access/access"); + if (!provider) + throw DatabaseException("Old access entry for nonexistant provider"); + + ChanAccess *access = provider->Create(); + access->ci = ci; + access->mask = params[0]; + access->Unserialize(params[1]); + access->last_seen = params[2].is_pos_number_only() ? convertTo<time_t>(params[2]) : 0; + access->creator = params[3]; + access->created = Anope::CurTime; + + ci->AddAccess(access); + } + else if (key.equals_ci("ACCESS2")) + { + service_reference<AccessProvider> provider(params[0]); + if (!provider) + throw DatabaseException("Access entry for nonexistant provider " + params[0]); + + ChanAccess *access = provider->Create(); + access->ci = ci; + access->mask = params[1]; + access->Unserialize(params[2]); + access->last_seen = params[3].is_pos_number_only() ? convertTo<time_t>(params[3]) : 0; + access->creator = params[4]; + access->created = params.size() > 5 && params[5].is_pos_number_only() ? convertTo<time_t>(params[5]) : Anope::CurTime; + + ci->AddAccess(access); + } + else if (key.equals_ci("AKICK")) + { + // 0 is the old stuck + bool Nick = params[1].equals_ci("NICK"); + NickCore *nc = NULL; + if (Nick) + { + nc = findcore(params[2]); + if (!nc) + throw DatabaseException("Akick for nonexistant core " + params[2] + " on " + ci->name); + } + + AutoKick *ak; + if (Nick) + ak = ci->AddAkick(params[3], nc, params.size() > 6 ? params[6] : "", params[4].is_pos_number_only() ? convertTo<time_t>(params[4]) : 0, params[5].is_pos_number_only() ? convertTo<time_t>(params[5]) : 0); + else + ak = ci->AddAkick(params[3], params[2], params.size() > 6 ? params[6] : "", params[4].is_pos_number_only() ? convertTo<time_t>(params[4]) : 0, params[5].is_pos_number_only() ? convertTo<time_t>(params[5]) : 0); + if (Nick) + ak->SetFlag(AK_ISNICK); + + } + else if (key.equals_ci("LOG")) + { + LogSetting l; + + l.service_name = params[0]; + l.command_service = params[1]; + l.command_name = params[2]; + l.method = params[3]; + l.creator = params[4]; + l.created = params[5].is_pos_number_only() ? convertTo<time_t>(params[5]) : Anope::CurTime; + l.extra = params.size() > 6 ? params[6] : ""; + + ci->log_settings.push_back(l); + } + else if (key.equals_ci("MLOCK")) + { + bool set = params[0] == "1" ? true : false; + Anope::string mode_name = params[1]; + Anope::string setter = params[2]; + time_t mcreated = params[3].is_pos_number_only() ? convertTo<time_t>(params[3]) : Anope::CurTime; + Anope::string param = params.size() > 4 ? params[4] : ""; + for (size_t i = CMODE_BEGIN + 1; i < CMODE_END; ++i) + if (ChannelModeNameStrings[i] == mode_name) + { + ChannelModeName n = static_cast<ChannelModeName>(i); + ci->mode_locks.insert(std::make_pair(n, ModeLock(ci, set, n, param, setter, mcreated))); + break; + } + } + else if (key.equals_ci("MI")) + { + Memo *m = new Memo; + m->time = params[0].is_pos_number_only() ? convertTo<time_t>(params[0]) : 0; + m->sender = params[1]; + for (unsigned j = 2; params[j].equals_ci("UNREAD") || params[j].equals_ci("RECEIPT"); ++j) + { + if (params[j].equals_ci("UNREAD")) + m->SetFlag(MF_UNREAD); + else if (params[j].equals_ci("RECEIPT")) + m->SetFlag(MF_RECEIPT); + } + m->text = params[params.size() - 1]; + ci->memos.memos.push_back(m); + } + else if (key.equals_ci("MIG")) + ci->memos.ignores.push_back(params[0].ci_str()); + else if (key.equals_ci("BI")) + { + if (params[0].equals_ci("NAME")) + ci->bi = findbot(params[1]); + else if (params[0].equals_ci("FLAGS")) + ci->botflags.FromVector(params); + else if (params[0].equals_ci("TTB")) + { + for (unsigned j = 1, end = params.size(); j < end; j += 2) + { + if (params[j].equals_ci("BOLDS")) + ci->ttb[0] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0; + else if (params[j].equals_ci("COLORS")) + ci->ttb[1] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0; + else if (params[j].equals_ci("REVERSES")) + ci->ttb[2] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0; + else if (params[j].equals_ci("UNDERLINES")) + ci->ttb[3] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0; + else if (params[j].equals_ci("BADWORDS")) + ci->ttb[4] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0; + else if (params[j].equals_ci("CAPS")) + ci->ttb[5] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0; + else if (params[j].equals_ci("FLOOD")) + ci->ttb[6] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0; + else if (params[j].equals_ci("REPEAT")) + ci->ttb[7] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0; + else if (params[j].equals_ci("ITALICS")) + ci->ttb[8] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0; + else if (params[j].equals_ci("AMSGS")) + ci->ttb[9] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0; + } + } + else if (params[0].equals_ci("CAPSMIN")) + ci->capsmin = params[1].is_pos_number_only() ? convertTo<int16>(params[1]) : 0; + else if (params[0].equals_ci("CAPSPERCENT")) + ci->capspercent = params[1].is_pos_number_only() ? convertTo<int16>(params[1]) : 0; + else if (params[0].equals_ci("FLOODLINES")) + ci->floodlines = params[1].is_pos_number_only() ? convertTo<int16>(params[1]) : 0; + else if (params[0].equals_ci("FLOODSECS")) + ci->floodsecs = params[1].is_pos_number_only() ? convertTo<int16>(params[1]) : 0; + else if (params[0].equals_ci("REPEATTIMES")) + ci->repeattimes = params[1].is_pos_number_only() ? convertTo<int16>(params[1]) : 0; + else if (params[0].equals_ci("BADWORD")) + { + BadWordType Type; + if (params[1].equals_ci("SINGLE")) + Type = BW_SINGLE; + else if (params[1].equals_ci("START")) + Type = BW_START; + else if (params[1].equals_ci("END")) + Type = BW_END; + else + Type = BW_ANY; + ci->AddBadWord(params[2], Type); + } + } + } + catch (const ConvertException &ex) + { + throw DatabaseException(ex.GetReason()); + } + return EVENT_CONTINUE; +} + /* Character for newlines, in my research I have concluded it is significantly faster * to use \n instead of std::endl because std::endl also flushes the buffer, which * is not necessary here @@ -39,7 +340,7 @@ static const char endl = '\n'; */ static void ReadDatabase(Module *m = NULL) { - EventReturn MOD_RESULT; + //EventReturn MOD_RESULT; MDType Type = MD_NONE; std::fstream db; @@ -81,12 +382,13 @@ static void ReadDatabase(Module *m = NULL) params.push_back(buf); } - if (m) + /*if (m) MOD_RESULT = m->OnDatabaseRead(params); else FOREACH_RESULT(I_OnDatabaseRead, OnDatabaseRead(params)); if (MOD_RESULT == EVENT_STOP) - continue; + continue;*/ + OnDatabaseRead(params); if (!params.empty()) { @@ -120,10 +422,7 @@ static void ReadDatabase(Module *m = NULL) { try { - if (m) - m->OnDatabaseReadMetadata(nc, key, params); - else - FOREACH_RESULT(I_OnDatabaseReadMetadata, OnDatabaseReadMetadata(nc, key, params)); + OnDatabaseReadMetadata(nc, key, params); } catch (const DatabaseException &ex) { @@ -134,10 +433,7 @@ static void ReadDatabase(Module *m = NULL) { try { - if (m) - m->OnDatabaseReadMetadata(na, key, params); - else - FOREACH_RESULT(I_OnDatabaseReadMetadata, OnDatabaseReadMetadata(na, key, params)); + OnDatabaseReadMetadata(na, key, params); } catch (const DatabaseException &ex) { @@ -148,10 +444,7 @@ static void ReadDatabase(Module *m = NULL) { try { - if (m) - m->OnDatabaseReadMetadata(bi, key, params); - else - FOREACH_RESULT(I_OnDatabaseReadMetadata, OnDatabaseReadMetadata(bi, key, params)); + OnDatabaseReadMetadata(bi, key, params); } catch (const DatabaseException &ex) { @@ -162,10 +455,7 @@ static void ReadDatabase(Module *m = NULL) { try { - if (m) - m->OnDatabaseReadMetadata(ci, key, params); - else - FOREACH_RESULT(I_OnDatabaseReadMetadata, OnDatabaseReadMetadata(ci, key, params)); + OnDatabaseReadMetadata(ci, key, params); } catch (const DatabaseException &ex) { @@ -179,19 +469,6 @@ static void ReadDatabase(Module *m = NULL) db.close(); } -static Anope::string ToString(const std::vector<Anope::string> &strings) -{ - Anope::string ret; - - for (unsigned i = 0; i < strings.size(); ++i) - ret += " " + strings[i]; - - if (!ret.empty()) - ret.erase(ret.begin()); - - return ret; -} - static void LoadNickCore(const std::vector<Anope::string> ¶ms) { NickCore *nc = new NickCore(params[0]); @@ -278,7 +555,7 @@ static void LoadOperInfo(const std::vector<Anope::string> ¶ms) } } } - else if (params[0].equals_ci("EXCEPTION") && SessionInterface) + else if (params[0].equals_ci("EXCEPTION") && session_service) { Exception *exception = new Exception(); exception->mask = params[1]; @@ -287,7 +564,7 @@ static void LoadOperInfo(const std::vector<Anope::string> ¶ms) exception->time = params[4].is_pos_number_only() ? convertTo<time_t>(params[4]) : 0; exception->expires = params[5].is_pos_number_only() ? convertTo<time_t>(params[5]) : 0; exception->reason = params[6]; - SessionInterface->AddException(exception); + session_service->AddException(exception); } } @@ -312,7 +589,7 @@ class DBPlain : public Module { this->SetAuthor("Anope"); - Implementation i[] = { I_OnReload, I_OnDatabaseRead, I_OnLoadDatabase, I_OnDatabaseReadMetadata, I_OnSaveDatabase, I_OnModuleLoad }; + Implementation i[] = { I_OnReload, I_OnLoadDatabase, I_OnSaveDatabase }; ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); OnReload(); @@ -370,308 +647,17 @@ class DBPlain : public Module DatabaseFile = config.ReadValue("db_plain", "database", "anope.db", 0); } - EventReturn OnDatabaseRead(const std::vector<Anope::string> ¶ms) - { - Anope::string key = params[0]; - std::vector<Anope::string> otherparams = params; - otherparams.erase(otherparams.begin()); - - if (key.equals_ci("NC")) - LoadNickCore(otherparams); - else if (key.equals_ci("NA")) - LoadNickAlias(otherparams); - else if (key.equals_ci("BI")) - LoadBotInfo(otherparams); - else if (key.equals_ci("CH")) - LoadChanInfo(otherparams); - else if (key.equals_ci("OS")) - LoadOperInfo(otherparams); - - return EVENT_CONTINUE; - } - EventReturn OnLoadDatabase() { ReadDatabase(); /* No need to ever reload this again, although this should never be trigged again */ ModuleManager::Detach(I_OnLoadDatabase, this); - ModuleManager::Detach(I_OnDatabaseReadMetadata, this); + //ModuleManager::Detach(I_OnDatabaseReadMetadata, this); return EVENT_STOP; } - EventReturn OnDatabaseReadMetadata(NickCore *nc, const Anope::string &key, const std::vector<Anope::string> ¶ms) - { - try - { - if (key.equals_ci("LANGUAGE")) - nc->language = params[0]; - else if (key.equals_ci("MEMOMAX")) - nc->memos.memomax = params[0].is_pos_number_only() ? convertTo<int16>(params[0]) : -1; - else if (key.equals_ci("EMAIL")) - nc->email = params[0]; - else if (key.equals_ci("GREET")) - nc->greet = params[0]; - else if (key.equals_ci("ACCESS")) - nc->AddAccess(params[0]); - else if (key.equals_ci("CERT")) - nc->AddCert(params[0]); - else if (key.equals_ci("FLAGS")) - nc->FromString(params); - else if (key.equals_ci("MI")) - { - Memo *m = new Memo; - m->time = params[0].is_pos_number_only() ? convertTo<time_t>(params[0]) : 0; - m->sender = params[1]; - for (unsigned j = 2; params[j].equals_ci("UNREAD") || params[j].equals_ci("RECEIPT"); ++j) - { - if (params[j].equals_ci("UNREAD")) - m->SetFlag(MF_UNREAD); - else if (params[j].equals_ci("RECEIPT")) - m->SetFlag(MF_RECEIPT); - } - m->text = params[params.size() - 1]; - nc->memos.memos.push_back(m); - } - else if (key.equals_ci("MIG")) - nc->memos.ignores.push_back(params[0].ci_str()); - } - catch (const ConvertException &ex) - { - throw DatabaseException(ex.GetReason()); - } - - return EVENT_CONTINUE; - } - - EventReturn OnDatabaseReadMetadata(NickAlias *na, const Anope::string &key, const std::vector<Anope::string> ¶ms) - { - if (key.equals_ci("LAST_USERMASK")) - na->last_usermask = params[0]; - else if (key.equals_ci("LAST_REALHOST")) - na->last_realhost = params[0]; - else if (key.equals_ci("LAST_REALNAME")) - na->last_realname = params[0]; - else if (key.equals_ci("LAST_QUIT")) - na->last_quit = params[0]; - else if (key.equals_ci("FLAGS")) - na->FromString(params); - else if (key.equals_ci("VHOST")) - na->hostinfo.SetVhost(params.size() > 3 ? params[3] : "", params[2], params[0], params[1].is_pos_number_only() ? convertTo<time_t>(params[1]) : 0); - - return EVENT_CONTINUE; - } - - EventReturn OnDatabaseReadMetadata(BotInfo *bi, const Anope::string &key, const std::vector<Anope::string> ¶ms) - { - if (key.equals_ci("FLAGS")) - bi->FromString(params); - - return EVENT_CONTINUE; - } - - EventReturn OnDatabaseReadMetadata(ChannelInfo *ci, const Anope::string &key, const std::vector<Anope::string> ¶ms) - { - try - { - if (key.equals_ci("BANTYPE")) - ci->bantype = params[0].is_pos_number_only() ? convertTo<int16>(params[0]) : Config->CSDefBantype; - else if (key.equals_ci("MEMOMAX")) - ci->memos.memomax = params[0].is_pos_number_only() ? convertTo<int16>(params[0]) : -1; - else if (key.equals_ci("FOUNDER")) - ci->SetFounder(findcore(params[0])); - else if (key.equals_ci("SUCCESSOR")) - ci->successor = findcore(params[0]); - else if (key.equals_ci("LEVELS")) - { - for (unsigned j = 0, end = params.size(); j < end; j += 2) - { - Privilege *p = PrivilegeManager::FindPrivilege(params[j]); - if (p == NULL) - continue; - ci->SetLevel(p->name, params[j + 1].is_number_only() ? convertTo<int16>(params[j + 1]) : 0); - } - } - else if (key.equals_ci("FLAGS")) - ci->FromString(params); - else if (key.equals_ci("DESC")) - ci->desc = params[0]; - else if (key.equals_ci("TOPIC")) - { - ci->last_topic_setter = params[0]; - ci->last_topic_time = params[1].is_pos_number_only() ? convertTo<time_t>(params[1]) : 0; - ci->last_topic = params[2]; - } - else if (key.equals_ci("SUSPEND")) - { - ci->Extend("suspend_by", new ExtensibleItemRegular<Anope::string>(params[0])); - ci->Extend("suspend_reason", new ExtensibleItemRegular<Anope::string>(params[1])); - } - else if (key.equals_ci("ACCESS")) // Older access system, from Anope 1.9.4. - { - service_reference<AccessProvider> provider("access/access"); - if (!provider) - throw DatabaseException("Old access entry for nonexistant provider"); - - ChanAccess *access = provider->Create(); - access->ci = ci; - access->mask = params[0]; - access->Unserialize(params[1]); - access->last_seen = params[2].is_pos_number_only() ? convertTo<time_t>(params[2]) : 0; - access->creator = params[3]; - access->created = Anope::CurTime; - - ci->AddAccess(access); - } - else if (key.equals_ci("ACCESS2")) - { - service_reference<AccessProvider> provider(params[0]); - if (!provider) - throw DatabaseException("Access entry for nonexistant provider " + params[0]); - - ChanAccess *access = provider->Create(); - access->ci = ci; - access->mask = params[1]; - access->Unserialize(params[2]); - access->last_seen = params[3].is_pos_number_only() ? convertTo<time_t>(params[3]) : 0; - access->creator = params[4]; - access->created = params.size() > 5 && params[5].is_pos_number_only() ? convertTo<time_t>(params[5]) : Anope::CurTime; - - ci->AddAccess(access); - } - else if (key.equals_ci("AKICK")) - { - // 0 is the old stuck - bool Nick = params[1].equals_ci("NICK"); - NickCore *nc = NULL; - if (Nick) - { - nc = findcore(params[2]); - if (!nc) - throw DatabaseException("Akick for nonexistant core " + params[2] + " on " + ci->name); - } - - AutoKick *ak; - if (Nick) - ak = ci->AddAkick(params[3], nc, params.size() > 6 ? params[6] : "", params[4].is_pos_number_only() ? convertTo<time_t>(params[4]) : 0, params[5].is_pos_number_only() ? convertTo<time_t>(params[5]) : 0); - else - ak = ci->AddAkick(params[3], params[2], params.size() > 6 ? params[6] : "", params[4].is_pos_number_only() ? convertTo<time_t>(params[4]) : 0, params[5].is_pos_number_only() ? convertTo<time_t>(params[5]) : 0); - if (Nick) - ak->SetFlag(AK_ISNICK); - - } - else if (key.equals_ci("LOG")) - { - LogSetting l; - - l.service_name = params[0]; - l.command_service = params[1]; - l.command_name = params[2]; - l.method = params[3]; - l.creator = params[4]; - l.created = params[5].is_pos_number_only() ? convertTo<time_t>(params[5]) : Anope::CurTime; - l.extra = params.size() > 6 ? params[6] : ""; - - ci->log_settings.push_back(l); - } - else if (key.equals_ci("MLOCK")) - { - bool set = params[0] == "1" ? true : false; - Anope::string mode_name = params[1]; - Anope::string setter = params[2]; - time_t mcreated = params[3].is_pos_number_only() ? convertTo<time_t>(params[3]) : Anope::CurTime; - Anope::string param = params.size() > 4 ? params[4] : ""; - - for (size_t i = CMODE_BEGIN + 1; i < CMODE_END; ++i) - if (ChannelModeNameStrings[i] == mode_name) - { - ChannelModeName n = static_cast<ChannelModeName>(i); - ci->mode_locks.insert(std::make_pair(n, ModeLock(set, n, param, setter, mcreated))); - break; - } - } - else if (key.equals_ci("MI")) - { - Memo *m = new Memo; - m->time = params[0].is_pos_number_only() ? convertTo<time_t>(params[0]) : 0; - m->sender = params[1]; - for (unsigned j = 2; params[j].equals_ci("UNREAD") || params[j].equals_ci("RECEIPT"); ++j) - { - if (params[j].equals_ci("UNREAD")) - m->SetFlag(MF_UNREAD); - else if (params[j].equals_ci("RECEIPT")) - m->SetFlag(MF_RECEIPT); - } - m->text = params[params.size() - 1]; - ci->memos.memos.push_back(m); - } - else if (key.equals_ci("MIG")) - ci->memos.ignores.push_back(params[0].ci_str()); - else if (key.equals_ci("BI")) - { - if (params[0].equals_ci("NAME")) - ci->bi = findbot(params[1]); - else if (params[0].equals_ci("FLAGS")) - ci->botflags.FromString(params); - else if (params[0].equals_ci("TTB")) - { - for (unsigned j = 1, end = params.size(); j < end; j += 2) - { - if (params[j].equals_ci("BOLDS")) - ci->ttb[0] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0; - else if (params[j].equals_ci("COLORS")) - ci->ttb[1] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0; - else if (params[j].equals_ci("REVERSES")) - ci->ttb[2] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0; - else if (params[j].equals_ci("UNDERLINES")) - ci->ttb[3] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0; - else if (params[j].equals_ci("BADWORDS")) - ci->ttb[4] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0; - else if (params[j].equals_ci("CAPS")) - ci->ttb[5] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0; - else if (params[j].equals_ci("FLOOD")) - ci->ttb[6] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0; - else if (params[j].equals_ci("REPEAT")) - ci->ttb[7] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0; - else if (params[j].equals_ci("ITALICS")) - ci->ttb[8] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0; - else if (params[j].equals_ci("AMSGS")) - ci->ttb[9] = params[j + 1].is_pos_number_only() ? convertTo<int16>(params[j + 1]) : 0; - } - } - else if (params[0].equals_ci("CAPSMIN")) - ci->capsmin = params[1].is_pos_number_only() ? convertTo<int16>(params[1]) : 0; - else if (params[0].equals_ci("CAPSPERCENT")) - ci->capspercent = params[1].is_pos_number_only() ? convertTo<int16>(params[1]) : 0; - else if (params[0].equals_ci("FLOODLINES")) - ci->floodlines = params[1].is_pos_number_only() ? convertTo<int16>(params[1]) : 0; - else if (params[0].equals_ci("FLOODSECS")) - ci->floodsecs = params[1].is_pos_number_only() ? convertTo<int16>(params[1]) : 0; - else if (params[0].equals_ci("REPEATTIMES")) - ci->repeattimes = params[1].is_pos_number_only() ? convertTo<int16>(params[1]) : 0; - else if (params[0].equals_ci("BADWORD")) - { - BadWordType Type; - if (params[1].equals_ci("SINGLE")) - Type = BW_SINGLE; - else if (params[1].equals_ci("START")) - Type = BW_START; - else if (params[1].equals_ci("END")) - Type = BW_END; - else - Type = BW_ANY; - ci->AddBadWord(params[2], Type); - } - } - } - catch (const ConvertException &ex) - { - throw DatabaseException(ex.GetReason()); - } - - return EVENT_CONTINUE; - } EventReturn OnSaveDatabase() { @@ -705,7 +691,7 @@ class DBPlain : public Module db_buffer << "MD CERT " << *it << endl; } if (nc->FlagCount()) - db_buffer << "MD FLAGS " << ToString(nc->ToString()) << endl; + db_buffer << "MD FLAGS " << nc->ToString() << endl; MemoInfo *mi = &nc->memos; for (unsigned k = 0, end = mi->memos.size(); k < end; ++k) { @@ -718,7 +704,7 @@ class DBPlain : public Module } for (unsigned k = 0, end = mi->ignores.size(); k < end; ++k) db_buffer << "MD MIG " << Anope::string(mi->ignores[k]) << endl; - FOREACH_MOD(I_OnDatabaseWriteMetadata, OnDatabaseWriteMetadata(WriteMetadata, nc)); + //FOREACH_MOD(I_OnDatabaseWriteMetadata, OnDatabaseWriteMetadata(WriteMetadata, nc)); } for (nickalias_map::const_iterator it = NickAliasList.begin(), it_end = NickAliasList.end(); it != it_end; ++it) @@ -735,11 +721,11 @@ class DBPlain : public Module if (!na->last_quit.empty()) db_buffer << "MD LAST_QUIT :" << na->last_quit << endl; if (na->FlagCount()) - db_buffer << "MD FLAGS " << ToString(na->ToString()) << endl; + db_buffer << "MD FLAGS " << na->ToString() << endl; if (na->hostinfo.HasVhost()) db_buffer << "MD VHOST " << na->hostinfo.GetCreator() << " " << na->hostinfo.GetTime() << " " << na->hostinfo.GetHost() << " :" << na->hostinfo.GetIdent() << endl; - FOREACH_MOD(I_OnDatabaseWriteMetadata, OnDatabaseWriteMetadata(WriteMetadata, na)); + //FOREACH_MOD(I_OnDatabaseWriteMetadata, OnDatabaseWriteMetadata(WriteMetadata, na)); } for (Anope::insensitive_map<BotInfo *>::const_iterator it = BotListByNick.begin(), it_end = BotListByNick.end(); it != it_end; ++it) @@ -751,7 +737,7 @@ class DBPlain : public Module db_buffer << "BI " << bi->nick << " " << bi->GetIdent() << " " << bi->host << " " << bi->created << " " << bi->chancount << " :" << bi->realname << endl; if (bi->FlagCount()) - db_buffer << "MD FLAGS " << ToString(bi->ToString()) << endl; + db_buffer << "MD FLAGS " << bi->ToString() << endl; } for (registered_channel_map::const_iterator cit = RegisteredChannelList.begin(), cit_end = RegisteredChannelList.end(); cit != cit_end; ++cit) @@ -778,13 +764,12 @@ class DBPlain : public Module } db_buffer << endl; if (ci->FlagCount()) - db_buffer << "MD FLAGS " << ToString(ci->ToString()) << endl; + db_buffer << "MD FLAGS " << ci->ToString() << endl; if (ci->HasFlag(CI_SUSPENDED)) { - Anope::string by, reason; - ci->GetExtRegular("suspend_by", by); - ci->GetExtRegular("suspend_reason", reason); - db_buffer << "MD SUSPEND " << by << " :" << reason << endl; + Anope::string *by = ci->GetExt<Anope::string *>("suspend_by"), *reason = ci->GetExt<Anope::string *>("suspend_reason"); + if (by && reason) + db_buffer << "MD SUSPEND " << *by << " :" << *reason << endl; } for (unsigned k = 0, end = ci->GetAccessCount(); k < end; ++k) { @@ -805,21 +790,12 @@ class DBPlain : public Module db_buffer << "MD LOG " << l.service_name << " " << l.command_service << " " << l.command_name << " " << l.method << " " << l.creator << " " << l.created << " " << l.extra << endl; } + for (std::multimap<ChannelModeName, ModeLock>::const_iterator it = ci->GetMLock().begin(), it_end = ci->GetMLock().end(); it != it_end; ++it) { - std::vector<Anope::string> mlocks; - if (ci->GetExtRegular("db_mlock", mlocks)) - for (unsigned i = 0; i < mlocks.size(); ++i) - db_buffer << mlocks[i] << endl; - else - { - for (std::multimap<ChannelModeName, ModeLock>::const_iterator it = ci->GetMLock().begin(), it_end = ci->GetMLock().end(); it != it_end; ++it) - { - const ModeLock &ml = it->second; - ChannelMode *cm = ModeManager::FindChannelModeByName(ml.name); - if (cm != NULL) - db_buffer << "MD MLOCK " << (ml.set ? 1 : 0) << " " << cm->NameAsString() << " " << ml.setter << " " << ml.created << " " << ml.param << endl; - } - } + const ModeLock &ml = it->second; + ChannelMode *cm = ModeManager::FindChannelModeByName(ml.name); + if (cm != NULL) + db_buffer << "MD MLOCK " << (ml.set ? 1 : 0) << " " << cm->NameAsString() << " " << ml.setter << " " << ml.created << " " << ml.param << endl; } MemoInfo *memos = &ci->memos; for (unsigned k = 0, end = memos->memos.size(); k < end; ++k) @@ -836,7 +812,7 @@ class DBPlain : public Module if (ci->bi) db_buffer << "MD BI NAME " << ci->bi->nick << endl; if (ci->botflags.FlagCount()) - db_buffer << "MD BI FLAGS " << ToString(ci->botflags.ToString()) << endl; + db_buffer << "MD BI FLAGS " << ci->botflags.ToString() << endl; db_buffer << "MD BI TTB BOLDS " << ci->ttb[0] << " COLORS " << ci->ttb[1] << " REVERSES " << ci->ttb[2] << " UNDERLINES " << ci->ttb[3] << " BADWORDS " << ci->ttb[4] << " CAPS " << ci->ttb[5] << " FLOOD " << ci->ttb[6] << " REPEAT " << ci->ttb[7] << " ITALICS " << ci->ttb[8] << " AMSGS " << ci->ttb[9] << endl; if (ci->capsmin) db_buffer << "MD BI CAPSMIN " << ci->capsmin << endl; @@ -852,7 +828,7 @@ class DBPlain : public Module db_buffer << "MD BI BADWORD " << (ci->GetBadWord(k)->type == BW_ANY ? "ANY " : "") << (ci->GetBadWord(k)->type == BW_SINGLE ? "SINGLE " : "") << (ci->GetBadWord(k)->type == BW_START ? "START " : "") << (ci->GetBadWord(k)->type == BW_END ? "END " : "") << ":" << ci->GetBadWord(k)->word << endl; - FOREACH_MOD(I_OnDatabaseWriteMetadata, OnDatabaseWriteMetadata(WriteMetadata, ci)); + //FOREACH_MOD(I_OnDatabaseWriteMetadata, OnDatabaseWriteMetadata(WriteMetadata, ci)); } db_buffer << "OS STATS " << maxusercnt << " " << maxusertime << endl; @@ -867,14 +843,14 @@ class DBPlain : public Module } } - if (SessionInterface) - for (SessionService::ExceptionVector::iterator it = SessionInterface->GetExceptions().begin(); it != SessionInterface->GetExceptions().end(); ++it) + if (session_service) + for (SessionService::ExceptionVector::iterator it = session_service->GetExceptions().begin(); it != session_service->GetExceptions().end(); ++it) { Exception *e = *it; db_buffer << "OS EXCEPTION " << e->mask << " " << e->limit << " " << e->who << " " << e->time << " " << e->expires << " " << e->reason << endl; } - FOREACH_MOD(I_OnDatabaseWrite, OnDatabaseWrite(Write)); + //FOREACH_MOD(I_OnDatabaseWrite, OnDatabaseWrite(Write)); std::fstream db; db.open(DatabaseFile.c_str(), std::ios_base::out | std::ios_base::trunc); @@ -892,22 +868,6 @@ class DBPlain : public Module return EVENT_CONTINUE; } - - void OnModuleLoad(User *u, Module *m) - { - if (!u) - return; - - Implementation events[] = {I_OnDatabaseRead, I_OnDatabaseReadMetadata}; - for (int i = 0; i < 2; ++i) - { - std::vector<Module *>::iterator it = std::find(ModuleManager::EventHandlers[events[i]].begin(), ModuleManager::EventHandlers[events[i]].end(), m); - /* This module wants to read from the database */ - if (it != ModuleManager::EventHandlers[events[i]].end()) - /* Loop over the database and call the events it would on a normal startup */ - ReadDatabase(m); - } - } }; MODULE_INIT(DBPlain) diff --git a/modules/database/db_sql.cpp b/modules/database/db_sql.cpp new file mode 100644 index 000000000..43e7cfe6d --- /dev/null +++ b/modules/database/db_sql.cpp @@ -0,0 +1,169 @@ +/* + * (C) 2003-2011 Anope Team + * Contact us at team@anope.org + * + * Please read COPYING and README for further details. + * + * Based on the original code of Epona by Lara. + * Based on the original code of Services by Andy Church. + */ + +#include "module.h" +#include "../extra/sql.h" + +class SQLSQLInterface : public SQLInterface +{ + public: + SQLSQLInterface(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 DBSQL : public Module +{ + service_reference<SQLProvider, Base> sql; + SQLSQLInterface sqlinterface; + + void RunBackground(const SQLQuery &q) + { + if (!quitting) + this->sql->Run(&sqlinterface, q); + else + this->sql->RunQuery(q); + } + + void DropTable(const Anope::string &table) + { + SQLQuery query("DROP TABLE `" + table + "`"); + this->RunBackground(query); + } + + void AlterTable(const Anope::string &table, const SerializableBase::serialized_data &oldd, const SerializableBase::serialized_data &newd) + { + for (SerializableBase::serialized_data::const_iterator it = newd.begin(), it_end = newd.end(); it != it_end; ++it) + { + if (oldd.count(it->first) > 0) + continue; + + Anope::string query_text = "ALTER TABLE `" + table + "` ADD `" + it->first + "` "; + if (it->second.getType() == Serialize::DT_INT) + query_text += "int(11)"; + else if (it->second.getMax() > 0) + query_text += "varchar(" + stringify(it->second.getMax()) + ")"; + else + query_text += "text"; + + this->RunBackground(SQLQuery(query_text)); + } + } + + void Insert(const Anope::string &table, const SerializableBase::serialized_data &data) + { + 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 += ")"; + + 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->RunBackground(query); + } + + public: + DBSQL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE), sql(""), sqlinterface(this) + { + this->SetAuthor("Anope"); + + Implementation i[] = { I_OnReload, I_OnSaveDatabase, I_OnLoadDatabase }; + ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); + + this->OnReload(); + } + + void OnReload() + { + ConfigReader config; + Anope::string engine = config.ReadValue("db_sql", "engine", "", 0); + this->sql = engine; + } + + EventReturn OnSaveDatabase() + { + if (!this->sql) + { + Log() << "db_sql: Unable to save databases, is SQL configured correctly?"; + return EVENT_CONTINUE; + } + + std::map<Anope::string, SerializableBase::serialized_data> table_layout; + for (std::list<SerializableBase *>::iterator it = serialized_items.begin(), it_end = serialized_items.end(); it != it_end; ++it) + { + SerializableBase *base = *it; + SerializableBase::serialized_data data = base->serialize(); + + if (data.empty()) + continue; + + if (table_layout.count(base->serialize_name()) == 0) + { + this->DropTable(base->serialize_name()); + this->RunBackground(this->sql->CreateTable(base->serialize_name(), data)); + } + else + this->AlterTable(base->serialize_name(), table_layout[base->serialize_name()], data); + table_layout[base->serialize_name()] = data; + + this->Insert(base->serialize_name(), data); + } + return EVENT_CONTINUE; + } + + EventReturn OnLoadDatabase() + { + if (!this->sql) + { + Log() << "db_sql: Unable to load databases, is SQL configured correctly?"; + return EVENT_CONTINUE; + } + + for (std::vector<SerializableBase *>::iterator it = serialized_types.begin(), it_end = serialized_types.end(); it != it_end; ++it) + { + SerializableBase *sb = *it; + + SQLQuery query("SELECT * FROM `" + sb->serialize_name() + "`"); + SQLResult res = this->sql->RunQuery(query); + for (int i = 0; i < res.Rows(); ++i) + { + SerializableBase::serialized_data data; + const std::map<Anope::string, Anope::string> &row = res.Row(i); + for (std::map<Anope::string, Anope::string>::const_iterator rit = row.begin(), rit_end = row.end(); rit != rit_end; ++rit) + data[rit->first] << rit->second; + + sb->alloc(data); + } + } + + return EVENT_CONTINUE; + } +}; + +MODULE_INIT(DBSQL) + 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) + diff --git a/modules/database/db_mysql_live.cpp b/modules/database/db_sql_live_write.cpp index d583c394c..769c53b66 100644 --- a/modules/database/db_mysql_live.cpp +++ b/modules/database/db_sql_live_write.cpp @@ -32,19 +32,25 @@ class SQLCache : public Timer } }; -static void ChanInfoUpdate(const SQLResult &res) +static void ChanInfoUpdate(const Anope::string &name, const SQLResult &res) { + ChannelInfo *ci = cs_findchan(name); + if (res.Rows() == 0) + { + delete ci; + return; + } + try { - ChannelInfo *ci = cs_findchan(res.Get(0, "name")); if (!ci) - ci = new ChannelInfo(res.Get(0, "name")); + ci = new ChannelInfo(name); ci->SetFounder(findcore(res.Get(0, "founder"))); ci->successor = findcore(res.Get(0, "successor")); ci->desc = res.Get(0, "descr"); ci->time_registered = convertTo<time_t>(res.Get(0, "time_registered")); ci->ClearFlags(); - ci->FromString(BuildStringVector(res.Get(0, "flags"))); + ci->FromString(res.Get(0, "flags")); ci->bantype = convertTo<int>(res.Get(0, "bantype")); ci->memos.memomax = convertTo<unsigned>(res.Get(0, "memomax")); @@ -68,21 +74,27 @@ static void ChanInfoUpdate(const SQLResult &res) } catch (const SQLException &ex) { - Log(LOG_DEBUG) << ex.GetReason(); + Log() << ex.GetReason(); } catch (const ConvertException &) { } } -static void NickInfoUpdate(const SQLResult &res) +static void NickInfoUpdate(const Anope::string &name, const SQLResult &res) { + NickAlias *na = findnick(name); + if (res.Rows() == 0) + { + delete na; + return; + } + try { NickCore *nc = findcore(res.Get(0, "display")); if (!nc) return; - NickAlias *na = findnick(res.Get(0, "nick")); if (!na) - na = new NickAlias(res.Get(0, "nick"), nc); + na = new NickAlias(name, nc); na->last_quit = res.Get(0, "last_quit"); na->last_realname = res.Get(0, "last_realname"); @@ -91,7 +103,7 @@ static void NickInfoUpdate(const SQLResult &res) na->time_registered = convertTo<time_t>(res.Get(0, "time_registered")); na->last_seen = convertTo<time_t>(res.Get(0, "last_seen")); na->ClearFlags(); - na->FromString(BuildStringVector(res.Get(0, "flags"))); + na->FromString(res.Get(0, "flags")); if (na->nc != nc) { @@ -105,29 +117,35 @@ static void NickInfoUpdate(const SQLResult &res) } catch (const SQLException &ex) { - Log(LOG_DEBUG) << ex.GetReason(); + Log() << ex.GetReason(); } catch (const ConvertException &) { } } -static void NickCoreUpdate(const SQLResult &res) +static void NickCoreUpdate(const Anope::string &name, const SQLResult &res) { + NickCore *nc = findcore(name); + if (res.Rows() == 0) + { + delete nc; + return; + } + try { - NickCore *nc = findcore(res.Get(0, "display")); if (!nc) - nc = new NickCore(res.Get(0, "display")); + nc = new NickCore(name); nc->pass = res.Get(0, "pass"); nc->email = res.Get(0, "email"); nc->greet = res.Get(0, "greet"); nc->ClearFlags(); - nc->FromString(BuildStringVector(res.Get(0, "flags"))); + nc->FromString(res.Get(0, "flags")); nc->language = res.Get(0, "language"); } catch (const SQLException &ex) { - Log(LOG_DEBUG) << ex.GetReason(); + Log() << ex.GetReason(); } catch (const ConvertException &) { } } @@ -141,7 +159,7 @@ class MySQLLiveModule : public Module SQLResult RunQuery(const SQLQuery &query) { if (!this->SQL) - throw SQLException("Unable to locate SQL reference, is m_mysql loaded and configured correctly?"); + throw SQLException("Unable to locate SQL reference, is db_sql loaded and configured correctly?"); SQLResult res = SQL->RunQuery(query); if (!res.GetError().empty()) @@ -151,12 +169,19 @@ class MySQLLiveModule : public Module public: MySQLLiveModule(const Anope::string &modname, const Anope::string &creator) : - Module(modname, creator, DATABASE), SQL("mysql/main") + Module(modname, creator, DATABASE), SQL("") { - Implementation i[] = { I_OnFindChan, I_OnFindNick, I_OnFindCore, I_OnShutdown }; + Implementation i[] = { I_OnReload, I_OnFindChan, I_OnFindNick, I_OnFindCore, I_OnShutdown }; ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); } + void OnReload() + { + ConfigReader config; + Anope::string engine = config.ReadValue("db_sql", "engine", "", 0); + this->SQL = engine; + } + void OnShutdown() { Implementation i[] = { I_OnFindChan, I_OnFindNick, I_OnFindCore }; @@ -171,10 +196,10 @@ class MySQLLiveModule : public Module try { - SQLQuery query("SELECT * FROM `anope_cs_info` WHERE `name` = @name"); + SQLQuery query("SELECT * FROM `ChannelInfo` WHERE `name` = @name@"); query.setValue("name", chname); SQLResult res = this->RunQuery(query); - ChanInfoUpdate(res); + ChanInfoUpdate(chname, res); } catch (const SQLException &ex) { @@ -189,10 +214,10 @@ class MySQLLiveModule : public Module try { - SQLQuery query("SELECT * FROM `anope_ns_alias` WHERE `nick` = @nick"); + SQLQuery query("SELECT * FROM `NickAlias` WHERE `nick` = @nick@"); query.setValue("nick", nick); SQLResult res = this->RunQuery(query); - NickInfoUpdate(res); + NickInfoUpdate(nick, res); } catch (const SQLException &ex) { @@ -207,10 +232,10 @@ class MySQLLiveModule : public Module try { - SQLQuery query("SELECT * FROM `anope_ns_core` WHERE `display` = @display"); + SQLQuery query("SELECT * FROM `NickCore` WHERE `display` = @display@"); query.setValue("display", nick); SQLResult res = this->RunQuery(query); - NickCoreUpdate(res); + NickCoreUpdate(nick, res); } catch (const SQLException &ex) { diff --git a/modules/extra/m_dnsbl.cpp b/modules/extra/m_dnsbl.cpp index c8f18a34c..894eebb8a 100644 --- a/modules/extra/m_dnsbl.cpp +++ b/modules/extra/m_dnsbl.cpp @@ -30,7 +30,7 @@ class DNSBLResolver : public DNSRequest void OnLookupComplete(const DNSQuery *record) { - if (!user || user->GetExt("m_dnsbl_akilled")) + if (!user || user->HasExt("m_dnsbl_akilled")) return; const ResourceRecord &ans_record = record->answers[0]; @@ -50,7 +50,7 @@ class DNSBLResolver : public DNSRequest record_reason = this->blacklist.replies[result]; } - user->Extend("m_dnsbl_akilled"); + user->Extend("m_dnsbl_akilled", NULL); Anope::string reason = this->blacklist.reason; reason = reason.replace_all_cs("%n", user->nick); diff --git a/modules/extra/m_ldap_authentication.cpp b/modules/extra/m_ldap_authentication.cpp index 8a4ef2702..148ee8250 100644 --- a/modules/extra/m_ldap_authentication.cpp +++ b/modules/extra/m_ldap_authentication.cpp @@ -49,7 +49,7 @@ class IdentifyInterface : public LDAPInterface User *u = ii->user; Command *c = ii->command; - u->Extend("m_ldap_authentication_authenticated"); + u->Extend("m_ldap_authentication_authenticated", NULL); NickAlias *na = findnick(ii->account); if (na == NULL) @@ -87,7 +87,7 @@ class IdentifyInterface : public LDAPInterface User *u = ii->user; Command *c = ii->command; - u->Extend("m_ldap_authentication_error"); + u->Extend("m_ldap_authentication_error", NULL); c->Execute(ii->source, ii->params); @@ -218,12 +218,12 @@ class NSIdentifyLDAP : public Module return EVENT_CONTINUE; User *u = source->u; - if (u->GetExt("m_ldap_authentication_authenticated")) + if (u->HasExt("m_ldap_authentication_authenticated")) { u->Shrink("m_ldap_authentication_authenticated"); return EVENT_ALLOW; } - else if (u->GetExt("m_ldap_authentication_error")) + else if (u->HasExt("m_ldap_authentication_error")) { u->Shrink("m_ldap_authentication_error"); return EVENT_CONTINUE; diff --git a/modules/extra/m_mysql.cpp b/modules/extra/m_mysql.cpp index 05a85b93c..876d2ae4e 100644 --- a/modules/extra/m_mysql.cpp +++ b/modules/extra/m_mysql.cpp @@ -82,8 +82,6 @@ class MySQLResult : public SQLResult MySQLResult(const SQLQuery &q, const Anope::string &fq, const Anope::string &err) : SQLResult(q, fq, err), res(NULL) { - if (this->finished_query.empty()) - this->finished_query = q.query; } ~MySQLResult() @@ -125,6 +123,8 @@ class MySQLService : public SQLProvider SQLResult RunQuery(const SQLQuery &query); + SQLQuery CreateTable(const Anope::string &table, const SerializableBase::serialized_data &data); + void Connect(); bool CheckConnection(); @@ -211,7 +211,7 @@ class ModuleSQL : public Module, public Pipe for (i = 0, num = config.Enumerate("mysql"); i < num; ++i) { - Anope::string connname = config.ReadValue("mysql", "name", "main", i); + Anope::string connname = config.ReadValue("mysql", "name", "mysql/main", i); if (this->MySQLServices.find(connname) == this->MySQLServices.end()) { @@ -284,7 +284,7 @@ class ModuleSQL : public Module, public Pipe }; MySQLService::MySQLService(Module *o, const Anope::string &n, const Anope::string &d, const Anope::string &s, const Anope::string &u, const Anope::string &p, int po) -: SQLProvider(o, "mysql/" + n), database(d), server(s), user(u), password(p), port(po), sql(NULL) +: SQLProvider(o, n), database(d), server(s), user(u), password(p), port(po), sql(NULL) { Connect(); } @@ -323,16 +323,7 @@ SQLResult MySQLService::RunQuery(const SQLQuery &query) { this->Lock.Lock(); - Anope::string real_query; - try - { - real_query = this->BuildQuery(query); - } - catch (const SQLException &ex) - { - this->Lock.Unlock(); - return MySQLResult(query, real_query, ex.GetReason()); - } + Anope::string real_query = this->BuildQuery(query); if (this->CheckConnection() && !mysql_real_query(this->sql, real_query.c_str(), real_query.length())) { @@ -349,6 +340,40 @@ SQLResult MySQLService::RunQuery(const SQLQuery &query) } } +SQLQuery MySQLService::CreateTable(const Anope::string &table, const SerializableBase::serialized_data &data) +{ + Anope::string query_text = "CREATE TABLE `" + table + "` (", key_buf; + for (SerializableBase::serialized_data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it) + { + query_text += "`" + it->first + "` "; + if (it->second.getType() == Serialize::DT_INT) + query_text += "int(11)"; + else if (it->second.getMax() > 0) + query_text += "varchar(" + stringify(it->second.getMax()) + ")"; + else + query_text += "text"; + query_text += ","; + + if (it->second.getKey()) + { + if (key_buf.empty()) + key_buf = "UNIQUE KEY `ukey` ("; + key_buf += "`" + it->first + "`,"; + } + } + if (!key_buf.empty()) + { + key_buf.erase(key_buf.end() - 1); + key_buf += ")"; + query_text += " " + key_buf; + } + else + query_text.erase(query_text.end() - 1); + query_text += ")"; + + return SQLQuery(query_text); +} + void MySQLService::Connect() { this->sql = mysql_init(this->sql); @@ -392,7 +417,7 @@ Anope::string MySQLService::BuildQuery(const SQLQuery &q) Anope::string real_query = q.query; for (std::map<Anope::string, Anope::string>::const_iterator it = q.parameters.begin(), it_end = q.parameters.end(); it != it_end; ++it) - real_query = real_query.replace_all_cs("@" + it->first, "'" + this->Escape(it->second) + "'"); + real_query = real_query.replace_all_cs("@" + it->first + "@", "'" + this->Escape(it->second) + "'"); return real_query; } diff --git a/modules/extra/m_sqlite.cpp b/modules/extra/m_sqlite.cpp new file mode 100644 index 000000000..adf244bbd --- /dev/null +++ b/modules/extra/m_sqlite.cpp @@ -0,0 +1,235 @@ +/* RequiredLibraries: sqlite3 */ + +#include "module.h" +#include <sqlite3.h> +#include "sql.h" + +/* SQLite3 API, based from InspiRCd */ + +/** A SQLite result + */ +class SQLiteResult : public SQLResult +{ + public: + SQLiteResult(const SQLQuery &q, const Anope::string &fq) : SQLResult(q, fq) + { + } + + SQLiteResult(const SQLQuery &q, const Anope::string &fq, const Anope::string &err) : SQLResult(q, fq, err) + { + } + + void addRow(const std::map<Anope::string, Anope::string> &data) + { + this->entries.push_back(data); + } +}; + +/** A SQLite database, there can be multiple + */ +class SQLiteService : public SQLProvider +{ + Anope::string database; + + sqlite3 *sql; + + Anope::string Escape(const Anope::string &query); + + public: + SQLiteService(Module *o, const Anope::string &n, const Anope::string &d); + + ~SQLiteService(); + + void Run(SQLInterface *i, const SQLQuery &query); + + SQLResult RunQuery(const SQLQuery &query); + + SQLQuery CreateTable(const Anope::string &table, const SerializableBase::serialized_data &data); + + Anope::string BuildQuery(const SQLQuery &q); +}; + +class ModuleSQLite : public Module +{ + /* SQL connections */ + std::map<Anope::string, SQLiteService *> SQLiteServices; + public: + ModuleSQLite(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, SUPPORTED) + { + Implementation i[] = { I_OnReload }; + ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); + + OnReload(); + } + + ~ModuleSQLite() + { + for (std::map<Anope::string, SQLiteService *>::iterator it = this->SQLiteServices.begin(); it != this->SQLiteServices.end(); ++it) + delete it->second; + SQLiteServices.clear(); + } + + void OnReload() + { + ConfigReader config; + int i, num; + + for (std::map<Anope::string, SQLiteService *>::iterator it = this->SQLiteServices.begin(); it != this->SQLiteServices.end();) + { + const Anope::string &cname = it->first; + SQLiteService *s = it->second; + ++it; + + for (i = 0, num = config.Enumerate("sqlite"); i < num; ++i) + if (config.ReadValue("sqlite", "name", "sqlite/main", i) == cname) + break; + + if (i == num) + { + Log(LOG_NORMAL, "sqlite") << "SQLite: Removing server connection " << cname; + + delete s; + this->SQLiteServices.erase(cname); + } + } + + for (i = 0, num = config.Enumerate("sqlite"); i < num; ++i) + { + Anope::string connname = config.ReadValue("sqlite", "name", "sqlite/main", i); + + if (this->SQLiteServices.find(connname) == this->SQLiteServices.end()) + { + Anope::string database = config.ReadValue("sqlite", "database", "anope", i); + + try + { + SQLiteService *ss = new SQLiteService(this, connname, database); + this->SQLiteServices[connname] = ss; + + Log(LOG_NORMAL, "sqlite") << "SQLite: Successfully added database " << database; + } + catch (const SQLException &ex) + { + Log(LOG_NORMAL, "sqlite") << "SQLite: " << ex.GetReason(); + } + } + } + } +}; + +SQLiteService::SQLiteService(Module *o, const Anope::string &n, const Anope::string &d) +: SQLProvider(o, n), database(d), sql(NULL) +{ + int db = sqlite3_open_v2(database.c_str(), &this->sql, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0); + if (db != SQLITE_OK) + throw SQLException("Unable to open SQLite database " + database + ": " + sqlite3_errmsg(this->sql)); +} + +SQLiteService::~SQLiteService() +{ + sqlite3_interrupt(this->sql); + sqlite3_close(this->sql); +} + +void SQLiteService::Run(SQLInterface *i, const SQLQuery &query) +{ + SQLResult res = this->RunQuery(query); + if (!res.GetError().empty()) + i->OnError(res); + else + i->OnResult(res); +} + +SQLResult SQLiteService::RunQuery(const SQLQuery &query) +{ + Anope::string real_query = this->BuildQuery(query); + sqlite3_stmt *stmt; + int err = sqlite3_prepare_v2(this->sql, real_query.c_str(), real_query.length(), &stmt, NULL); + if (err != SQLITE_OK) + return SQLiteResult(query, real_query, sqlite3_errmsg(this->sql)); + + std::vector<Anope::string> columns; + int cols = sqlite3_column_count(stmt); + columns.resize(cols); + for (int i = 0; i < cols; ++i) + columns[i] = sqlite3_column_name(stmt, i); + + SQLiteResult result(query, real_query); + + do + { + err = sqlite3_step(stmt); + if (err == SQLITE_ROW) + { + std::map<Anope::string, Anope::string> items; + for (int i = 0; i < cols; ++i) + { + const char *data = reinterpret_cast<const char *>(sqlite3_column_text(stmt, i)); + if (data && *data) + items[columns[i]] = data; + } + result.addRow(items); + } + } + while (err == SQLITE_ROW); + + if (err != SQLITE_DONE) + return SQLiteResult(query, real_query, sqlite3_errmsg(this->sql)); + + return result; +} + +SQLQuery SQLiteService::CreateTable(const Anope::string &table, const SerializableBase::serialized_data &data) +{ + Anope::string query_text = "CREATE TABLE `" + table + "` (", key_buf; + for (SerializableBase::serialized_data::const_iterator it = data.begin(), it_end = data.end(); it != it_end; ++it) + { + query_text += "`" + it->first + "` "; + if (it->second.getType() == Serialize::DT_INT) + query_text += "int(11)"; + else if (it->second.getMax() > 0) + query_text += "varchar(" + stringify(it->second.getMax()) + ")"; + else + query_text += "text"; + query_text += ","; + + if (it->second.getKey()) + { + if (key_buf.empty()) + key_buf = "UNIQUE ("; + key_buf += "`" + it->first + "`,"; + } + } + if (!key_buf.empty()) + { + key_buf.erase(key_buf.end() - 1); + key_buf += ")"; + query_text += " " + key_buf; + } + else + query_text.erase(query_text.end() - 1); + query_text += ")"; + + return SQLQuery(query_text); +} + +Anope::string SQLiteService::Escape(const Anope::string &query) +{ + char *e = sqlite3_mprintf("%q", query.c_str()); + Anope::string buffer = e; + sqlite3_free(e); + return buffer; +} + +Anope::string SQLiteService::BuildQuery(const SQLQuery &q) +{ + Anope::string real_query = q.query; + + for (std::map<Anope::string, Anope::string>::const_iterator it = q.parameters.begin(), it_end = q.parameters.end(); it != it_end; ++it) + real_query = real_query.replace_all_cs("@" + it->first + "@", "'" + this->Escape(it->second) + "'"); + + return real_query; +} + +MODULE_INIT(ModuleSQLite) + diff --git a/modules/extra/sql.h b/modules/extra/sql.h index 2487b2305..85b3c291a 100644 --- a/modules/extra/sql.h +++ b/modules/extra/sql.h @@ -116,5 +116,7 @@ class SQLProvider : public Service<Base> virtual void Run(SQLInterface *i, const SQLQuery &query) = 0; virtual SQLResult RunQuery(const SQLQuery &query) = 0; + + virtual SQLQuery CreateTable(const Anope::string &table, const SerializableBase::serialized_data &data) = 0; }; diff --git a/modules/protocol/inspircd11.cpp b/modules/protocol/inspircd11.cpp index 6d72c5d61..062ad92f0 100644 --- a/modules/protocol/inspircd11.cpp +++ b/modules/protocol/inspircd11.cpp @@ -268,8 +268,7 @@ class InspIRCdProto : public IRCDProto Anope::string svidbuf = stringify(u->timestamp); - u->Account()->Shrink("authenticationtoken"); - u->Account()->Extend("authenticationtoken", new ExtensibleItemRegular<Anope::string>(svidbuf)); + u->Account()->Extend("authenticationtoken", new ExtensibleString(svidbuf)); } }; @@ -321,8 +320,8 @@ class InspircdIRCdMessage : public IRCdMessage user->SetCloakedHost(params[3]); NickAlias *na = findnick(user->nick); - Anope::string svidbuf; - if (na && na->nc->GetExtRegular("authenticationtoken", svidbuf) && svidbuf == params[0]) + Anope::string *svidbuf = na ? na->nc->GetExt<Anope::string *>("authenticationtoken") : NULL; + if (na && svidbuf && *svidbuf == params[0]) { user->Login(na->nc); if (na->nc->HasFlag(NI_UNCONFIRMED)) diff --git a/modules/pseudoclients/memoserv.cpp b/modules/pseudoclients/memoserv.cpp index c1f99bc41..a713b7409 100644 --- a/modules/pseudoclients/memoserv.cpp +++ b/modules/pseudoclients/memoserv.cpp @@ -85,6 +85,7 @@ class MyMemoServService : public MemoServService Memo *m = new Memo(); mi->memos.push_back(m); + m->owner = target; m->sender = source; m->time = Anope::CurTime; m->text = message; diff --git a/modules/pseudoclients/operserv.cpp b/modules/pseudoclients/operserv.cpp index c30809e49..6dfacd19f 100644 --- a/modules/pseudoclients/operserv.cpp +++ b/modules/pseudoclients/operserv.cpp @@ -273,6 +273,19 @@ class OperServCore : public Module XLineManager::RegisterXLineManager(&sglines); XLineManager::RegisterXLineManager(&sqlines); XLineManager::RegisterXLineManager(&snlines); + + Serializable<XLine>::Alloc.Register("XLine"); + } + + ~OperServCore() + { + this->sglines.Clear(); + this->sqlines.Clear(); + this->snlines.Clear(); + + XLineManager::UnregisterXLineManager(&sglines); + XLineManager::UnregisterXLineManager(&sqlines); + XLineManager::UnregisterXLineManager(&snlines); } EventReturn OnBotPrivmsg(User *u, BotInfo *bi, Anope::string &message) |