]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_alias.cpp
Modify aliases to use a multimap rather than a vector for storage + a map for quick...
[user/henk/code/inspircd.git] / src / modules / m_alias.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 #include "inspircd.h"
15
16 /* $ModDesc: Provides aliases of commands. */
17
18 /** An alias definition
19  */
20 class Alias : public classbase
21 {
22  public:
23         /** The text of the alias command */
24         irc::string text;
25         /** Text to replace with */
26         std::string replace_with;
27         /** Nickname required to perform alias */
28         std::string requires;
29         /** Alias requires ulined server */
30         bool uline;
31         /** Requires oper? */
32         bool operonly;
33         /* is case sensitive params */
34         bool case_sensitive;
35         /** Format that must be matched for use */
36         std::string format;
37 };
38
39 class ModuleAlias : public Module
40 {
41  private:
42         /* We cant use a map, there may be multiple aliases with the same name.
43          * We can, however, use a fancy invention: the multimap. Maps a key to one or more values.
44          *              -- w00t
45    */
46         std::multimap<std::string, Alias> Aliases;
47
48         virtual void ReadAliases()
49         {
50                 ConfigReader MyConf(ServerInstance);
51
52                 Aliases.clear();
53                 for (int i = 0; i < MyConf.Enumerate("alias"); i++)
54                 {
55                         Alias a;
56                         std::string txt;
57                         txt = MyConf.ReadValue("alias", "text", i);
58                         a.text = txt.c_str();
59                         a.replace_with = MyConf.ReadValue("alias", "replace", i, true);
60                         a.requires = MyConf.ReadValue("alias", "requires", i);
61                         a.uline = MyConf.ReadFlag("alias", "uline", i);
62                         a.operonly = MyConf.ReadFlag("alias", "operonly", i);
63                         a.format = MyConf.ReadValue("alias", "format", i);
64                         a.case_sensitive = MyConf.ReadFlag("alias", "matchcase", i);
65                         Aliases.insert(std::make_pair(txt, a));
66                 }
67         }
68
69  public:
70
71         ModuleAlias(InspIRCd* Me)
72                 : Module(Me)
73         {
74                 ReadAliases();
75                 Me->Modules->Attach(I_OnPreCommand, this);
76                 Me->Modules->Attach(I_OnRehash, this);
77
78         }
79
80         virtual ~ModuleAlias()
81         {
82         }
83
84         virtual Version GetVersion()
85         {
86                 return Version("$Id$", VF_VENDOR,API_VERSION);
87         }
88
89         std::string GetVar(std::string varname, const std::string &original_line)
90         {
91                 irc::spacesepstream ss(original_line);
92                 varname.erase(varname.begin());
93                 int index = *(varname.begin()) - 48;
94                 varname.erase(varname.begin());
95                 bool everything_after = (varname == "-");
96                 std::string word;
97
98                 for (int j = 0; j < index; j++)
99                         ss.GetToken(word);
100
101                 if (everything_after)
102                 {
103                         std::string more;
104                         while (ss.GetToken(more))
105                         {
106                                 word.append(" ");
107                                 word.append(more);
108                         }
109                 }
110
111                 return word;
112         }
113
114         void SearchAndReplace(std::string& newline, const std::string &find, const std::string &replace)
115         {
116                 std::string::size_type x = newline.find(find);
117                 while (x != std::string::npos)
118                 {
119                         newline.erase(x, find.length());
120                         newline.insert(x, replace);
121                         x = newline.find(find);
122                 }
123         }
124
125         virtual int OnPreCommand(std::string &command, std::vector<std::string> &parameters, User *user, bool validated, const std::string &original_line)
126         {
127                 User *u = NULL;
128                 std::multimap<std::string, Alias>::iterator i;
129
130                 /* If theyre not registered yet, we dont want
131                  * to know.
132                  */
133                 if (user->registered != REG_ALL)
134                         return 0;
135
136                 /* We dont have any commands looking like this? Stop processing. */
137                 i = Aliases.find(command);
138                 if (i == Aliases.end())
139                         return 0;
140
141                 irc::string c = command.c_str();
142                 /* The parameters for the command in their original form, with the command stripped off */
143                 std::string compare = original_line.substr(command.length());
144                 while (*(compare.c_str()) == ' ')
145                         compare.erase(compare.begin());
146
147                 std::string safe(original_line);
148
149                 /* Escape out any $ symbols in the user provided text */
150
151                 SearchAndReplace(safe, "$", "\r");
152
153                 while (i != Aliases.end())
154                 {
155                         /* Does it match the pattern? */
156                         if (!i->second.format.empty())
157                         {
158                                 if (i->second.case_sensitive)
159                                 {
160                                         if (InspIRCd::Match(compare, i->second.format, case_sensitive_map))
161                                                 continue;
162                                 }
163                                 else
164                                 {
165                                         if (InspIRCd::Match(compare, i->second.format))
166                                                 continue;
167                                 }
168                         }
169
170                         if ((i->second.operonly) && (!IS_OPER(user)))
171                                 return 0;
172
173                         if (!i->second.requires.empty())
174                         {
175                                 u = ServerInstance->FindNick(i->second.requires);
176                                 if (!u)
177                                 {
178                                         user->WriteNumeric(401, ""+std::string(user->nick)+" "+i->second.requires+" :is currently unavailable. Please try again later.");
179                                         return 1;
180                                 }
181                         }
182                         if ((u != NULL) && (!i->second.requires.empty()) && (i->second.uline))
183                         {
184                                 if (!ServerInstance->ULine(u->server))
185                                 {
186                                         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!");
187                                         user->WriteNumeric(401, ""+std::string(user->nick)+" "+i->second.requires+" :is an imposter! Please inform an IRC operator as soon as possible.");
188                                         return 1;
189                                 }
190                         }
191
192                         /* Now, search and replace in a copy of the original_line, replacing $1 through $9 and $1- etc */
193
194                         std::string::size_type crlf = i->second.replace_with.find('\n');
195
196                         if (crlf == std::string::npos)
197                         {
198                                 DoCommand(i->second.replace_with, user, safe);
199                                 return 1;
200                         }
201                         else
202                         {
203                                 irc::sepstream commands(i->second.replace_with, '\n');
204                                 std::string scommand;
205                                 while (commands.GetToken(scommand))
206                                 {
207                                         DoCommand(scommand, user, safe);
208                                 }
209                                 return 1;
210                         }
211
212                         i++;
213                 }
214                 return 0;
215         }
216
217         void DoCommand(std::string newline, User* user, const std::string &original_line)
218         {
219                 std::vector<std::string> pars;
220
221                 for (int v = 1; v < 10; v++)
222                 {
223                         std::string var = "$";
224                         var.append(ConvToStr(v));
225                         var.append("-");
226                         std::string::size_type x = newline.find(var);
227
228                         while (x != std::string::npos)
229                         {
230                                 newline.erase(x, var.length());
231                                 newline.insert(x, GetVar(var, original_line));
232                                 x = newline.find(var);
233                         }
234
235                         var = "$";
236                         var.append(ConvToStr(v));
237                         x = newline.find(var);
238
239                         while (x != std::string::npos)
240                         {
241                                 newline.erase(x, var.length());
242                                 newline.insert(x, GetVar(var, original_line));
243                                 x = newline.find(var);
244                         }
245                 }
246
247                 /* Special variables */
248                 SearchAndReplace(newline, "$nick", user->nick);
249                 SearchAndReplace(newline, "$ident", user->ident);
250                 SearchAndReplace(newline, "$host", user->host);
251                 SearchAndReplace(newline, "$vhost", user->dhost);
252
253                 /* Unescape any variable names in the user text before sending */
254                 SearchAndReplace(newline, "\r", "$");
255
256                 irc::tokenstream ss(newline);
257                 pars.clear();
258                 std::string command, token;
259
260                 ss.GetToken(command);
261                 while (ss.GetToken(token) && (pars.size() <= MAXPARAMETERS))
262                 {
263                         pars.push_back(token);
264                 }
265                 ServerInstance->Parser->CallHandler(command, pars, user);
266         }
267
268         virtual void OnRehash(User* user, const std::string &parameter)
269         {
270                 ReadAliases();
271         }
272 };
273
274 MODULE_INIT(ModuleAlias)