]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/modules/m_alias.cpp
Don't send an override notice if no modes were actually applied, thanks Ankit.
[user/henk/code/inspircd.git] / src / modules / m_alias.cpp
index 096bdb5881f06887555ae4b683053bc28f511bea..ad5f84034c7cf1e1b727d5a0e40fb8c7d453015f 100644 (file)
@@ -21,17 +21,29 @@ class Alias : public classbase
 {
  public:
        /** The text of the alias command */
-       irc::string text;
+       irc::string AliasedCommand;
+
        /** Text to replace with */
-       std::string replace_with;
+       std::string ReplaceFormat;
+
        /** Nickname required to perform alias */
-       std::string requires;
+       std::string RequiredNick;
+
        /** Alias requires ulined server */
-       bool uline;
+       bool ULineOnly;
+
        /** Requires oper? */
-       bool operonly;
+       bool OperOnly;
+
        /* is case sensitive params */
-       bool case_sensitive;
+       bool CaseSensitive;
+
+       /* whether or not it may be executed via fantasy (default OFF) */
+       bool ChannelCommand;
+
+       /* whether or not it may be executed via /command (default ON) */
+       bool UserCommand;
+
        /** Format that must be matched for use */
        std::string format;
 };
@@ -55,13 +67,15 @@ class ModuleAlias : public Module
                        Alias a;
                        std::string txt;
                        txt = MyConf.ReadValue("alias", "text", i);
-                       a.text = txt.c_str();
-                       a.replace_with = MyConf.ReadValue("alias", "replace", i, true);
-                       a.requires = MyConf.ReadValue("alias", "requires", i);
-                       a.uline = MyConf.ReadFlag("alias", "uline", i);
-                       a.operonly = MyConf.ReadFlag("alias", "operonly", i);
+                       a.AliasedCommand = txt.c_str();
+                       a.ReplaceFormat = MyConf.ReadValue("alias", "replace", i, true);
+                       a.RequiredNick = MyConf.ReadValue("alias", "requires", i);
+                       a.ULineOnly = MyConf.ReadFlag("alias", "uline", i);
+                       a.ChannelCommand = MyConf.ReadFlag("alias", "channelcommand", "no", i);
+                       a.UserCommand = MyConf.ReadFlag("alias", "usercommand", "yes", i);
+                       a.OperOnly = MyConf.ReadFlag("alias", "operonly", i);
                        a.format = MyConf.ReadValue("alias", "format", i);
-                       a.case_sensitive = MyConf.ReadFlag("alias", "matchcase", i);
+                       a.CaseSensitive = MyConf.ReadFlag("alias", "matchcase", i);
                        Aliases.insert(std::make_pair(txt, a));
                }
        }
@@ -74,6 +88,7 @@ class ModuleAlias : public Module
                ReadAliases();
                Me->Modules->Attach(I_OnPreCommand, this);
                Me->Modules->Attach(I_OnRehash, this);
+               Me->Modules->Attach(I_OnUserPreMessage, this);
 
        }
 
@@ -124,7 +139,6 @@ class ModuleAlias : public Module
 
        virtual int OnPreCommand(std::string &command, std::vector<std::string> &parameters, User *user, bool validated, const std::string &original_line)
        {
-               User *u = NULL;
                std::multimap<std::string, Alias>::iterator i;
 
                /* If theyre not registered yet, we dont want
@@ -152,69 +166,160 @@ class ModuleAlias : public Module
 
                while (i != Aliases.end())
                {
-                       /* Does it match the pattern? */
-                       if (!i->second.format.empty())
+                       if (i->second.UserCommand)
                        {
-                               if (i->second.case_sensitive)
+                               if (DoAlias(user, NULL, &(i->second), compare, safe))
                                {
-                                       if (InspIRCd::Match(compare, i->second.format, case_sensitive_map))
-                                               continue;
-                               }
-                               else
-                               {
-                                       if (InspIRCd::Match(compare, i->second.format))
-                                               continue;
+                                       return 1;
                                }
                        }
 
-                       if ((i->second.operonly) && (!IS_OPER(user)))
-                               return 0;
+                       i++;
+               }
+
+               // If aliases have been processed, aliases took it.
+               return 1;
+       }
+
+       virtual int OnUserPreMessage(User *user, void *dest, int target_type, std::string &text, char status, CUList &exempt_list)
+       {
+               if (target_type != TYPE_CHANNEL)
+               {
+                       ServerInstance->Logs->Log("FANTASY", DEBUG, "fantasy: not a channel msg");
+                       return 0;
+               }
+
+               // fcommands are only for local users. Spanningtree will send them back out as their original cmd.
+               if (!IS_LOCAL(user))
+               {
+                       ServerInstance->Logs->Log("FANTASY", DEBUG, "fantasy: not local");
+                       return 0;
+               }
+
+               Channel *c = (Channel *)dest;
+               std::string fcommand;
+
+               // text is like "!moo cows bite me", we want "!moo" first
+               irc::spacesepstream ss(text);
+               ss.GetToken(fcommand);
+
+               if (fcommand.empty())
+               {
+                       ServerInstance->Logs->Log("FANTASY", DEBUG, "fantasy: empty (?)");
+                       return 0; // wtfbbq
+               }
+
+               ServerInstance->Logs->Log("FANTASY", DEBUG, "fantasy: looking at fcommand %s", fcommand.c_str());
+
+               // we don't want to touch non-fantasy stuff
+               if (*fcommand.c_str() != '!')
+               {
+                       ServerInstance->Logs->Log("FANTASY", DEBUG, "fantasy: not a fcommand");
+                       return 0;
+               }
+
+               // nor do we give a shit about the !
+               fcommand.erase(fcommand.begin());
+               std::transform(fcommand.begin(), fcommand.end(), fcommand.begin(), ::toupper);
+               ServerInstance->Logs->Log("FANTASY", DEBUG, "fantasy: now got %s", fcommand.c_str());
+
+
+               std::multimap<std::string, Alias>::iterator i = Aliases.find(fcommand);
+
+               if (i == Aliases.end())
+                       return 0;
+
+
+               /* The parameters for the command in their original form, with the command stripped off */
+               std::string compare = text.substr(fcommand.length() + 1);
+               while (*(compare.c_str()) == ' ')
+                       compare.erase(compare.begin());
+
+               std::string safe(compare);
+
+               /* Escape out any $ symbols in the user provided text (ugly, but better than crashy) */
+               SearchAndReplace(safe, "$", "\r");
+
+               ServerInstance->Logs->Log("FANTASY", DEBUG, "fantasy: compare is %s and safe is %s", compare.c_str(), safe.c_str());
+
+               while (i != Aliases.end())
+               {
+                       if (i->second.ChannelCommand)
+                       {
+                               if (DoAlias(user, c, &(i->second), compare, safe))
+                                       return 0;
+                       }
+
+                       i++;
+               }
+               
+               return 0;
+       }
+
+
+       int DoAlias(User *user, Channel *c, Alias *a, const std::string compare, const std::string safe)
+       {
+               User *u = NULL;
 
-                       if (!i->second.requires.empty())
+               /* Does it match the pattern? */
+               if (!a->format.empty())
+               {
+                       if (a->CaseSensitive)
                        {
-                               u = ServerInstance->FindNick(i->second.requires);
-                               if (!u)
-                               {
-                                       user->WriteNumeric(401, ""+std::string(user->nick)+" "+i->second.requires+" :is currently unavailable. Please try again later.");
-                                       return 1;
-                               }
+                               if (InspIRCd::Match(compare, a->format, case_sensitive_map))
+                                       return 0;
                        }
-                       if ((u != NULL) && (!i->second.requires.empty()) && (i->second.uline))
+                       else
                        {
-                               if (!ServerInstance->ULine(u->server))
-                               {
-                                       ServerInstance->SNO->WriteToSnoMask('A', "NOTICE -- Service "+i->second.requires+" required by alias "+std::string(i->second.text.c_str())+" is not on a u-lined server, possibly underhanded antics detected!");
-                                       user->WriteNumeric(401, ""+std::string(user->nick)+" "+i->second.requires+" :is an imposter! Please inform an IRC operator as soon as possible.");
-                                       return 1;
-                               }
+                               if (InspIRCd::Match(compare, a->format))
+                                       return 0;
                        }
+               }
 
-                       /* Now, search and replace in a copy of the original_line, replacing $1 through $9 and $1- etc */
-
-                       std::string::size_type crlf = i->second.replace_with.find('\n');
+               if ((a->OperOnly) && (!IS_OPER(user)))
+                       return 0;
 
-                       if (crlf == std::string::npos)
+               if (!a->RequiredNick.empty())
+               {
+                       u = ServerInstance->FindNick(a->RequiredNick);
+                       if (!u)
                        {
-                               DoCommand(i->second.replace_with, user, safe);
+                               user->WriteNumeric(401, ""+std::string(user->nick)+" "+a->RequiredNick+" :is currently unavailable. Please try again later.");
                                return 1;
                        }
-                       else
+               }
+               if ((u != NULL) && (!a->RequiredNick.empty()) && (a->ULineOnly))
+               {
+                       if (!ServerInstance->ULine(u->server))
                        {
-                               irc::sepstream commands(i->second.replace_with, '\n');
-                               std::string scommand;
-                               while (commands.GetToken(scommand))
-                               {
-                                       DoCommand(scommand, user, safe);
-                               }
+                               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->WriteNumeric(401, ""+std::string(user->nick)+" "+a->RequiredNick+" :is an imposter! Please inform an IRC operator as soon as possible.");
                                return 1;
                        }
+               }
 
-                       i++;
+               /* Now, search and replace in a copy of the original_line, replacing $1 through $9 and $1- etc */
+
+               std::string::size_type crlf = a->ReplaceFormat.find('\n');
+
+               if (crlf == std::string::npos)
+               {
+                       DoCommand(a->ReplaceFormat, user, c, safe);
+                       return 1;
+               }
+               else
+               {
+                       irc::sepstream commands(a->ReplaceFormat, '\n');
+                       std::string scommand;
+                       while (commands.GetToken(scommand))
+                       {
+                               DoCommand(scommand, user, c, safe);
+                       }
+                       return 1;
                }
-               return 0;
        }
 
-       void DoCommand(std::string newline, User* user, const std::string &original_line)
+       void DoCommand(std::string newline, User* user, Channel *c, const std::string &original_line)
        {
                std::vector<std::string> pars;
 
@@ -250,6 +355,12 @@ class ModuleAlias : public Module
                SearchAndReplace(newline, "$host", user->host);
                SearchAndReplace(newline, "$vhost", user->dhost);
 
+               if (c)
+               {
+                       /* Channel specific variables */
+                       SearchAndReplace(newline, "$chan", c->name);                    
+               }
+
                /* Unescape any variable names in the user text before sending */
                SearchAndReplace(newline, "\r", "$");