]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_dccallow.cpp
AURGH 4 space indents :/
[user/henk/code/inspircd.git] / src / modules / m_dccallow.cpp
1  /* m_dccallow - Jamie Penman-Smithson <jamie@silverdream.org> - September 2006 */
2
3 using namespace std;
4
5 #include <stdio.h>
6 #include <vector>
7 #include <string.h>
8 #include "users.h"
9 #include "channels.h"
10 #include "modules.h"
11 #include "inspircd.h"
12
13 /* $ModDesc: Povides support for the /DCCALLOW command */
14
15 static ConfigReader *Conf;
16
17 class BannedFileList
18 {
19  public:
20 std::string filemask;
21 std::string action;
22 };
23
24 class DCCAllow
25 {
26  public:
27 std::string nickname;
28 std::string hostmask;
29 time_t set_on;
30 long length;
31
32 DCCAllow() { }
33
34 DCCAllow(std::string nick, std::string hm, time_t so, long ln) : nickname(nick), hostmask(hm), set_on(so), length(ln) { }
35 };
36
37 typedef std::vector<userrec *> userlist;
38 userlist ul;
39 typedef std::vector<DCCAllow> dccallowlist;
40 dccallowlist* dl;
41 typedef std::vector<BannedFileList> bannedfilelist;
42 bannedfilelist bfl;
43
44 class cmd_dccallow : public command_t
45 {
46  public:
47 cmd_dccallow(InspIRCd* Me) : command_t(Me, "DCCALLOW", 0, 0)
48 {
49         this->source = "m_dccallow.so";
50         syntax = "{[+|-]<nick> <time>}";
51 }
52
53 CmdResult Handle(const char **parameters, int pcnt, userrec *user)
54 {
55         /* syntax: DCCALLOW [+|-]<nick> (<time>) */
56         
57         if (!pcnt)
58         {
59         // display current DCCALLOW list
60         DisplayDCCAllowList(user);
61
62         return CMD_SUCCESS;
63         }
64         else if (pcnt > 0)
65         {
66         char action = *parameters[0];
67         
68         // if they didn't specify an action, this is probably a command
69         if (action != '+' && action != '-')
70         {
71                 if (!strcasecmp(parameters[0], "LIST"))
72                 {
73                 // list current DCCALLOW list
74                 DisplayDCCAllowList(user);
75                 return CMD_SUCCESS;
76                 } 
77                 else if (!strcasecmp(parameters[0], "HELP"))
78                 {
79                 // display help
80                 DisplayHelp(user);
81                 return CMD_SUCCESS;
82                 }
83         }
84                 
85         std::string nick = parameters[0] + 1;
86         userrec *target = ServerInstance->FindNick(nick);
87
88         if (target)
89         {
90                 ServerInstance->Log(DEBUG, "m_dccallow.so: got target %s and action %c", target->nick, action);
91                         
92                 if (action == '-')
93                 {
94                 user->GetExt("dccallow_list", dl);
95                 // check if it contains any entries
96                 if (dl)
97                 {
98                         if (dl->size())
99                         {
100                         for (dccallowlist::iterator i = dl->begin(); i != dl->end(); ++i)
101                         {
102                                 // search through list
103                                 if (i->nickname == target->nick)
104                                 {
105                                 dl->erase(i);
106                                 user->WriteServ("995 %s %s :Removed %s from your DCCALLOW list", user->nick, user->nick, target->nick);
107                                 break;
108                                 }
109                         }
110                         }
111                 }
112                 else
113                 {
114                         DELETE(dl);
115                         user->Shrink("dccallow_list");
116                         
117                         // remove from userlist
118                         for (userlist::iterator j = ul.begin(); j != ul.end(); ++j)
119                         {
120                         userrec* u = (userrec*)(*j);
121                         if (u->nick == user->nick)
122                         {
123                                 ul.erase(j);
124                                 break;
125                         }
126                         }
127                 }
128                 }
129                 else if (action == '+')
130                 {
131                 // fetch current DCCALLOW list
132                 user->GetExt("dccallow_list", dl);
133                 // they don't have one, create it
134                 if (!dl)
135                 {
136                         dl = new dccallowlist;
137                         user->Extend(std::string("dccallow_list"), dl);
138                         // add this user to the userlist
139                         ul.push_back(user);
140                 }
141                 for (dccallowlist::const_iterator k = dl->begin(); k != dl->end(); ++k)
142                 {
143                         if (k->nickname == target->nick)
144                         {
145                         user->WriteServ("996 %s %s :%s is already on your DCCALLOW list", user->nick, user->nick, target->nick);
146                         return CMD_SUCCESS;
147                         }
148                 }
149                 
150                 std::string mask = std::string(target->nick)+"!"+std::string(target->ident)+"@"+std::string(target->dhost);
151                 const char* default_length = Conf->ReadValue("dccallow", "length", 0).c_str();
152
153                 long length;
154                 if (pcnt == 1 || ServerInstance->Duration(parameters[1]) < 1)
155                 {
156                         length = ServerInstance->Duration(default_length);
157                 } 
158                 else if (parameters[1] == 0)
159                 {
160                         length = 0;
161                 }
162                 else
163                 {
164                         length = ServerInstance->Duration(parameters[1]);
165                 }
166
167                 if (!ServerInstance->IsValidMask(mask.c_str()))
168                 {
169                         return CMD_FAILURE;
170                 }
171                 
172                 dl->push_back(DCCAllow(target->nick, mask, ServerInstance->Time(), length));
173
174                 if (length > 0)
175                 {
176                         user->WriteServ("993 %s %s :Added %s to DCCALLOW list for %d seconds", user->nick, user->nick, target->nick, length);
177                 }
178                 else
179                 {
180                         user->WriteServ("994 %s %s :Added %s to DCCALLOW list for this session", user->nick, user->nick, target->nick);
181                 }
182                 
183                 return CMD_SUCCESS;
184                 }
185         }
186         else
187         {
188                 // nick doesn't exist
189                 user->WriteServ("401 %s %s :No such nick/channel", user->nick, nick.c_str());
190                 return CMD_FAILURE;
191         }
192         }
193 return CMD_SUCCESS;
194 }
195
196 void DisplayHelp(userrec* user)
197 {
198         user->WriteServ("998 %s :DCCALLOW [<+|->nick [time]] [list] [help]", user->nick);
199         user->WriteServ("998 %s :You may allow DCCs from specific users by specifying a", user->nick);
200         user->WriteServ("998 %s :DCC allow for the user you want to receive DCCs from.", user->nick);
201         user->WriteServ("998 %s :For example, to allow the user Brain to send you inspircd.exe", user->nick);
202         user->WriteServ("998 %s :you would type:", user->nick);
203         user->WriteServ("998 %s :/DCCALLOW +Brain", user->nick);
204         user->WriteServ("998 %s :Brain would then be able to send you files. They would have to", user->nick);
205         user->WriteServ("998 %s :resend the file again if the server gave them an error message", user->nick);
206         user->WriteServ("998 %s :before you added them to your DCCALLOW list.", user->nick);
207         user->WriteServ("998 %s :DCCALLOW entries will be temporary by default, if you want to add", user->nick);
208         user->WriteServ("998 %s :them to your DCCALLOW list until you leave IRC, type:", user->nick);
209         user->WriteServ("998 %s :/DCCALLOW +Brain 0", user->nick);
210         user->WriteServ("998 %s :To remove the user from your DCCALLOW list, type:", user->nick);
211         user->WriteServ("998 %s :/DCCALLOW -Brain", user->nick);
212         user->WriteServ("998 %s :To see the users in your DCCALLOW list, type:", user->nick);
213         user->WriteServ("998 %s :/DCCALLOW LIST", user->nick);
214         user->WriteServ("998 %s :NOTE: If the user leaves IRC or changes their nickname", user->nick);
215         user->WriteServ("998 %s :  they will be removed from your DCCALLOW list.", user->nick);
216         user->WriteServ("998 %s :  your DCCALLOW list will be deleted when you leave IRC.", user->nick);
217         user->WriteServ("999 %s :End of DCCALLOW HELP", user->nick);
218 }
219
220 void DisplayDCCAllowList(userrec* user)
221 {
222          // display current DCCALLOW list
223         user->WriteServ("990 %s :Users on your DCCALLOW list:", user->nick);
224         user->GetExt("dccallow_list", dl);
225         
226         if (dl)
227         {
228         for (dccallowlist::const_iterator c = dl->begin(); c != dl->end(); ++c)
229         {
230                 user->WriteServ("991 %s %s :%s (%s)", user->nick, user->nick, c->nickname.c_str(), c->hostmask.c_str());
231         }
232         }
233         
234         user->WriteServ("992 %s :End of DCCALLOW list", user->nick);
235 }                       
236
237 };
238         
239 class ModuleDCCAllow : public Module
240 {
241 cmd_dccallow* mycommand;
242
243  public:
244 ModuleDCCAllow(InspIRCd* Me)
245         : Module::Module(Me)
246 {
247         Conf = new ConfigReader(ServerInstance);
248         mycommand = new cmd_dccallow(ServerInstance);
249         ServerInstance->AddCommand(mycommand);
250         ReadFileConf();
251 }
252
253 void Implements(char* List)
254 {
255         List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnUserQuit] = List[I_OnUserPreNick] = List[I_OnRehash] = 1;
256 }
257
258 virtual void OnRehash(const std::string &parameter)
259 {
260                 delete Conf;
261         Conf = new ConfigReader(ServerInstance);
262 }
263
264 virtual void OnUserQuit(userrec* user, const std::string &reason)
265 {
266         dccallowlist* dl;
267
268         // remove their DCCALLOW list if they have one
269         user->GetExt("dccallow_list", dl);
270         if (dl)
271         {
272         DELETE(dl);
273         user->Shrink("dccallow_list");
274         RemoveFromUserlist(user);
275         }
276         
277         // remove them from any DCCALLOW lists
278         // they are currently on
279         RemoveNick(user);
280 }
281
282
283 virtual int OnUserPreNick(userrec* user, const std::string &newnick)
284 {
285         RemoveNick(user);
286         return 0;
287 }
288
289 virtual int OnUserPreMessage(userrec* user, void* dest, int target_type, std::string &text, char status)
290 {
291         return OnUserPreNotice(user, dest, target_type, text, status);
292 }
293
294 virtual int OnUserPreNotice(userrec* user, void* dest, int target_type, std::string &text, char status)
295 {
296         Expire();
297
298         if (target_type == TYPE_USER)
299         {
300         userrec* u = (userrec*)dest;
301         
302         if ((text.length()) && (text[0] == '\1'))
303         {
304                 // :jamie!jamie@test-D4457903BA652E0F.silverdream.org PRIVMSG eimaj :DCC SEND m_dnsbl.cpp 3232235786 52650 9676
305                 // :jamie!jamie@test-D4457903BA652E0F.silverdream.org PRIVMSG eimaj :VERSION
306                         
307                 if (strncmp(text.c_str(), "\1DCC ", 5) == 0)
308                 {
309                 u->GetExt("dccallow_list", dl);
310
311                 if (dl)
312                 {
313                         if (dl->size())
314                         {
315                         for (dccallowlist::const_iterator iter = dl->begin(); iter != dl->end(); ++iter)
316                         {
317                                 if (ServerInstance->MatchText(user->GetFullHost(), iter->hostmask))
318                                 {
319                                 return 0;
320                                 }
321                         }
322                         }
323                 }
324
325                 // tokenize
326                 stringstream ss(text);
327                 std::string buf;
328                 vector<string> tokens;
329
330                 while (ss >> buf)
331                         tokens.push_back(buf);
332
333                 irc::string type = tokens[1].c_str();
334                 ServerInstance->Log(DEBUG, "m_dccallow.so: got DCC type %s", type.c_str());
335
336                 bool blockchat = Conf->ReadBool("dccallow", "blockchat", 0);
337
338                 if (type == "SEND")
339                 {
340                         std::string defaultaction = Conf->ReadValue("dccallow", "action", 0);
341                         std::string filename = tokens[2];
342                         
343                         if (defaultaction == "allow") 
344                         {
345                         return 0;
346                         }
347                         
348                         for (unsigned int i = 0; i < bfl.size(); i++)
349                         {
350                         if (ServerInstance->MatchText(filename, bfl[i].filemask))
351                         {
352                                 if (strcmp(bfl[i].action.c_str(), "allow") == 0)
353                                 {
354                                 return 0;
355                                 }
356                         }
357                         else
358                         {
359                                 if (defaultaction == "allow")
360                                 {
361                                 return 0;
362                                 }
363                         }
364                         user->WriteServ("NOTICE %s :The user %s is not accepting DCC SENDs from you. Your file %s was not sent.", user->nick, u->nick, filename.c_str());
365                         u->WriteServ("NOTICE %s :%s (%s@%s) attempted to send you a file named %s, which was blocked.", u->nick, user->nick, user->ident, user->dhost, filename.c_str());
366                         u->WriteServ("NOTICE %s :If you trust %s and were expecting this, you can type /DCCALLOW HELP for information on the DCCALLOW system.", u->nick, user->nick);
367                         }
368                 }
369                 else if ((type == "CHAT") && (strcmp(blockchat, "yes") == 0))
370                 {
371                         user->WriteServ("NOTICE %s :The user %s is not accepting DCC CHAT requests from you.", user->nick, u->nick);
372                         u->WriteServ("NOTICE %s :%s (%s@%s) attempted to initiate a DCC CHAT session, which was blocked.", u->nick, user->nick, user->ident, user->dhost);
373                         u->WriteServ("NOTICE %s :If you trust %s and were expecting this, you can type /DCCALLOW HELP for information on the DCCALLOW system.", u->nick, user->nick);
374                 }
375                 return 1;
376                 }
377         }
378         }
379         return 0;
380 }
381
382 void Expire()
383 {
384         for (userlist::iterator iter = ul.begin(); iter != ul.end(); ++iter)
385         {
386         userrec* u = (userrec*)(*iter);
387         u->GetExt("dccallow_list", dl);
388
389         if (dl)
390         {
391                 if (dl->size())
392                 {
393                 dccallowlist::iterator iter = dl->begin();
394                 while (iter != dl->end())
395                 {
396                         if ((iter->set_on + iter->length) <= ServerInstance->Time())
397                         {
398                         u->WriteServ("997 %s %s :DCCALLOW entry for %s has expired", u->nick, u->nick, iter->nickname.c_str());
399                         iter = dl->erase(iter);
400                         }
401                         else
402                         {
403                         ++iter;
404                         }
405                 }
406                 }
407         }
408         else
409         {
410                 DELETE(dl);
411                 u->Shrink("dccallow_list");
412                 RemoveFromUserlist(u);
413                 ServerInstance->Log(DEBUG, "m_dccallow.so: UH OH! Couldn't get DCCALLOW list for %s", u->nick);
414         }
415         }
416 }
417
418 void RemoveNick(userrec* user)
419 {
420         /* Iterate through all DCCALLOW lists and remove user */
421         for (userlist::iterator iter = ul.begin(); iter != ul.end(); ++iter)
422         {
423         userrec *u = (userrec*)(*iter);
424         u->GetExt("dccallow_list", dl);
425
426         if (dl)
427         {
428                 if (dl->size())
429                 {
430                 for (dccallowlist::iterator i = dl->begin(); i != dl->end(); ++i)
431                 {
432                         if (i->nickname == user->nick)
433                         {
434                         
435                         u->WriteServ("NOTICE %s :%s left the network or changed their nickname and has been removed from your DCCALLOW list", u->nick, i->nickname.c_str());
436                         u->WriteServ("995 %s %s :Removed %s from your DCCALLOW list", u->nick, u->nick, i->nickname.c_str());
437                         dl->erase(i);
438                         break;
439                         }
440                 }
441                 }
442         }
443         else
444         {
445                 DELETE(dl);
446                 u->Shrink("dccallow_list");
447                 RemoveFromUserlist(u);
448         }
449         }
450 }
451
452 void RemoveFromUserlist(userrec *user)
453 {
454         // remove user from userlist
455         for (userlist::iterator j = ul.begin(); j != ul.end(); ++j)
456         {
457         userrec* u = (userrec*)(*j);
458         if (u->nick == user->nick)
459         {
460                 ul.erase(j);
461                 break;
462         }
463         }
464 }
465
466 void ReadFileConf()
467 {
468         bfl.clear();
469         for (int i = 0; i < Conf->Enumerate("banfile"); i++)
470         {
471         BannedFileList bf;
472         std::string fileglob = Conf->ReadValue("banfile", "pattern", i);
473         std::string action = Conf->ReadValue("banfile", "action", i);
474         bf.filemask = fileglob;
475         bf.action = action;
476         bfl.push_back(bf);
477         }
478
479 }
480
481 virtual ~ModuleDCCAllow()
482 {
483 }
484
485 virtual Version GetVersion()
486 {
487         return Version(1,0,0,0,VF_COMMON,API_VERSION);
488 }
489 };
490
491 class ModuleDCCAllowFactory : public ModuleFactory
492 {
493  public:
494 ModuleDCCAllowFactory()
495 {
496 }
497
498 ~ModuleDCCAllowFactory()
499 {
500 }
501
502 virtual Module * CreateModule(InspIRCd* Me)
503 {
504         return new ModuleDCCAllow(Me);
505 }
506
507 };
508
509 extern "C" void * init_module( void )
510 {
511         return new ModuleDCCAllowFactory;
512 }