From 8a9a39c0655f2b967eeb4ab8d156ff4e4504ccf3 Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 16 Aug 2011 01:42:30 -0400 Subject: Renamed the core pseudoclient modules to match their names --- data/botserv.example.conf | 2 +- data/chanserv.example.conf | 2 +- data/global.example.conf | 2 +- data/hostserv.example.conf | 2 +- data/memoserv.example.conf | 2 +- data/nickserv.example.conf | 2 +- data/operserv.example.conf | 2 +- modules/pseudoclients/botserv.cpp | 212 +++++++++++++++++++++++ modules/pseudoclients/bs_main.cpp | 212 ----------------------- modules/pseudoclients/chanserv.cpp | 143 ++++++++++++++++ modules/pseudoclients/cs_main.cpp | 143 ---------------- modules/pseudoclients/gl_main.cpp | 93 ---------- modules/pseudoclients/global.cpp | 93 ++++++++++ modules/pseudoclients/hostserv.cpp | 85 +++++++++ modules/pseudoclients/hs_main.cpp | 85 --------- modules/pseudoclients/memoserv.cpp | 232 +++++++++++++++++++++++++ modules/pseudoclients/ms_main.cpp | 232 ------------------------- modules/pseudoclients/nickserv.cpp | 308 +++++++++++++++++++++++++++++++++ modules/pseudoclients/ns_main.cpp | 308 --------------------------------- modules/pseudoclients/operserv.cpp | 343 +++++++++++++++++++++++++++++++++++++ modules/pseudoclients/os_main.cpp | 343 ------------------------------------- 21 files changed, 1423 insertions(+), 1423 deletions(-) create mode 100644 modules/pseudoclients/botserv.cpp delete mode 100644 modules/pseudoclients/bs_main.cpp create mode 100644 modules/pseudoclients/chanserv.cpp delete mode 100644 modules/pseudoclients/cs_main.cpp delete mode 100644 modules/pseudoclients/gl_main.cpp create mode 100644 modules/pseudoclients/global.cpp create mode 100644 modules/pseudoclients/hostserv.cpp delete mode 100644 modules/pseudoclients/hs_main.cpp create mode 100644 modules/pseudoclients/memoserv.cpp delete mode 100644 modules/pseudoclients/ms_main.cpp create mode 100644 modules/pseudoclients/nickserv.cpp delete mode 100644 modules/pseudoclients/ns_main.cpp create mode 100644 modules/pseudoclients/operserv.cpp delete mode 100644 modules/pseudoclients/os_main.cpp diff --git a/data/botserv.example.conf b/data/botserv.example.conf index c896aff0b..076c2a22e 100644 --- a/data/botserv.example.conf +++ b/data/botserv.example.conf @@ -53,7 +53,7 @@ service * * Provides essential functionality for BotServ. */ -module { name = "bs_main" } +module { name = "botserv" } /* * Configuration for BotServ provided by bs_main. diff --git a/data/chanserv.example.conf b/data/chanserv.example.conf index 418f3ae86..391941522 100644 --- a/data/chanserv.example.conf +++ b/data/chanserv.example.conf @@ -53,7 +53,7 @@ service * * Provides essential functionality for ChanServ. */ -module { name = "cs_main" } +module { name = "chanserv" } /* * Configuration for ChanServ provided by cs_main. diff --git a/data/global.example.conf b/data/global.example.conf index fb10dd47c..b23365359 100644 --- a/data/global.example.conf +++ b/data/global.example.conf @@ -53,7 +53,7 @@ service * * Provides essential functionality for Global. */ -module { name = "gl_main" } +module { name = "global" } /* * Configuration for Global provided by gl_main. diff --git a/data/hostserv.example.conf b/data/hostserv.example.conf index 2edc68e1c..575c6a416 100644 --- a/data/hostserv.example.conf +++ b/data/hostserv.example.conf @@ -53,7 +53,7 @@ service * * Provides essential functionality for HostServ. */ -module { name = "hs_main" } +module { name = "hostserv" } /* * Configuration for HostServ provided by hs_main. diff --git a/data/memoserv.example.conf b/data/memoserv.example.conf index a0b16271a..da4156d31 100644 --- a/data/memoserv.example.conf +++ b/data/memoserv.example.conf @@ -53,7 +53,7 @@ service * * Provides essential functionality for MemoServ. */ -module { name = "ms_main" } +module { name = "memoserv" } /* * Configuration for MemoServ provided by ms_main. diff --git a/data/nickserv.example.conf b/data/nickserv.example.conf index dfa3bf542..5c60c60d8 100644 --- a/data/nickserv.example.conf +++ b/data/nickserv.example.conf @@ -53,7 +53,7 @@ service * * Provides essential functionality for NickServ. */ -module { name = "ns_main" } +module { name = "nickserv" } /* * Configuration for NickServ provided by ns_main. diff --git a/data/operserv.example.conf b/data/operserv.example.conf index ad239dd3e..69467516c 100644 --- a/data/operserv.example.conf +++ b/data/operserv.example.conf @@ -53,7 +53,7 @@ service * * Provides essential functionality for OperServ. */ -module { name = "os_main" } +module { name = "operserv" } /* * Configuration for OperServ provided by os_main. diff --git a/modules/pseudoclients/botserv.cpp b/modules/pseudoclients/botserv.cpp new file mode 100644 index 000000000..a286c54e7 --- /dev/null +++ b/modules/pseudoclients/botserv.cpp @@ -0,0 +1,212 @@ +/* BotServ core functions + * + * (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" + +class BotServCore : public Module +{ + Channel *fantasy_channel; + public: + BotServCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE), fantasy_channel(NULL) + { + this->SetAuthor("Anope"); + + BotInfo *BotServ = findbot(Config->BotServ); + if (BotServ == NULL) + throw ModuleException("No bot named " + Config->BotServ); + + Implementation i[] = { I_OnPrivmsg, I_OnPreCommand, I_OnJoinChannel, I_OnLeaveChannel, + I_OnPreHelp, I_OnPostHelp, I_OnChannelModeSet }; + ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); + + } + + void OnPrivmsg(User *u, Channel *c, Anope::string &msg) + { + if (!u || !c || !c->ci || !c->ci->bi || msg.empty()) + return; + + /* Answer to ping if needed */ + if (msg.substr(0, 6).equals_ci("\1PING ") && msg[msg.length() - 1] == '\1') + { + Anope::string ctcp = msg; + ctcp.erase(ctcp.begin()); + ctcp.erase(ctcp.length() - 1); + ircdproto->SendCTCP(c->ci->bi, u->nick, "%s", ctcp.c_str()); + } + + + Anope::string realbuf = msg; + + bool was_action = false; + if (realbuf.substr(0, 8).equals_ci("\1ACTION ") && realbuf[realbuf.length() - 1] == '\1') + { + realbuf.erase(0, 8); + realbuf.erase(realbuf.length() - 1); + was_action = true; + } + + if (realbuf.empty()) + return; + + /* Fantaisist commands */ + if (c->ci->botflags.HasFlag(BS_FANTASY) && realbuf[0] == Config->BSFantasyCharacter[0] && !was_action) + { + /* Strip off the fantasy character */ + realbuf.erase(realbuf.begin()); + + size_t space = realbuf.find(' '); + Anope::string command, rest; + if (space == Anope::string::npos) + command = realbuf; + else + { + command = realbuf.substr(0, space); + rest = realbuf.substr(space + 1); + } + + BotInfo *bi = findbot(Config->ChanServ); + if (bi == NULL) + bi = findbot(Config->BotServ); + if (bi == NULL || !bi->commands.count(command)) + return; + + if (c->ci->AccessFor(u).HasPriv(CA_FANTASIA)) + { + + this->fantasy_channel = c; + bi->OnMessage(u, realbuf); + this->fantasy_channel = NULL; + + FOREACH_MOD(I_OnBotFantasy, OnBotFantasy(command, u, c->ci, rest)); + } + else + { + FOREACH_MOD(I_OnBotNoFantasyAccess, OnBotNoFantasyAccess(command, u, c->ci, rest)); + } + } + } + + EventReturn OnPreCommand(CommandSource &source, Command *command, std::vector ¶ms) + { + if (this->fantasy_channel != NULL) + { + if (!command->HasFlag(CFLAG_STRIP_CHANNEL)) + { + params.insert(params.begin(), this->fantasy_channel->name); + if (command->MaxParams && params.size() > command->MaxParams) + { + params[params.size() - 2] += " " + params[params.size() - 1]; + params.erase(params.end() - 1); + } + } + source.c = this->fantasy_channel; + source.service = this->fantasy_channel->ci->WhoSends(); + } + + return EVENT_CONTINUE; + } + + void OnJoinChannel(User *user, Channel *c) + { + if (c->ci && c->ci->bi) + { + /** + * We let the bot join even if it was an ignored user, as if we don't, + * and the ignored user doesnt just leave, the bot will never + * make it into the channel, leaving the channel botless even for + * legit users - Rob + **/ + if (c->users.size() >= Config->BSMinUsers && !c->FindUser(c->ci->bi)) + c->ci->bi->Join(c, &Config->BotModeList); + /* Only display the greet if the main uplink we're connected + * to has synced, or we'll get greet-floods when the net + * recovers from a netsplit. -GD + */ + if (c->FindUser(c->ci->bi) && c->ci->botflags.HasFlag(BS_GREET) && user->Account() && !user->Account()->greet.empty() && c->ci->AccessFor(user).HasPriv(CA_GREET) && user->server->IsSynced()) + { + ircdproto->SendPrivmsg(c->ci->bi, c->name, "[%s] %s", user->Account()->display.c_str(), user->Account()->greet.c_str()); + c->ci->bi->lastmsg = Anope::CurTime; + } + } + } + + void OnLeaveChannel(User *u, Channel *c) + { + /* Channel is persistent, it shouldn't be deleted and the service bot should stay */ + if (c->HasFlag(CH_PERSIST) || (c->ci && c->ci->HasFlag(CI_PERSIST))) + return; + + /* Channel is syncing from a netburst, don't destroy it as more users are probably wanting to join immediatly + * We also don't part the bot here either, if necessary we will part it after the sync + */ + if (c->HasFlag(CH_SYNCING)) + return; + + /* Additionally, do not delete this channel if ChanServ/a BotServ bot is inhabiting it */ + if (c->HasFlag(CH_INHABIT)) + return; + + if (c->ci && c->ci->bi && u != c->ci->bi && c->users.size() - 1 <= Config->BSMinUsers && c->FindUser(c->ci->bi)) + { + bool persist = c->HasFlag(CH_PERSIST); + c->SetFlag(CH_PERSIST); + c->ci->bi->Part(c->ci->c); + if (!persist) + c->UnsetFlag(CH_PERSIST); + } + } + + void OnPreHelp(CommandSource &source, const std::vector ¶ms) + { + if (!params.empty() || source.owner->nick != Config->BotServ) + return; + source.Reply(_("\002%s\002 allows you to have a bot on your own channel.\n" + "It has been created for users that can't host or\n" + "configure a bot, or for use on networks that don't\n" + "allow user bots. Available commands are listed \n" + "below; to use them, type \002%s%s \037command\037\002. For\n" + "more information on a specific command, type\n" + "\002%s%s %s \037command\037\002.\n "), + Config->BotServ.c_str(), Config->UseStrictPrivMsgString.c_str(), Config->BotServ.c_str(), + Config->UseStrictPrivMsgString.c_str(), Config->BotServ.c_str(), source.command.c_str()); + } + + void OnPostHelp(CommandSource &source, const std::vector ¶ms) + { + if (!params.empty() || source.owner->nick != Config->BotServ) + return; + source.Reply(_(" \n" + "Bot will join a channel whenever there is at least\n" + "\002%d\002 user(s) on it. Additionally, all %s commands\n" + "can be used if fantasy is enabled by prefixing the command\n" + "name with a %c."), Config->BSMinUsers, Config->ChanServ.c_str(), Config->BSFantasyCharacter[0]); + } + + EventReturn OnChannelModeSet(Channel *c, ChannelModeName Name, const Anope::string ¶m) + { + if (Config->BSSmartJoin && Name == CMODE_BAN && c->ci && c->ci->bi && c->FindUser(c->ci->bi)) + { + BotInfo *bi = c->ci->bi; + + Entry ban(CMODE_BAN, param); + if (ban.Matches(bi)) + c->RemoveMode(bi, CMODE_BAN, param); + } + + return EVENT_CONTINUE; + } +}; + +MODULE_INIT(BotServCore) + diff --git a/modules/pseudoclients/bs_main.cpp b/modules/pseudoclients/bs_main.cpp deleted file mode 100644 index a286c54e7..000000000 --- a/modules/pseudoclients/bs_main.cpp +++ /dev/null @@ -1,212 +0,0 @@ -/* BotServ core functions - * - * (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" - -class BotServCore : public Module -{ - Channel *fantasy_channel; - public: - BotServCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE), fantasy_channel(NULL) - { - this->SetAuthor("Anope"); - - BotInfo *BotServ = findbot(Config->BotServ); - if (BotServ == NULL) - throw ModuleException("No bot named " + Config->BotServ); - - Implementation i[] = { I_OnPrivmsg, I_OnPreCommand, I_OnJoinChannel, I_OnLeaveChannel, - I_OnPreHelp, I_OnPostHelp, I_OnChannelModeSet }; - ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); - - } - - void OnPrivmsg(User *u, Channel *c, Anope::string &msg) - { - if (!u || !c || !c->ci || !c->ci->bi || msg.empty()) - return; - - /* Answer to ping if needed */ - if (msg.substr(0, 6).equals_ci("\1PING ") && msg[msg.length() - 1] == '\1') - { - Anope::string ctcp = msg; - ctcp.erase(ctcp.begin()); - ctcp.erase(ctcp.length() - 1); - ircdproto->SendCTCP(c->ci->bi, u->nick, "%s", ctcp.c_str()); - } - - - Anope::string realbuf = msg; - - bool was_action = false; - if (realbuf.substr(0, 8).equals_ci("\1ACTION ") && realbuf[realbuf.length() - 1] == '\1') - { - realbuf.erase(0, 8); - realbuf.erase(realbuf.length() - 1); - was_action = true; - } - - if (realbuf.empty()) - return; - - /* Fantaisist commands */ - if (c->ci->botflags.HasFlag(BS_FANTASY) && realbuf[0] == Config->BSFantasyCharacter[0] && !was_action) - { - /* Strip off the fantasy character */ - realbuf.erase(realbuf.begin()); - - size_t space = realbuf.find(' '); - Anope::string command, rest; - if (space == Anope::string::npos) - command = realbuf; - else - { - command = realbuf.substr(0, space); - rest = realbuf.substr(space + 1); - } - - BotInfo *bi = findbot(Config->ChanServ); - if (bi == NULL) - bi = findbot(Config->BotServ); - if (bi == NULL || !bi->commands.count(command)) - return; - - if (c->ci->AccessFor(u).HasPriv(CA_FANTASIA)) - { - - this->fantasy_channel = c; - bi->OnMessage(u, realbuf); - this->fantasy_channel = NULL; - - FOREACH_MOD(I_OnBotFantasy, OnBotFantasy(command, u, c->ci, rest)); - } - else - { - FOREACH_MOD(I_OnBotNoFantasyAccess, OnBotNoFantasyAccess(command, u, c->ci, rest)); - } - } - } - - EventReturn OnPreCommand(CommandSource &source, Command *command, std::vector ¶ms) - { - if (this->fantasy_channel != NULL) - { - if (!command->HasFlag(CFLAG_STRIP_CHANNEL)) - { - params.insert(params.begin(), this->fantasy_channel->name); - if (command->MaxParams && params.size() > command->MaxParams) - { - params[params.size() - 2] += " " + params[params.size() - 1]; - params.erase(params.end() - 1); - } - } - source.c = this->fantasy_channel; - source.service = this->fantasy_channel->ci->WhoSends(); - } - - return EVENT_CONTINUE; - } - - void OnJoinChannel(User *user, Channel *c) - { - if (c->ci && c->ci->bi) - { - /** - * We let the bot join even if it was an ignored user, as if we don't, - * and the ignored user doesnt just leave, the bot will never - * make it into the channel, leaving the channel botless even for - * legit users - Rob - **/ - if (c->users.size() >= Config->BSMinUsers && !c->FindUser(c->ci->bi)) - c->ci->bi->Join(c, &Config->BotModeList); - /* Only display the greet if the main uplink we're connected - * to has synced, or we'll get greet-floods when the net - * recovers from a netsplit. -GD - */ - if (c->FindUser(c->ci->bi) && c->ci->botflags.HasFlag(BS_GREET) && user->Account() && !user->Account()->greet.empty() && c->ci->AccessFor(user).HasPriv(CA_GREET) && user->server->IsSynced()) - { - ircdproto->SendPrivmsg(c->ci->bi, c->name, "[%s] %s", user->Account()->display.c_str(), user->Account()->greet.c_str()); - c->ci->bi->lastmsg = Anope::CurTime; - } - } - } - - void OnLeaveChannel(User *u, Channel *c) - { - /* Channel is persistent, it shouldn't be deleted and the service bot should stay */ - if (c->HasFlag(CH_PERSIST) || (c->ci && c->ci->HasFlag(CI_PERSIST))) - return; - - /* Channel is syncing from a netburst, don't destroy it as more users are probably wanting to join immediatly - * We also don't part the bot here either, if necessary we will part it after the sync - */ - if (c->HasFlag(CH_SYNCING)) - return; - - /* Additionally, do not delete this channel if ChanServ/a BotServ bot is inhabiting it */ - if (c->HasFlag(CH_INHABIT)) - return; - - if (c->ci && c->ci->bi && u != c->ci->bi && c->users.size() - 1 <= Config->BSMinUsers && c->FindUser(c->ci->bi)) - { - bool persist = c->HasFlag(CH_PERSIST); - c->SetFlag(CH_PERSIST); - c->ci->bi->Part(c->ci->c); - if (!persist) - c->UnsetFlag(CH_PERSIST); - } - } - - void OnPreHelp(CommandSource &source, const std::vector ¶ms) - { - if (!params.empty() || source.owner->nick != Config->BotServ) - return; - source.Reply(_("\002%s\002 allows you to have a bot on your own channel.\n" - "It has been created for users that can't host or\n" - "configure a bot, or for use on networks that don't\n" - "allow user bots. Available commands are listed \n" - "below; to use them, type \002%s%s \037command\037\002. For\n" - "more information on a specific command, type\n" - "\002%s%s %s \037command\037\002.\n "), - Config->BotServ.c_str(), Config->UseStrictPrivMsgString.c_str(), Config->BotServ.c_str(), - Config->UseStrictPrivMsgString.c_str(), Config->BotServ.c_str(), source.command.c_str()); - } - - void OnPostHelp(CommandSource &source, const std::vector ¶ms) - { - if (!params.empty() || source.owner->nick != Config->BotServ) - return; - source.Reply(_(" \n" - "Bot will join a channel whenever there is at least\n" - "\002%d\002 user(s) on it. Additionally, all %s commands\n" - "can be used if fantasy is enabled by prefixing the command\n" - "name with a %c."), Config->BSMinUsers, Config->ChanServ.c_str(), Config->BSFantasyCharacter[0]); - } - - EventReturn OnChannelModeSet(Channel *c, ChannelModeName Name, const Anope::string ¶m) - { - if (Config->BSSmartJoin && Name == CMODE_BAN && c->ci && c->ci->bi && c->FindUser(c->ci->bi)) - { - BotInfo *bi = c->ci->bi; - - Entry ban(CMODE_BAN, param); - if (ban.Matches(bi)) - c->RemoveMode(bi, CMODE_BAN, param); - } - - return EVENT_CONTINUE; - } -}; - -MODULE_INIT(BotServCore) - diff --git a/modules/pseudoclients/chanserv.cpp b/modules/pseudoclients/chanserv.cpp new file mode 100644 index 000000000..5c490e4ff --- /dev/null +++ b/modules/pseudoclients/chanserv.cpp @@ -0,0 +1,143 @@ +/* ChanServ core functions + * + * (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" + +class ChanServCore : public Module +{ + public: + ChanServCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE) + { + this->SetAuthor("Anope"); + + BotInfo *ChanServ = findbot(Config->ChanServ); + if (ChanServ == NULL) + throw ModuleException("No bot named " + Config->ChanServ); + + Implementation i[] = { I_OnBotPrivmsg, I_OnDelCore, I_OnPreHelp, I_OnPostHelp }; + ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); + } + + EventReturn OnBotPrivmsg(User *u, BotInfo *bi, Anope::string &message) + { + if (Config->CSOpersOnly && !u->HasMode(UMODE_OPER) && bi->nick == Config->ChanServ) + { + u->SendMessage(bi, ACCESS_DENIED); + return EVENT_STOP; + } + + return EVENT_CONTINUE; + } + + void OnDelCore(NickCore *nc) + { + // XXX this is slightly inefficient + for (registered_channel_map::const_iterator it = RegisteredChannelList.begin(), it_end = RegisteredChannelList.end(); it != it_end;) + { + ChannelInfo *ci = it->second; + ++it; + + if (ci->GetFounder() == nc) + { + NickCore *newowner = NULL; + if (ci->successor && (ci->successor->IsServicesOper() || !Config->CSMaxReg || ci->successor->channelcount < Config->CSMaxReg)) + newowner = ci->successor; + else + { + ChanAccess *highest = NULL; + for (unsigned j = 0; j < ci->GetAccessCount(); ++j) + { + ChanAccess *ca = ci->GetAccess(j); + NickCore *anc = findcore(ca->mask); + + if (!anc || (!anc->IsServicesOper() && Config->CSMaxReg && anc->channelcount >= Config->CSMaxReg) || (anc == nc)) + continue; + if (!highest || *ca > *highest) + highest = ca; + } + if (highest) + newowner = findcore(highest->mask); + } + + if (newowner) + { + Log(LOG_NORMAL, "chanserv/expire") << "Transferring foundership of " << ci->name << " from deleted nick " << nc->display << " to " << newowner->display; + ci->SetFounder(newowner); + ci->successor = NULL; + } + else + { + Log(LOG_NORMAL, "chanserv/expire") << "Deleting channel " << ci->name << " owned by deleted nick " << nc->display; + + delete ci; + continue; + } + } + + if (ci->successor == nc) + ci->successor = NULL; + + for (unsigned j = 0; j < ci->GetAccessCount(); ++j) + { + ChanAccess *ca = ci->GetAccess(j); + NickCore *anc = findcore(ca->mask); + + if (anc && anc == nc) + { + ci->EraseAccess(j); + break; + } + } + + for (unsigned j = ci->GetAkickCount(); j > 0; --j) + { + AutoKick *akick = ci->GetAkick(j - 1); + if (akick->HasFlag(AK_ISNICK) && akick->nc == nc) + ci->EraseAkick(j - 1); + } + } + } + + void OnPreHelp(CommandSource &source, const std::vector ¶ms) + { + if (!params.empty() || source.owner->nick != Config->ChanServ) + return; + source.Reply(_("\002%s\002 allows you to register and control various\n" + "aspects of channels. %s can often prevent\n" + "malicious users from \"taking over\" channels by limiting\n" + "who is allowed channel operator privileges. Available\n" + "commands are listed below; to use them, type\n" + "\002%s%s \037command\037\002. For more information on a\n" + "specific command, type \002%s%s HELP \037command\037\002.\n "), + Config->ChanServ.c_str(), Config->ChanServ.c_str(), Config->UseStrictPrivMsgString.c_str(), Config->ChanServ.c_str(), Config->UseStrictPrivMsgString.c_str(), Config->ChanServ.c_str(), Config->ChanServ.c_str(), source.command.c_str()); + } + + void OnPostHelp(CommandSource &source, const std::vector ¶ms) + { + if (!params.empty() || source.owner->nick != Config->ChanServ) + return; + if (Config->CSExpire >= 86400) + source.Reply(_(" \n" + "Note that any channel which is not used for %d days\n" + "(i.e. which no user on the channel's access list enters\n" + "for that period of time) will be automatically dropped."), Config->CSExpire / 86400); + if (source.u->IsServicesOper()) + source.Reply(_(" \n" + "Services Operators can also drop any channel without needing\n" + "to identify via password, and may view the access, akick,\n" + "and level setting lists for any channel.")); + } +}; + +MODULE_INIT(ChanServCore) + diff --git a/modules/pseudoclients/cs_main.cpp b/modules/pseudoclients/cs_main.cpp deleted file mode 100644 index 5c490e4ff..000000000 --- a/modules/pseudoclients/cs_main.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* ChanServ core functions - * - * (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" - -class ChanServCore : public Module -{ - public: - ChanServCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE) - { - this->SetAuthor("Anope"); - - BotInfo *ChanServ = findbot(Config->ChanServ); - if (ChanServ == NULL) - throw ModuleException("No bot named " + Config->ChanServ); - - Implementation i[] = { I_OnBotPrivmsg, I_OnDelCore, I_OnPreHelp, I_OnPostHelp }; - ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); - } - - EventReturn OnBotPrivmsg(User *u, BotInfo *bi, Anope::string &message) - { - if (Config->CSOpersOnly && !u->HasMode(UMODE_OPER) && bi->nick == Config->ChanServ) - { - u->SendMessage(bi, ACCESS_DENIED); - return EVENT_STOP; - } - - return EVENT_CONTINUE; - } - - void OnDelCore(NickCore *nc) - { - // XXX this is slightly inefficient - for (registered_channel_map::const_iterator it = RegisteredChannelList.begin(), it_end = RegisteredChannelList.end(); it != it_end;) - { - ChannelInfo *ci = it->second; - ++it; - - if (ci->GetFounder() == nc) - { - NickCore *newowner = NULL; - if (ci->successor && (ci->successor->IsServicesOper() || !Config->CSMaxReg || ci->successor->channelcount < Config->CSMaxReg)) - newowner = ci->successor; - else - { - ChanAccess *highest = NULL; - for (unsigned j = 0; j < ci->GetAccessCount(); ++j) - { - ChanAccess *ca = ci->GetAccess(j); - NickCore *anc = findcore(ca->mask); - - if (!anc || (!anc->IsServicesOper() && Config->CSMaxReg && anc->channelcount >= Config->CSMaxReg) || (anc == nc)) - continue; - if (!highest || *ca > *highest) - highest = ca; - } - if (highest) - newowner = findcore(highest->mask); - } - - if (newowner) - { - Log(LOG_NORMAL, "chanserv/expire") << "Transferring foundership of " << ci->name << " from deleted nick " << nc->display << " to " << newowner->display; - ci->SetFounder(newowner); - ci->successor = NULL; - } - else - { - Log(LOG_NORMAL, "chanserv/expire") << "Deleting channel " << ci->name << " owned by deleted nick " << nc->display; - - delete ci; - continue; - } - } - - if (ci->successor == nc) - ci->successor = NULL; - - for (unsigned j = 0; j < ci->GetAccessCount(); ++j) - { - ChanAccess *ca = ci->GetAccess(j); - NickCore *anc = findcore(ca->mask); - - if (anc && anc == nc) - { - ci->EraseAccess(j); - break; - } - } - - for (unsigned j = ci->GetAkickCount(); j > 0; --j) - { - AutoKick *akick = ci->GetAkick(j - 1); - if (akick->HasFlag(AK_ISNICK) && akick->nc == nc) - ci->EraseAkick(j - 1); - } - } - } - - void OnPreHelp(CommandSource &source, const std::vector ¶ms) - { - if (!params.empty() || source.owner->nick != Config->ChanServ) - return; - source.Reply(_("\002%s\002 allows you to register and control various\n" - "aspects of channels. %s can often prevent\n" - "malicious users from \"taking over\" channels by limiting\n" - "who is allowed channel operator privileges. Available\n" - "commands are listed below; to use them, type\n" - "\002%s%s \037command\037\002. For more information on a\n" - "specific command, type \002%s%s HELP \037command\037\002.\n "), - Config->ChanServ.c_str(), Config->ChanServ.c_str(), Config->UseStrictPrivMsgString.c_str(), Config->ChanServ.c_str(), Config->UseStrictPrivMsgString.c_str(), Config->ChanServ.c_str(), Config->ChanServ.c_str(), source.command.c_str()); - } - - void OnPostHelp(CommandSource &source, const std::vector ¶ms) - { - if (!params.empty() || source.owner->nick != Config->ChanServ) - return; - if (Config->CSExpire >= 86400) - source.Reply(_(" \n" - "Note that any channel which is not used for %d days\n" - "(i.e. which no user on the channel's access list enters\n" - "for that period of time) will be automatically dropped."), Config->CSExpire / 86400); - if (source.u->IsServicesOper()) - source.Reply(_(" \n" - "Services Operators can also drop any channel without needing\n" - "to identify via password, and may view the access, akick,\n" - "and level setting lists for any channel.")); - } -}; - -MODULE_INIT(ChanServCore) - diff --git a/modules/pseudoclients/gl_main.cpp b/modules/pseudoclients/gl_main.cpp deleted file mode 100644 index c7ccf9209..000000000 --- a/modules/pseudoclients/gl_main.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* Global core functions - * - * (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 "global.h" - -class MyGlobalService : public GlobalService -{ - void ServerGlobal(Server *s, const Anope::string &message) - { - if (s != Me && !s->HasFlag(SERVER_JUPED)) - notice_server(Config->Global, s, "%s", message.c_str()); - for (unsigned i = 0, j = s->GetLinks().size(); i < j; ++i) - this->ServerGlobal(s->GetLinks()[i], message); - } - - public: - MyGlobalService(Module *m) : GlobalService(m) { } - - void SendGlobal(BotInfo *sender, const Anope::string &source, const Anope::string &message) - { - if (Me->GetLinks().empty()) - return; - - Anope::string rmessage; - - if (!source.empty() && !Config->AnonymousGlobal) - rmessage = "[" + source + "] " + message; - else - rmessage = message; - - this->ServerGlobal(Me->GetLinks().front(), rmessage); - } -}; - -class GlobalCore : public Module -{ - MyGlobalService myglobalservice; - - public: - GlobalCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE), - myglobalservice(this) - { - this->SetAuthor("Anope"); - - BotInfo *Global = findbot(Config->Global); - if (Global == NULL) - throw ModuleException("No bot named " + Config->Global); - - ModuleManager::RegisterService(&this->myglobalservice); - - Implementation i[] = { I_OnRestart, I_OnShutdown, I_OnNewServer, I_OnPreHelp }; - ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); - } - - void OnRestart() - { - if (Config->GlobalOnCycle) - global->SendGlobal(findbot(Config->Global), "", Config->GlobalOnCycleMessage); - } - - void OnShutdown() - { - if (Config->GlobalOnCycle) - global->SendGlobal(findbot(Config->Global), "", Config->GlobalOnCycleMessage); - } - - void OnNewServer(Server *s) - { - if (Config->GlobalOnCycle && !Config->GlobalOnCycleUP.empty()) - notice_server(Config->Global, s, "%s", Config->GlobalOnCycleUP.c_str()); - } - - void OnPreHelp(CommandSource &source, const std::vector ¶ms) - { - if (!params.empty() || source.owner->nick != Config->Global) - return; - source.Reply(_("%s commands:\n"), Config->Global.c_str()); - } -}; - -MODULE_INIT(GlobalCore) - diff --git a/modules/pseudoclients/global.cpp b/modules/pseudoclients/global.cpp new file mode 100644 index 000000000..c7ccf9209 --- /dev/null +++ b/modules/pseudoclients/global.cpp @@ -0,0 +1,93 @@ +/* Global core functions + * + * (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 "global.h" + +class MyGlobalService : public GlobalService +{ + void ServerGlobal(Server *s, const Anope::string &message) + { + if (s != Me && !s->HasFlag(SERVER_JUPED)) + notice_server(Config->Global, s, "%s", message.c_str()); + for (unsigned i = 0, j = s->GetLinks().size(); i < j; ++i) + this->ServerGlobal(s->GetLinks()[i], message); + } + + public: + MyGlobalService(Module *m) : GlobalService(m) { } + + void SendGlobal(BotInfo *sender, const Anope::string &source, const Anope::string &message) + { + if (Me->GetLinks().empty()) + return; + + Anope::string rmessage; + + if (!source.empty() && !Config->AnonymousGlobal) + rmessage = "[" + source + "] " + message; + else + rmessage = message; + + this->ServerGlobal(Me->GetLinks().front(), rmessage); + } +}; + +class GlobalCore : public Module +{ + MyGlobalService myglobalservice; + + public: + GlobalCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE), + myglobalservice(this) + { + this->SetAuthor("Anope"); + + BotInfo *Global = findbot(Config->Global); + if (Global == NULL) + throw ModuleException("No bot named " + Config->Global); + + ModuleManager::RegisterService(&this->myglobalservice); + + Implementation i[] = { I_OnRestart, I_OnShutdown, I_OnNewServer, I_OnPreHelp }; + ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); + } + + void OnRestart() + { + if (Config->GlobalOnCycle) + global->SendGlobal(findbot(Config->Global), "", Config->GlobalOnCycleMessage); + } + + void OnShutdown() + { + if (Config->GlobalOnCycle) + global->SendGlobal(findbot(Config->Global), "", Config->GlobalOnCycleMessage); + } + + void OnNewServer(Server *s) + { + if (Config->GlobalOnCycle && !Config->GlobalOnCycleUP.empty()) + notice_server(Config->Global, s, "%s", Config->GlobalOnCycleUP.c_str()); + } + + void OnPreHelp(CommandSource &source, const std::vector ¶ms) + { + if (!params.empty() || source.owner->nick != Config->Global) + return; + source.Reply(_("%s commands:\n"), Config->Global.c_str()); + } +}; + +MODULE_INIT(GlobalCore) + diff --git a/modules/pseudoclients/hostserv.cpp b/modules/pseudoclients/hostserv.cpp new file mode 100644 index 000000000..a6cc6bbb7 --- /dev/null +++ b/modules/pseudoclients/hostserv.cpp @@ -0,0 +1,85 @@ +/* HostServ core functions + * + * (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" + +class HostServCore : public Module +{ + public: + HostServCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE) + { + this->SetAuthor("Anope"); + + if (!ircd || !ircd->vhost) + throw ModuleException("Your IRCd does not suppor vhosts"); + + BotInfo *HostServ = findbot(Config->HostServ); + if (HostServ == NULL) + throw ModuleException("No bot named " + Config->HostServ); + + Implementation i[] = { I_OnNickIdentify, I_OnNickUpdate, I_OnPreHelp }; + ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); + } + + void OnNickIdentify(User *u) + { + HostInfo *ho = NULL; + NickAlias *na = findnick(u->nick); + if (na && na->hostinfo.HasVhost()) + ho = &na->hostinfo; + else + { + na = findnick(u->Account()->display); + if (na && na->hostinfo.HasVhost()) + ho = &na->hostinfo; + } + if (ho == NULL) + return; + + if (u->vhost.empty() || !u->vhost.equals_cs(na->hostinfo.GetHost()) || (!na->hostinfo.GetIdent().empty() && !u->GetVIdent().equals_cs(na->hostinfo.GetIdent()))) + { + ircdproto->SendVhost(u, na->hostinfo.GetIdent(), na->hostinfo.GetHost()); + if (ircd->vhost) + { + u->vhost = na->hostinfo.GetHost(); + u->UpdateHost(); + } + if (ircd->vident && !na->hostinfo.GetIdent().empty()) + u->SetVIdent(na->hostinfo.GetIdent()); + + BotInfo *bi = findbot(Config->HostServ); + if (bi) + { + if (!na->hostinfo.GetIdent().empty()) + u->SendMessage(bi, _("Your vhost of \002%s\002@\002%s\002 is now activated."), na->hostinfo.GetIdent().c_str(), na->hostinfo.GetHost().c_str()); + else + u->SendMessage(bi, _("Your vhost of \002%s\002 is now activated."), na->hostinfo.GetHost().c_str()); + } + } + } + + void OnNickUpdate(User *u) + { + this->OnNickIdentify(u); + } + + void OnPreHelp(CommandSource &source, const std::vector ¶ms) + { + if (!params.empty() || source.owner->nick != Config->HostServ) + return; + source.Reply(_("%s commands:\n"), Config->HostServ.c_str()); + } +}; + +MODULE_INIT(HostServCore) + diff --git a/modules/pseudoclients/hs_main.cpp b/modules/pseudoclients/hs_main.cpp deleted file mode 100644 index a6cc6bbb7..000000000 --- a/modules/pseudoclients/hs_main.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* HostServ core functions - * - * (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" - -class HostServCore : public Module -{ - public: - HostServCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE) - { - this->SetAuthor("Anope"); - - if (!ircd || !ircd->vhost) - throw ModuleException("Your IRCd does not suppor vhosts"); - - BotInfo *HostServ = findbot(Config->HostServ); - if (HostServ == NULL) - throw ModuleException("No bot named " + Config->HostServ); - - Implementation i[] = { I_OnNickIdentify, I_OnNickUpdate, I_OnPreHelp }; - ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); - } - - void OnNickIdentify(User *u) - { - HostInfo *ho = NULL; - NickAlias *na = findnick(u->nick); - if (na && na->hostinfo.HasVhost()) - ho = &na->hostinfo; - else - { - na = findnick(u->Account()->display); - if (na && na->hostinfo.HasVhost()) - ho = &na->hostinfo; - } - if (ho == NULL) - return; - - if (u->vhost.empty() || !u->vhost.equals_cs(na->hostinfo.GetHost()) || (!na->hostinfo.GetIdent().empty() && !u->GetVIdent().equals_cs(na->hostinfo.GetIdent()))) - { - ircdproto->SendVhost(u, na->hostinfo.GetIdent(), na->hostinfo.GetHost()); - if (ircd->vhost) - { - u->vhost = na->hostinfo.GetHost(); - u->UpdateHost(); - } - if (ircd->vident && !na->hostinfo.GetIdent().empty()) - u->SetVIdent(na->hostinfo.GetIdent()); - - BotInfo *bi = findbot(Config->HostServ); - if (bi) - { - if (!na->hostinfo.GetIdent().empty()) - u->SendMessage(bi, _("Your vhost of \002%s\002@\002%s\002 is now activated."), na->hostinfo.GetIdent().c_str(), na->hostinfo.GetHost().c_str()); - else - u->SendMessage(bi, _("Your vhost of \002%s\002 is now activated."), na->hostinfo.GetHost().c_str()); - } - } - } - - void OnNickUpdate(User *u) - { - this->OnNickIdentify(u); - } - - void OnPreHelp(CommandSource &source, const std::vector ¶ms) - { - if (!params.empty() || source.owner->nick != Config->HostServ) - return; - source.Reply(_("%s commands:\n"), Config->HostServ.c_str()); - } -}; - -MODULE_INIT(HostServCore) - diff --git a/modules/pseudoclients/memoserv.cpp b/modules/pseudoclients/memoserv.cpp new file mode 100644 index 000000000..eb8af114f --- /dev/null +++ b/modules/pseudoclients/memoserv.cpp @@ -0,0 +1,232 @@ +/* MemoServ core functions + * + * (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 "memoserv.h" + +static BotInfo *MemoServ; + +static bool SendMemoMail(NickCore *nc, MemoInfo *mi, Memo *m) +{ + Anope::string subject = translate(nc, Config->MailMemoSubject.c_str()); + Anope::string message = translate(nc, Config->MailMemoMessage.c_str()); + + subject = subject.replace_all_cs("%n", nc->display); + subject = subject.replace_all_cs("%s", m->sender); + subject = subject.replace_all_cs("%d", mi->GetIndex(m)); + subject = subject.replace_all_cs("%t", m->text); + + message = message.replace_all_cs("%n", nc->display); + message = message.replace_all_cs("%s", m->sender); + message = message.replace_all_cs("%d", mi->GetIndex(m)); + message = message.replace_all_cs("%t", m->text); + + return Mail(nc, subject, message); +} + +class MyMemoServService : public MemoServService +{ + public: + MyMemoServService(Module *m) : MemoServService(m) { } + + MemoInfo *GetMemoInfo(const Anope::string &target, bool &ischan) + { + if (!target.empty() && target[0] == '#') + { + ischan = true; + ChannelInfo *ci = cs_findchan(target); + if (ci != NULL) + return &ci->memos; + } + else + { + ischan = false; + NickAlias *na = findnick(target); + if (na != NULL) + return &na->nc->memos; + } + + return NULL; + } + + MemoResult Send(const Anope::string &source, const Anope::string &target, const Anope::string &message, bool force) + { + bool ischan; + MemoInfo *mi = this->GetMemoInfo(target, ischan); + + if (mi == NULL) + return MEMO_INVALID_TARGET; + + User *sender = finduser(source); + if (sender != NULL && !sender->HasPriv("memoserv/no-limit") && !force) + { + if (Config->MSSendDelay > 0 && sender->lastmemosend + Config->MSSendDelay > Anope::CurTime) + return MEMO_TOO_FAST; + else if (!mi->memomax) + return MEMO_TARGET_FULL; + else if (mi->memomax > 0 && mi->memos.size() >= mi->memomax) + return MEMO_TARGET_FULL; + else if (mi->HasIgnore(sender)) + return MEMO_SUCCESS; + } + + if (sender != NULL) + sender->lastmemosend = Anope::CurTime; + + Memo *m = new Memo(); + mi->memos.push_back(m); + m->sender = source; + m->time = Anope::CurTime; + m->text = message; + m->SetFlag(MF_UNREAD); + + FOREACH_MOD(I_OnMemoSend, OnMemoSend(source, target, mi, m)); + + if (ischan) + { + ChannelInfo *ci = cs_findchan(target); + + if (ci->c) + { + for (CUserList::iterator it = ci->c->users.begin(), it_end = ci->c->users.end(); it != it_end; ++it) + { + UserContainer *cu = *it; + + if (ci->AccessFor(cu->user).HasPriv(CA_MEMO)) + { + if (cu->user->Account() && cu->user->Account()->HasFlag(NI_MEMO_RECEIVE)) + cu->user->SendMessage(MemoServ, MEMO_NEW_X_MEMO_ARRIVED, ci->name.c_str(), Config->UseStrictPrivMsgString.c_str(), Config->MemoServ.c_str(), ci->name.c_str(), mi->memos.size()); + } + } + } + } + else + { + NickCore *nc = findnick(target)->nc; + + if (nc->HasFlag(NI_MEMO_RECEIVE)) + { + for (std::list::iterator it = nc->aliases.begin(), it_end = nc->aliases.end(); it != it_end; ++it) + { + NickAlias *na = *it; + User *user = finduser(na->nick); + if (user && user->IsIdentified()) + user->SendMessage(MemoServ, MEMO_NEW_MEMO_ARRIVED, source.c_str(), Config->UseStrictPrivMsgString.c_str(), Config->MemoServ.c_str(), mi->memos.size()); + } + } + + /* let's get out the mail if set in the nickcore - certus */ + if (nc->HasFlag(NI_MEMO_MAIL)) + SendMemoMail(nc, mi, m); + } + + return MEMO_SUCCESS; + } + + void Check(User *u) + { + NickCore *nc = u->Account(); + if (!nc) + return; + + unsigned i = 0, end = nc->memos.memos.size(), newcnt = 0; + for (; i < end; ++i) + { + if (nc->memos.memos[i]->HasFlag(MF_UNREAD)) + ++newcnt; + } + if (newcnt > 0) + u->SendMessage(MemoServ, newcnt == 1 ? _("You have 1 new memo.") : _("You have %d new memos."), newcnt); + if (nc->memos.memomax > 0 && nc->memos.memos.size() >= nc->memos.memomax) + { + if (nc->memos.memos.size() > nc->memos.memomax) + u->SendMessage(MemoServ, _("You are over your maximum number of memos (%d). You will be unable to receive any new memos until you delete some of your current ones."), nc->memos.memomax); + else + u->SendMessage(MemoServ, _("You have reached your maximum number of memos (%d). You will be unable to receive any new memos until you delete some of your current ones."), nc->memos.memomax); + } + } +}; + +class MemoServCore : public Module +{ + MyMemoServService mymemoserv; + public: + MemoServCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE), + mymemoserv(this) + { + this->SetAuthor("Anope"); + + MemoServ = findbot(Config->MemoServ); + if (MemoServ == NULL) + throw ModuleException("No bot named " + Config->MemoServ); + + Implementation i[] = { I_OnNickIdentify, I_OnJoinChannel, I_OnUserAway, I_OnNickUpdate, I_OnPreHelp, I_OnPostHelp }; + ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); + + ModuleManager::RegisterService(&this->mymemoserv); + } + + void OnNickIdentify(User *u) + { + this->mymemoserv.Check(u); + } + + void OnJoinChannel(User *u, Channel *c) + { + if (c->ci && c->ci->AccessFor(u).HasPriv(CA_MEMO) && c->ci->memos.memos.size() > 0) + { + if (c->ci->memos.memos.size() == 1) + u->SendMessage(MemoServ, _("There is \002%d\002 memo on channel %s."), c->ci->memos.memos.size(), c->ci->name.c_str()); + else + u->SendMessage(MemoServ, _("There are \002%d\002 memos on channel %s."), c->ci->memos.memos.size(), c->ci->name.c_str()); + } + } + + void OnUserAway(User *u, const Anope::string &message) + { + if (message.empty()) + this->mymemoserv.Check(u); + } + + void OnNickUpdate(User *u) + { + this->mymemoserv.Check(u); + } + + void OnPreHelp(CommandSource &source, const std::vector ¶ms) + { + if (!params.empty() || source.owner->nick != Config->MemoServ) + return; + source.Reply(_("\002%s\002 is a utility allowing IRC users to send short\n" + "messages to other IRC users, whether they are online at\n" + "the time or not, or to channels(*). Both the sender's\n" + "nickname and the target nickname or channel must be\n" + "registered in order to send a memo.\n" + "%s's commands include:"), Config->MemoServ.c_str(), Config->MemoServ.c_str()); + } + + void OnPostHelp(CommandSource &source, const std::vector ¶ms) + { + if (!params.empty() || source.owner->nick != Config->MemoServ) + return; + source.Reply(_(" \n" + "Type \002%s%s HELP \037command\037\002 for help on any of the\n" + "above commands.\n" + "(*) By default, any user with at least level 10 access on a\n" + " channel can read that channel's memos. This can be\n" + " changed with the %s \002LEVELS\002 command."), Config->UseStrictPrivMsgString.c_str(), Config->MemoServ.c_str(), Config->ChanServ.c_str()); + } +}; + +MODULE_INIT(MemoServCore) + diff --git a/modules/pseudoclients/ms_main.cpp b/modules/pseudoclients/ms_main.cpp deleted file mode 100644 index eb8af114f..000000000 --- a/modules/pseudoclients/ms_main.cpp +++ /dev/null @@ -1,232 +0,0 @@ -/* MemoServ core functions - * - * (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 "memoserv.h" - -static BotInfo *MemoServ; - -static bool SendMemoMail(NickCore *nc, MemoInfo *mi, Memo *m) -{ - Anope::string subject = translate(nc, Config->MailMemoSubject.c_str()); - Anope::string message = translate(nc, Config->MailMemoMessage.c_str()); - - subject = subject.replace_all_cs("%n", nc->display); - subject = subject.replace_all_cs("%s", m->sender); - subject = subject.replace_all_cs("%d", mi->GetIndex(m)); - subject = subject.replace_all_cs("%t", m->text); - - message = message.replace_all_cs("%n", nc->display); - message = message.replace_all_cs("%s", m->sender); - message = message.replace_all_cs("%d", mi->GetIndex(m)); - message = message.replace_all_cs("%t", m->text); - - return Mail(nc, subject, message); -} - -class MyMemoServService : public MemoServService -{ - public: - MyMemoServService(Module *m) : MemoServService(m) { } - - MemoInfo *GetMemoInfo(const Anope::string &target, bool &ischan) - { - if (!target.empty() && target[0] == '#') - { - ischan = true; - ChannelInfo *ci = cs_findchan(target); - if (ci != NULL) - return &ci->memos; - } - else - { - ischan = false; - NickAlias *na = findnick(target); - if (na != NULL) - return &na->nc->memos; - } - - return NULL; - } - - MemoResult Send(const Anope::string &source, const Anope::string &target, const Anope::string &message, bool force) - { - bool ischan; - MemoInfo *mi = this->GetMemoInfo(target, ischan); - - if (mi == NULL) - return MEMO_INVALID_TARGET; - - User *sender = finduser(source); - if (sender != NULL && !sender->HasPriv("memoserv/no-limit") && !force) - { - if (Config->MSSendDelay > 0 && sender->lastmemosend + Config->MSSendDelay > Anope::CurTime) - return MEMO_TOO_FAST; - else if (!mi->memomax) - return MEMO_TARGET_FULL; - else if (mi->memomax > 0 && mi->memos.size() >= mi->memomax) - return MEMO_TARGET_FULL; - else if (mi->HasIgnore(sender)) - return MEMO_SUCCESS; - } - - if (sender != NULL) - sender->lastmemosend = Anope::CurTime; - - Memo *m = new Memo(); - mi->memos.push_back(m); - m->sender = source; - m->time = Anope::CurTime; - m->text = message; - m->SetFlag(MF_UNREAD); - - FOREACH_MOD(I_OnMemoSend, OnMemoSend(source, target, mi, m)); - - if (ischan) - { - ChannelInfo *ci = cs_findchan(target); - - if (ci->c) - { - for (CUserList::iterator it = ci->c->users.begin(), it_end = ci->c->users.end(); it != it_end; ++it) - { - UserContainer *cu = *it; - - if (ci->AccessFor(cu->user).HasPriv(CA_MEMO)) - { - if (cu->user->Account() && cu->user->Account()->HasFlag(NI_MEMO_RECEIVE)) - cu->user->SendMessage(MemoServ, MEMO_NEW_X_MEMO_ARRIVED, ci->name.c_str(), Config->UseStrictPrivMsgString.c_str(), Config->MemoServ.c_str(), ci->name.c_str(), mi->memos.size()); - } - } - } - } - else - { - NickCore *nc = findnick(target)->nc; - - if (nc->HasFlag(NI_MEMO_RECEIVE)) - { - for (std::list::iterator it = nc->aliases.begin(), it_end = nc->aliases.end(); it != it_end; ++it) - { - NickAlias *na = *it; - User *user = finduser(na->nick); - if (user && user->IsIdentified()) - user->SendMessage(MemoServ, MEMO_NEW_MEMO_ARRIVED, source.c_str(), Config->UseStrictPrivMsgString.c_str(), Config->MemoServ.c_str(), mi->memos.size()); - } - } - - /* let's get out the mail if set in the nickcore - certus */ - if (nc->HasFlag(NI_MEMO_MAIL)) - SendMemoMail(nc, mi, m); - } - - return MEMO_SUCCESS; - } - - void Check(User *u) - { - NickCore *nc = u->Account(); - if (!nc) - return; - - unsigned i = 0, end = nc->memos.memos.size(), newcnt = 0; - for (; i < end; ++i) - { - if (nc->memos.memos[i]->HasFlag(MF_UNREAD)) - ++newcnt; - } - if (newcnt > 0) - u->SendMessage(MemoServ, newcnt == 1 ? _("You have 1 new memo.") : _("You have %d new memos."), newcnt); - if (nc->memos.memomax > 0 && nc->memos.memos.size() >= nc->memos.memomax) - { - if (nc->memos.memos.size() > nc->memos.memomax) - u->SendMessage(MemoServ, _("You are over your maximum number of memos (%d). You will be unable to receive any new memos until you delete some of your current ones."), nc->memos.memomax); - else - u->SendMessage(MemoServ, _("You have reached your maximum number of memos (%d). You will be unable to receive any new memos until you delete some of your current ones."), nc->memos.memomax); - } - } -}; - -class MemoServCore : public Module -{ - MyMemoServService mymemoserv; - public: - MemoServCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE), - mymemoserv(this) - { - this->SetAuthor("Anope"); - - MemoServ = findbot(Config->MemoServ); - if (MemoServ == NULL) - throw ModuleException("No bot named " + Config->MemoServ); - - Implementation i[] = { I_OnNickIdentify, I_OnJoinChannel, I_OnUserAway, I_OnNickUpdate, I_OnPreHelp, I_OnPostHelp }; - ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); - - ModuleManager::RegisterService(&this->mymemoserv); - } - - void OnNickIdentify(User *u) - { - this->mymemoserv.Check(u); - } - - void OnJoinChannel(User *u, Channel *c) - { - if (c->ci && c->ci->AccessFor(u).HasPriv(CA_MEMO) && c->ci->memos.memos.size() > 0) - { - if (c->ci->memos.memos.size() == 1) - u->SendMessage(MemoServ, _("There is \002%d\002 memo on channel %s."), c->ci->memos.memos.size(), c->ci->name.c_str()); - else - u->SendMessage(MemoServ, _("There are \002%d\002 memos on channel %s."), c->ci->memos.memos.size(), c->ci->name.c_str()); - } - } - - void OnUserAway(User *u, const Anope::string &message) - { - if (message.empty()) - this->mymemoserv.Check(u); - } - - void OnNickUpdate(User *u) - { - this->mymemoserv.Check(u); - } - - void OnPreHelp(CommandSource &source, const std::vector ¶ms) - { - if (!params.empty() || source.owner->nick != Config->MemoServ) - return; - source.Reply(_("\002%s\002 is a utility allowing IRC users to send short\n" - "messages to other IRC users, whether they are online at\n" - "the time or not, or to channels(*). Both the sender's\n" - "nickname and the target nickname or channel must be\n" - "registered in order to send a memo.\n" - "%s's commands include:"), Config->MemoServ.c_str(), Config->MemoServ.c_str()); - } - - void OnPostHelp(CommandSource &source, const std::vector ¶ms) - { - if (!params.empty() || source.owner->nick != Config->MemoServ) - return; - source.Reply(_(" \n" - "Type \002%s%s HELP \037command\037\002 for help on any of the\n" - "above commands.\n" - "(*) By default, any user with at least level 10 access on a\n" - " channel can read that channel's memos. This can be\n" - " changed with the %s \002LEVELS\002 command."), Config->UseStrictPrivMsgString.c_str(), Config->MemoServ.c_str(), Config->ChanServ.c_str()); - } -}; - -MODULE_INIT(MemoServCore) - diff --git a/modules/pseudoclients/nickserv.cpp b/modules/pseudoclients/nickserv.cpp new file mode 100644 index 000000000..c31590881 --- /dev/null +++ b/modules/pseudoclients/nickserv.cpp @@ -0,0 +1,308 @@ +/* NickServ core functions + * + * (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 "nickserv.h" + +static BotInfo *NickServ; + +class MyNickServService : public NickServService +{ + public: + MyNickServService(Module *m) : NickServService(m) { } + + void Validate(User *u) + { + NickAlias *na = findnick(u->nick); + if (!na) + return; + + if (na->nc->HasFlag(NI_SUSPENDED)) + { + u->SendMessage(NickServ, NICK_X_SUSPENDED, u->nick.c_str()); + u->Collide(na); + return; + } + + if (!(u->Account() == na->nc) && !u->fingerprint.empty() && na->nc->FindCert(u->fingerprint)) + { + u->SendMessage(NickServ, _("SSL Fingerprint accepted, you are now identified.")); + Log(u) << "automatically identified for account " << na->nc->display << " using a valid SSL fingerprint."; + u->Identify(na); + return; + } + + if (!na->nc->HasFlag(NI_SECURE) && u->IsRecognized()) + { + na->last_seen = Anope::CurTime; + Anope::string last_usermask = u->GetIdent() + "@" + u->GetDisplayedHost(); + na->last_usermask = last_usermask; + na->last_realname = u->realname; + return; + } + + if (u->IsRecognized() || !na->nc->HasFlag(NI_KILL_IMMED)) + { + if (na->nc->HasFlag(NI_SECURE)) + u->SendMessage(NickServ, NICK_IS_SECURE, Config->UseStrictPrivMsgString.c_str(), Config->NickServ.c_str()); + else + u->SendMessage(NickServ, NICK_IS_REGISTERED, Config->UseStrictPrivMsgString.c_str(), Config->NickServ.c_str()); + } + + if (na->nc->HasFlag(NI_KILLPROTECT) && !u->IsRecognized()) + { + if (na->nc->HasFlag(NI_KILL_IMMED)) + { + u->SendMessage(NickServ, FORCENICKCHANGE_NOW); + u->Collide(na); + } + else if (na->nc->HasFlag(NI_KILL_QUICK)) + { + u->SendMessage(NickServ, _("If you do not change within 20 seconds, I will change your nick.")); + new NickServCollide(u, 20); + } + else + { + u->SendMessage(NickServ, _("If you do not change within one minute, I will change your nick.")); + new NickServCollide(u, 60); + } + } + + } +}; + +class ExpireCallback : public CallBack +{ + public: + ExpireCallback(Module *owner) : CallBack(owner, Config->ExpireTimeout, Anope::CurTime, true) { } + + void Tick(time_t) + { + if (noexpire || readonly) + return; + + for (nickalias_map::const_iterator it = NickAliasList.begin(), it_end = NickAliasList.end(); it != it_end; ) + { + NickAlias *na = it->second; + ++it; + + User *u = finduser(na->nick); + if (u && (na->nc->HasFlag(NI_SECURE) ? u->IsIdentified(true) : u->IsRecognized(true))) + na->last_seen = Anope::CurTime; + + bool expire = false; + + if (na->nc->HasFlag(NI_UNCONFIRMED)) + if (Config->NSUnconfirmedExpire && Anope::CurTime - na->time_registered >= Config->NSUnconfirmedExpire) + expire = true; + if (na->nc->HasFlag(NI_SUSPENDED)) + { + if (Config->NSSuspendExpire && Anope::CurTime - na->last_seen >= Config->NSSuspendExpire) + expire = true; + } + else if (Config->NSExpire && Anope::CurTime - na->last_seen >= Config->NSExpire) + expire = true; + if (na->HasFlag(NS_NO_EXPIRE)) + expire = false; + + if (expire) + { + EventReturn MOD_RESULT; + FOREACH_RESULT(I_OnPreNickExpire, OnPreNickExpire(na)); + if (MOD_RESULT == EVENT_STOP) + continue; + Anope::string extra; + if (na->nc->HasFlag(NI_SUSPENDED)) + extra = "suspended "; + Log(LOG_NORMAL, "expire") << "Expiring " << extra << "nickname " << na->nick << " (group: " << na->nc->display << ") (e-mail: " << (na->nc->email.empty() ? "none" : na->nc->email) << ")"; + FOREACH_MOD(I_OnNickExpire, OnNickExpire(na)); + delete na; + } + } + } +}; + +class NickServCore : public Module +{ + MyNickServService mynickserv; + ExpireCallback expires; + + public: + NickServCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE), mynickserv(this), expires(this) + { + this->SetAuthor("Anope"); + + NickServ = findbot(Config->NickServ); + if (NickServ == NULL) + throw ModuleException("No bot named " + Config->NickServ); + + Implementation i[] = { I_OnDelNick, I_OnDelCore, I_OnChangeCoreDisplay, I_OnNickIdentify, I_OnNickGroup, + I_OnNickUpdate, I_OnUserNickChange, I_OnPreHelp, I_OnPostHelp }; + ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); + + ModuleManager::RegisterService(&this->mynickserv); + } + + void OnDelNick(NickAlias *na) + { + User *u = finduser(na->nick); + if (u && u->Account() == na->nc) + { + u->RemoveMode(NickServ, UMODE_REGISTERED); + ircdproto->SendAccountLogout(u, u->Account()); + ircdproto->SendUnregisteredNick(u); + u->Logout(); + } + } + + void OnDelCore(NickCore *nc) + { + Log(NickServ, "nick") << "deleting nickname group " << nc->display; + + /* Clean up this nick core from any users online using it + * (ones that /nick but remain unidentified) + */ + for (std::list::iterator it = nc->Users.begin(); it != nc->Users.end();) + { + User *user = *it++; + ircdproto->SendAccountLogout(user, user->Account()); + user->RemoveMode(NickServ, UMODE_REGISTERED); + ircdproto->SendUnregisteredNick(user); + user->Logout(); + FOREACH_MOD(I_OnNickLogout, OnNickLogout(user)); + } + nc->Users.clear(); + } + + void OnChangeCoreDisplay(NickCore *nc, const Anope::string &newdisplay) + { + Log(LOG_NORMAL, "nick", NickServ) << "Changing " << nc->display << " nickname group display to " << newdisplay; + } + + void OnNickIdentify(User *u) + { + NickAlias *this_na = findnick(u->nick); + if (this_na && this_na->nc == u->Account() && u->Account()->HasFlag(NI_UNCONFIRMED) == false) + u->SetMode(NickServ, UMODE_REGISTERED); + + if (Config->NSModeOnID) + for (UChannelList::iterator it = u->chans.begin(), it_end = u->chans.end(); it != it_end; ++it) + { + ChannelContainer *cc = *it; + Channel *c = cc->chan; + if (c) + chan_set_correct_modes(u, c, 1); + } + + if (Config->NSForceEmail && u->Account()->email.empty()) + { + u->SendMessage(NickServ, _("You must now supply an e-mail for your nick.\n" + "This e-mail will allow you to retrieve your password in\n" + "case you forget it.")); + u->SendMessage(NickServ, _("Type \002%s%s SET EMAIL \037e-mail\037\002 in order to set your e-mail.\n" + "Your privacy is respected; this e-mail won't be given to\n" + "any third-party person."), Config->UseStrictPrivMsgString.c_str(), Config->NickServ.c_str()); + } + + if (u->Account()->HasFlag(NI_UNCONFIRMED)) + { + u->SendMessage(NickServ, _("Your email address is not confirmed. To confirm it, follow the instructions that were emailed to you when you registered.")); + this_na = findnick(u->Account()->display); + time_t time_registered = Anope::CurTime - this_na->time_registered; + if (Config->NSUnconfirmedExpire > time_registered) + u->SendMessage(NickServ, _("Your account will expire, if not confirmed, in %s"), duration(Config->NSUnconfirmedExpire - time_registered).c_str()); + } + } + + void OnNickGroup(User *u, NickAlias *target) + { + if (target->nc->HasFlag(NI_UNCONFIRMED) == false) + u->SetMode(NickServ, UMODE_REGISTERED); + } + + void OnNickUpdate(User *u) + { + for (UChannelList::iterator it = u->chans.begin(), it_end = u->chans.end(); it != it_end; ++it) + { + ChannelContainer *cc = *it; + Channel *c = cc->chan; + if (c) + chan_set_correct_modes(u, c, 1); + } + } + + void OnUserNickChange(User *u, const Anope::string &oldnick) + { + NickAlias *na = findnick(u->nick); + /* If the new nick isnt registerd or its registerd and not yours */ + if (!na || na->nc != u->Account()) + { + u->RemoveMode(NickServ, UMODE_REGISTERED); + ircdproto->SendUnregisteredNick(u); + + this->mynickserv.Validate(u); + } + else + { + if (na->nc->HasFlag(NI_UNCONFIRMED) == false) + { + u->SetMode(NickServ, UMODE_REGISTERED); + ircdproto->SetAutoIdentificationToken(u); + } + Log(NickServ) << u->GetMask() << " automatically identified for group " << u->Account()->display; + } + } + + void OnUserModeSet(User *u, UserModeName Name) + { + if (Name == UMODE_REGISTERED && !u->IsIdentified()) + u->RemoveMode(NickServ, Name); + } + + void OnPreHelp(CommandSource &source, const std::vector ¶ms) + { + if (!params.empty() || source.owner->nick != Config->NickServ) + return; + source.Reply(_("\002%s\002 allows you to \"register\" a nickname and\n" + "prevent others from using it. The following\n" + "commands allow for registration and maintenance of\n" + "nicknames; to use them, type \002%s%s \037command\037\002.\n" + "For more information on a specific command, type\n" + "\002%s%s %s \037command\037\002.\n "), Config->NickServ.c_str(), Config->UseStrictPrivMsgString.c_str(), Config->NickServ.c_str(), Config->UseStrictPrivMsgString.c_str(), Config->NickServ.c_str(), source.command.c_str()); + } + + void OnPostHelp(CommandSource &source, const std::vector ¶ms) + { + if (!params.empty() || source.owner->nick != Config->NickServ) + return; + if (source.u->IsServicesOper()) + source.Reply(_(" \n" + "Services Operators can also drop any nickname without needing\n" + "to identify for the nick, and may view the access list for\n" + "any nickname.")); + if (Config->NSExpire >= 86400) + source.Reply(_("Nicknames that are not used anymore are subject to \n" + "the automatic expiration, i.e. they will be deleted\n" + "after %d days if not used."), Config->NSExpire / 86400); + source.Reply(_(" \n" + "\002NOTICE:\002 This service is intended to provide a way for\n" + "IRC users to ensure their identity is not compromised.\n" + "It is \002NOT\002 intended to facilitate \"stealing\" of\n" + "nicknames or other malicious actions. Abuse of %s\n" + "will result in, at minimum, loss of the abused\n" + "nickname(s)."), Config->NickServ.c_str()); + } +}; + +MODULE_INIT(NickServCore) + diff --git a/modules/pseudoclients/ns_main.cpp b/modules/pseudoclients/ns_main.cpp deleted file mode 100644 index c31590881..000000000 --- a/modules/pseudoclients/ns_main.cpp +++ /dev/null @@ -1,308 +0,0 @@ -/* NickServ core functions - * - * (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 "nickserv.h" - -static BotInfo *NickServ; - -class MyNickServService : public NickServService -{ - public: - MyNickServService(Module *m) : NickServService(m) { } - - void Validate(User *u) - { - NickAlias *na = findnick(u->nick); - if (!na) - return; - - if (na->nc->HasFlag(NI_SUSPENDED)) - { - u->SendMessage(NickServ, NICK_X_SUSPENDED, u->nick.c_str()); - u->Collide(na); - return; - } - - if (!(u->Account() == na->nc) && !u->fingerprint.empty() && na->nc->FindCert(u->fingerprint)) - { - u->SendMessage(NickServ, _("SSL Fingerprint accepted, you are now identified.")); - Log(u) << "automatically identified for account " << na->nc->display << " using a valid SSL fingerprint."; - u->Identify(na); - return; - } - - if (!na->nc->HasFlag(NI_SECURE) && u->IsRecognized()) - { - na->last_seen = Anope::CurTime; - Anope::string last_usermask = u->GetIdent() + "@" + u->GetDisplayedHost(); - na->last_usermask = last_usermask; - na->last_realname = u->realname; - return; - } - - if (u->IsRecognized() || !na->nc->HasFlag(NI_KILL_IMMED)) - { - if (na->nc->HasFlag(NI_SECURE)) - u->SendMessage(NickServ, NICK_IS_SECURE, Config->UseStrictPrivMsgString.c_str(), Config->NickServ.c_str()); - else - u->SendMessage(NickServ, NICK_IS_REGISTERED, Config->UseStrictPrivMsgString.c_str(), Config->NickServ.c_str()); - } - - if (na->nc->HasFlag(NI_KILLPROTECT) && !u->IsRecognized()) - { - if (na->nc->HasFlag(NI_KILL_IMMED)) - { - u->SendMessage(NickServ, FORCENICKCHANGE_NOW); - u->Collide(na); - } - else if (na->nc->HasFlag(NI_KILL_QUICK)) - { - u->SendMessage(NickServ, _("If you do not change within 20 seconds, I will change your nick.")); - new NickServCollide(u, 20); - } - else - { - u->SendMessage(NickServ, _("If you do not change within one minute, I will change your nick.")); - new NickServCollide(u, 60); - } - } - - } -}; - -class ExpireCallback : public CallBack -{ - public: - ExpireCallback(Module *owner) : CallBack(owner, Config->ExpireTimeout, Anope::CurTime, true) { } - - void Tick(time_t) - { - if (noexpire || readonly) - return; - - for (nickalias_map::const_iterator it = NickAliasList.begin(), it_end = NickAliasList.end(); it != it_end; ) - { - NickAlias *na = it->second; - ++it; - - User *u = finduser(na->nick); - if (u && (na->nc->HasFlag(NI_SECURE) ? u->IsIdentified(true) : u->IsRecognized(true))) - na->last_seen = Anope::CurTime; - - bool expire = false; - - if (na->nc->HasFlag(NI_UNCONFIRMED)) - if (Config->NSUnconfirmedExpire && Anope::CurTime - na->time_registered >= Config->NSUnconfirmedExpire) - expire = true; - if (na->nc->HasFlag(NI_SUSPENDED)) - { - if (Config->NSSuspendExpire && Anope::CurTime - na->last_seen >= Config->NSSuspendExpire) - expire = true; - } - else if (Config->NSExpire && Anope::CurTime - na->last_seen >= Config->NSExpire) - expire = true; - if (na->HasFlag(NS_NO_EXPIRE)) - expire = false; - - if (expire) - { - EventReturn MOD_RESULT; - FOREACH_RESULT(I_OnPreNickExpire, OnPreNickExpire(na)); - if (MOD_RESULT == EVENT_STOP) - continue; - Anope::string extra; - if (na->nc->HasFlag(NI_SUSPENDED)) - extra = "suspended "; - Log(LOG_NORMAL, "expire") << "Expiring " << extra << "nickname " << na->nick << " (group: " << na->nc->display << ") (e-mail: " << (na->nc->email.empty() ? "none" : na->nc->email) << ")"; - FOREACH_MOD(I_OnNickExpire, OnNickExpire(na)); - delete na; - } - } - } -}; - -class NickServCore : public Module -{ - MyNickServService mynickserv; - ExpireCallback expires; - - public: - NickServCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE), mynickserv(this), expires(this) - { - this->SetAuthor("Anope"); - - NickServ = findbot(Config->NickServ); - if (NickServ == NULL) - throw ModuleException("No bot named " + Config->NickServ); - - Implementation i[] = { I_OnDelNick, I_OnDelCore, I_OnChangeCoreDisplay, I_OnNickIdentify, I_OnNickGroup, - I_OnNickUpdate, I_OnUserNickChange, I_OnPreHelp, I_OnPostHelp }; - ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); - - ModuleManager::RegisterService(&this->mynickserv); - } - - void OnDelNick(NickAlias *na) - { - User *u = finduser(na->nick); - if (u && u->Account() == na->nc) - { - u->RemoveMode(NickServ, UMODE_REGISTERED); - ircdproto->SendAccountLogout(u, u->Account()); - ircdproto->SendUnregisteredNick(u); - u->Logout(); - } - } - - void OnDelCore(NickCore *nc) - { - Log(NickServ, "nick") << "deleting nickname group " << nc->display; - - /* Clean up this nick core from any users online using it - * (ones that /nick but remain unidentified) - */ - for (std::list::iterator it = nc->Users.begin(); it != nc->Users.end();) - { - User *user = *it++; - ircdproto->SendAccountLogout(user, user->Account()); - user->RemoveMode(NickServ, UMODE_REGISTERED); - ircdproto->SendUnregisteredNick(user); - user->Logout(); - FOREACH_MOD(I_OnNickLogout, OnNickLogout(user)); - } - nc->Users.clear(); - } - - void OnChangeCoreDisplay(NickCore *nc, const Anope::string &newdisplay) - { - Log(LOG_NORMAL, "nick", NickServ) << "Changing " << nc->display << " nickname group display to " << newdisplay; - } - - void OnNickIdentify(User *u) - { - NickAlias *this_na = findnick(u->nick); - if (this_na && this_na->nc == u->Account() && u->Account()->HasFlag(NI_UNCONFIRMED) == false) - u->SetMode(NickServ, UMODE_REGISTERED); - - if (Config->NSModeOnID) - for (UChannelList::iterator it = u->chans.begin(), it_end = u->chans.end(); it != it_end; ++it) - { - ChannelContainer *cc = *it; - Channel *c = cc->chan; - if (c) - chan_set_correct_modes(u, c, 1); - } - - if (Config->NSForceEmail && u->Account()->email.empty()) - { - u->SendMessage(NickServ, _("You must now supply an e-mail for your nick.\n" - "This e-mail will allow you to retrieve your password in\n" - "case you forget it.")); - u->SendMessage(NickServ, _("Type \002%s%s SET EMAIL \037e-mail\037\002 in order to set your e-mail.\n" - "Your privacy is respected; this e-mail won't be given to\n" - "any third-party person."), Config->UseStrictPrivMsgString.c_str(), Config->NickServ.c_str()); - } - - if (u->Account()->HasFlag(NI_UNCONFIRMED)) - { - u->SendMessage(NickServ, _("Your email address is not confirmed. To confirm it, follow the instructions that were emailed to you when you registered.")); - this_na = findnick(u->Account()->display); - time_t time_registered = Anope::CurTime - this_na->time_registered; - if (Config->NSUnconfirmedExpire > time_registered) - u->SendMessage(NickServ, _("Your account will expire, if not confirmed, in %s"), duration(Config->NSUnconfirmedExpire - time_registered).c_str()); - } - } - - void OnNickGroup(User *u, NickAlias *target) - { - if (target->nc->HasFlag(NI_UNCONFIRMED) == false) - u->SetMode(NickServ, UMODE_REGISTERED); - } - - void OnNickUpdate(User *u) - { - for (UChannelList::iterator it = u->chans.begin(), it_end = u->chans.end(); it != it_end; ++it) - { - ChannelContainer *cc = *it; - Channel *c = cc->chan; - if (c) - chan_set_correct_modes(u, c, 1); - } - } - - void OnUserNickChange(User *u, const Anope::string &oldnick) - { - NickAlias *na = findnick(u->nick); - /* If the new nick isnt registerd or its registerd and not yours */ - if (!na || na->nc != u->Account()) - { - u->RemoveMode(NickServ, UMODE_REGISTERED); - ircdproto->SendUnregisteredNick(u); - - this->mynickserv.Validate(u); - } - else - { - if (na->nc->HasFlag(NI_UNCONFIRMED) == false) - { - u->SetMode(NickServ, UMODE_REGISTERED); - ircdproto->SetAutoIdentificationToken(u); - } - Log(NickServ) << u->GetMask() << " automatically identified for group " << u->Account()->display; - } - } - - void OnUserModeSet(User *u, UserModeName Name) - { - if (Name == UMODE_REGISTERED && !u->IsIdentified()) - u->RemoveMode(NickServ, Name); - } - - void OnPreHelp(CommandSource &source, const std::vector ¶ms) - { - if (!params.empty() || source.owner->nick != Config->NickServ) - return; - source.Reply(_("\002%s\002 allows you to \"register\" a nickname and\n" - "prevent others from using it. The following\n" - "commands allow for registration and maintenance of\n" - "nicknames; to use them, type \002%s%s \037command\037\002.\n" - "For more information on a specific command, type\n" - "\002%s%s %s \037command\037\002.\n "), Config->NickServ.c_str(), Config->UseStrictPrivMsgString.c_str(), Config->NickServ.c_str(), Config->UseStrictPrivMsgString.c_str(), Config->NickServ.c_str(), source.command.c_str()); - } - - void OnPostHelp(CommandSource &source, const std::vector ¶ms) - { - if (!params.empty() || source.owner->nick != Config->NickServ) - return; - if (source.u->IsServicesOper()) - source.Reply(_(" \n" - "Services Operators can also drop any nickname without needing\n" - "to identify for the nick, and may view the access list for\n" - "any nickname.")); - if (Config->NSExpire >= 86400) - source.Reply(_("Nicknames that are not used anymore are subject to \n" - "the automatic expiration, i.e. they will be deleted\n" - "after %d days if not used."), Config->NSExpire / 86400); - source.Reply(_(" \n" - "\002NOTICE:\002 This service is intended to provide a way for\n" - "IRC users to ensure their identity is not compromised.\n" - "It is \002NOT\002 intended to facilitate \"stealing\" of\n" - "nicknames or other malicious actions. Abuse of %s\n" - "will result in, at minimum, loss of the abused\n" - "nickname(s)."), Config->NickServ.c_str()); - } -}; - -MODULE_INIT(NickServCore) - diff --git a/modules/pseudoclients/operserv.cpp b/modules/pseudoclients/operserv.cpp new file mode 100644 index 000000000..9bc830335 --- /dev/null +++ b/modules/pseudoclients/operserv.cpp @@ -0,0 +1,343 @@ +/* OperServ core functions + * + * (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" + +static BotInfo *OperServ; + +class SGLineManager : public XLineManager +{ + public: + SGLineManager(Module *creator) : XLineManager(creator, "xlinemanager/sgline", 'G') { } + + XLine *Add(const Anope::string &mask, const Anope::string &creator, time_t expires, const Anope::string &reason) + { + XLine *x = new XLine(mask, creator, expires, reason); + + this->AddXLine(x); + + if (UplinkSock && Config->AkillOnAdd) + this->Send(NULL, x); + + return x; + } + + void Del(XLine *x) + { + try + { + if (!ircd->szline) + throw SocketException("SZLine is not supported"); + else if (x->GetUser() != "*") + throw SocketException("Can not ZLine a username"); + x->GetIP(); + ircdproto->SendSZLineDel(x); + } + catch (const SocketException &) + { + ircdproto->SendAkillDel(x); + } + } + + void OnMatch(User *u, XLine *x) + { + if (u) + u->Kill(Config->OperServ, x->Reason); + this->Send(u, x); + } + + void OnExpire(XLine *x) + { + if (Config->WallAkillExpire) + ircdproto->SendGlobops(OperServ, "AKILL on %s has expired", x->Mask.c_str()); + } + + void Send(User *u, XLine *x) + { + try + { + if (!ircd->szline) + throw SocketException("SZLine is not supported"); + else if (x->GetUser() != "*") + throw SocketException("Can not ZLine a username"); + x->GetIP(); + ircdproto->SendSZLine(u, x); + } + catch (const SocketException &) + { + ircdproto->SendAkill(u, x); + } + } +}; + +class SQLineManager : public XLineManager +{ + public: + SQLineManager(Module *creator) : XLineManager(creator, "xlinemanager/sqline", 'Q') { } + + XLine *Add(const Anope::string &mask, const Anope::string &creator, time_t expires, const Anope::string &reason) + { + XLine *x = new XLine(mask, creator, expires, reason); + + this->AddXLine(x); + + if (Config->KillonSQline) + { + Anope::string rreason = "Q-Lined: " + reason; + + if (mask[0] == '#') + { + for (channel_map::const_iterator cit = ChannelList.begin(), cit_end = ChannelList.end(); cit != cit_end; ++cit) + { + Channel *c = cit->second; + + if (!Anope::Match(c->name, mask)) + continue; + for (CUserList::iterator it = c->users.begin(), it_end = c->users.end(); it != it_end; ) + { + UserContainer *uc = *it; + ++it; + + if (uc->user->HasMode(UMODE_OPER) || uc->user->server == Me) + continue; + c->Kick(NULL, uc->user, "%s", reason.c_str()); + } + } + } + else + { + for (Anope::insensitive_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end();) + { + User *user = it->second; + ++it; + + if (!user->HasMode(UMODE_OPER) && user->server != Me && Anope::Match(user->nick, x->Mask)) + user->Kill(Config->ServerName, rreason); + } + } + } + + if (UplinkSock) + this->Send(NULL, x); + + return x; + } + + void Del(XLine *x) + { + ircdproto->SendSQLineDel(x); + } + + void OnMatch(User *u, XLine *x) + { + if (u) + { + Anope::string reason = "Q-Lined: " + x->Reason; + u->Kill(Config->OperServ, reason); + } + + this->Send(u, x); + } + + void OnExpire(XLine *x) + { + if (Config->WallSQLineExpire) + ircdproto->SendGlobops(OperServ, "SQLINE on \2%s\2 has expired", x->Mask.c_str()); + } + + void Send(User *u, XLine *x) + { + ircdproto->SendSQLine(u, x); + } + + bool CheckChannel(Channel *c) + { + if (ircd->chansqline) + for (std::vector::const_iterator it = this->GetList().begin(), it_end = this->GetList().end(); it != it_end; ++it) + if (Anope::Match(c->name, (*it)->Mask)) + return true; + return false; + } +}; + +class SNLineManager : public XLineManager +{ + public: + SNLineManager(Module *creator) : XLineManager(creator, "xlinemanager/snline", 'N') { } + + XLine *Add(const Anope::string &mask, const Anope::string &creator, time_t expires, const Anope::string &reason) + { + XLine *x = new XLine(mask, creator, expires, reason); + + this->AddXLine(x); + + if (Config->KillonSNline && !ircd->sglineenforce) + { + Anope::string rreason = "G-Lined: " + reason; + + for (Anope::insensitive_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end();) + { + User *user = it->second; + ++it; + + if (!user->HasMode(UMODE_OPER) && user->server != Me && Anope::Match(user->realname, x->Mask)) + user->Kill(Config->ServerName, rreason); + } + } + + return x; + } + + void Del(XLine *x) + { + ircdproto->SendSGLineDel(x); + } + + void OnMatch(User *u, XLine *x) + { + if (u) + { + Anope::string reason = "G-Lined: " + x->Reason; + u->Kill(Config->OperServ, reason); + } + this->Send(u, x); + } + + void OnExpire(XLine *x) + { + if (Config->WallSNLineExpire) + ircdproto->SendGlobops(OperServ, "SNLINE on \2%s\2 has expired", x->Mask.c_str()); + } + + void Send(User *u, XLine *x) + { + ircdproto->SendSGLine(u, x); + } + + XLine *Check(User *u) + { + for (unsigned i = this->XLines.size(); i > 0; --i) + { + XLine *x = this->XLines[i - 1]; + + if (x->Expires && x->Expires < Anope::CurTime) + { + this->OnExpire(x); + this->Del(x); + delete x; + this->XLines.erase(XLines.begin() + i - 1); + continue; + } + + if (Anope::Match(u->realname, x->Mask)) + { + this->OnMatch(u, x); + return x; + } + } + + return NULL; + } +}; + +class OperServCore : public Module +{ + SGLineManager sglines; + SQLineManager sqlines; + SNLineManager snlines; + + public: + OperServCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE), + sglines(this), sqlines(this), snlines(this) + { + this->SetAuthor("Anope"); + + OperServ = findbot(Config->OperServ); + if (OperServ == NULL) + throw ModuleException("No bot named " + Config->OperServ); + + Implementation i[] = { I_OnBotPrivmsg, I_OnServerQuit, I_OnUserModeSet, I_OnUserModeUnset, I_OnUserConnect, I_OnUserNickChange, I_OnPreHelp }; + ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); + + ModuleManager::RegisterService(&sglines); + ModuleManager::RegisterService(&sqlines); + ModuleManager::RegisterService(&snlines); + + /* Yes, these are in this order for a reason. Most violent->least violent. */ + XLineManager::RegisterXLineManager(&sglines); + XLineManager::RegisterXLineManager(&sqlines); + XLineManager::RegisterXLineManager(&snlines); + } + + EventReturn OnBotPrivmsg(User *u, BotInfo *bi, Anope::string &message) + { + if (Config->OSOpersOnly && !u->HasMode(UMODE_OPER) && bi->nick == Config->OperServ) + { + u->SendMessage(bi, ACCESS_DENIED); + return EVENT_STOP; + } + + return EVENT_CONTINUE; + } + + void OnServerQuit(Server *server) + { + if (server->HasFlag(SERVER_JUPED)) + ircdproto->SendGlobops(OperServ, "Received SQUIT for juped server %s", server->GetName().c_str()); + } + + void OnUserModeSet(User *u, UserModeName Name) + { + if (Name == UMODE_OPER) + { + if (Config->WallOper) + ircdproto->SendGlobops(OperServ, "\2%s\2 is now an IRC operator.", u->nick.c_str()); + Log(OperServ) << u->nick << " is now an IRC operator"; + } + } + + void OnUserModeUnset(User *u, UserModeName Name) + { + if (Name == UMODE_OPER) + Log(OperServ) << u->nick << " is no longer an IRC operator"; + } + + void OnUserConnect(dynamic_reference &u, bool &exempt) + { + if (u && !exempt) + XLineManager::CheckAll(u); + } + + void OnUserNickChange(User *u, const Anope::string &oldnick) + { + if (ircd->sqline && !u->HasMode(UMODE_OPER)) + this->sqlines.Check(u); + } + + EventReturn OnCheckKick(User *u, ChannelInfo *ci, bool &kick) + { + if (this->sqlines.CheckChannel(ci->c)) + kick = true; + return EVENT_CONTINUE; + } + + void OnPreHelp(CommandSource &source, const std::vector ¶ms) + { + if (!params.empty() || source.owner->nick != Config->OperServ) + return; + source.Reply(_("%s commands:"), Config->OperServ.c_str()); + } +}; + +MODULE_INIT(OperServCore) + diff --git a/modules/pseudoclients/os_main.cpp b/modules/pseudoclients/os_main.cpp deleted file mode 100644 index 9bc830335..000000000 --- a/modules/pseudoclients/os_main.cpp +++ /dev/null @@ -1,343 +0,0 @@ -/* OperServ core functions - * - * (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" - -static BotInfo *OperServ; - -class SGLineManager : public XLineManager -{ - public: - SGLineManager(Module *creator) : XLineManager(creator, "xlinemanager/sgline", 'G') { } - - XLine *Add(const Anope::string &mask, const Anope::string &creator, time_t expires, const Anope::string &reason) - { - XLine *x = new XLine(mask, creator, expires, reason); - - this->AddXLine(x); - - if (UplinkSock && Config->AkillOnAdd) - this->Send(NULL, x); - - return x; - } - - void Del(XLine *x) - { - try - { - if (!ircd->szline) - throw SocketException("SZLine is not supported"); - else if (x->GetUser() != "*") - throw SocketException("Can not ZLine a username"); - x->GetIP(); - ircdproto->SendSZLineDel(x); - } - catch (const SocketException &) - { - ircdproto->SendAkillDel(x); - } - } - - void OnMatch(User *u, XLine *x) - { - if (u) - u->Kill(Config->OperServ, x->Reason); - this->Send(u, x); - } - - void OnExpire(XLine *x) - { - if (Config->WallAkillExpire) - ircdproto->SendGlobops(OperServ, "AKILL on %s has expired", x->Mask.c_str()); - } - - void Send(User *u, XLine *x) - { - try - { - if (!ircd->szline) - throw SocketException("SZLine is not supported"); - else if (x->GetUser() != "*") - throw SocketException("Can not ZLine a username"); - x->GetIP(); - ircdproto->SendSZLine(u, x); - } - catch (const SocketException &) - { - ircdproto->SendAkill(u, x); - } - } -}; - -class SQLineManager : public XLineManager -{ - public: - SQLineManager(Module *creator) : XLineManager(creator, "xlinemanager/sqline", 'Q') { } - - XLine *Add(const Anope::string &mask, const Anope::string &creator, time_t expires, const Anope::string &reason) - { - XLine *x = new XLine(mask, creator, expires, reason); - - this->AddXLine(x); - - if (Config->KillonSQline) - { - Anope::string rreason = "Q-Lined: " + reason; - - if (mask[0] == '#') - { - for (channel_map::const_iterator cit = ChannelList.begin(), cit_end = ChannelList.end(); cit != cit_end; ++cit) - { - Channel *c = cit->second; - - if (!Anope::Match(c->name, mask)) - continue; - for (CUserList::iterator it = c->users.begin(), it_end = c->users.end(); it != it_end; ) - { - UserContainer *uc = *it; - ++it; - - if (uc->user->HasMode(UMODE_OPER) || uc->user->server == Me) - continue; - c->Kick(NULL, uc->user, "%s", reason.c_str()); - } - } - } - else - { - for (Anope::insensitive_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end();) - { - User *user = it->second; - ++it; - - if (!user->HasMode(UMODE_OPER) && user->server != Me && Anope::Match(user->nick, x->Mask)) - user->Kill(Config->ServerName, rreason); - } - } - } - - if (UplinkSock) - this->Send(NULL, x); - - return x; - } - - void Del(XLine *x) - { - ircdproto->SendSQLineDel(x); - } - - void OnMatch(User *u, XLine *x) - { - if (u) - { - Anope::string reason = "Q-Lined: " + x->Reason; - u->Kill(Config->OperServ, reason); - } - - this->Send(u, x); - } - - void OnExpire(XLine *x) - { - if (Config->WallSQLineExpire) - ircdproto->SendGlobops(OperServ, "SQLINE on \2%s\2 has expired", x->Mask.c_str()); - } - - void Send(User *u, XLine *x) - { - ircdproto->SendSQLine(u, x); - } - - bool CheckChannel(Channel *c) - { - if (ircd->chansqline) - for (std::vector::const_iterator it = this->GetList().begin(), it_end = this->GetList().end(); it != it_end; ++it) - if (Anope::Match(c->name, (*it)->Mask)) - return true; - return false; - } -}; - -class SNLineManager : public XLineManager -{ - public: - SNLineManager(Module *creator) : XLineManager(creator, "xlinemanager/snline", 'N') { } - - XLine *Add(const Anope::string &mask, const Anope::string &creator, time_t expires, const Anope::string &reason) - { - XLine *x = new XLine(mask, creator, expires, reason); - - this->AddXLine(x); - - if (Config->KillonSNline && !ircd->sglineenforce) - { - Anope::string rreason = "G-Lined: " + reason; - - for (Anope::insensitive_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end();) - { - User *user = it->second; - ++it; - - if (!user->HasMode(UMODE_OPER) && user->server != Me && Anope::Match(user->realname, x->Mask)) - user->Kill(Config->ServerName, rreason); - } - } - - return x; - } - - void Del(XLine *x) - { - ircdproto->SendSGLineDel(x); - } - - void OnMatch(User *u, XLine *x) - { - if (u) - { - Anope::string reason = "G-Lined: " + x->Reason; - u->Kill(Config->OperServ, reason); - } - this->Send(u, x); - } - - void OnExpire(XLine *x) - { - if (Config->WallSNLineExpire) - ircdproto->SendGlobops(OperServ, "SNLINE on \2%s\2 has expired", x->Mask.c_str()); - } - - void Send(User *u, XLine *x) - { - ircdproto->SendSGLine(u, x); - } - - XLine *Check(User *u) - { - for (unsigned i = this->XLines.size(); i > 0; --i) - { - XLine *x = this->XLines[i - 1]; - - if (x->Expires && x->Expires < Anope::CurTime) - { - this->OnExpire(x); - this->Del(x); - delete x; - this->XLines.erase(XLines.begin() + i - 1); - continue; - } - - if (Anope::Match(u->realname, x->Mask)) - { - this->OnMatch(u, x); - return x; - } - } - - return NULL; - } -}; - -class OperServCore : public Module -{ - SGLineManager sglines; - SQLineManager sqlines; - SNLineManager snlines; - - public: - OperServCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE), - sglines(this), sqlines(this), snlines(this) - { - this->SetAuthor("Anope"); - - OperServ = findbot(Config->OperServ); - if (OperServ == NULL) - throw ModuleException("No bot named " + Config->OperServ); - - Implementation i[] = { I_OnBotPrivmsg, I_OnServerQuit, I_OnUserModeSet, I_OnUserModeUnset, I_OnUserConnect, I_OnUserNickChange, I_OnPreHelp }; - ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); - - ModuleManager::RegisterService(&sglines); - ModuleManager::RegisterService(&sqlines); - ModuleManager::RegisterService(&snlines); - - /* Yes, these are in this order for a reason. Most violent->least violent. */ - XLineManager::RegisterXLineManager(&sglines); - XLineManager::RegisterXLineManager(&sqlines); - XLineManager::RegisterXLineManager(&snlines); - } - - EventReturn OnBotPrivmsg(User *u, BotInfo *bi, Anope::string &message) - { - if (Config->OSOpersOnly && !u->HasMode(UMODE_OPER) && bi->nick == Config->OperServ) - { - u->SendMessage(bi, ACCESS_DENIED); - return EVENT_STOP; - } - - return EVENT_CONTINUE; - } - - void OnServerQuit(Server *server) - { - if (server->HasFlag(SERVER_JUPED)) - ircdproto->SendGlobops(OperServ, "Received SQUIT for juped server %s", server->GetName().c_str()); - } - - void OnUserModeSet(User *u, UserModeName Name) - { - if (Name == UMODE_OPER) - { - if (Config->WallOper) - ircdproto->SendGlobops(OperServ, "\2%s\2 is now an IRC operator.", u->nick.c_str()); - Log(OperServ) << u->nick << " is now an IRC operator"; - } - } - - void OnUserModeUnset(User *u, UserModeName Name) - { - if (Name == UMODE_OPER) - Log(OperServ) << u->nick << " is no longer an IRC operator"; - } - - void OnUserConnect(dynamic_reference &u, bool &exempt) - { - if (u && !exempt) - XLineManager::CheckAll(u); - } - - void OnUserNickChange(User *u, const Anope::string &oldnick) - { - if (ircd->sqline && !u->HasMode(UMODE_OPER)) - this->sqlines.Check(u); - } - - EventReturn OnCheckKick(User *u, ChannelInfo *ci, bool &kick) - { - if (this->sqlines.CheckChannel(ci->c)) - kick = true; - return EVENT_CONTINUE; - } - - void OnPreHelp(CommandSource &source, const std::vector ¶ms) - { - if (!params.empty() || source.owner->nick != Config->OperServ) - return; - source.Reply(_("%s commands:"), Config->OperServ.c_str()); - } -}; - -MODULE_INIT(OperServCore) - -- cgit