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