The InspIRCd Project
Home | Developers | Wiki | Forums | Bug Tracker | SVN | Download
Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

m_blockamsg.cpp

Go to the documentation of this file.
00001 /*       +------------------------------------+
00002  *       | Inspire Internet Relay Chat Daemon |
00003  *       +------------------------------------+
00004  *
00005  *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
00006  * See: http://www.inspircd.org/wiki/index.php/Credits
00007  *
00008  * This program is free but copyrighted software; see
00009  *            the file COPYING for details.
00010  *
00011  * ---------------------------------------------------
00012  */
00013 
00014 #include "inspircd.h"
00015 
00016 /* $ModDesc: Attempt to block /amsg, at least some of the irritating mIRC scripts. */
00017 
00018 enum BlockAction { IBLOCK_KILL, IBLOCK_KILLOPERS, IBLOCK_NOTICE, IBLOCK_NOTICEOPERS, IBLOCK_SILENT };
00019 /*      IBLOCK_NOTICE           - Send a notice to the user informing them of what happened.
00020  *      IBLOCK_NOTICEOPERS      - Send a notice to the user informing them and send an oper notice.
00021  *      IBLOCK_SILENT           - Generate no output, silently drop messages.
00022  *      IBLOCK_KILL                     - Kill the user with the reason "Global message (/amsg or /ame) detected".
00023  *      IBLOCK_KILLOPERS        - As above, but send an oper notice as well. This is the default.
00024  */
00025 
00028 class BlockedMessage : public classbase
00029 {
00030 public:
00031         std::string message;
00032         irc::string target;
00033         time_t sent;
00034 
00035         BlockedMessage(const std::string &msg, const irc::string &tgt, time_t when)
00036         : message(msg), target(tgt), sent(when)
00037         {
00038         }
00039 };
00040 
00041 class ModuleBlockAmsg : public Module
00042 {
00043         int ForgetDelay;
00044         BlockAction action;
00045 
00046  public:
00047         ModuleBlockAmsg(InspIRCd* Me) : Module(Me)
00048         {
00049                 this->OnRehash(NULL,"");
00050                 Implementation eventlist[] = { I_OnRehash, I_OnPreCommand, I_OnCleanup };
00051                 ServerInstance->Modules->Attach(eventlist, this, 3);
00052         }
00053 
00054 
00055         virtual ~ModuleBlockAmsg()
00056         {
00057         }
00058 
00059         virtual Version GetVersion()
00060         {
00061                 return Version("$Id: m_blockamsg.cpp 10291 2008-08-25 20:35:51Z w00t $",VF_VENDOR,API_VERSION);
00062         }
00063 
00064         virtual void OnRehash(User* user, const std::string &parameter)
00065         {
00066                 ConfigReader Conf(ServerInstance);
00067 
00068                 ForgetDelay = Conf.ReadInteger("blockamsg", "delay", 0, false);
00069 
00070                 if(Conf.GetError() == CONF_VALUE_NOT_FOUND)
00071                         ForgetDelay = -1;
00072 
00073                 std::string act = Conf.ReadValue("blockamsg", "action", 0);
00074 
00075                 if(act == "notice")
00076                         action = IBLOCK_NOTICE;
00077                 else if(act == "noticeopers")
00078                         action = IBLOCK_NOTICEOPERS;
00079                 else if(act == "silent")
00080                         action = IBLOCK_SILENT;
00081                 else if(act == "kill")
00082                         action = IBLOCK_KILL;
00083                 else
00084                         action = IBLOCK_KILLOPERS;
00085         }
00086 
00087         virtual int OnPreCommand(std::string &command, std::vector<std::string> &parameters, User *user, bool validated, const std::string &original_line)
00088         {
00089                 // Don't do anything with unregistered users, or remote ones.
00090                 if(!user || (user->registered != REG_ALL) || !IS_LOCAL(user))
00091                         return 0;
00092 
00093                 // We want case insensitive command comparison.
00094                 // Add std::string contructor for irc::string :x
00095                 irc::string cmd = command.c_str();
00096 
00097                 if(validated && (cmd == "PRIVMSG" || cmd == "NOTICE") && (parameters.size() >= 2))
00098                 {
00099                         // parameters[0] should have the target(s) in it.
00100                         // I think it will be faster to first check if there are any commas, and if there are then try and parse it out.
00101                         // Most messages have a single target so...
00102 
00103                         int targets = 1;
00104                         int userchans = 0;
00105 
00106                         if(*parameters[0].c_str() != '#')
00107                         {
00108                                 // Decrement if the first target wasn't a channel.
00109                                 targets--;
00110                         }
00111 
00112                         for(const char* c = parameters[0].c_str(); *c; c++)
00113                                 if((*c == ',') && *(c+1) && (*(c+1) == '#'))
00114                                         targets++;
00115 
00116                         /* targets should now contain the number of channel targets the msg/notice was pointed at.
00117                          * If the msg/notice was a PM there should be no channel targets and 'targets' should = 0.
00118                          * We don't want to block PMs so...
00119                          */
00120                         if(targets == 0)
00121                         {
00122                                 return 0;
00123                         }
00124 
00125                         userchans = user->chans.size();
00126 
00127                         // Check that this message wasn't already sent within a few seconds.
00128                         BlockedMessage* m;
00129                         user->GetExt("amsgblock", m);
00130 
00131                         // If the message is identical and within the time.
00132                         // We check the target is *not* identical, that'd straying into the realms of flood control. Which isn't what we're doing...
00133                         // OR
00134                         // The number of target channels is equal to the number of channels the sender is on..a little suspicious.
00135                         // Check it's more than 1 too, or else users on one channel would have fun.
00136                         if((m && (m->message == parameters[1]) && (m->target != parameters[0]) && (ForgetDelay != -1) && (m->sent >= ServerInstance->Time()-ForgetDelay)) || ((targets > 1) && (targets == userchans)))
00137                         {
00138                                 // Block it...
00139                                 if(action == IBLOCK_KILLOPERS || action == IBLOCK_NOTICEOPERS)
00140                                         ServerInstance->SNO->WriteToSnoMask('A', "%s had an /amsg or /ame denied", user->nick.c_str());
00141 
00142                                 if(action == IBLOCK_KILL || action == IBLOCK_KILLOPERS)
00143                                         ServerInstance->Users->QuitUser(user, "Global message (/amsg or /ame) detected");
00144                                 else if(action == IBLOCK_NOTICE || action == IBLOCK_NOTICEOPERS)
00145                                         user->WriteServ( "NOTICE %s :Global message (/amsg or /ame) detected", user->nick.c_str());
00146 
00147                                 return 1;
00148                         }
00149 
00150                         if(m)
00151                         {
00152                                 // If there's already a BlockedMessage allocated, use it.
00153                                 m->message = parameters[1];
00154                                 m->target = parameters[0].c_str();
00155                                 m->sent = ServerInstance->Time();
00156                         }
00157                         else
00158                         {
00159                                 m = new BlockedMessage(parameters[1], parameters[0].c_str(), ServerInstance->Time());
00160                                 user->Extend("amsgblock", (char*)m);
00161                         }
00162                 }
00163                 return 0;
00164         }
00165 
00166         void OnCleanup(int target_type, void* item)
00167         {
00168                 if(target_type == TYPE_USER)
00169                 {
00170                         User* user = (User*)item;
00171                         BlockedMessage* m;
00172                         user->GetExt("amsgblock", m);
00173                         if(m)
00174                         {
00175                                 delete m;
00176                                 user->Shrink("amsgblock");
00177                         }
00178                 }
00179         }
00180 };
00181 
00182 
00183 MODULE_INIT(ModuleBlockAmsg)