]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_operprefix.cpp
Make an error message more verbose to help users
[user/henk/code/inspircd.git] / src / modules / m_operprefix.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 /* 
15    by Chernov-Phoenix Alexey (Phoenix@RusNet) mailto:phoenix /email address separator/ pravmail.ru */
16
17 #include "inspircd.h"
18
19 static char prefixchar;
20
21 std::set<std::string>* SetupExt(User* user)
22 {
23         std::set<std::string>* ext;
24         if (!user->GetExt("m_operprefix",ext))
25         {
26                 ext=new std::set<std::string>;
27                 ext->clear();
28                 user->Extend("m_operprefix",ext);
29         }
30         return ext;
31 }
32
33
34 void DelPrefixChan(User* user, Channel* channel)
35 {
36         std::set<std::string>* chans = SetupExt(user);
37         chans->erase(channel->name);
38 }
39
40
41 void AddPrefixChan(User* user, Channel* channel)
42 {
43         std::set<std::string>* chans = SetupExt(user);
44         chans->insert(channel->name);
45 }
46
47
48 class OperPrefixMode : public ModeHandler
49 {
50         public:
51                 OperPrefixMode(InspIRCd* Instance) : ModeHandler(Instance, 'y', 1, 1, true, MODETYPE_CHANNEL, false, prefixchar) { }
52
53                 unsigned int GetPrefixRank()
54                 {
55                         return 40000;
56                 }
57
58                 ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding, bool servermode)
59                 {
60                         if (servermode || (source && ServerInstance->ULine(source->server)))
61                                 return MODEACTION_ALLOW;
62                         else
63                         {
64                                 if (source && channel)
65                                         source->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Only servers are permitted to change channel mode '%c'", source->nick.c_str(), channel->name.c_str(), 'y');
66                                 return MODEACTION_DENY;
67                         }
68                 }
69
70                 ModePair ModeSet(User* source, User* dest, Channel* channel, const std::string &parameter)
71                 {
72                         User* x = ServerInstance->FindNick(parameter);
73                         if (x)
74                         {
75                                 if (!channel->HasUser(x))
76                                 {
77                                         return std::make_pair(false, parameter);
78                                 }
79                                 else
80                                 {
81                                         std::set<std::string>* ext;
82                                         if (x->GetExt("m_operprefix",ext))
83                                         {
84                                                 if (ext->find(channel->name)!=ext->end())
85                                                 {
86                                                         return std::make_pair(true, x->nick);
87                                                 }
88                                                 else
89                                                         return std::make_pair(false, parameter);
90                                         }
91                                         else
92                                         {
93                                                 return std::make_pair(false, parameter);
94                                         }
95                                 }
96                         }
97                         return std::make_pair(false, parameter);
98                 }
99
100                 bool NeedsOper() { return true; }
101 };
102
103 class ModuleOperPrefixMode : public Module
104 {
105  private:
106         OperPrefixMode* opm;
107  public:
108         ModuleOperPrefixMode(InspIRCd* Me) : Module(Me)
109         {
110                 ConfigReader Conf(ServerInstance);
111                 std::string tmp;
112                 tmp = Conf.ReadValue("operprefix", "prefix", "!", 0, false);
113                 strlcpy(&prefixchar,tmp.c_str(),2);
114
115                 opm = new OperPrefixMode(ServerInstance);
116                 if ((!ServerInstance->Modes->AddMode(opm)))
117                         throw ModuleException("Could not add a new mode!");
118                         
119                 Implementation eventlist[] = { I_OnPostJoin, I_OnCleanup, I_OnUserQuit, I_OnUserKick, I_OnUserPart };
120                 ServerInstance->Modules->Attach(eventlist, this, 5);
121         }
122
123         virtual void PushChanMode(Channel* channel, User* user, bool negate = false)
124         {
125                 if (negate)
126                         DelPrefixChan(user, channel);
127                 else
128                         AddPrefixChan(user, channel);
129                 char modeline[]="+y";
130                 if (negate)
131                         modeline [0]='-';
132                 std::vector<std::string> modechange;
133                 modechange.push_back(channel->name);
134                 modechange.push_back(modeline);
135                 modechange.push_back(user->nick);
136                 ServerInstance->SendMode(modechange,this->ServerInstance->FakeClient);
137         }
138
139         virtual void OnPostJoin(User *user, Channel *channel)
140         {
141                 // This may look wrong, but I don't think it is.. PushChanMode will send FMODE which should sort it all out.
142                 if (!IS_LOCAL(user))
143                         return;
144
145                 if (user && IS_OPER(user))
146                 {
147                         if (user->IsModeSet('H'))
148                         {
149                                 /* we respect your wish to be invisible */
150                                 return;
151                         }
152                         PushChanMode(channel, user);
153                 }
154         }
155
156         // XXX: is there a better way to do this?
157         virtual int OnRawMode(User* user, Channel* chan, const char mode, const std::string &param, bool adding, int pcnt, bool servermode)
158         {
159                 /* force event propagation to its ModeHandler */
160                 if (!servermode && chan && (mode == 'y'))
161                         return ACR_ALLOW;
162                 return 0;
163         }
164
165         virtual ~ModuleOperPrefixMode()
166         {
167                 ServerInstance->Modes->DelMode(opm);
168                 delete opm;
169         }
170
171         virtual void CleanUser(User* user, bool quitting=false)
172         {
173                 if (!IS_LOCAL(user))
174                         return;
175
176                 std::set<std::string>* ext;
177                 if (user->GetExt("m_operprefix",ext))
178                 {
179                         // Don't want to announce -mode when they're quitting anyway..
180                         if (!quitting)
181                         {
182                                 for (UCListIter v = user->chans.begin(); v != user->chans.end(); v++)
183                                 {
184                                         ModePair ms=opm->ModeSet(NULL, NULL , v->first, user->nick);
185                                         if (ms.first)
186                                         {
187                                                 PushChanMode(v->first, user, true);
188                                         }
189                                 }
190                         }
191                         ext->clear();
192                         delete ext;
193                         user->Shrink("m_operprefix");
194                 }
195         }
196
197         virtual void OnCleanup(int target_type, void* item)
198         {
199                 if (target_type == TYPE_USER)
200                 {
201                         User* user = (User*)item;
202                         CleanUser(user);
203                 }
204         }
205
206         virtual void OnUserQuit(User* user, const std::string &reason, const std::string &oper_message)
207         {
208                 CleanUser(user,true);
209         }
210
211         virtual void OnUserKick(User* source, User* user, Channel* chan, const std::string &reason, bool &silent)
212         {
213                 DelPrefixChan(user, chan);
214         }
215
216         virtual void OnUserPart(User* user, Channel* channel, std::string &partreason, bool &silent)
217         {
218                 DelPrefixChan(user, channel);
219         }
220
221         virtual Version GetVersion()
222         {
223                 return Version("$Id$", VF_COMMON, API_VERSION);
224         }
225 };
226
227 MODULE_INIT(ModuleOperPrefixMode)
228