]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_namedmodes.cpp
af520080fe6651b61b96b1003b91c01e36ed754e
[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                 LocalUser* luser = IS_LOCAL(user);
117                 if (luser)
118                         ::DisplayList(luser, chan);
119         }
120 };
121
122 class ModuleNamedModes : public Module
123 {
124         CommandProp cmd;
125         DummyZ dummyZ;
126  public:
127         ModuleNamedModes() : cmd(this), dummyZ(this)
128         {
129         }
130
131         Version GetVersion() CXX11_OVERRIDE
132         {
133                 return Version("Provides the ability to manipulate modes via long names", VF_VENDOR);
134         }
135
136         void Prioritize() CXX11_OVERRIDE
137         {
138                 ServerInstance->Modules->SetPriority(this, I_OnPreMode, PRIORITY_FIRST);
139         }
140
141         ModResult OnPreMode(User* source, User* dest, Channel* channel, Modes::ChangeList& modes) CXX11_OVERRIDE
142         {
143                 if (!channel)
144                         return MOD_RES_PASSTHRU;
145
146                 Modes::ChangeList::List& list = modes.getlist();
147                 for (Modes::ChangeList::List::iterator i = list.begin(); i != list.end(); )
148                 {
149                         Modes::Change& curr = *i;
150                         // Replace all namebase (dummyZ) modes being changed with the actual
151                         // mode handler and parameter. The parameter format of the namebase mode is
152                         // <modename>[=<parameter>].
153                         if (curr.mh == &dummyZ)
154                         {
155                                 std::string name = curr.param;
156                                 std::string value;
157                                 std::string::size_type eq = name.find('=');
158                                 if (eq != std::string::npos)
159                                 {
160                                         value.assign(name, eq + 1, std::string::npos);
161                                         name.erase(eq);
162                                 }
163
164                                 ModeHandler* mh = ServerInstance->Modes->FindMode(name, MODETYPE_CHANNEL);
165                                 if (!mh)
166                                 {
167                                         // Mode handler not found
168                                         i = list.erase(i);
169                                         continue;
170                                 }
171
172                                 curr.param.clear();
173                                 if (mh->NeedsParam(curr.adding))
174                                 {
175                                         if (value.empty())
176                                         {
177                                                 // Mode needs a parameter but there wasn't one
178                                                 i = list.erase(i);
179                                                 continue;
180                                         }
181
182                                         // Change parameter to the text after the '='
183                                         curr.param = value;
184                                 }
185
186                                 // Put the actual ModeHandler in place of the namebase handler
187                                 curr.mh = mh;
188                         }
189
190                         ++i;
191                 }
192
193                 return MOD_RES_PASSTHRU;
194         }
195 };
196
197 MODULE_INIT(ModuleNamedModes)