Anope IRC Services  Version 2.0
cs_mode.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 
16 {
17  ModeLockImpl() : Serializable("ModeLock")
18  {
19  }
20 
22  {
24  if (chan)
25  {
26  ModeLocks *ml = chan->GetExt<ModeLocks>("modelocks");
27  if (ml)
28  ml->RemoveMLock(this);
29  }
30  }
31 
32  void Serialize(Serialize::Data &data) const anope_override;
34 };
35 
37 {
40 
41  ModeLocksImpl(Extensible *obj) : ci(anope_dynamic_static_cast<ChannelInfo *>(obj)), mlocks("ModeLock")
42  {
43  }
44 
46  {
47  for (ModeList::iterator it = this->mlocks->begin(); it != this->mlocks->end();)
48  {
49  ModeLock *ml = *it;
50  ++it;
51  delete ml;
52  }
53  }
54 
55  bool HasMLock(ChannelMode *mode, const Anope::string &param, bool status) const anope_override
56  {
57  if (!mode)
58  return false;
59 
60  for (ModeList::const_iterator it = this->mlocks->begin(); it != this->mlocks->end(); ++it)
61  {
62  const ModeLock *ml = *it;
63 
64  if (ml->name == mode->name && ml->set == status && ml->param == param)
65  return true;
66  }
67 
68  return false;
69  }
70 
71  bool SetMLock(ChannelMode *mode, bool status, const Anope::string &param, Anope::string setter, time_t created = Anope::CurTime) anope_override
72  {
73  if (!mode)
74  return false;
75 
76  RemoveMLock(mode, status, param);
77 
78  if (setter.empty())
79  setter = ci->GetFounder() ? ci->GetFounder()->display : "Unknown";
80 
81  ModeLock *ml = new ModeLockImpl();
82  ml->ci = ci->name;
83  ml->set = status;
84  ml->name = mode->name;
85  ml->param = param;
86  ml->setter = setter;
87  ml->created = created;
88 
89  EventReturn MOD_RESULT;
90  FOREACH_RESULT(OnMLock, MOD_RESULT, (this->ci, ml));
91  if (MOD_RESULT == EVENT_STOP)
92  {
93  delete ml;
94  return false;
95  }
96 
97  this->mlocks->push_back(ml);
98  return true;
99  }
100 
101  bool RemoveMLock(ChannelMode *mode, bool status, const Anope::string &param = "") anope_override
102  {
103  if (!mode)
104  return false;
105 
106  for (ModeList::iterator it = this->mlocks->begin(); it != this->mlocks->end(); ++it)
107  {
108  ModeLock *m = *it;
109 
110  if (m->name == mode->name)
111  {
112  // For list or status modes, we must check the parameter
113  if (mode->type == MODE_LIST || mode->type == MODE_STATUS)
114  if (m->param != param)
115  continue;
116 
117  EventReturn MOD_RESULT;
118  FOREACH_RESULT(OnUnMLock, MOD_RESULT, (this->ci, m));
119  if (MOD_RESULT == EVENT_STOP)
120  break;
121 
122  delete m;
123  return true;
124  }
125  }
126 
127  return false;
128  }
129 
131  {
132  ModeList::iterator it = std::find(this->mlocks->begin(), this->mlocks->end(), mlock);
133  if (it != this->mlocks->end())
134  this->mlocks->erase(it);
135  }
136 
138  {
139  ModeList ml;
140  this->mlocks->swap(ml);
141  for (unsigned i = 0; i < ml.size(); ++i)
142  delete ml[i];
143  }
144 
146  {
147  return this->mlocks;
148  }
149 
150  std::list<ModeLock *> GetModeLockList(const Anope::string &name) anope_override
151  {
152  std::list<ModeLock *> mlist;
153  for (ModeList::const_iterator it = this->mlocks->begin(); it != this->mlocks->end(); ++it)
154  {
155  ModeLock *m = *it;
156  if (m->name == name)
157  mlist.push_back(m);
158  }
159  return mlist;
160  }
161 
162  const ModeLock *GetMLock(const Anope::string &mname, const Anope::string &param = "") anope_override
163  {
164  for (ModeList::const_iterator it = this->mlocks->begin(); it != this->mlocks->end(); ++it)
165  {
166  ModeLock *m = *it;
167 
168  if (m->name == mname && m->param == param)
169  return m;
170  }
171 
172  return NULL;
173  }
174 
176  {
177  Anope::string pos = "+", neg = "-", params;
178 
179  for (ModeList::const_iterator it = this->mlocks->begin(); it != this->mlocks->end(); ++it)
180  {
181  const ModeLock *ml = *it;
183 
184  if (!cm || cm->type == MODE_LIST || cm->type == MODE_STATUS)
185  continue;
186 
187  if (ml->set)
188  pos += cm->mchar;
189  else
190  neg += cm->mchar;
191 
192  if (complete && ml->set && !ml->param.empty() && cm->type == MODE_PARAM)
193  params += " " + ml->param;
194  }
195 
196  if (pos.length() == 1)
197  pos.clear();
198  if (neg.length() == 1)
199  neg.clear();
200 
201  return pos + neg + params;
202  }
203 
205  {
206  if (this->mlocks->empty())
207  ci->Shrink<ModeLocks>("modelocks");
208  }
209 };
210 
212 {
213  data["ci"] << this->ci;
214  data["set"] << this->set;
215  data["name"] << this->name;
216  data["param"] << this->param;
217  data["setter"] << this->setter;
218  data.SetType("created", Serialize::Data::DT_INT); data["created"] << this->created;
219 }
220 
222 {
223  Anope::string sci;
224 
225  data["ci"] >> sci;
226 
228  if (!ci)
229  return NULL;
230 
231  ModeLockImpl *ml;
232  if (obj)
234  else
235  {
236  ml = new ModeLockImpl();
237  ml->ci = ci->name;
238  }
239 
240  data["set"] >> ml->set;
241  data["created"] >> ml->created;
242  data["setter"] >> ml->setter;
243  data["name"] >> ml->name;
244  data["param"] >> ml->param;
245 
246  if (!obj)
247  ci->Require<ModeLocksImpl>("modelocks")->mlocks->push_back(ml);
248 
249  return ml;
250 }
251 
252 class CommandCSMode : public Command
253 {
254  bool CanSet(CommandSource &source, ChannelInfo *ci, ChannelMode *cm, bool self)
255  {
256  if (!ci || !cm || cm->type != MODE_STATUS)
257  return false;
258 
259  return source.AccessFor(ci).HasPriv(cm->name + (self ? "ME" : ""));
260  }
261 
262  void DoLock(CommandSource &source, ChannelInfo *ci, const std::vector<Anope::string> &params)
263  {
264  User *u = source.GetUser();
265  const Anope::string &subcommand = params[2];
266  const Anope::string &param = params.size() > 3 ? params[3] : "";
267 
268  bool override = !source.AccessFor(ci).HasPriv("MODE");
269  ModeLocks *modelocks = ci->Require<ModeLocks>("modelocks");
270 
271  if (Anope::ReadOnly && !subcommand.equals_ci("LIST"))
272  {
273  source.Reply(READ_ONLY_MODE);
274  return;
275  }
276 
277  if ((subcommand.equals_ci("ADD") || subcommand.equals_ci("SET")) && !param.empty())
278  {
279  /* If setting, remove the existing locks */
280  if (subcommand.equals_ci("SET"))
281  {
282  const ModeLocks::ModeList mlocks = modelocks->GetMLock();
283  for (ModeLocks::ModeList::const_iterator it = mlocks.begin(); it != mlocks.end(); ++it)
284  {
285  const ModeLock *ml = *it;
287  if (cm && cm->CanSet(source.GetUser()))
288  modelocks->RemoveMLock(cm, ml->set, ml->param);
289  }
290  }
291 
292  spacesepstream sep(param);
294 
295  sep.GetToken(modes);
296 
297  Anope::string pos = "+", neg = "-", pos_params, neg_params;
298 
299  int adding = 1;
300  bool needreply = true;
301  for (size_t i = 0; i < modes.length(); ++i)
302  {
303  switch (modes[i])
304  {
305  case '+':
306  adding = 1;
307  break;
308  case '-':
309  adding = 0;
310  break;
311  default:
312  needreply = false;
314  if (!cm)
315  {
316  source.Reply(_("Unknown mode character %c ignored."), modes[i]);
317  break;
318  }
319  else if (u && !cm->CanSet(u))
320  {
321  source.Reply(_("You may not (un)lock mode %c."), modes[i]);
322  break;
323  }
324 
325  Anope::string mode_param;
326  if (((cm->type == MODE_STATUS || cm->type == MODE_LIST) && !sep.GetToken(mode_param)) || (cm->type == MODE_PARAM && adding && !sep.GetToken(mode_param)))
327  source.Reply(_("Missing parameter for mode %c."), cm->mchar);
328  else if (cm->type == MODE_LIST && ci->c && IRCD->GetMaxListFor(ci->c) && ci->c->HasMode(cm->name) >= IRCD->GetMaxListFor(ci->c))
329  source.Reply(_("List for mode %c is full."), cm->mchar);
330  else
331  {
332  modelocks->SetMLock(cm, adding, mode_param, source.GetNick());
333 
334  if (adding)
335  {
336  pos += cm->mchar;
337  if (!mode_param.empty())
338  pos_params += " " + mode_param;
339  }
340  else
341  {
342  neg += cm->mchar;
343  if (!mode_param.empty())
344  neg_params += " " + mode_param;
345  }
346  }
347  }
348  }
349 
350  if (pos == "+")
351  pos.clear();
352  if (neg == "-")
353  neg.clear();
354  Anope::string reply = pos + neg + pos_params + neg_params;
355 
356  if (!reply.empty())
357  {
358  source.Reply(_("%s locked on %s."), reply.c_str(), ci->name.c_str());
359  Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to lock " << reply;
360  }
361  else if (needreply)
362  source.Reply(_("Nothing to do."));
363 
364  if (ci->c)
365  ci->c->CheckModes();
366  }
367  else if (subcommand.equals_ci("DEL") && !param.empty())
368  {
369  spacesepstream sep(param);
371 
372  sep.GetToken(modes);
373 
374  int adding = 1;
375  bool needreply = true;
376  for (size_t i = 0; i < modes.length(); ++i)
377  {
378  switch (modes[i])
379  {
380  case '+':
381  adding = 1;
382  break;
383  case '-':
384  adding = 0;
385  break;
386  default:
387  needreply = false;
389  if (!cm)
390  {
391  source.Reply(_("Unknown mode character %c ignored."), modes[i]);
392  break;
393  }
394  else if (u && !cm->CanSet(u))
395  {
396  source.Reply(_("You may not (un)lock mode %c."), modes[i]);
397  break;
398  }
399 
400  Anope::string mode_param;
401  if (cm->type != MODE_REGULAR && !sep.GetToken(mode_param))
402  source.Reply(_("Missing parameter for mode %c."), cm->mchar);
403  else
404  {
405  if (modelocks->RemoveMLock(cm, adding, mode_param))
406  {
407  if (!mode_param.empty())
408  mode_param = " " + mode_param;
409  source.Reply(_("%c%c%s has been unlocked from %s."), adding == 1 ? '+' : '-', cm->mchar, mode_param.c_str(), ci->name.c_str());
410  Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to unlock " << (adding ? '+' : '-') << cm->mchar << mode_param;
411  }
412  else
413  source.Reply(_("%c%c is not locked on %s."), adding == 1 ? '+' : '-', cm->mchar, ci->name.c_str());
414  }
415  }
416  }
417 
418  if (needreply)
419  source.Reply(_("Nothing to do."));
420  }
421  else if (subcommand.equals_ci("LIST"))
422  {
423  const ModeLocks::ModeList mlocks = modelocks->GetMLock();
424  if (mlocks.empty())
425  {
426  source.Reply(_("Channel %s has no mode locks."), ci->name.c_str());
427  }
428  else
429  {
430  ListFormatter list(source.GetAccount());
431  list.AddColumn(_("Mode")).AddColumn(_("Param")).AddColumn(_("Creator")).AddColumn(_("Created"));
432 
433  for (ModeLocks::ModeList::const_iterator it = mlocks.begin(), it_end = mlocks.end(); it != it_end; ++it)
434  {
435  const ModeLock *ml = *it;
437  if (!cm)
438  continue;
439 
441  entry["Mode"] = Anope::printf("%c%c", ml->set ? '+' : '-', cm->mchar);
442  entry["Param"] = ml->param;
443  entry["Creator"] = ml->setter;
444  entry["Created"] = Anope::strftime(ml->created, NULL, true);
445  list.AddEntry(entry);
446  }
447 
448  source.Reply(_("Mode locks for %s:"), ci->name.c_str());
449 
450  std::vector<Anope::string> replies;
451  list.Process(replies);
452 
453  for (unsigned i = 0; i < replies.size(); ++i)
454  source.Reply(replies[i]);
455  }
456  }
457  else
458  this->OnSyntaxError(source, subcommand);
459  }
460 
461  void DoSet(CommandSource &source, ChannelInfo *ci, const std::vector<Anope::string> &params)
462  {
463  User *u = source.GetUser();
464 
465  bool has_access = source.AccessFor(ci).HasPriv("MODE") || source.HasPriv("chanserv/administration");
466  bool can_override = source.HasPriv("chanserv/administration");
467 
468  spacesepstream sep(params.size() > 3 ? params[3] : "");
469  Anope::string modes = params[2], param;
470 
471  bool override = !source.AccessFor(ci).HasPriv("MODE") && source.HasPriv("chanserv/administration");
472  Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "to set " << params[2] << (params.size() > 3 ? " " + params[3] : "");
473 
474  int adding = -1;
475  for (size_t i = 0; i < modes.length(); ++i)
476  {
477  switch (modes[i])
478  {
479  case '+':
480  adding = 1;
481  break;
482  case '-':
483  adding = 0;
484  break;
485  case '*':
486  if (adding == -1 || !has_access)
487  break;
488  for (unsigned j = 0; j < ModeManager::GetChannelModes().size(); ++j)
489  {
491 
492  if (!u || cm->CanSet(u) || can_override)
493  {
494  if (cm->type == MODE_REGULAR || (!adding && cm->type == MODE_PARAM))
495  {
496  if (adding)
497  ci->c->SetMode(NULL, cm);
498  else
499  ci->c->RemoveMode(NULL, cm);
500  }
501  }
502  }
503  break;
504  default:
505  if (adding == -1)
506  break;
508  if (!cm || (u && !cm->CanSet(u) && !can_override))
509  continue;
510  switch (cm->type)
511  {
512  case MODE_REGULAR:
513  if (!has_access)
514  break;
515  if (adding)
516  ci->c->SetMode(NULL, cm);
517  else
518  ci->c->RemoveMode(NULL, cm);
519  break;
520  case MODE_PARAM:
521  if (!has_access)
522  break;
523  if (adding && !sep.GetToken(param))
524  break;
525  if (adding)
526  ci->c->SetMode(NULL, cm, param);
527  else
528  ci->c->RemoveMode(NULL, cm);
529  break;
530  case MODE_STATUS:
531  {
532  if (!sep.GetToken(param))
533  param = source.GetNick();
534 
535  AccessGroup u_access = source.AccessFor(ci);
536 
537  if (param.find_first_of("*?") != Anope::string::npos)
538  {
539  if (!this->CanSet(source, ci, cm, false) && !can_override)
540  {
541  source.Reply(_("You do not have access to set mode %c."), cm->mchar);
542  break;
543  }
544 
545  for (Channel::ChanUserList::const_iterator it = ci->c->users.begin(), it_end = ci->c->users.end(); it != it_end;)
546  {
547  ChanUserContainer *uc = it->second;
548  ++it;
549 
550  AccessGroup targ_access = ci->AccessFor(uc->user);
551 
552  if (uc->user->IsProtected() || (ci->HasExt("PEACE") && targ_access >= u_access && !can_override))
553  {
554  source.Reply(_("You do not have the access to change %s's modes."), uc->user->nick.c_str());
555  continue;
556  }
557 
558  if (Anope::Match(uc->user->GetMask(), param))
559  {
560  if (adding)
561  ci->c->SetMode(NULL, cm, uc->user->GetUID());
562  else
563  ci->c->RemoveMode(NULL, cm, uc->user->GetUID());
564  }
565  }
566  }
567  else
568  {
569  User *target = User::Find(param, true);
570  if (target == NULL)
571  {
572  source.Reply(NICK_X_NOT_IN_USE, param.c_str());
573  break;
574  }
575 
576  if (!this->CanSet(source, ci, cm, source.GetUser() == target) && !can_override)
577  {
578  source.Reply(_("You do not have access to set mode %c."), cm->mchar);
579  break;
580  }
581 
582  if (source.GetUser() != target)
583  {
584  AccessGroup targ_access = ci->AccessFor(target);
585  if (ci->HasExt("PEACE") && targ_access >= u_access && !can_override)
586  {
587  source.Reply(_("You do not have the access to change %s's modes."), target->nick.c_str());
588  break;
589  }
590  else if (target->IsProtected())
591  {
592  source.Reply(ACCESS_DENIED);
593  break;
594  }
595  }
596 
597  if (adding)
598  ci->c->SetMode(NULL, cm, target->GetUID());
599  else
600  ci->c->RemoveMode(NULL, cm, target->GetUID());
601  }
602  break;
603  }
604  case MODE_LIST:
605  if (!has_access)
606  break;
607  if (!sep.GetToken(param))
608  break;
609  if (adding)
610  {
611  if (IRCD->GetMaxListFor(ci->c) && ci->c->HasMode(cm->name) < IRCD->GetMaxListFor(ci->c))
612  ci->c->SetMode(NULL, cm, param);
613  }
614  else
615  {
616  std::pair<Channel::ModeList::iterator, Channel::ModeList::iterator> its = ci->c->GetModeList(cm->name);
617  for (; its.first != its.second;)
618  {
619  const Anope::string &mask = its.first->second;
620  ++its.first;
621 
622  if (Anope::Match(mask, param))
623  ci->c->RemoveMode(NULL, cm, mask);
624  }
625  }
626  }
627  }
628  }
629  }
630 
631  void DoClear(CommandSource &source, ChannelInfo *ci, const std::vector<Anope::string> &params)
632  {
633  const Anope::string &param = params.size() > 2 ? params[2] : "";
634 
635  if (param.empty())
636  {
637  std::vector<Anope::string> new_params;
638  new_params.push_back(params[0]);
639  new_params.push_back("SET");
640  new_params.push_back("-*");
641  this->DoSet(source, ci, new_params);
642  return;
643  }
644 
645  ChannelMode *cm;
646  if (param.length() == 1)
647  cm = ModeManager::FindChannelModeByChar(param[0]);
648  else
649  {
651  if (!cm)
652  cm = ModeManager::FindChannelModeByName(param.substr(0, param.length() - 1).upper());
653  }
654 
655  if (!cm)
656  {
657  source.Reply(_("There is no such mode %s."), param.c_str());
658  return;
659  }
660 
661  if (cm->type != MODE_STATUS && cm->type != MODE_LIST)
662  {
663  source.Reply(_("Mode %s is not a status or list mode."), param.c_str());
664  return;
665  }
666 
667  std::vector<Anope::string> new_params;
668  new_params.push_back(params[0]);
669  new_params.push_back("SET");
670  new_params.push_back("-" + stringify(cm->mchar));
671  new_params.push_back("*");
672  this->DoSet(source, ci, new_params);
673  }
674 
675  public:
676  CommandCSMode(Module *creator) : Command(creator, "chanserv/mode", 2, 4)
677  {
678  this->SetDesc(_("Control modes and mode locks on a channel"));
679  this->SetSyntax(_("\037channel\037 LOCK {ADD|DEL|SET|LIST} [\037what\037]"));
680  this->SetSyntax(_("\037channel\037 SET \037modes\037"));
681  this->SetSyntax(_("\037channel\037 CLEAR [\037what\037]"));
682  }
683 
684  void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
685  {
686  const Anope::string &subcommand = params[1];
687 
688  ChannelInfo *ci = ChannelInfo::Find(params[0]);
689 
690  if (!ci)
691  source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
692  else if (subcommand.equals_ci("LOCK") && params.size() > 2)
693  {
694  if (!source.AccessFor(ci).HasPriv("MODE") && !source.HasPriv("chanserv/administration"))
695  source.Reply(ACCESS_DENIED);
696  else
697  this->DoLock(source, ci, params);
698  }
699  else if (!ci->c)
700  source.Reply(CHAN_X_NOT_IN_USE, params[0].c_str());
701  else if (subcommand.equals_ci("SET") && params.size() > 2)
702  this->DoSet(source, ci, params);
703  else if (subcommand.equals_ci("CLEAR"))
704  {
705  if (!source.AccessFor(ci).HasPriv("MODE") && !source.HasPriv("chanserv/administration"))
706  source.Reply(ACCESS_DENIED);
707  else
708  this->DoClear(source, ci, params);
709  }
710  else
711  this->OnSyntaxError(source, "");
712  }
713 
714  bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
715  {
716  this->SendSyntax(source);
717  source.Reply(" ");
718  source.Reply(_("Mainly controls mode locks and mode access (which is different from channel access)\n"
719  "on a channel.\n"
720  " \n"
721  "The \002%s LOCK\002 command allows you to add, delete, and view mode locks on a channel.\n"
722  "If a mode is locked on or off, services will not allow that mode to be changed. The \002SET\002\n"
723  "command will clear all existing mode locks and set the new one given, while \002ADD\002 and \002DEL\002\n"
724  "modify the existing mode lock.\n"
725  "Example:\n"
726  " \002MODE #channel LOCK ADD +bmnt *!*@*aol*\002\n"
727  " \n"
728  "The \002%s SET\002 command allows you to set modes through services. Wildcards * and ? may\n"
729  "be given as parameters for list and status modes.\n"
730  "Example:\n"
731  " \002MODE #channel SET +v *\002\n"
732  " Sets voice status to all users in the channel.\n"
733  " \n"
734  " \002MODE #channel SET -b ~c:*\n"
735  " Clears all extended bans that start with ~c:\n"
736  " \n"
737  "The \002%s CLEAR\002 command is an easy way to clear modes on a channel. \037what\037 may be\n"
738  "any mode name. Examples include bans, excepts, inviteoverrides, ops, halfops, and voices. If \037what\037\n"
739  "is not given then all basic modes are removed."),
740  source.command.upper().c_str(), source.command.upper().c_str(), source.command.upper().c_str());
741  return true;
742  }
743 };
744 
746 
747 class CommandCSModes : public Command
748 {
749  public:
750  CommandCSModes(Module *creator) : Command(creator, "chanserv/modes", 1, 2)
751  {
752  this->SetSyntax(_("\037channel\037 [\037user\037]"));
753  }
754 
755  void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
756  {
757  User *u = source.GetUser(),
758  *targ = params.size() > 1 ? User::Find(params[1], true) : u;
759  ChannelInfo *ci = ChannelInfo::Find(params[0]);
760 
761  if (!targ)
762  {
763  if (params.size() > 1)
764  source.Reply(NICK_X_NOT_IN_USE, params[1].c_str());
765  return;
766  }
767 
768  if (!ci)
769  {
770  source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
771  return;
772  }
773  else if (!ci->c)
774  {
775  source.Reply(CHAN_X_NOT_IN_USE, ci->name.c_str());
776  return;
777  }
778 
779  AccessGroup u_access = source.AccessFor(ci), targ_access = ci->AccessFor(targ);
780  const std::pair<bool, Anope::string> &m = modes[source.command];
781 
782  bool can_override = source.HasPriv("chanserv/administration");
783  bool override = false;
784 
785  if (m.second.empty())
786  {
787  source.Reply(ACCESS_DENIED);
788  return;
789  }
790 
791  if (u == targ ? !u_access.HasPriv(m.second + "ME") : !u_access.HasPriv(m.second))
792  {
793  if (!can_override)
794  {
795  source.Reply(ACCESS_DENIED);
796  return;
797  }
798  else
799  override = true;
800  }
801 
802  if (!override && !m.first && u != targ && (targ->IsProtected() || (ci->HasExt("PEACE") && targ_access >= u_access)))
803  {
804  if (!can_override)
805  {
806  source.Reply(ACCESS_DENIED);
807  return;
808  }
809  else
810  override = true;
811  }
812 
813  if (!ci->c->FindUser(targ))
814  {
815  source.Reply(NICK_X_NOT_ON_CHAN, targ->nick.c_str(), ci->name.c_str());
816  return;
817  }
818 
819  if (m.first)
820  ci->c->SetMode(NULL, m.second, targ->GetUID());
821  else
822  ci->c->RemoveMode(NULL, m.second, targ->GetUID());
823 
824  Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "on " << targ->nick;
825  }
826 
828  {
829  const std::pair<bool, Anope::string> &m = modes[source.command];
830  if (!m.second.empty())
831  {
832  if (m.first)
833  return Anope::printf(Language::Translate(source.GetAccount(), _("Gives you or the specified nick %s status on a channel")), m.second.c_str());
834  else
835  return Anope::printf(Language::Translate(source.GetAccount(), _("Removes %s status from you or the specified nick on a channel")), m.second.c_str());
836  }
837  else
838  return "";
839  }
840 
841  bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
842  {
843  const std::pair<bool, Anope::string> &m = modes[source.command];
844  if (m.second.empty())
845  return false;
846 
847  this->SendSyntax(source);
848  source.Reply(" ");
849  if (m.first)
850  source.Reply(_("Gives %s status to the selected nick on a channel. If \037nick\037 is\n"
851  "not given, it will %s you."),
852  m.second.upper().c_str(), m.second.lower().c_str());
853  else
854  source.Reply(_("Removes %s status from the selected nick on a channel. If \037nick\037 is\n"
855  "not given, it will de%s you."),
856  m.second.upper().c_str(), m.second.lower().c_str());
857  source.Reply(" ");
858  source.Reply(_("You must have the %s(ME) privilege on the channel to use this command."), m.second.upper().c_str());
859 
860  return true;
861  }
862 };
863 
864 class CSMode : public Module
865 {
870 
871  public:
872  CSMode(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
873  commandcsmode(this), commandcsmodes(this),
874  modelocks(this, "modelocks"),
875  modelocks_type("ModeLock", ModeLockImpl::Unserialize)
876  {
877 
878  }
879 
881  {
882  modes.clear();
883 
884  for (int i = 0; i < conf->CountBlock("command"); ++i)
885  {
886  Configuration::Block *block = conf->GetBlock("command", i);
887 
888  const Anope::string &cname = block->Get<const Anope::string>("name"),
889  &cmd = block->Get<const Anope::string>("command");
890 
891  if (cname.empty() || cmd != "chanserv/modes")
892  continue;
893 
894  const Anope::string &set = block->Get<const Anope::string>("set"),
895  &unset = block->Get<const Anope::string>("unset");
896 
897  if (set.empty() && unset.empty())
898  continue;
899 
900  modes[cname] = std::make_pair(!set.empty(), !set.empty() ? set : unset);
901  }
902  }
903 
905  {
906  if (!c || !c->ci)
907  return;
908 
909  ModeLocks *locks = modelocks.Get(c->ci);
910  if (locks)
911  for (ModeLocks::ModeList::const_iterator it = locks->GetMLock().begin(), it_end = locks->GetMLock().end(); it != it_end; ++it)
912  {
913  const ModeLock *ml = *it;
915  if (!cm)
916  continue;
917 
918  if (cm->type == MODE_REGULAR)
919  {
920  if (!c->HasMode(cm->name) && ml->set)
921  c->SetMode(NULL, cm, "", false);
922  else if (c->HasMode(cm->name) && !ml->set)
923  c->RemoveMode(NULL, cm, "", false);
924  }
925  else if (cm->type == MODE_PARAM)
926  {
927  /* If the channel doesnt have the mode, or it does and it isn't set correctly */
928  if (ml->set)
929  {
930  Anope::string param;
931  c->GetParam(cm->name, param);
932 
933  if (!c->HasMode(cm->name) || (!param.empty() && !ml->param.empty() && !param.equals_cs(ml->param)))
934  c->SetMode(NULL, cm, ml->param, false);
935  }
936  else
937  {
938  if (c->HasMode(cm->name))
939  c->RemoveMode(NULL, cm, "", false);
940  }
941 
942  }
943  else if (cm->type == MODE_LIST || cm->type == MODE_STATUS)
944  {
945  if (ml->set)
946  c->SetMode(NULL, cm, ml->param, false);
947  else
948  c->RemoveMode(NULL, cm, ml->param, false);
949  }
950  }
951  }
952 
954  {
955  ModeLocks *ml = modelocks.Require(ci);
956  Anope::string mlock;
957  spacesepstream sep(Config->GetModule(this)->Get<const Anope::string>("mlock", "+nt"));
958  if (sep.GetToken(mlock))
959  {
960  bool add = true;
961  for (unsigned i = 0; i < mlock.length(); ++i)
962  {
963  if (mlock[i] == '+')
964  add = true;
965  else if (mlock[i] == '-')
966  add = false;
967  else
968  {
970  Anope::string param;
971  if (cm && (cm->type == MODE_REGULAR || sep.GetToken(param)))
972  ml->SetMLock(cm, add, param);
973  }
974  }
975  }
976  ml->Check();
977  }
978 
979  void OnChanInfo(CommandSource &source, ChannelInfo *ci, InfoFormatter &info, bool show_hidden) anope_override
980  {
981  if (!show_hidden)
982  return;
983 
984  ModeLocks *ml = modelocks.Get(ci);
985  if (ml)
986  info[_("Mode lock")] = ml->GetMLockAsString(true);
987  }
988 };
989 
CoreExport bool ReadOnly
Definition: main.cpp:28
CommandCSMode(Module *creator)
Definition: cs_mode.cpp:676
bool equals_cs(const char *_str) const
Definition: anope.h:74
static const std::vector< ChannelMode * > & GetChannelModes()
Definition: modes.cpp:571
void Serialize(Serialize::Data &data) const anope_override
Definition: cs_mode.cpp:211
CommandCSModes(Module *creator)
Definition: cs_mode.cpp:750
bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
Definition: cs_mode.cpp:841
const ModeLock * GetMLock(const Anope::string &mname, const Anope::string &param="") anope_override
Definition: cs_mode.cpp:162
bool set
Definition: cs_mode.h:15
static ChannelMode * FindChannelModeByName(const Anope::string &name)
Definition: modes.cpp:542
void OnCheckModes(Reference< Channel > &c) anope_override
Definition: cs_mode.cpp:904
bool RemoveMLock(ChannelMode *mode, bool status, const Anope::string &param="") anope_override
Definition: cs_mode.cpp:101
Definition: hashcomp.h:84
void OnChanInfo(CommandSource &source, ChannelInfo *ci, InfoFormatter &info, bool show_hidden) anope_override
Definition: cs_mode.cpp:979
void Execute(CommandSource &source, const std::vector< Anope::string > &params) anope_override
Definition: cs_mode.cpp:684
void clear()
Definition: anope.h:187
Serialize::Reference< ChannelInfo > ci
Definition: cs_mode.cpp:38
Anope::string name
Definition: regchannel.h:63
Anope::string GetMLockAsString(bool complete) const anope_override
Definition: cs_mode.cpp:175
#define CHAN_X_NOT_IN_USE
Definition: language.h:85
CSMode(const Anope::string &modname, const Anope::string &creator)
Definition: cs_mode.cpp:872
static Serializable * Unserialize(Serializable *obj, Serialize::Data &data)
Definition: cs_mode.cpp:221
void push_back(char c)
Definition: anope.h:142
void DoSet(CommandSource &source, ChannelInfo *ci, const std::vector< Anope::string > &params)
Definition: cs_mode.cpp:461
virtual bool RemoveMLock(ChannelMode *mode, bool status, const Anope::string &param="")=0
#define ACCESS_DENIED
Definition: language.h:73
CommandCSModes commandcsmodes
Definition: cs_mode.cpp:867
CoreExport string printf(const char *fmt,...)
Definition: misc.cpp:536
void Execute(CommandSource &source, const std::vector< Anope::string > &params) anope_override
Definition: cs_mode.cpp:755
ModeLocksImpl(Extensible *obj)
Definition: cs_mode.cpp:41
Definition: users.h:34
void RemoveMLock(ModeLock *mlock) anope_override
Definition: cs_mode.cpp:130
virtual void Check()=0
Anope::string setter
Definition: cs_mode.h:18
string upper() const
Definition: anope.h:266
#define READ_ONLY_MODE
Definition: language.h:71
virtual bool SetMLock(ChannelMode *mode, bool status, const Anope::string &param="", Anope::string setter="", time_t created=Anope::CurTime)=0
bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
Definition: cs_mode.cpp:714
Serialize::Type modelocks_type
Definition: cs_mode.cpp:869
#define FOREACH_RESULT(ename, ret, args)
Definition: modules.h:95
void SetDesc(const Anope::string &d)
Definition: command.cpp:130
bool equals_ci(const char *_str) const
Definition: anope.h:78
void OnChanRegistered(ChannelInfo *ci) anope_override
Definition: cs_mode.cpp:953
virtual void SetType(const Anope::string &key, Type t)
Definition: serialize.h:38
T * Require(const Anope::string &name)
Definition: extensible.h:244
std::list< ModeLock * > GetModeLockList(const Anope::string &name) anope_override
Definition: cs_mode.cpp:150
CoreExport time_t CurTime
Definition: main.cpp:41
bool HasPriv(const Anope::string &priv) const
Definition: access.cpp:384
bool HasMLock(ChannelMode *mode, const Anope::string &param, bool status) const anope_override
Definition: cs_mode.cpp:55
const Anope::string & GetNick() const
Definition: command.cpp:26
std::pair< ModeList::iterator, ModeList::iterator > GetModeList(const Anope::string &name)
Definition: channels.cpp:243
static ChannelInfo * Find(const Anope::string &name)
Definition: regchannel.cpp:630
#define NICK_X_NOT_IN_USE
Definition: language.h:80
std::vector< ModeLock * > ModeList
Definition: cs_mode.h:28
string substr(size_type pos=0, size_type n=npos) const
Definition: anope.h:277
T * Require(Extensible *obj)
Definition: extensible.h:116
bool IsProtected()
Definition: users.cpp:724
std::map< Anope::string, Anope::string > ListEntry
Definition: lists.h:68
virtual Anope::string GetMLockAsString(bool complete) const =0
size_type length() const
Definition: anope.h:131
void CheckModes()
Definition: channels.cpp:105
void OnReload(Configuration::Conf *conf) anope_override
Definition: cs_mode.cpp:880
Block * GetBlock(const Anope::string &name, int num=0)
Definition: config.cpp:43
NickCore * GetFounder() const
Definition: regchannel.cpp:364
ModeType type
Definition: modes.h:49
Definition: Config.cs:26
Channel * c
Definition: regchannel.h:79
void Shrink(const Anope::string &name)
Definition: extensible.h:253
CoreExport bool Match(const string &str, const string &mask, bool case_sensitive=false, bool use_regex=false)
Definition: misc.cpp:407
virtual void OnSyntaxError(CommandSource &source, const Anope::string &subcommand)
Definition: command.cpp:191
static const size_type npos
Definition: anope.h:44
void Reply(const char *message,...)
Definition: command.cpp:96
const Anope::string & GetUID() const
Definition: users.cpp:230
void DoLock(CommandSource &source, ChannelInfo *ci, const std::vector< Anope::string > &params)
Definition: cs_mode.cpp:262
bool HasPriv(const Anope::string &cmd)
Definition: command.cpp:69
Anope::string GetMask() const
Definition: users.cpp:269
Anope::string display
Definition: account.h:113
char mchar
Definition: modes.h:47
static ChannelMode * FindChannelModeByChar(char mode)
Definition: modes.cpp:524
static Anope::map< std::pair< bool, Anope::string > > modes
Definition: cs_mode.cpp:745
virtual const ModeList & GetMLock() const =0
Serialize::Checker< ModeList > mlocks
Definition: cs_mode.cpp:39
#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
CoreExport const char * Translate(const char *string)
Definition: language.cpp:59
ChanUserList users
Definition: channels.h:56
ChanUserContainer * FindUser(User *u) const
Definition: channels.cpp:173
User * GetUser()
Definition: command.cpp:31
bool CanSet(User *u) const anope_override
Definition: modes.cpp:144
void SetSyntax(const Anope::string &s)
Definition: command.cpp:140
const Anope::string GetDesc(CommandSource &source) const anope_override
Definition: cs_mode.cpp:827
AccessGroup AccessFor(const User *u)
Definition: regchannel.cpp:413
size_t HasMode(const Anope::string &name, const Anope::string &param="")
Definition: channels.cpp:201
Anope::string stringify(const T &x)
Definition: anope.h:710
virtual unsigned GetMaxListFor(Channel *c)
Definition: protocol.cpp:432
#define CHAN_X_NOT_REGISTERED
Definition: language.h:84
Anope::string nick
Definition: users.h:62
AccessGroup AccessFor(ChannelInfo *ci)
Definition: command.cpp:41
ExtensibleItem< ModeLocksImpl > modelocks
Definition: cs_mode.cpp:868
static User * Find(const Anope::string &name, bool nick_only=false)
Definition: users.cpp:815
Anope::string name
Definition: cs_mode.h:16
Anope::string ci
Definition: cs_mode.h:14
void ClearMLock() anope_override
Definition: cs_mode.cpp:137
bool GetToken(Anope::string &token)
Definition: hashcomp.cpp:99
void DoClear(CommandSource &source, ChannelInfo *ci, const std::vector< Anope::string > &params)
Definition: cs_mode.cpp:631
CommandCSMode commandcsmode
Definition: cs_mode.cpp:866
T * Get(const Extensible *obj) const
Definition: extensible.h:103
T anope_dynamic_static_cast(O ptr)
Definition: anope.h:774
Anope::string name
Definition: access.cpp:22
void SetMode(BotInfo *bi, ChannelMode *cm, const Anope::string &param="", bool enforce_mlock=true)
Definition: channels.cpp:401
void SendSyntax(CommandSource &)
Definition: command.cpp:145
bool CanSet(CommandSource &source, ChannelInfo *ci, ChannelMode *cm, bool self)
Definition: cs_mode.cpp:254
NickCore * GetAccount()
Definition: command.cpp:36
const char * c_str() const
Definition: anope.h:117
Definition: logger.h:53
Anope::string param
Definition: cs_mode.h:17
T Get(const Anope::string &tag)
Definition: config.h:44
T * GetExt(const Anope::string &name) const
Definition: extensible.h:213
time_t created
Definition: cs_mode.h:19
CoreExport Anope::string strftime(time_t t, const NickCore *nc=NULL, bool short_output=false)
Definition: misc.cpp:356
Anope::string name
Definition: modes.h:43
bool SetMLock(ChannelMode *mode, bool status, const Anope::string &param, Anope::string setter, time_t created=Anope::CurTime) anope_override
Definition: cs_mode.cpp:71
#define _(x)
Definition: services.h:50
bool HasExt(const Anope::string &name) const
Definition: extensible.cpp:31
ListFormatter & AddColumn(const Anope::string &name)
Definition: misc.cpp:128
Type(const Anope::string &n, unserialize_func f, Module *owner=NULL)
void Check() anope_override
Definition: cs_mode.cpp:204
const ModeList & GetMLock() const anope_override
Definition: cs_mode.cpp:145
#define NICK_X_NOT_ON_CHAN
Definition: language.h:81
void RemoveMode(BotInfo *bi, ChannelMode *cm, const Anope::string &param="", bool enforce_mlock=true)
Definition: channels.cpp:459