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