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_permchannels.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 support for channel mode +P to provide permanent channels */
00017 
00018 
00021 class PermChannel : public ModeHandler
00022 {
00023  public:
00024         PermChannel(InspIRCd* Instance) : ModeHandler(Instance, 'P', 0, 0, false, MODETYPE_CHANNEL, false) { }
00025 
00026         ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding, bool sm)
00027         {
00028                 if (adding)
00029                 {
00030                         if (!channel->IsModeSet('P'))
00031                         {
00032                                 channel->SetMode('P',true);
00033                                 return MODEACTION_ALLOW;
00034                         }
00035                 }
00036                 else
00037                 {
00038                         if (channel->IsModeSet('P'))
00039                         {
00040                                 if (channel->GetUserCounter() == 0 && !sm)
00041                                 {
00042                                         /*
00043                                          * ugh, ugh, UGH!
00044                                          *
00045                                          * We can't delete this channel the way things work at the moment,
00046                                          * because of the following scenario:
00047                                          * s1:#c <-> s2:#c
00048                                          *
00049                                          * s1 has a user in #c, s2 does not. s2 has +P set. s2 has a losing TS.
00050                                          *
00051                                          * On netmerge, s2 loses, so s2 removes all modes (including +P) which
00052                                          * would subsequently delete the channel here causing big fucking problems.
00053                                          *
00054                                          * I don't think there's really a way around this, so just deny -P on a 0 user chan.
00055                                          * -- w00t
00056                                          *
00057                                          * delete channel;
00058                                          */
00059                                         return MODEACTION_DENY;
00060                                 }
00061 
00062                                 /* for servers, remove +P (to avoid desyncs) but don't bother trying to delete. */
00063                                 channel->SetMode('P',false);
00064                                 return MODEACTION_ALLOW;
00065                         }
00066                 }
00067 
00068                 return MODEACTION_DENY;
00069         }
00070 };
00071 
00072 class ModulePermanentChannels : public Module
00073 {
00074         PermChannel *p;
00075 public:
00076 
00077         ModulePermanentChannels(InspIRCd* Me) : Module(Me)
00078         {
00079                 p = new PermChannel(ServerInstance);
00080                 if (!ServerInstance->Modes->AddMode(p))
00081                 {
00082                         delete p;
00083                         throw ModuleException("Could not add new modes!");
00084                 }
00085                 Implementation eventlist[] = { I_OnChannelPreDelete };
00086                 ServerInstance->Modules->Attach(eventlist, this, 1);
00087 
00088                 OnRehash(NULL, "");
00089         }
00090 
00091         virtual ~ModulePermanentChannels()
00092         {
00093                 ServerInstance->Modes->DelMode(p);
00094                 delete p;
00095         }
00096 
00097         virtual void OnRehash(User *user, const std::string &parameter)
00098         {
00099                 /*
00100                  * Process config-defined list of permanent channels.
00101                  * -- w00t
00102                  */
00103                 ConfigReader MyConf(ServerInstance);
00104                 for (int i = 0; i < MyConf.Enumerate("permchannels"); i++)
00105                 {
00106                         std::string channel = MyConf.ReadValue("permchannels", "channel", i);
00107                         std::string topic = MyConf.ReadValue("permchannels", "topic", i);
00108                         std::string modes = MyConf.ReadValue("permchannels", "modes", i);
00109 
00110                         if (channel.empty())
00111                         {
00112                                 ServerInstance->Logs->Log("blah", DEBUG, "Malformed permchannels tag with empty channel name.");
00113                                 continue;
00114                         }
00115 
00116                         Channel *c = ServerInstance->FindChan(channel);
00117 
00118                         if (!c)
00119                         {
00120                                 c = new Channel(ServerInstance, channel, ServerInstance->Time());
00121                                 if (!topic.empty())
00122                                         c->SetTopic(NULL, topic, true);
00123                                 ServerInstance->Logs->Log("blah", DEBUG, "Added %s with topic %s", channel.c_str(), topic.c_str());
00124 
00125                                 if (modes.empty())
00126                                         continue;
00127 
00128                                 irc::spacesepstream list(modes);
00129                                 std::string modeseq;
00130                                 std::string par;
00131 
00132                                 list.GetToken(modeseq);
00133 
00134                                 // XXX bleh, should we pass this to the mode parser instead? ugly. --w00t
00135                                 for (std::string::iterator n = modeseq.begin(); n != modeseq.end(); ++n)
00136                                 {
00137                                         ModeHandler* mode = ServerInstance->Modes->FindMode(*n, MODETYPE_CHANNEL);
00138                                         if (mode)
00139                                         {
00140                                                 if (mode->GetNumParams(true))
00141                                                         list.GetToken(par);
00142                                                 else
00143                                                         par.clear();
00144 
00145                                                 mode->OnModeChange(ServerInstance->FakeClient, ServerInstance->FakeClient, c, par, true);
00146                                         }
00147                                 }
00148                         }
00149                 }
00150         }
00151 
00152         virtual Version GetVersion()
00153         {
00154                 return Version("$Id: m_permchannels.cpp 10695 2008-10-23 21:39:00Z w00t $",VF_COMMON|VF_VENDOR,API_VERSION);
00155         }
00156 
00157         virtual int OnChannelPreDelete(Channel *c)
00158         {
00159                 if (c->IsModeSet('P'))
00160                         return 1;
00161 
00162                 return 0;
00163         }
00164 };
00165 
00166 MODULE_INIT(ModulePermanentChannels)