]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_services_account.cpp
Missed another
[user/henk/code/inspircd.git] / src / modules / m_services_account.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 #include "inspircd.h"
15 #include "account.h"
16
17 /* $ModDesc: Povides support for ircu-style services accounts, including chmode +R, etc. */
18
19 /** Channel mode +R - unidentified users cannot join
20  */
21 class AChannel_R : public SimpleChannelModeHandler
22 {
23  public:
24         AChannel_R(InspIRCd* Instance) : SimpleChannelModeHandler(Instance, 'R') { }
25 };
26
27 /** User mode +R - unidentified users cannot message
28  */
29 class AUser_R : public SimpleUserModeHandler
30 {
31  public:
32         AUser_R(InspIRCd* Instance) : SimpleUserModeHandler(Instance, 'R') { }
33 };
34
35 /** Channel mode +M - unidentified users cannot message channel
36  */
37 class AChannel_M : public SimpleChannelModeHandler
38 {
39  public:
40         AChannel_M(InspIRCd* Instance) : SimpleChannelModeHandler(Instance, 'M') { }
41 };
42
43 class ModuleServicesAccount : public Module
44 {
45
46         AChannel_R* m1;
47         AChannel_M* m2;
48         AUser_R* m3;
49  public:
50         ModuleServicesAccount(InspIRCd* Me) : Module(Me)
51         {
52
53                 m1 = new AChannel_R(ServerInstance);
54                 m2 = new AChannel_M(ServerInstance);
55                 m3 = new AUser_R(ServerInstance);
56                 if (!ServerInstance->Modes->AddMode(m1) || !ServerInstance->Modes->AddMode(m2) || !ServerInstance->Modes->AddMode(m3))
57                         throw ModuleException("Could not add new modes!");
58
59                 Implementation eventlist[] = { I_OnWhois, I_OnUserPreMessage, I_OnUserPreNotice, I_OnUserPreJoin,
60                         I_OnSyncUserMetaData, I_OnUserQuit, I_OnCleanup, I_OnDecodeMetaData, I_On005Numeric };
61
62                 ServerInstance->Modules->Attach(eventlist, this, 9);
63         }
64
65         virtual void On005Numeric(std::string &t)
66         {
67                 ServerInstance->AddExtBanChar('R');
68                 ServerInstance->AddExtBanChar('M');
69         }
70
71         /* <- :twisted.oscnet.org 330 w00t2 w00t2 w00t :is logged in as */
72         virtual void OnWhois(User* source, User* dest)
73         {
74                 std::string *account;
75                 dest->GetExt("accountname", account);
76
77                 if (account)
78                 {
79                         ServerInstance->SendWhoisLine(source, dest, 330, "%s %s %s :is logged in as", source->nick.c_str(), dest->nick.c_str(), account->c_str());
80                 }
81         }
82
83
84         virtual int OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
85         {
86                 std::string *account;
87
88                 if (!IS_LOCAL(user))
89                         return 0;
90
91                 user->GetExt("accountname", account);
92
93                 if ((ServerInstance->ULine(user->nick.c_str())) || (ServerInstance->ULine(user->server)))
94                 {
95                         // user is ulined, can speak regardless
96                         return 0;
97                 }
98
99                 if (target_type == TYPE_CHANNEL)
100                 {
101                         Channel* c = (Channel*)dest;
102
103                         if ((c->IsModeSet('M')) && (!account))
104                         {
105                                 // user messaging a +M channel and is not registered
106                                 user->WriteNumeric(477, ""+std::string(user->nick)+" "+std::string(c->name)+" :You need to be identified to a registered account to message this channel");
107                                 return 1;
108                         }
109
110                         if (account)
111                         {
112                                 if (c->IsExtBanned(*account, 'M'))
113                                 {
114                                         // may not speak
115                                         user->WriteNumeric(477, ""+std::string(user->nick)+" "+std::string(c->name)+" :You may not speak in this channel");
116                                         return 1;
117                                 }
118                         }
119                 }
120
121                 if (target_type == TYPE_USER)
122                 {
123                         User* u = (User*)dest;
124
125                         if ((u->modes['R'-65]) && (!account))
126                         {
127                                 // user messaging a +R user and is not registered
128                                 user->WriteNumeric(477, ""+ user->nick +" "+ u->nick +" :You need to be identified to a registered account to message this user");
129                                 return 1;
130                         }
131                 }
132                 return 0;
133         }
134
135         virtual int OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
136         {
137                 return OnUserPreMessage(user, dest, target_type, text, status, exempt_list);
138         }
139
140         virtual int OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven)
141         {
142                 std::string *account;
143                 user->GetExt("accountname", account);
144
145                 if (chan)
146                 {
147                         if (chan->IsModeSet('R'))
148                         {
149                                 if (!account)
150                                 {
151                                         if ((ServerInstance->ULine(user->nick.c_str())) || (ServerInstance->ULine(user->server)))
152                                         {
153                                                 // user is ulined, won't be stopped from joining
154                                                 return 0;
155                                         }
156                                         // joining a +R channel and not identified
157                                         user->WriteNumeric(477, user->nick + " " + chan->name + " :You need to be identified to a registered account to join this channel");
158                                         return 1;
159                                 }
160                         }
161
162                         if (account)
163                         {
164                                 if (chan->IsExtBanned(*account, 'R'))
165                                 {
166                                         // may not join
167                                         user->WriteNumeric(ERR_BANNEDFROMCHAN, "%s %s :Cannot join channel (You're banned)", user->nick.c_str(),  chan->name.c_str());
168                                         return 1;
169                                 }
170                         }
171                 }
172                 return 0;
173         }
174
175         // Whenever the linking module wants to send out data, but doesnt know what the data
176         // represents (e.g. it is metadata, added to a User or Channel by a module) then
177         // this method is called. We should use the ProtoSendMetaData function after we've
178         // corrected decided how the data should look, to send the metadata on its way if
179         // it is ours.
180         virtual void OnSyncUserMetaData(User* user, Module* proto, void* opaque, const std::string &extname, bool displayable)
181         {
182                 // check if the linking module wants to know about OUR metadata
183                 if (extname == "accountname")
184                 {
185                         // check if this user has an swhois field to send
186                         std::string* account;
187                         user->GetExt("accountname", account);
188                         if (account)
189                         {
190                                 // remove any accidental leading/trailing spaces
191                                 trim(*account);
192
193                                 // call this function in the linking module, let it format the data how it
194                                 // sees fit, and send it on its way. We dont need or want to know how.
195                                 proto->ProtoSendMetaData(opaque,TYPE_USER,user,extname,*account);
196                         }
197                 }
198         }
199
200         // when a user quits, tidy up their metadata
201         virtual void OnUserQuit(User* user, const std::string &message, const std::string &oper_message)
202         {
203                 std::string* account;
204                 user->GetExt("accountname", account);
205                 if (account)
206                 {
207                         user->Shrink("accountname");
208                         delete account;
209                 }
210         }
211
212         // if the module is unloaded, tidy up all our dangling metadata
213         virtual void OnCleanup(int target_type, void* item)
214         {
215                 if (target_type == TYPE_USER)
216                 {
217                         User* user = (User*)item;
218                         std::string* account;
219                         user->GetExt("accountname", account);
220                         if (account)
221                         {
222                                 user->Shrink("accountname");
223                                 delete account;
224                         }
225                 }
226         }
227
228         // Whenever the linking module receives metadata from another server and doesnt know what
229         // to do with it (of course, hence the 'meta') it calls this method, and it is up to each
230         // module in turn to figure out if this metadata key belongs to them, and what they want
231         // to do with it.
232         // In our case we're only sending a single string around, so we just construct a std::string.
233         // Some modules will probably get much more complex and format more detailed structs and classes
234         // in a textual way for sending over the link.
235         virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)
236         {
237                 // check if its our metadata key, and its associated with a user
238                 if ((target_type == TYPE_USER) && (extname == "accountname"))
239                 {
240                         User* dest = (User*)target;
241
242                         /* logging them out? */
243                         if (extdata.empty())
244                         {
245                                 std::string* account;
246                                 dest->GetExt("accountname", account);
247                                 if (account)
248                                 {
249                                         dest->Shrink("accountname");
250                                         delete account;
251                                 }
252                         }
253                         else
254                         {
255                                 // if they dont already have an accountname field, accept the remote server's
256                                 std::string* text;
257                                 if (!dest->GetExt("accountname", text))
258                                 {
259                                         text = new std::string(extdata);
260                                         // remove any accidental leading/trailing spaces
261                                         trim(*text);
262                                         dest->Extend("accountname", text);
263
264                                         if (IS_LOCAL(dest))
265                                                 dest->WriteNumeric(900, "%s %s %s :You are now logged in as %s", dest->nick.c_str(), dest->GetFullHost().c_str(), text->c_str(), text->c_str());
266
267                                         AccountData ac;
268                                         ac.user = dest;
269                                         ac.account = *text;
270                                         Event n((char*)&ac, this, "account_login");
271                                         n.Send(ServerInstance);
272                                 }
273                         }
274                 }
275         }
276
277         virtual ~ModuleServicesAccount()
278         {
279                 ServerInstance->Modes->DelMode(m1);
280                 ServerInstance->Modes->DelMode(m2);
281                 ServerInstance->Modes->DelMode(m3);
282                 delete m1;
283                 delete m2;
284                 delete m3;
285         }
286
287         virtual Version GetVersion()
288         {
289                 return Version(1,2,0,0,VF_COMMON|VF_VENDOR,API_VERSION);
290         }
291 };
292
293 MODULE_INIT(ModuleServicesAccount)