]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_namedmodes.cpp
73c5cb521fdc919572e5576ca2a474b8fef6a3da
[user/henk/code/inspircd.git] / src / modules / m_namedmodes.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
5  *
6  * This file is part of InspIRCd.  InspIRCd is free software: you can
7  * redistribute it and/or modify it under the terms of the GNU General Public
8  * License as published by the Free Software Foundation, version 2.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
13  * details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19
20 #include "inspircd.h"
21
22 enum
23 {
24         // InspIRCd-specific.
25         RPL_ENDOFPROPLIST = 960,
26         RPL_PROPLIST = 961
27 };
28
29 static void DisplayList(LocalUser* user, Channel* channel)
30 {
31         Numeric::ParamBuilder<1> numeric(user, RPL_PROPLIST);
32         numeric.AddStatic(channel->name);
33
34         const ModeParser::ModeHandlerMap& mhs = ServerInstance->Modes->GetModes(MODETYPE_CHANNEL);
35         for (ModeParser::ModeHandlerMap::const_iterator i = mhs.begin(); i != mhs.end(); ++i)
36         {
37                 ModeHandler* mh = i->second;
38                 if (!channel->IsModeSet(mh))
39                         continue;
40                 numeric.Add("+" + mh->name);
41                 if (mh->NeedsParam(true))
42                 {
43                         if ((mh->name == "key") && (!channel->HasUser(user)) && (!user->HasPrivPermission("channels/auspex")))
44                                 numeric.Add("<key>");
45                         else
46                                 numeric.Add(channel->GetModeParameter(mh));
47                 }
48         }
49         numeric.Flush();
50         user->WriteNumeric(RPL_ENDOFPROPLIST, channel->name, "End of mode list");
51 }
52
53 class CommandProp : public SplitCommand
54 {
55  public:
56         CommandProp(Module* parent)
57                 : SplitCommand(parent, "PROP", 1)
58         {
59                 syntax = "<user|channel> {[+-]<mode> [<value>]}*";
60         }
61
62         CmdResult HandleLocal(const std::vector<std::string>& parameters, LocalUser* src) CXX11_OVERRIDE
63         {
64                 Channel* const chan = ServerInstance->FindChan(parameters[0]);
65                 if (!chan)
66                 {
67                         src->WriteNumeric(Numerics::NoSuchChannel(parameters[0]));
68                         return CMD_FAILURE;
69                 }
70
71                 if (parameters.size() == 1)
72                 {
73                         DisplayList(src, chan);
74                         return CMD_SUCCESS;
75                 }
76                 unsigned int i = 1;
77                 Modes::ChangeList modes;
78                 while (i < parameters.size())
79                 {
80                         std::string prop = parameters[i++];
81                         if (prop.empty())
82                                 continue;
83                         bool plus = prop[0] != '-';
84                         if (prop[0] == '+' || prop[0] == '-')
85                                 prop.erase(prop.begin());
86
87                         ModeHandler* mh = ServerInstance->Modes->FindMode(prop, MODETYPE_CHANNEL);
88                         if (mh)
89                         {
90                                 if (mh->NeedsParam(plus))
91                                 {
92                                         if (i != parameters.size())
93                                                 modes.push(mh, plus, parameters[i++]);
94                                 }
95                                 else
96                                         modes.push(mh, plus);
97                         }
98                 }
99                 ServerInstance->Modes->ProcessSingle(src, chan, NULL, modes, ModeParser::MODE_CHECKACCESS);
100                 return CMD_SUCCESS;
101         }
102 };
103
104 class DummyZ : public ModeHandler
105 {
106  public:
107         DummyZ(Module* parent) : ModeHandler(parent, "namebase", 'Z', PARAM_ALWAYS, MODETYPE_CHANNEL)
108         {
109                 list = true;
110         }
111
112         // Handle /MODE #chan Z
113         void DisplayList(User* user, Channel* chan) CXX11_OVERRIDE
114         {
115                 if (IS_LOCAL(user))
116                         ::DisplayList(static_cast<LocalUser*>(user), chan);
117         }
118 };
119
120 class ModuleNamedModes : public Module
121 {
122         CommandProp cmd;
123         DummyZ dummyZ;
124  public:
125         ModuleNamedModes() : cmd(this), dummyZ(this)
126         {
127         }
128
129         Version GetVersion() CXX11_OVERRIDE
130         {
131                 return Version("Provides the ability to manipulate modes via long names.",VF_VENDOR);
132         }
133
134         void Prioritize() CXX11_OVERRIDE
135         {
136                 ServerInstance->Modules->SetPriority(this, I_OnPreMode, PRIORITY_FIRST);
137         }
138
139         ModResult OnPreMode(User* source, User* dest, Channel* channel, Modes::ChangeList& modes) CXX11_OVERRIDE
140         {
141                 if (!channel)
142                         return MOD_RES_PASSTHRU;
143
144                 Modes::ChangeList::List& list = modes.getlist();
145                 for (Modes::ChangeList::List::iterator i = list.begin(); i != list.end(); )
146                 {
147                         Modes::Change& curr = *i;
148                         // Replace all namebase (dummyZ) modes being changed with the actual
149                         // mode handler and parameter. The parameter format of the namebase mode is
150                         // <modename>[=<parameter>].
151                         if (curr.mh == &dummyZ)
152                         {
153                                 std::string name = curr.param;
154                                 std::string value;
155                                 std::string::size_type eq = name.find('=');
156                                 if (eq != std::string::npos)
157                                 {
158                                         value.assign(name, eq + 1, std::string::npos);
159                                         name.erase(eq);
160                                 }
161
162                                 ModeHandler* mh = ServerInstance->Modes->FindMode(name, MODETYPE_CHANNEL);
163                                 if (!mh)
164                                 {
165                                         // Mode handler not found
166                                         i = list.erase(i);
167                                         continue;
168                                 }
169
170                                 curr.param.clear();
171                                 if (mh->NeedsParam(curr.adding))
172                                 {
173                                         if (value.empty())
174                                         {
175                                                 // Mode needs a parameter but there wasn't one
176                                                 i = list.erase(i);
177                                                 continue;
178                                         }
179
180                                         // Change parameter to the text after the '='
181                                         curr.param = value;
182                                 }
183
184                                 // Put the actual ModeHandler in place of the namebase handler
185                                 curr.mh = mh;
186                         }
187
188                         ++i;
189                 }
190
191                 return MOD_RES_PASSTHRU;
192         }
193 };
194
195 MODULE_INIT(ModuleNamedModes)