]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_namedmodes.cpp
Fix left/right inversion in ListDifference
[user/henk/code/inspircd.git] / src / modules / m_namedmodes.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2010 InspIRCd Development Team
6  * See: http://wiki.inspircd.org/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 static void DisplayList(User* user, Channel* channel)
17 {
18         std::stringstream items;
19         for(char letter = 'A'; letter <= 'z'; letter++)
20         {
21                 ModeHandler* mh = ServerInstance->Modes->FindMode(letter, MODETYPE_CHANNEL);
22                 if (!mh || mh->IsListMode())
23                         continue;
24                 if (!channel->IsModeSet(letter))
25                         continue;
26                 std::string item = mh->name;
27                 if (mh->GetNumParams(true))
28                         item += "=" + channel->GetModeParameter(letter);
29                 items << item << " ";
30         }
31         char pfx[MAXBUF];
32         snprintf(pfx, MAXBUF, ":%s 961 %s %s", ServerInstance->Config->ServerName.c_str(), user->nick.c_str(), channel->name.c_str());
33         user->SendText(std::string(pfx), items);
34         user->WriteNumeric(960, "%s %s :End of mode list", user->nick.c_str(), channel->name.c_str());
35 }
36
37 class CommandProp : public Command
38 {
39  public:
40         CommandProp(Module* parent) : Command(parent, "PROP", 1)
41         {
42                 syntax = "<user|channel> [{+|-}<mode>[=value]]";
43                 TRANSLATE3(TR_TEXT, TR_TEXT, TR_END);
44         }
45
46         CmdResult Handle(const std::vector<std::string> &parameters, User *src)
47         {
48                 if (parameters.size() == 1)
49                 {
50                         Channel* chan = ServerInstance->FindChan(parameters[0]);
51                         if (chan)
52                                 DisplayList(src, chan);
53                         return CMD_SUCCESS;
54                 }
55
56                 std::string prop = parameters[1], value;
57                 std::string::size_type eq = prop.find('=');
58                 if (eq != std::string::npos)
59                 {
60                         value = prop.substr(eq + 1);
61                         prop = prop.substr(0, eq);
62                 }
63                 bool plus = prop[0] != '-';
64                 if (prop[0] == '+' || prop[0] == '-')
65                         prop.erase(prop.begin());
66
67                 for(char letter = 'A'; letter <= 'z'; letter++)
68                 {
69                         ModeHandler* mh = ServerInstance->Modes->FindMode(letter, MODETYPE_CHANNEL);
70                         if (mh && mh->name == prop)
71                         {
72                                 if (mh->GetNumParams(plus) && value.empty())
73                                         return CMD_FAILURE;
74                                 std::vector<std::string> modes;
75                                 modes.push_back(parameters[0]);
76                                 modes.push_back((plus ? "+" : "-") + std::string(1, letter));
77                                 modes.push_back(value);
78                                 ServerInstance->SendGlobalMode(modes, src);
79                                 return CMD_SUCCESS;
80                         }
81                 }
82                 return CMD_FAILURE;
83         }
84 };
85
86 class ModuleNamedModes : public Module
87 {
88         CommandProp cmd;
89  public:
90         ModuleNamedModes() : cmd(this)
91         {
92         }
93
94         void init()
95         {
96                 ServerInstance->Modules->AddService(cmd);
97                 Implementation eventlist[] = { I_OnPreMode, I_On005Numeric };
98                 ServerInstance->Modules->Attach(eventlist, this, 2);
99         }
100
101         Version GetVersion()
102         {
103                 return Version("Provides the ability to manipulate modes via long names.",VF_VENDOR);
104         }
105
106         void Prioritize()
107         {
108                 ServerInstance->Modules->SetPriority(this, I_OnPreMode, PRIORITY_FIRST);
109         }
110
111         void On005Numeric(std::string& line)
112         {
113                 std::string::size_type pos = line.find(" CHANMODES=");
114                 if (pos != std::string::npos)
115                 {
116                         pos += 11;
117                         while (line[pos] > 'A' && line[pos] < 'Z')
118                                 pos++;
119                         line.insert(pos, 1, 'Z');
120                 }
121         }
122
123         ModResult OnPreMode(User* source, User* dest, Channel* channel, const std::vector<std::string>& parameters)
124         {
125                 if (!channel)
126                         return MOD_RES_PASSTHRU;
127                 if (parameters[1].find('Z') == std::string::npos)
128                         return MOD_RES_PASSTHRU;
129                 if (parameters.size() <= 2)
130                 {
131                         DisplayList(source, channel);
132                         return MOD_RES_DENY;
133                 }
134
135                 std::vector<std::string> newparms;
136                 newparms.push_back(parameters[0]);
137                 newparms.push_back(parameters[1]);
138
139                 std::string modelist = newparms[1];
140                 bool adding = true;
141                 unsigned int param_at = 2;
142                 for(unsigned int i = 0; i < modelist.length(); i++)
143                 {
144                         unsigned char modechar = modelist[i];
145                         if (modechar == '+' || modechar == '-')
146                         {
147                                 adding = (modechar == '+');
148                                 continue;
149                         }
150                         ModeHandler *mh = ServerInstance->Modes->FindMode(modechar, MODETYPE_CHANNEL);
151                         if (modechar == 'Z')
152                         {
153                                 modechar = 0;
154                                 std::string name, value;
155                                 if (param_at < parameters.size())
156                                         name = parameters[param_at++];
157                                 std::string::size_type eq = name.find('=');
158                                 if (eq != std::string::npos)
159                                 {
160                                         value = name.substr(eq + 1);
161                                         name = name.substr(0, eq);
162                                 }
163                                 for(char letter = 'A'; modechar == 0 && letter <= 'z'; letter++)
164                                 {
165                                         mh = ServerInstance->Modes->FindMode(letter, MODETYPE_CHANNEL);
166                                         if (mh && mh->name == name)
167                                         {
168                                                 if (mh->GetNumParams(adding))
169                                                 {
170                                                         if (!value.empty())
171                                                         {
172                                                                 newparms.push_back(value);
173                                                                 modechar = letter;
174                                                                 break;
175                                                         }
176                                                 }
177                                                 else
178                                                 {
179                                                         modechar = letter;
180                                                         break;
181                                                 }
182                                         }
183                                 }
184                                 if (modechar)
185                                         modelist[i] = modechar;
186                                 else
187                                         modelist.erase(i--, 1);
188                         }
189                         else if (mh && mh->GetNumParams(adding) && param_at < parameters.size())
190                         {
191                                 newparms.push_back(parameters[param_at++]);
192                         }
193                 }
194                 newparms[1] = modelist;
195                 ServerInstance->Modes->Process(newparms, source, false);
196                 return MOD_RES_DENY;
197         }
198 };
199
200 MODULE_INIT(ModuleNamedModes)