diff options
| author | 2010-08-07 19:44:39 -0400 | |
|---|---|---|
| committer | 2010-08-07 19:44:39 -0400 | |
| commit | baf3d1671ee7a030f4e44a10c15482958e161b47 (patch) | |
| tree | f97478d47cd13fe81e5aa1c8a910fc4c0ec0ff71 /src/modules/m_serverbots.cpp | |
| parent | Add ECHO command to m_alias for user feedback (diff) | |
| download | inspircd++-baf3d1671ee7a030f4e44a10c15482958e161b47.tar.gz inspircd++-baf3d1671ee7a030f4e44a10c15482958e161b47.tar.bz2 inspircd++-baf3d1671ee7a030f4e44a10c15482958e161b47.zip | |
Add m_serverbots
Diffstat (limited to 'src/modules/m_serverbots.cpp')
| -rw-r--r-- | src/modules/m_serverbots.cpp | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/src/modules/m_serverbots.cpp b/src/modules/m_serverbots.cpp new file mode 100644 index 000000000..aec150c5c --- /dev/null +++ b/src/modules/m_serverbots.cpp @@ -0,0 +1,294 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2010 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +/* $ModDesc: Provides fake clients that respond to messages. */ + +/** Command definition + */ +class Alias +{ + public: + /** The text of the alias command */ + irc::string AliasedCommand; + + /** Text to replace with */ + std::string ReplaceFormat; + + /** Nickname required to perform alias */ + std::string RequiredNick; + + /** RequiredNick must be on a ulined server */ + bool ULineOnly; + + /** Format that must be matched for use */ + std::string format; +}; + +typedef std::multimap<irc::string, Alias>::iterator AliasIter; + +class BotData +{ + public: + std::multimap<irc::string, Alias> Aliases; + FakeUser* const bot; + BotData(FakeUser* Bot) : bot(Bot) {} + + void HandleMessage(User* user, const std::string& text) + { + irc::spacesepstream ss(text); + std::string command, params; + ss.GetToken(command); + params = ss.GetRemaining(); + + std::pair<AliasIter, AliasIter> range = Aliases.equal_range(assign(command)); + + for(AliasIter i = range.first; i != range.second; i++) + { + DoAlias(user, &i->second, params, text); + } + + // also support no-command aliases (presumably they have format checks) + range = Aliases.equal_range(""); + for(AliasIter i = range.first; i != range.second; i++) + { + DoAlias(user, &i->second, text, text); + } + } + + void DoAlias(User *user, Alias *a, const std::string& params, const std::string& text) + { + /* Does it match the pattern? */ + if (!a->format.empty()) + { + if (!InspIRCd::Match(params, a->format)) + return; + } + + if (!a->RequiredNick.empty()) + { + User* u = ServerInstance->FindNick(a->RequiredNick); + if (!u) + { + user->WriteFrom(bot, "NOTICE %s :%s is currently unavailable. Please try again later.", + user->nick.c_str(), a->RequiredNick.c_str()); + return; + } + if (a->ULineOnly && !ServerInstance->ULine(u->server)) + { + ServerInstance->SNO->WriteToSnoMask('a', "NOTICE -- Service "+a->RequiredNick+" required by alias "+std::string(a->AliasedCommand.c_str())+" is not on a u-lined server, possibly underhanded antics detected!"); + user->WriteFrom(bot, "NOTICE %s :%s is an imposter! Please inform an IRC operator as soon as possible.", + user->nick.c_str(), a->RequiredNick.c_str()); + return; + } + } + + /* Now, search and replace in a copy of the original_line, replacing $1 through $9 and $1- etc */ + + irc::sepstream commands(a->ReplaceFormat, '\n'); + std::string scommand; + while (commands.GetToken(scommand)) + { + DoCommand(scommand, user, text); + } + } + + void DoCommand(const std::string& format, User* user, const std::string &text) + { + std::string result; + result.reserve(MAXBUF); + for (unsigned int i = 0; i < format.length(); i++) + { + char c = format[i]; + if (c == '$') + { + if (isdigit(format[i+1])) + { + int len = (format[i+2] == '-') ? 3 : 2; + std::string var = format.substr(i, len); + result.append(GetVar(var, text)); + i += len - 1; + } + else if (format.substr(i, 4) == "$bot") + { + result.append(bot->nick); + i += 3; + } + else if (format.substr(i, 5) == "$nick") + { + result.append(user->nick); + i += 4; + } + else if (format.substr(i, 5) == "$host") + { + result.append(user->host); + i += 4; + } + else if (format.substr(i, 6) == "$ident") + { + result.append(user->ident); + i += 5; + } + else if (format.substr(i, 6) == "$vhost") + { + result.append(user->dhost); + i += 5; + } + else if (format.substr(i, 8) == "$fullbot") + { + result.append(bot->User::GetFullHost()); + } + else + result.push_back(c); + } + else + result.push_back(c); + } + + irc::tokenstream ss(result); + std::vector<std::string> pars; + std::string command, token; + + ss.GetToken(command); + while (ss.GetToken(token) && (pars.size() <= MAXPARAMETERS)) + { + pars.push_back(token); + } + ServerInstance->Parser->CallHandler(command, pars, user); + } + + std::string GetVar(std::string varname, const std::string &original_line) + { + irc::spacesepstream ss(original_line); + int index = varname[1] - '0'; + bool everything_after = (varname.length() == 3); + std::string word; + + for (int j = 0; j < index; j++) + ss.GetToken(word); + + if (everything_after) + return ss.GetRemaining(); + + ss.GetToken(word); + return word; + } +}; + +class ModuleServerBots : public Module +{ + std::vector<FakeUser*> bots; + SimpleExtItem<BotData> dataExt; + bool recursing; + int botID; + + public: + ModuleServerBots() : dataExt("serverbot", this) {} + + void init() + { + recursing = false; + botID = 0; + OnRehash(NULL); + ServerInstance->Modules->Attach(I_OnRehash, this); + ServerInstance->Modules->Attach(I_OnUserMessage, this); + } + + Version GetVersion() + { + return Version("Provides fake clients for handling IRCd commands.", VF_VENDOR); + } + + void OnUserMessage(User *user, void *dest, int target_type, const std::string &text, char status, const CUList &exempt_list) + { + if (target_type != TYPE_USER) + return; + User* b = (User*)dest; + BotData* bot = dataExt.get(b); + if (!bot) + return; + + if (recursing) + { + user->WriteFrom(bot->bot, "NOTICE %s :Your command caused a recursive bot message which was not processed.", user->nick.c_str()); + return; + } + + recursing = true; + bot->HandleMessage(user, text); + recursing = false; + } + + void OnRehash(User* user) + { + // TODO don't recreate all bots on rehash + cull(); + + ConfigTagList tags = ServerInstance->Config->ConfTags("bot"); + for(ConfigIter i = tags.first; i != tags.second; i++) + { + ConfigTag* tag = i->second; + // UID is of the form "12!BOT" + std::string nick = tag->getString("nick"); + if (nick.empty()) + continue; + // TODO bump nicks out of the way + if (ServerInstance->FindNick(nick)) + continue; + std::string uid = ConvToStr(++botID) + "!BOT"; + FakeUser* bot = new FakeUser(uid, ServerInstance->Config->ServerName); + bots.push_back(bot); + bot->ChangeNick(nick, true); + bot->ident = tag->getString("ident", "bot"); + bot->host = tag->getString("host", ServerInstance->Config->ServerName); + bot->dhost = bot->host; + bot->fullname = tag->getString("name", "Server-side Bot"); + // TODO should we oper it? + + dataExt.set(bot, new BotData(bot)); + } + + tags = ServerInstance->Config->ConfTags("botcmd"); + for(ConfigIter i = tags.first; i != tags.second; i++) + { + ConfigTag* tag = i->second; + std::string botnick = tag->getString("bot"); + User* u = ServerInstance->FindNick(botnick); + if (!u) + continue; + BotData* bot = dataExt.get(u); + if (!bot) + continue; + Alias a; + a.AliasedCommand = tag->getString("text").c_str(); + tag->readString("replace", a.ReplaceFormat, true); + a.RequiredNick = tag->getString("requires"); + a.ULineOnly = tag->getBool("uline"); + a.format = tag->getString("format"); + + bot->Aliases.insert(std::make_pair(a.AliasedCommand, a)); + } + } + + CullResult cull() + { + for(std::vector<FakeUser*>::iterator i = bots.begin(); i != bots.end(); i++) + { + ServerInstance->GlobalCulls.AddItem(*i); + } + return Module::cull(); + } +}; + +MODULE_INIT(ModuleServerBots) |
