]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_namedmodes.cpp
977ac625fbbefc7e20e8bbc2cf5d2d89442c0f71
[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                 ParamModeBase* pm = mh->IsParameterMode();
42                 if (pm)
43                 {
44                         if ((pm->IsParameterSecret()) && (!channel->HasUser(user)) && (!user->HasPrivPermission("channels/auspex")))
45                                 numeric.Add("<" + mh->name + ">");
46                         else
47                                 numeric.Add(channel->GetModeParameter(mh));
48                 }
49         }
50         numeric.Flush();
51         user->WriteNumeric(RPL_ENDOFPROPLIST, channel->name, "End of mode list");
52 }
53
54 class CommandProp : public SplitCommand
55 {
56  public:
57         CommandProp(Module* parent)
58                 : SplitCommand(parent, "PROP", 1)
59         {
60                 syntax = "<channel> [[(+|-)]<mode> [<value>]]";
61         }
62
63         CmdResult HandleLocal(LocalUser* src, const Params& parameters) CXX11_OVERRIDE
64         {
65                 Channel* const chan = ServerInstance->FindChan(parameters[0]);
66                 if (!chan)
67                 {
68                         src->WriteNumeric(Numerics::NoSuchChannel(parameters[0]));
69                         return CMD_FAILURE;
70                 }
71
72                 if (parameters.size() == 1)
73                 {
74                         DisplayList(src, chan);
75                         return CMD_SUCCESS;
76                 }
77                 unsigned int i = 1;
78                 Modes::ChangeList modes;
79                 while (i < parameters.size())
80                 {
81                         std::string prop = parameters[i++];
82                         if (prop.empty())
83                                 continue;
84                         bool plus = prop[0] != '-';
85                         if (prop[0] == '+' || prop[0] == '-')
86                                 prop.erase(prop.begin());
87
88                         ModeHandler* mh = ServerInstance->Modes->FindMode(prop, MODETYPE_CHANNEL);
89                         if (mh)
90                         {
91                                 if (mh->NeedsParam(plus))
92                                 {
93                                         if (i != parameters.size())
94                                                 modes.push(mh, plus, parameters[i++]);
95                                 }
96                                 else
97                                         modes.push(mh, plus);
98                         }
99                 }
100                 ServerInstance->Modes->ProcessSingle(src, chan, NULL, modes, ModeParser::MODE_CHECKACCESS);
101                 return CMD_SUCCESS;
102         }
103 };
104
105 class DummyZ : public ModeHandler
106 {
107  public:
108         DummyZ(Module* parent) : ModeHandler(parent, "namebase", 'Z', PARAM_ALWAYS, MODETYPE_CHANNEL)
109         {
110                 list = true;
111         }
112
113         // Handle /MODE #chan Z
114         void DisplayList(User* user, Channel* chan) CXX11_OVERRIDE
115         {
116                 if (IS_LOCAL(user))
117                         ::DisplayList(static_cast<LocalUser*>(user), chan);
118         }
119 };
120
121 class ModuleNamedModes : public Module
122 {
123         CommandProp cmd;
124         DummyZ dummyZ;
125  public:
126         ModuleNamedModes() : cmd(this), dummyZ(this)
127         {
128         }
129
130         Version GetVersion() CXX11_OVERRIDE
131         {
132                 return Version("Provides the ability to manipulate modes via long names.",VF_VENDOR);
133         }
134
135         void Prioritize() CXX11_OVERRIDE
136         {
137                 ServerInstance->Modules->SetPriority(this, I_OnPreMode, PRIORITY_FIRST);
138         }
139
140         ModResult OnPreMode(User* source, User* dest, Channel* channel, Modes::ChangeList& modes) CXX11_OVERRIDE
141         {
142                 if (!channel)
143                         return MOD_RES_PASSTHRU;
144
145                 Modes::ChangeList::List& list = modes.getlist();
146                 for (Modes::ChangeList::List::iterator i = list.begin(); i != list.end(); )
147                 {
148                         Modes::Change& curr = *i;
149                         // Replace all namebase (dummyZ) modes being changed with the actual
150                         // mode handler and parameter. The parameter format of the namebase mode is
151                         // <modename>[=<parameter>].
152                         if (curr.mh == &dummyZ)
153                         {
154                                 std::string name = curr.param;
155                                 std::string value;
156                                 std::string::size_type eq = name.find('=');
157                                 if (eq != std::string::npos)
158                                 {
159                                         value.assign(name, eq + 1, std::string::npos);
160                                         name.erase(eq);
161                                 }
162
163                                 ModeHandler* mh = ServerInstance->Modes->FindMode(name, MODETYPE_CHANNEL);
164                                 if (!mh)
165                                 {
166                                         // Mode handler not found
167                                         i = list.erase(i);
168                                         continue;
169                                 }
170
171                                 curr.param.clear();
172                                 if (mh->NeedsParam(curr.adding))
173                                 {
174                                         if (value.empty())
175                                         {
176                                                 // Mode needs a parameter but there wasn't one
177                                                 i = list.erase(i);
178                                                 continue;
179                                         }
180
181                                         // Change parameter to the text after the '='
182                                         curr.param = value;
183                                 }
184
185                                 // Put the actual ModeHandler in place of the namebase handler
186                                 curr.mh = mh;
187                         }
188
189                         ++i;
190                 }
191
192                 return MOD_RES_PASSTHRU;
193         }
194 };
195
196 MODULE_INIT(ModuleNamedModes)