]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_blockamsg.cpp
Header rearrangement, move inspircd.h to top, remove stdio, stdlib, stdblahblah that...
[user/henk/code/inspircd.git] / src / modules / m_blockamsg.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2007 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 "users.h"
16 #include "channels.h"
17 #include "modules.h"
18 #include "hashcomp.h"
19
20 /* $ModDesc: Attempt to block /amsg, at least some of the irritating mIRC scripts. */
21
22 enum BlockAction { IBLOCK_KILL, IBLOCK_KILLOPERS, IBLOCK_NOTICE, IBLOCK_NOTICEOPERS, IBLOCK_SILENT };
23
24 /** Holds a blocked message's details
25  */
26 class BlockedMessage : public classbase
27 {
28 public:
29         std::string message;
30         irc::string target;
31         time_t sent;
32
33         BlockedMessage(const std::string &msg, const irc::string &tgt, time_t when) : message(msg), target(tgt), sent(when)
34         {
35         }
36 };
37
38 class ModuleBlockAmsg : public Module
39 {
40         
41         int ForgetDelay;
42         BlockAction action;
43 public:
44         ModuleBlockAmsg(InspIRCd* Me) : Module(Me)
45         {
46                 
47                 this->OnRehash(NULL,"");
48         }
49
50         void Implements(char* List)
51         {
52                 List[I_OnRehash] = List[I_OnPreCommand] = List[I_OnCleanup] = 1;
53         }
54         
55         virtual ~ModuleBlockAmsg()
56         {
57         }
58         
59         virtual Version GetVersion()
60         {
61                 return Version(1,1,0,0,VF_VENDOR,API_VERSION);
62         }
63         
64         virtual void OnRehash(userrec* user, const std::string &parameter)
65         {
66                 ConfigReader* Conf = new ConfigReader(ServerInstance);
67                 
68                 ForgetDelay = Conf->ReadInteger("blockamsg", "delay", 0, false);
69                 if(Conf->GetError() == CONF_VALUE_NOT_FOUND)
70                         ForgetDelay = -1;
71                         
72                 std::string act = Conf->ReadValue("blockamsg", "action", 0);
73                 
74                 if(act == "notice")
75                         action = IBLOCK_NOTICE;
76                 else if(act == "noticeopers")
77                         action = IBLOCK_NOTICEOPERS;
78                 else if(act == "silent")
79                         action = IBLOCK_SILENT;
80                 else if(act == "kill")
81                         action = IBLOCK_KILL;
82                 else
83                         action = IBLOCK_KILLOPERS;
84
85                 DELETE(Conf);
86         }
87
88         virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
89         {
90                 // Don't do anything with unregistered users, or remote ones.
91                 if(!user || (user->registered != REG_ALL) || !IS_LOCAL(user))
92                         return 0;
93                         
94                 // We want case insensitive command comparison.
95                 // Add std::string contructor for irc::string :x
96                 irc::string cmd = command.c_str();
97                 
98                 if(validated && (cmd == "PRIVMSG" || cmd == "NOTICE") && (pcnt >= 2))
99                 {
100                         // parameters[0] should have the target(s) in it.
101                         // I think it will be faster to first check if there are any commas, and if there are then try and parse it out.
102                         // Most messages have a single target so...
103                         
104                         int targets = 1;
105                         int userchans = 0;
106                         
107                         // Decrement if the first target wasn't a channel.
108                         if(*parameters[0] != '#')
109                                 targets--;
110                         
111                         for(const char* c = parameters[0]; *c; c++)
112                                 if((*c == ',') && *(c+1) && (*(c+1) == '#'))
113                                         targets++;
114                                         
115                         userchans = user->chans.size();
116
117                         // Check that this message wasn't already sent within a few seconds.
118                         BlockedMessage* m;
119                         user->GetExt("amsgblock", m);
120                         
121                         // If the message is identical and within the time.
122                         // We check the target is *not* identical, that'd straying into the realms of flood control. Which isn't what we're doing...
123                         // OR
124                         // The number of target channels is equal to the number of channels the sender is on..a little suspicious.
125                         // Check it's more than 1 too, or else users on one channel would have fun.
126                         if((m && (m->message == parameters[1]) && (m->target != parameters[0]) && (ForgetDelay != -1) && (m->sent >= ServerInstance->Time()-ForgetDelay)) || ((targets > 1) && (targets == userchans)))
127                         {
128                                 // Block it...
129                                 if(action == IBLOCK_KILLOPERS || action == IBLOCK_NOTICEOPERS)
130                                         ServerInstance->WriteOpers("*** %s had an /amsg or /ame denied", user->nick);
131
132                                 if(action == IBLOCK_KILL || action == IBLOCK_KILLOPERS)
133                                         userrec::QuitUser(ServerInstance, user, "Global message (/amsg or /ame) detected");
134                                 else if(action == IBLOCK_NOTICE || action == IBLOCK_NOTICEOPERS)
135                                         user->WriteServ( "NOTICE %s :Global message (/amsg or /ame) detected", user->nick);
136                                                                         
137                                 return 1;
138                         }
139                         
140                         if(m)
141                         {
142                                 // If there's already a BlockedMessage allocated, use it.
143                                 m->message = parameters[1];
144                                 m->target = parameters[0];
145                                 m->sent = ServerInstance->Time();
146                         }
147                         else
148                         {
149                                 m = new BlockedMessage(parameters[1], parameters[0], ServerInstance->Time());
150                                 user->Extend("amsgblock", (char*)m);
151                         }
152                 }                                       
153                 return 0;
154         }
155         
156         void OnCleanup(int target_type, void* item)
157         {
158                 if(target_type == TYPE_USER)
159                 {
160                         userrec* user = (userrec*)item;
161                         BlockedMessage* m;
162                         user->GetExt("amsgblock", m);
163                         if(m)
164                         {
165                                 DELETE(m);
166                                 user->Shrink("amsgblock");
167                         }
168                 }
169         }
170 };
171
172
173 class ModuleBlockAmsgFactory : public ModuleFactory
174 {
175         public:
176                 ModuleBlockAmsgFactory()
177                 {
178                 }
179         
180                 ~ModuleBlockAmsgFactory()
181                 {
182                 }
183         
184                 virtual Module * CreateModule(InspIRCd* Me)
185                 {
186                         return new ModuleBlockAmsg(Me);
187                 }
188 };
189
190
191 extern "C" DllExport void * init_module( void )
192 {
193         return new ModuleBlockAmsgFactory;
194 }