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_kicknorejoin.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: Provides channel mode +J (delay rejoin after kick) */
00017 
00018 inline int strtoint(const std::string &str)
00019 {
00020         std::istringstream ss(str);
00021         int result;
00022         ss >> result;
00023         return result;
00024 }
00025 
00026 typedef std::map<User*, time_t> delaylist;
00027 
00030 class KickRejoin : public ModeHandler
00031 {
00032  public:
00033         KickRejoin(InspIRCd* Instance) : ModeHandler(Instance, 'J', 1, 0, false, MODETYPE_CHANNEL, false) { }
00034 
00035         ModePair ModeSet(User* source, User* dest, Channel* channel, const std::string &parameter)
00036         {
00037                 if (channel->IsModeSet('J'))
00038                         return std::make_pair(true, channel->GetModeParameter('J'));
00039                 else
00040                         return std::make_pair(false, parameter);
00041         }
00042 
00043         bool CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, Channel* channel)
00044         {
00045                 /* When TS is equal, the alphabetically later one wins */
00046                 return (their_param < our_param);
00047         }
00048 
00049         ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding, bool)
00050         {
00051                 if (!adding)
00052                 {
00053                         // Taking the mode off, we need to clean up.
00054                         delaylist* dl;
00055 
00056                         if (channel->GetExt("norejoinusers", dl))
00057                         {
00058                                 delete dl;
00059                                 channel->Shrink("norejoinusers");
00060                         }
00061 
00062                         if (!channel->IsModeSet('J'))
00063                         {
00064                                 return MODEACTION_DENY;
00065                         }
00066                         else
00067                         {
00068                                 channel->SetMode('J', false);
00069                                 return MODEACTION_ALLOW;
00070                         }
00071                 }
00072                 else if (atoi(parameter.c_str()) > 0)
00073                 {
00074                         if (!channel->IsModeSet('J'))
00075                         {
00076                                 parameter = ConvToStr(atoi(parameter.c_str()));
00077                                 channel->SetModeParam('J', parameter.c_str(), adding);
00078                                 channel->SetMode('J', adding);
00079                                 return MODEACTION_ALLOW;
00080                         }
00081                         else
00082                         {
00083                                 std::string cur_param = channel->GetModeParameter('J');
00084                                 if (cur_param == parameter)
00085                                 {
00086                                         // mode params match, don't change mode
00087                                         return MODEACTION_DENY;
00088                                 }
00089                                 else
00090                                 {
00091                                         // new mode param, replace old with new
00092                                         parameter = ConvToStr(atoi(parameter.c_str()));
00093                                         cur_param = ConvToStr(atoi(cur_param.c_str()));
00094                                         if (parameter != "0")
00095                                         {
00096                                                 channel->SetModeParam('J', cur_param.c_str(), false);
00097                                                 channel->SetModeParam('J', parameter.c_str(), adding);
00098                                                 return MODEACTION_ALLOW;
00099                                         }
00100                                         else
00101                                         {
00102                                                 /* Fix to jamie's fix, dont allow +J 0 on the new value! */
00103                                                 return MODEACTION_DENY;
00104                                         }
00105                                 }
00106                         }
00107                 }
00108                 else
00109                 {
00110                         return MODEACTION_DENY;
00111                 }
00112         }
00113 };
00114 
00115 class ModuleKickNoRejoin : public Module
00116 {
00117 
00118         KickRejoin* kr;
00119 
00120 public:
00121 
00122         ModuleKickNoRejoin(InspIRCd* Me)
00123                 : Module(Me)
00124         {
00125 
00126                 kr = new KickRejoin(ServerInstance);
00127                 if (!ServerInstance->Modes->AddMode(kr))
00128                         throw ModuleException("Could not add new modes!");
00129                 Implementation eventlist[] = { I_OnCleanup, I_OnChannelDelete, I_OnUserPreJoin, I_OnUserKick };
00130                 ServerInstance->Modules->Attach(eventlist, this, 4);
00131         }
00132 
00133         virtual int OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven)
00134         {
00135                 if (chan)
00136                 {
00137                         delaylist* dl;
00138                         if (chan->GetExt("norejoinusers", dl))
00139                         {
00140                                 std::vector<User*> itemstoremove;
00141 
00142                                 for (delaylist::iterator iter = dl->begin(); iter != dl->end(); iter++)
00143                                 {
00144                                         if (iter->second > ServerInstance->Time())
00145                                         {
00146                                                 if (iter->first == user)
00147                                                 {
00148                                                         user->WriteNumeric(ERR_DELAYREJOIN, "%s %s :You must wait %s seconds after being kicked to rejoin (+J)", user->nick.c_str(), chan->name.c_str(), chan->GetModeParameter('J').c_str());
00149                                                         return 1;
00150                                                 }
00151                                         }
00152                                         else
00153                                         {
00154                                                 // Expired record, remove.
00155                                                 itemstoremove.push_back(iter->first);
00156                                         }
00157                                 }
00158 
00159                                 for (unsigned int i = 0; i < itemstoremove.size(); i++)
00160                                         dl->erase(itemstoremove[i]);
00161 
00162                                 if (!dl->size())
00163                                 {
00164                                         // Now it's empty..
00165                                         delete dl;
00166                                         chan->Shrink("norejoinusers");
00167                                 }
00168                         }
00169                 }
00170                 return 0;
00171         }
00172 
00173         virtual void OnUserKick(User* source, User* user, Channel* chan, const std::string &reason, bool &silent)
00174         {
00175                 if (chan->IsModeSet('J') && (source != user))
00176                 {
00177                         delaylist* dl;
00178                         if (!chan->GetExt("norejoinusers", dl))
00179                         {
00180                                 dl = new delaylist;
00181                                 chan->Extend("norejoinusers", dl);
00182                         }
00183                         (*dl)[user] = ServerInstance->Time() + strtoint(chan->GetModeParameter('J'));
00184                 }
00185         }
00186 
00187         virtual void OnChannelDelete(Channel* chan)
00188         {
00189                 delaylist* dl;
00190 
00191                 if (chan->GetExt("norejoinusers", dl))
00192                 {
00193                         delete dl;
00194                         chan->Shrink("norejoinusers");
00195                 }
00196         }
00197 
00198         virtual void OnCleanup(int target_type, void* item)
00199         {
00200                 if(target_type == TYPE_CHANNEL)
00201                         OnChannelDelete((Channel*)item);
00202         }
00203 
00204 
00205         virtual ~ModuleKickNoRejoin()
00206         {
00207                 ServerInstance->Modes->DelMode(kr);
00208                 delete kr;
00209         }
00210 
00211         virtual Version GetVersion()
00212         {
00213                 return Version("$Id: m_kicknorejoin.cpp 10783 2008-11-01 23:02:23Z w00t $", VF_COMMON | VF_VENDOR, API_VERSION);
00214         }
00215 };
00216 
00217 
00218 MODULE_INIT(ModuleKickNoRejoin)