]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_operprefix.cpp
838cf5fcaa00ab6d5efb8b4e1e43f0c07f24445e
[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                 ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding, bool servermode)
54                 {
55                         if (servermode || (source && ServerInstance->ULine(source->server)))
56                                 return MODEACTION_ALLOW;
57                         else
58                         {
59                                 if (source && channel)
60                                         source->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Only servers are permitted to change channel mode '%c'", source->nick.c_str(), channel->name.c_str(), 'y');
61                                 return MODEACTION_DENY;
62                         }
63                 }
64
65                 ModePair ModeSet(User* source, User* dest, Channel* channel, const std::string &parameter)
66                 {
67                         User* x = ServerInstance->FindNick(parameter);
68                         if (x)
69                         {
70                                 if (!channel->HasUser(x))
71                                 {
72                                         return std::make_pair(false, parameter);
73                                 }
74                                 else
75                                 {
76                                         std::set<std::string>* ext;
77                                         if (x->GetExt("m_operprefix",ext))
78                                         {
79                                                 if (ext->find(channel->name)!=ext->end())
80                                                 {
81                                                         return std::make_pair(true, x->nick);
82                                                 }
83                                                 else
84                                                         return std::make_pair(false, parameter);
85                                         }
86                                         else
87                                         {
88                                                 return std::make_pair(false, parameter);
89                                         }
90                                 }
91                         }
92                         return std::make_pair(false, parameter);
93                 }
94
95                 bool NeedsOper() { return true; }
96 };
97
98 class ModuleOperPrefixMode : public Module
99 {
100  private:
101         OperPrefixMode* opm;
102  public:
103         ModuleOperPrefixMode(InspIRCd* Me) : Module(Me)
104         {
105                 ConfigReader Conf(ServerInstance);
106                 std::string tmp;
107                 tmp = Conf.ReadValue("operprefix", "prefix", "!", 0, false);
108                 strlcpy(&prefixchar,tmp.c_str(),2);
109
110                 opm = new OperPrefixMode(ServerInstance);
111                 if ((!ServerInstance->Modes->AddMode(opm)))
112                         throw ModuleException("Could not add a new mode!");
113                         
114                 Implementation eventlist[] = { I_OnPostJoin, I_OnCleanup, I_OnUserQuit, I_OnUserKick, I_OnUserPart };
115                 ServerInstance->Modules->Attach(eventlist, this, 6);
116         }
117
118         virtual void PushChanMode(Channel* channel, User* user, bool negate = false)
119         {
120                 if (negate)
121                         DelPrefixChan(user, channel);
122                 else
123                         AddPrefixChan(user, channel);
124                 char modeline[]="+y";
125                 if (negate)
126                         modeline [0]='-';
127                 std::vector<std::string> modechange;
128                 modechange.push_back(channel->name);
129                 modechange.push_back(modeline);
130                 modechange.push_back(user->nick);
131                 ServerInstance->SendMode(modechange,this->ServerInstance->FakeClient);
132         }
133
134         virtual void OnPostJoin(User *user, Channel *channel)
135         {
136                 // This may look wrong, but I don't think it is.. PushChanMode will send FMODE which should sort it all out.
137                 if (!IS_LOCAL(user))
138                         return;
139
140                 if (user && IS_OPER(user))
141                 {
142                         if (user->IsModeSet('H'))
143                         {
144                                 /* we respect your wish to be invisible */
145                                 return;
146                         }
147                         PushChanMode(channel, user);
148                 }
149         }
150
151         // XXX: is there a better way to do this?
152         virtual int OnRawMode(User* user, Channel* chan, const char mode, const std::string &param, bool adding, int pcnt, bool servermode)
153         {
154                 /* force event propagation to its ModeHandler */
155                 if (!servermode && chan && (mode == 'y'))
156                         return ACR_ALLOW;
157                 return 0;
158         }
159
160         virtual ~ModuleOperPrefixMode()
161         {
162                 ServerInstance->Modes->DelMode(opm);
163                 delete opm;
164         }
165
166         virtual void CleanUser(User* user, bool quitting=false)
167         {
168                 if (!IS_LOCAL(user))
169                         return;
170
171                 std::set<std::string>* ext;
172                 if (user->GetExt("m_operprefix",ext))
173                 {
174                         // Don't want to announce -mode when they're quitting anyway..
175                         if (!quitting)
176                         {
177                                 for (UCListIter v = user->chans.begin(); v != user->chans.end(); v++)
178                                 {
179                                         ModePair ms=opm->ModeSet(NULL, NULL , v->first, user->nick);
180                                         if (ms.first)
181                                         {
182                                                 PushChanMode(v->first, user, true);
183                                         }
184                                 }
185                         }
186                         ext->clear();
187                         delete ext;
188                         user->Shrink("m_operprefix");
189                 }
190         }
191
192         virtual void OnCleanup(int target_type, void* item)
193         {
194                 if (target_type == TYPE_USER)
195                 {
196                         User* user = (User*)item;
197                         CleanUser(user);
198                 }
199         }
200
201         virtual void OnUserQuit(User* user, const std::string &reason, const std::string &oper_message)
202         {
203                 CleanUser(user,true);
204         }
205
206         virtual void OnUserKick(User* source, User* user, Channel* chan, const std::string &reason, bool &silent)
207         {
208                 DelPrefixChan(user, chan);
209         }
210
211         virtual void OnUserPart(User* user, Channel* channel, std::string &partreason, bool &silent)
212         {
213                 DelPrefixChan(user, channel);
214         }
215
216         virtual Version GetVersion()
217         {
218                 return Version("$Id$", VF_COMMON, API_VERSION);
219         }
220 };
221
222 MODULE_INIT(ModuleOperPrefixMode)
223