Anope IRC Services  Version 2.0
chanserv.cpp
Go to the documentation of this file.
1 /* ChanServ core functions
2  *
3  * (C) 2003-2014 Anope Team
4  * Contact us at team@anope.org
5  *
6  * Please read COPYING and README for further details.
7  *
8  * Based on the original code of Epona by Lara.
9  * Based on the original code of Services by Andy Church.
10  */
11 
12 #include "module.h"
13 #include "modules/cs_mode.h"
14 
15 class ChanServCore : public Module, public ChanServService
16 {
18  std::vector<Anope::string> defaults;
22 
23  public:
24  ChanServCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, PSEUDOCLIENT | VENDOR),
25  ChanServService(this), inhabit(this, "inhabit"), persist("PERSIST"), always_lower(false)
26  {
27  }
28 
30  {
34  class ChanServTimer : public Timer
35  {
39 
40  public:
44  ChanServTimer(Reference<BotInfo> &cs, ExtensibleItem<bool> &i, Module *m, Channel *chan) : Timer(m, Config->GetModule(m)->Get<time_t>("inhabit", "15s")), ChanServ(cs), inhabit(i), c(chan)
45  {
46  if (!ChanServ || !c)
47  return;
48  inhabit.Set(c, true);
49  if (!c->ci || !c->ci->bi)
50  ChanServ->Join(c);
51  else if (!c->FindUser(c->ci->bi))
52  c->ci->bi->Join(c);
53 
54  /* Set +ntsi to prevent rejoin */
55  c->SetMode(NULL, "NOEXTERNAL");
56  c->SetMode(NULL, "TOPIC");
57  c->SetMode(NULL, "SECRET");
58  c->SetMode(NULL, "INVITE");
59  }
60 
64  void Tick(time_t) anope_override
65  {
66  if (!c)
67  return;
68 
69  inhabit.Unset(c);
70 
71  /* In the event we don't part */
72  c->RemoveMode(NULL, "SECRET");
73  c->RemoveMode(NULL, "INVITE");
74 
75  if (!c->ci || !c->ci->bi)
76  {
77  if (ChanServ)
78  ChanServ->Part(c);
79  }
80  /* If someone has rejoined this channel in the meantime, don't part the bot */
81  else if (c->users.size() <= 1)
82  c->ci->bi->Part(c);
83  }
84  };
85 
86  if (inhabit.HasExt(c))
87  return;
88 
89  new ChanServTimer(ChanServ, inhabit, this->owner, c);
90  }
91 
93  {
94  const Anope::string &channick = conf->GetModule(this)->Get<const Anope::string>("client");
95 
96  if (channick.empty())
97  throw ConfigException(Module::name + ": <client> must be defined");
98 
99  BotInfo *bi = BotInfo::Find(channick, true);
100  if (!bi)
101  throw ConfigException(Module::name + ": no bot named " + channick);
102 
103  ChanServ = bi;
104 
105  spacesepstream(conf->GetModule(this)->Get<const Anope::string>("defaults", "greet fantasy")).GetTokens(defaults);
106  if (defaults.empty())
107  {
108  defaults.push_back("KEEPTOPIC");
109  defaults.push_back("CS_SECURE");
110  defaults.push_back("SECUREFOUNDER");
111  defaults.push_back("SIGNKICK");
112  }
113  else if (defaults[0].equals_ci("none"))
114  defaults.clear();
115 
116  always_lower = conf->GetModule(this)->Get<bool>("always_lower_ts");
117  }
118 
120  {
121  if (bi == ChanServ)
122  ChanServ = NULL;
123  }
124 
126  {
127  if (bi == ChanServ && Config->GetModule(this)->Get<bool>("opersonly") && !u->HasMode("OPER"))
128  {
129  u->SendMessage(bi, ACCESS_DENIED);
130  return EVENT_STOP;
131  }
132 
133  return EVENT_CONTINUE;
134  }
135 
137  {
138  std::deque<ChannelInfo *> chans;
139  nc->GetChannelReferences(chans);
140  int max_reg = Config->GetModule(this)->Get<int>("maxregistered");
141 
142  for (unsigned i = 0; i < chans.size(); ++i)
143  {
144  ChannelInfo *ci = chans[i];
145 
146  if (ci->GetFounder() == nc)
147  {
148  NickCore *newowner = NULL;
149  if (ci->GetSuccessor() && ci->GetSuccessor() != nc && (ci->GetSuccessor()->IsServicesOper() || !max_reg || ci->GetSuccessor()->channelcount < max_reg))
150  newowner = ci->GetSuccessor();
151  else
152  {
153  const ChanAccess *highest = NULL;
154  for (unsigned j = 0; j < ci->GetAccessCount(); ++j)
155  {
156  const ChanAccess *ca = ci->GetAccess(j);
157  NickCore *anc = ca->GetAccount();
158 
159  if (!anc || (!anc->IsServicesOper() && max_reg && anc->channelcount >= max_reg) || (anc == nc))
160  continue;
161  if (!highest || *ca > *highest)
162  highest = ca;
163  }
164  if (highest)
165  newowner = highest->GetAccount();
166  }
167 
168  if (newowner)
169  {
170  Log(LOG_NORMAL, "chanserv/drop", ChanServ) << "Transferring foundership of " << ci->name << " from deleted nick " << nc->display << " to " << newowner->display;
171  ci->SetFounder(newowner);
172  ci->SetSuccessor(NULL);
173  }
174  else
175  {
176  Log(LOG_NORMAL, "chanserv/drop", ChanServ) << "Deleting channel " << ci->name << " owned by deleted nick " << nc->display;
177 
178  delete ci;
179  continue;
180  }
181  }
182 
183  if (ci->GetSuccessor() == nc)
184  ci->SetSuccessor(NULL);
185 
186  for (unsigned j = 0; j < ci->GetAccessCount(); ++j)
187  {
188  const ChanAccess *ca = ci->GetAccess(j);
189 
190  if (ca->GetAccount() == nc)
191  {
192  delete ci->EraseAccess(j);
193  break;
194  }
195  }
196 
197  for (unsigned j = 0; j < ci->GetAkickCount(); ++j)
198  {
199  const AutoKick *akick = ci->GetAkick(j);
200  if (akick->nc == nc)
201  {
202  ci->EraseAkick(j);
203  break;
204  }
205  }
206  }
207  }
208 
210  {
211  /* remove access entries that are this channel */
212 
213  std::deque<Anope::string> chans;
214  ci->GetChannelReferences(chans);
215 
216  for (unsigned i = 0; i < chans.size(); ++i)
217  {
218  ChannelInfo *c = ChannelInfo::Find(chans[i]);
219  if (!c)
220  continue;
221 
222  for (unsigned j = 0; j < c->GetAccessCount(); ++j)
223  {
224  ChanAccess *a = c->GetAccess(j);
225 
226  if (a->Mask().equals_ci(ci->name))
227  {
228  delete a;
229  break;
230  }
231  }
232  }
233 
234  if (ci->c)
235  {
236  ci->c->RemoveMode(ci->WhoSends(), "REGISTERED", "", false);
237 
238  const Anope::string &require = Config->GetModule(this)->Get<const Anope::string>("require");
239  if (!require.empty())
240  ci->c->SetModes(ci->WhoSends(), false, "-%s", require.c_str());
241  }
242  }
243 
244  EventReturn OnPreHelp(CommandSource &source, const std::vector<Anope::string> &params) anope_override
245  {
246  if (!params.empty() || source.c || source.service != *ChanServ)
247  return EVENT_CONTINUE;
248  source.Reply(_("\002%s\002 allows you to register and control various\n"
249  "aspects of channels. %s can often prevent\n"
250  "malicious users from \"taking over\" channels by limiting\n"
251  "who is allowed channel operator privileges. Available\n"
252  "commands are listed below; to use them, type\n"
253  "\002%s%s \037command\037\002. For more information on a\n"
254  "specific command, type \002%s%s HELP \037command\037\002.\n"),
255  ChanServ->nick.c_str(), ChanServ->nick.c_str(), Config->StrictPrivmsg.c_str(), ChanServ->nick.c_str(), Config->StrictPrivmsg.c_str(), ChanServ->nick.c_str(), ChanServ->nick.c_str(), source.command.c_str());
256  return EVENT_CONTINUE;
257  }
258 
259  void OnPostHelp(CommandSource &source, const std::vector<Anope::string> &params) anope_override
260  {
261  if (!params.empty() || source.c || source.service != *ChanServ)
262  return;
263  time_t chanserv_expire = Config->GetModule(this)->Get<time_t>("expire", "14d");
264  if (chanserv_expire >= 86400)
265  source.Reply(_(" \n"
266  "Note that any channel which is not used for %d days\n"
267  "(i.e. which no user on the channel's access list enters\n"
268  "for that period of time) will be automatically dropped."), chanserv_expire / 86400);
269  if (source.IsServicesOper())
270  source.Reply(_(" \n"
271  "Services Operators can also, depending on their access drop\n"
272  "any channel, view (and modify) the access, levels and akick\n"
273  "lists and settings for any channel."));
274  }
275 
277  {
278  if (!c)
279  return;
280 
281  if (c->ci)
282  c->SetMode(c->ci->WhoSends(), "REGISTERED", "", false);
283  else
284  c->RemoveMode(c->ci->WhoSends(), "REGISTERED", "", false);
285 
286  const Anope::string &require = Config->GetModule(this)->Get<const Anope::string>("require");
287  if (!require.empty())
288  {
289  if (c->ci)
290  c->SetModes(c->ci->WhoSends(), false, "+%s", require.c_str());
291  else
292  c->SetModes(c->ci->WhoSends(), false, "-%s", require.c_str());
293  }
294  }
295 
297  {
298  /* Set default chan flags */
299  for (unsigned i = 0; i < defaults.size(); ++i)
300  ci->Extend<bool>(defaults[i].upper());
301  }
302 
304  {
305  if (Config->GetModule(this)->Get<const Anope::string>("nomlock").find(cm->mchar) != Anope::string::npos
306  || Config->GetModule(this)->Get<const Anope::string>("require").find(cm->mchar) != Anope::string::npos)
307  return EVENT_STOP;
308  return EVENT_CONTINUE;
309  }
310 
312  {
313  bool perm = c->HasMode("PERM") || (c->ci && persist && persist->HasExt(c->ci));
314  if (!perm && !c->botchannel && (c->users.empty() || (c->users.size() == 1 && c->users.begin()->second->user->server == Me)))
315  {
316  this->Hold(c);
317  }
318  }
319 
321  {
322  if (l->type == LOG_CHANNEL)
323  l->bi = ChanServ;
324  }
325 
327  {
328  time_t chanserv_expire = Config->GetModule(this)->Get<time_t>("expire", "14d");
329 
330  if (!chanserv_expire || Anope::NoExpire || Anope::ReadOnly)
331  return;
332 
333  for (registered_channel_map::const_iterator it = RegisteredChannelList->begin(), it_end = RegisteredChannelList->end(); it != it_end; )
334  {
335  ChannelInfo *ci = it->second;
336  ++it;
337 
338  bool expire = false;
339 
340  if (Anope::CurTime - ci->last_used >= chanserv_expire)
341  {
342  if (ci->c)
343  {
344  time_t last_used = ci->last_used;
345  for (Channel::ChanUserList::const_iterator cit = ci->c->users.begin(), cit_end = ci->c->users.end(); cit != cit_end && last_used == ci->last_used; ++cit)
346  ci->AccessFor(cit->second->user);
347  expire = last_used == ci->last_used;
348  }
349  else
350  expire = true;
351  }
352 
353  FOREACH_MOD(OnPreChanExpire, (ci, expire));
354 
355  if (expire)
356  {
357  Log(LOG_NORMAL, "chanserv/expire", ChanServ) << "Expiring channel " << ci->name << " (founder: " << (ci->GetFounder() ? ci->GetFounder()->display : "(none)") << ")";
358  FOREACH_MOD(OnChanExpire, (ci));
359  delete ci;
360  }
361  }
362  }
363 
365  {
366  /* Do not delete this channel if ChanServ/a BotServ bot is inhabiting it */
367  if (inhabit.HasExt(c))
368  return EVENT_STOP;
369 
370  /* Channel is persistent, it shouldn't be deleted and the service bot should stay */
371  if (c->ci && persist && persist->Get(c->ci))
372  return EVENT_STOP;
373 
374  return EVENT_CONTINUE;
375  }
376 
378  {
379  if (!persist)
380  return;
381  /* Find all persistent channels and create them, as we are about to finish burst to our uplink */
382  for (registered_channel_map::iterator it = RegisteredChannelList->begin(), it_end = RegisteredChannelList->end(); it != it_end; ++it)
383  {
384  ChannelInfo *ci = it->second;
385  if (persist->Get(ci))
386  {
387  bool c;
388  ci->c = Channel::FindOrCreate(ci->name, c, ci->time_registered);
389 
390  if (ModeManager::FindChannelModeByName("PERM") != NULL)
391  {
392  if (c)
393  IRCD->SendChannel(ci->c);
394  ci->c->SetMode(NULL, "PERM");
395  }
396  else
397  {
398  if (!ci->bi)
399  ci->WhoSends()->Assign(NULL, ci);
400  if (ci->c->FindUser(ci->bi) == NULL)
401  {
402  ChannelStatus status(Config->GetModule("botserv")->Get<const Anope::string>("botmodes"));
403  ci->bi->Join(ci->c, &status);
404  }
405  }
406  }
407  }
408 
409  }
410 
412  {
413  if (!persist || !ci->c)
414  return;
415  /* Mark the channel as persistent */
416  if (ci->c->HasMode("PERM"))
417  persist->Set(ci);
418  /* Persist may be in def cflags, set it here */
419  else if (persist->Get(ci))
420  ci->c->SetMode(NULL, "PERM");
421  }
422 
424  {
425  if (always_lower && c->ci && c->creation_time > c->ci->time_registered)
426  {
427  Log(LOG_DEBUG) << "Changing TS of " << c->name << " from " << c->creation_time << " to " << c->ci->time_registered;
428  c->creation_time = c->ci->time_registered;
429  IRCD->SendChannel(c);
430  c->Reset();
431  }
432  }
433 
435  {
436  if (!always_lower && Anope::CurTime == c->creation_time && c->ci && setter.GetUser() && !setter.GetUser()->server->IsULined())
437  {
438  ChanUserContainer *cu = c->FindUser(setter.GetUser());
440  if (cu && cm && !cu->status.HasMode(cm->mchar))
441  {
442  /* Our -o and their mode change crossing, bounce their mode */
443  c->RemoveMode(c->ci->WhoSends(), mode, param);
444  /* We don't set mlocks until after the join has finished processing, it will stack with this change,
445  * so there isn't much for the user to remove except -nt etc which is likely locked anyway.
446  */
447  }
448  }
449 
450  return EVENT_CONTINUE;
451  }
452 
453  void OnChanInfo(CommandSource &source, ChannelInfo *ci, InfoFormatter &info, bool show_all) anope_override
454  {
455  if (!show_all)
456  return;
457 
458  time_t chanserv_expire = Config->GetModule(this)->Get<time_t>("expire", "14d");
459  if (!ci->HasExt("CS_NO_EXPIRE") && chanserv_expire && !Anope::NoExpire && ci->last_used != Anope::CurTime)
460  info[_("Expires")] = Anope::strftime(ci->last_used + chanserv_expire, source.GetAccount());
461  }
462 
463  void OnSetCorrectModes(User *user, Channel *chan, AccessGroup &access, bool &give_modes, bool &take_modes) anope_override
464  {
465  if (always_lower)
466  // Since we always lower the TS, the other side will remove the modes if the channel ts lowers, so we don't
467  // have to worry about it
468  take_modes = false;
469  else if (ModeManager::FindChannelModeByName("REGISTERED"))
470  // Otherwise if the registered channel mode exists, we should remove modes if the channel is not +r
471  take_modes = !chan->HasMode("REGISTERED");
472  }
473 };
474 
476 
Definition: bots.h:24
CoreExport bool ReadOnly
Definition: main.cpp:28
Definition: servers.h:42
void OnBotDelete(BotInfo *bi) anope_override
Definition: chanserv.cpp:119
Anope::string name
Definition: modules.h:221
bool always_lower
Definition: chanserv.cpp:21
std::vector< Anope::string > defaults
Definition: chanserv.cpp:18
static ChannelMode * FindChannelModeByName(const Anope::string &name)
Definition: modes.cpp:542
Definition: timers.h:18
void EraseAkick(unsigned index)
Definition: regchannel.cpp:567
Definition: hashcomp.h:84
unsigned GetAkickCount() const
Definition: regchannel.cpp:562
EventReturn OnCanSet(User *u, const ChannelMode *cm) anope_override
Definition: chanserv.cpp:303
Anope::string name
Definition: regchannel.h:63
void Join(Channel *c, ChannelStatus *status=NULL)
Definition: bots.cpp:193
void OnChanInfo(CommandSource &source, ChannelInfo *ci, InfoFormatter &info, bool show_all) anope_override
Definition: chanserv.cpp:453
EventReturn OnCheckDelete(Channel *c) anope_override
Definition: chanserv.cpp:364
void Assign(User *u, ChannelInfo *ci)
Definition: bots.cpp:153
void OnJoinChannel(User *u, Channel *c) anope_override
Definition: chanserv.cpp:423
#define ACCESS_DENIED
Definition: language.h:73
void OnPostHelp(CommandSource &source, const std::vector< Anope::string > &params) anope_override
Definition: chanserv.cpp:259
void OnPreUplinkSync(Server *serv) anope_override
Definition: chanserv.cpp:377
void GetTokens(T &token)
Definition: anope.h:587
virtual void OnPreChanExpire(ChannelInfo *ci, bool &expire)
Definition: modules.h:485
Definition: users.h:34
Reference< BotInfo > ChanServ
Definition: chanserv.cpp:17
void OnLog(Log *l) anope_override
Definition: chanserv.cpp:320
void OnChannelSync(Channel *c) anope_override
Definition: chanserv.cpp:311
NickCore * GetSuccessor() const
Definition: regchannel.cpp:378
EventReturn OnBotPrivmsg(User *u, BotInfo *bi, Anope::string &message) anope_override
Definition: chanserv.cpp:125
NickCore * GetAccount() const
Definition: access.cpp:204
ExtensibleItem< bool > inhabit
Definition: chanserv.cpp:19
EventReturn OnPreHelp(CommandSource &source, const std::vector< Anope::string > &params) anope_override
Definition: chanserv.cpp:244
bool equals_ci(const char *_str) const
Definition: anope.h:78
void Unset(Extensible *obj) anope_override
Definition: extensible.h:95
static Channel * FindOrCreate(const Anope::string &name, bool &created, time_t ts=Anope::CurTime)
Definition: channels.cpp:929
Serialize::Reference< ChannelInfo > ci
Definition: channels.h:46
bool HasMode(char c) const
Definition: modes.cpp:81
uint16_t channelcount
Definition: account.h:136
CoreExport time_t CurTime
Definition: main.cpp:41
void OnDelChan(ChannelInfo *ci) anope_override
Definition: chanserv.cpp:209
#define FOREACH_MOD(ename, args)
Definition: modules.h:62
void Hold(Channel *c) anope_override
Definition: chanserv.cpp:29
static ChannelInfo * Find(const Anope::string &name)
Definition: regchannel.cpp:630
BotInfo * WhoSends() const
Definition: regchannel.cpp:383
void SetSuccessor(NickCore *nc)
Definition: regchannel.cpp:369
void OnSetCorrectModes(User *user, Channel *chan, AccessGroup &access, bool &give_modes, bool &take_modes) anope_override
Definition: chanserv.cpp:463
NickCore * GetFounder() const
Definition: regchannel.cpp:364
Definition: Config.cs:26
Channel * c
Definition: regchannel.h:79
ChanAccess * EraseAccess(unsigned index)
Definition: regchannel.cpp:503
static const size_type npos
Definition: anope.h:44
T * Set(Extensible *obj, const T &value)
Definition: extensible.h:78
CoreExport Serialize::Checker< registered_channel_map > RegisteredChannelList
time_t last_used
Definition: regchannel.h:67
const Anope::string & Mask() const
Definition: access.cpp:196
const ChannelInfo * ci
Definition: logger.h:69
Anope::string display
Definition: account.h:113
char mchar
Definition: modes.h:47
void SetFounder(NickCore *nc)
Definition: regchannel.cpp:347
void Part(Channel *c, const Anope::string &reason="")
Definition: bots.cpp:211
unsigned GetAccessCount() const
Definition: regchannel.cpp:474
void OnReload(Configuration::Conf *conf) anope_override
Definition: chanserv.cpp:92
#define anope_override
Definition: services.h:56
bool empty() const
Definition: anope.h:126
CoreExport IRCDProto * IRCD
Definition: protocol.cpp:23
EventReturn
Definition: modules.h:129
#define MODULE_INIT(x)
Definition: modules.h:45
ChanUserList users
Definition: channels.h:56
ChanUserContainer * FindUser(User *u) const
Definition: channels.cpp:173
AutoKick * GetAkick(unsigned index) const
Definition: regchannel.cpp:552
AccessGroup AccessFor(const User *u)
Definition: regchannel.cpp:413
ChannelStatus status
Definition: channels.h:28
CoreExport bool NoExpire
Definition: main.cpp:28
Anope::string nick
Definition: users.h:62
virtual void SendChannel(Channel *c)
Definition: protocol.h:224
void OnCreateChan(ChannelInfo *ci) anope_override
Definition: chanserv.cpp:296
Serialize::Reference< NickCore > nc
Definition: regchannel.h:33
void SetMode(BotInfo *bi, ChannelMode *cm, const Anope::string &param="", bool enforce_mlock=true)
Definition: channels.cpp:401
ChanServCore(const Anope::string &modname, const Anope::string &creator)
Definition: chanserv.cpp:24
CoreExport Server * Me
Definition: servers.cpp:24
const char * c_str() const
Definition: anope.h:117
Definition: logger.h:53
void OnExpireTick() anope_override
Definition: chanserv.cpp:326
virtual bool IsServicesOper() const
Definition: nickcore.cpp:173
CoreExport Anope::string strftime(time_t t, const NickCore *nc=NULL, bool short_output=false)
Definition: misc.cpp:356
Serialize::Reference< BotInfo > bi
Definition: regchannel.h:82
bool HasExt(const Extensible *obj) const
Definition: extensible.h:111
ExtensibleRef< bool > persist
Definition: chanserv.cpp:20
void OnChanRegistered(ChannelInfo *ci) anope_override
Definition: chanserv.cpp:411
EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string &param) anope_override
Definition: chanserv.cpp:434
virtual void OnChanExpire(ChannelInfo *ci)
Definition: modules.h:490
#define _(x)
Definition: services.h:50
static BotInfo * Find(const Anope::string &nick, bool nick_only=false)
Definition: bots.cpp:249
void OnDelCore(NickCore *nc) anope_override
Definition: chanserv.cpp:136
void OnCheckModes(Reference< Channel > &c) anope_override
Definition: chanserv.cpp:276
time_t time_registered
Definition: regchannel.h:66
ChanAccess * GetAccess(unsigned index) const
Definition: regchannel.cpp:403
Module * owner
Definition: service.h:84
void RemoveMode(BotInfo *bi, ChannelMode *cm, const Anope::string &param="", bool enforce_mlock=true)
Definition: channels.cpp:459