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

u_listmode.h

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 #ifndef INSPIRCD_LISTMODE_PROVIDER
00015 #define INSPIRCD_LISTMODE_PROVIDER
00016 
00019 inline std::string stringtime()
00020 {
00021         std::ostringstream TIME;
00022         TIME << time(NULL); 
00023         return TIME.str();
00024 }
00025 
00028 class ListItem : public classbase
00029 {
00030 public:
00031         std::string nick;
00032         std::string mask;
00033         std::string time;
00034 };
00035 
00038 class ListLimit : public classbase
00039 {
00040 public:
00041         std::string mask;
00042         unsigned int limit;
00043 };
00044 
00047 typedef std::vector<ListItem> modelist;
00050 typedef std::vector<ListLimit> limitlist;
00051 
00054 class ListModeRequest : public Request
00055 {
00056  public:
00057         User* user;
00058         Channel* chan;
00059 
00067         ListModeRequest(Module* sender, Module* target, User* u, Channel* c) : Request(sender, target, "LM_CHECKLIST"), user(u), chan(c)
00068         {
00069         }
00070 
00073         ~ListModeRequest()
00074         {
00075         }
00076 };
00077 
00080 class ListModeBase : public ModeHandler
00081 {
00082  protected:
00085         std::string infokey;
00088         unsigned int listnumeric;
00091         unsigned int endoflistnumeric;
00094         std::string endofliststring;
00097         bool tidy;
00100         std::string configtag;
00104         limitlist chanlimits;
00105  
00106  public:
00116         ListModeBase(InspIRCd* Instance, char modechar, const std::string &eolstr, unsigned int lnum, unsigned int eolnum, bool autotidy, const std::string &ctag = "banlist")
00117         : ModeHandler(Instance, modechar, 1, 1, true, MODETYPE_CHANNEL, false), listnumeric(lnum), endoflistnumeric(eolnum), endofliststring(eolstr), tidy(autotidy), configtag(ctag)
00118         {
00119                 this->DoRehash();
00120                 infokey = "listbase_mode_" + std::string(1, mode) + "_list";
00121         }
00122 
00125         std::pair<bool,std::string> ModeSet(User*, User*, Channel* channel, const std::string &parameter)
00126         {
00127                 modelist* el;
00128                 channel->GetExt(infokey, el);
00129                 if (el)
00130                 {
00131                         for (modelist::iterator it = el->begin(); it != el->end(); it++)
00132                         {
00133                                 if(parameter == it->mask)
00134                                 {
00135                                         return std::make_pair(true, parameter);
00136                                 }
00137                         }
00138                 }
00139                 return std::make_pair(false, parameter);
00140         }
00141 
00146         virtual void DisplayList(User* user, Channel* channel)
00147         {
00148                 modelist* el;
00149                 channel->GetExt(infokey, el);
00150                 if (el)
00151                 {
00152                         for (modelist::reverse_iterator it = el->rbegin(); it != el->rend(); ++it)
00153                         {
00154                                 user->WriteNumeric(listnumeric, "%s %s %s %s %s", user->nick.c_str(), channel->name.c_str(), it->mask.c_str(), it->nick.c_str(), it->time.c_str());
00155                         }
00156                 }
00157                 user->WriteNumeric(endoflistnumeric, "%s %s :%s", user->nick.c_str(), channel->name.c_str(), endofliststring.c_str());
00158         }
00159 
00160         virtual void DisplayEmptyList(User* user, Channel* channel)
00161         {
00162                 user->WriteNumeric(endoflistnumeric, "%s %s :%s", user->nick.c_str(), channel->name.c_str(), endofliststring.c_str());
00163         }
00164 
00169         virtual void RemoveMode(Channel* channel, irc::modestacker* stack)
00170         {
00171                 modelist* el;
00172                 channel->GetExt(infokey, el);
00173                 if (el)
00174                 {
00175                         irc::modestacker modestack(ServerInstance, false);
00176                         std::deque<std::string> stackresult;
00177                         std::vector<std::string> mode_junk;
00178                         mode_junk.push_back(channel->name);
00179 
00180                         for (modelist::iterator it = el->begin(); it != el->end(); it++)
00181                         {
00182                                 if (stack)
00183                                         stack->Push(this->GetModeChar(), it->mask);
00184                                 else
00185                                         modestack.Push(this->GetModeChar(), it->mask);
00186                         }
00187 
00188                         if (stack)
00189                                 return;
00190 
00191                         while (modestack.GetStackedLine(stackresult))
00192                         {
00193                                 for (size_t j = 0; j < stackresult.size(); j++)
00194                                 {
00195                                         mode_junk.push_back(stackresult[j]);
00196                                 }
00197 
00198                                 ServerInstance->SendMode(mode_junk, ServerInstance->FakeClient);                
00199                         }
00200                 }
00201         }
00202 
00205         virtual void RemoveMode(User*, irc::modestacker* stack)
00206         {
00207                 /* Listmodes dont get set on users */
00208         }
00209 
00212         virtual void DoRehash()
00213         {
00214                 ConfigReader Conf(ServerInstance);
00215 
00216                 chanlimits.clear();
00217 
00218                 for (int i = 0; i < Conf.Enumerate(configtag); i++)
00219                 {
00220                         // For each <banlist> tag
00221                         ListLimit limit;
00222                         limit.mask = Conf.ReadValue(configtag, "chan", i);
00223                         limit.limit = Conf.ReadInteger(configtag, "limit", i, true);
00224 
00225                         if (limit.mask.size() && limit.limit > 0)
00226                                 chanlimits.push_back(limit);
00227                 }
00228                 if (chanlimits.size() == 0)
00229                 {
00230                         ListLimit limit;
00231                         limit.mask = "*";
00232                         limit.limit = 64;
00233                         chanlimits.push_back(limit);
00234                 }
00235         }
00236 
00239         virtual void DoImplements(Module* m)
00240         {
00241                 Implementation eventlist[] = { I_OnChannelDelete, I_OnSyncChannel, I_OnCleanup, I_OnRehash };
00242                 ServerInstance->Modules->Attach(eventlist, m, 4);
00243         }
00244 
00248         virtual ModeAction OnModeChange(User* source, User*, Channel* channel, std::string &parameter, bool adding, bool servermode)
00249         {
00250                 // Try and grab the list
00251                 modelist* el;
00252                 channel->GetExt(infokey, el);
00253 
00254                 if (adding)
00255                 {
00256                         // If there was no list
00257                         if (!el)
00258                         {
00259                                 // Make one
00260                                 el = new modelist;
00261                                 channel->Extend(infokey, el);
00262                         }
00263 
00264                         // Clean the mask up
00265                         if (this->tidy)
00266                                 ModeParser::CleanMask(parameter);
00267 
00268                         // Check if the item already exists in the list
00269                         for (modelist::iterator it = el->begin(); it != el->end(); it++)
00270                         {
00271                                 if (parameter == it->mask)
00272                                 {
00273                                         /* Give a subclass a chance to error about this */
00274                                         TellAlreadyOnList(source, channel, parameter);
00275                                         
00276                                         // it does, deny the change
00277                                         return MODEACTION_DENY;
00278                                 }
00279                         }
00280 
00281                         unsigned int maxsize = 0;
00282 
00283                         for (limitlist::iterator it = chanlimits.begin(); it != chanlimits.end(); it++)
00284                         {
00285                                 if (InspIRCd::Match(channel->name, it->mask))
00286                                 {
00287                                         // We have a pattern matching the channel...
00288                                         maxsize = el->size();
00289                                         if (IS_LOCAL(source) || (maxsize < it->limit))
00290                                         {
00291                                                 /* Ok, it *could* be allowed, now give someone subclassing us
00292                                                  * a chance to validate the parameter.
00293                                                  * The param is passed by reference, so they can both modify it
00294                                                  * and tell us if we allow it or not.
00295                                                  *
00296                                                  * eg, the subclass could:
00297                                                  * 1) allow
00298                                                  * 2) 'fix' parameter and then allow
00299                                                  * 3) deny
00300                                                  */
00301                                                 if (ValidateParam(source, channel, parameter))
00302                                                 {
00303                                                         // And now add the mask onto the list...
00304                                                         ListItem e;
00305                                                         e.mask = parameter;
00306                                                         e.nick = servermode ? ServerInstance->Config->ServerName : source->nick;
00307                                                         e.time = stringtime();
00308 
00309                                                         el->push_back(e);
00310                                                         return MODEACTION_ALLOW;
00311                                                 }
00312                                                 else
00313                                                 {
00314                                                         /* If they deny it they have the job of giving an error message */
00315                                                         return MODEACTION_DENY;
00316                                                 }
00317                                         }
00318                                 }
00319                         }
00320 
00321                         /* List is full, give subclass a chance to send a custom message */
00322                         if (!TellListTooLong(source, channel, parameter))
00323                         {
00324                                 source->WriteNumeric(478, "%s %s %s :Channel ban/ignore list is full", source->nick.c_str(), channel->name.c_str(), parameter.c_str());
00325                         }
00326                         
00327                         parameter = "";
00328                         return MODEACTION_DENY; 
00329                 }
00330                 else
00331                 {
00332                         // We're taking the mode off
00333                         if (el)
00334                         {
00335                                 for (modelist::iterator it = el->begin(); it != el->end(); it++)
00336                                 {
00337                                         if (parameter == it->mask)
00338                                         {
00339                                                 el->erase(it);
00340                                                 if (el->size() == 0)
00341                                                 {
00342                                                         channel->Shrink(infokey);
00343                                                         delete el;
00344                                                 }
00345                                                 return MODEACTION_ALLOW;
00346                                         }
00347                                 }
00348                                 /* Tried to remove something that wasn't set */
00349                                 TellNotSet(source, channel, parameter);
00350                                 parameter = "";
00351                                 return MODEACTION_DENY;
00352                         }
00353                         else
00354                         {
00355                                 /* Hmm, taking an exception off a non-existant list, DIE */
00356                                 TellNotSet(source, channel, parameter);
00357                                 parameter = "";
00358                                 return MODEACTION_DENY;
00359                         }
00360                 }
00361                 return MODEACTION_DENY;
00362         }
00363 
00366         virtual std::string& GetInfoKey()
00367         {
00368                 return infokey;
00369         }
00370 
00375         virtual void DoChannelDelete(Channel* chan)
00376         {
00377                 modelist* mlist;
00378                 chan->GetExt(infokey, mlist);
00379 
00380                 if (mlist)
00381                 {
00382                         chan->Shrink(infokey);
00383                         delete mlist;
00384                 }
00385         }
00386 
00393         virtual void DoSyncChannel(Channel* chan, Module* proto, void* opaque)
00394         {
00395                 modelist* mlist;
00396                 chan->GetExt(infokey, mlist);
00397                 irc::modestacker modestack(ServerInstance, true);
00398                 std::deque<std::string> stackresult;
00399                 if (mlist)
00400                 {
00401                         for (modelist::iterator it = mlist->begin(); it != mlist->end(); it++)
00402                         {
00403                                 modestack.Push(std::string(1, mode)[0], it->mask);
00404                         }
00405                 }
00406                 while (modestack.GetStackedLine(stackresult))
00407                 {
00408                         irc::stringjoiner mode_join(" ", stackresult, 0, stackresult.size() - 1);
00409                         std::string line = mode_join.GetJoined();
00410                         proto->ProtoSendMode(opaque, TYPE_CHANNEL, chan, line);
00411                 }
00412         }
00413 
00418         virtual void DoCleanup(int, void*)
00419         {
00420         }
00421         
00429         virtual bool ValidateParam(User*, Channel*, std::string&)
00430         {
00431                 return true;
00432         }
00433         
00441         virtual bool TellListTooLong(User*, Channel*, std::string&)
00442         {
00443                 return false;
00444         }
00445         
00452         virtual void TellAlreadyOnList(User*, Channel*, std::string&)
00453         {
00454         }
00455         
00462         virtual void TellNotSet(User*, Channel*, std::string&)
00463         {
00464         }
00465 };
00466 
00467 #endif
00468