]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_dccallow.cpp
GACK! you cannot ConfigReader::ReadValue to a const char*! you need to read to a...
[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->ReadValue("dccallow", "blockchat", 0);
337                     ServerInstance->Log(DEBUG, "m_dccallow.so: got blockchat: %s", blockchat);
338
339                     if (type == "SEND")
340                     {
341                         std::string defaultaction = Conf->ReadValue("dccallow", "action", 0);
342                         std::string filename = tokens[2];
343                         
344                         if (strcmp(defaultaction, "allow") == 0) 
345                         {
346                             return 0;
347                         }
348                         
349                         for (unsigned int i = 0; i < bfl.size(); i++)
350                         {
351                             if (ServerInstance->MatchText(filename, bfl[i].filemask))
352                             {
353                                 if (strcmp(bfl[i].action.c_str(), "allow") == 0)
354                                 {
355                                     return 0;
356                                 }
357                             }
358                             else
359                             {
360                                 if (strcmp(defaultaction, "allow") == 0)
361                                 {
362                                     return 0;
363                                 }
364                             }
365                             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());
366                             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());
367                             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);
368                         }
369                     }
370                     else if ((type == "CHAT") && (strcmp(blockchat, "yes") == 0))
371                     {
372                         user->WriteServ("NOTICE %s :The user %s is not accepting DCC CHAT requests from you.", user->nick, u->nick);
373                         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);
374                         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);
375                     }
376                     return 1;    
377                 }
378             }
379         }
380         return 0;
381     }
382
383     void Expire()
384     {
385         for (userlist::iterator iter = ul.begin(); iter != ul.end(); ++iter)
386         {
387             userrec* u = (userrec*)(*iter);
388             u->GetExt("dccallow_list", dl);
389
390             if (dl)
391             {
392                 if (dl->size())
393                 {
394                     dccallowlist::iterator iter = dl->begin();
395                     while (iter != dl->end())
396                     {
397                         if ((iter->set_on + iter->length) <= ServerInstance->Time())
398                         {
399                             u->WriteServ("997 %s %s :DCCALLOW entry for %s has expired", u->nick, u->nick, iter->nickname.c_str());
400                             iter = dl->erase(iter);
401                         }
402                         else
403                         {
404                             ++iter;
405                         }
406                     }
407                 }
408             }
409             else
410             {
411                 DELETE(dl);
412                 u->Shrink("dccallow_list");
413                 RemoveFromUserlist(u);
414                 ServerInstance->Log(DEBUG, "m_dccallow.so: UH OH! Couldn't get DCCALLOW list for %s", u->nick);
415             }
416         }
417     }
418
419     void RemoveNick(userrec* user)
420     {
421         /* Iterate through all DCCALLOW lists and remove user */
422         for (userlist::iterator iter = ul.begin(); iter != ul.end(); ++iter)
423         {
424             userrec *u = (userrec*)(*iter);
425             u->GetExt("dccallow_list", dl);
426
427             if (dl)
428             {
429                 if (dl->size())
430                 {
431                     for (dccallowlist::iterator i = dl->begin(); i != dl->end(); ++i)
432                     {
433                         if (i->nickname == user->nick)
434                         {
435                             
436                             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());
437                             u->WriteServ("995 %s %s :Removed %s from your DCCALLOW list", u->nick, u->nick, i->nickname.c_str());
438                             dl->erase(i);
439                             break;
440                         }
441                     }
442                 }
443             }
444             else
445             {
446                 DELETE(dl);
447                 u->Shrink("dccallow_list");
448                 RemoveFromUserlist(u);
449             }
450         }
451     }
452
453     void RemoveFromUserlist(userrec *user)
454     {
455         // remove user from userlist
456         for (userlist::iterator j = ul.begin(); j != ul.end(); ++j)
457         {
458             userrec* u = (userrec*)(*j);
459             if (u->nick == user->nick)
460             {
461                 ul.erase(j);
462                 break;
463             }
464         }
465     }
466
467     void ReadFileConf()
468     {
469         bfl.clear();
470         for (int i = 0; i < Conf->Enumerate("banfile"); i++)
471         {
472             BannedFileList bf;
473             std::string fileglob = Conf->ReadValue("banfile", "pattern", i);
474             std::string action = Conf->ReadValue("banfile", "action", i);
475             bf.filemask = fileglob;
476             bf.action = action;
477             bfl.push_back(bf);
478         }
479     
480     }
481
482     virtual ~ModuleDCCAllow()
483     {
484     }
485
486     virtual Version GetVersion()
487     {
488         return Version(1,0,0,0,VF_COMMON,API_VERSION);
489     }
490 };
491
492 class ModuleDCCAllowFactory : public ModuleFactory
493 {
494  public:
495     ModuleDCCAllowFactory()
496     {
497     }
498
499     ~ModuleDCCAllowFactory()
500     {
501     }
502
503     virtual Module * CreateModule(InspIRCd* Me)
504     {
505         return new ModuleDCCAllow(Me);
506     }
507
508 };
509
510 extern "C" void * init_module( void )
511 {
512     return new ModuleDCCAllowFactory;
513 }