anope- supernets anope source code & configuration |
git clone git://git.acid.vegas/anope.git |
Log | Files | Refs | Archive | README |
os_ignore.cpp (10282B)
1 /* OperServ core functions 2 * 3 * (C) 2003-2022 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/os_ignore.h" 14 15 struct IgnoreDataImpl : IgnoreData, Serializable 16 { 17 IgnoreDataImpl() : Serializable("IgnoreData") { } 18 ~IgnoreDataImpl(); 19 void Serialize(Serialize::Data &data) const anope_override; 20 static Serializable* Unserialize(Serializable *obj, Serialize::Data &data); 21 }; 22 23 IgnoreDataImpl::~IgnoreDataImpl() 24 { 25 if (ignore_service) 26 ignore_service->DelIgnore(this); 27 } 28 29 void IgnoreDataImpl::Serialize(Serialize::Data &data) const 30 { 31 data["mask"] << this->mask; 32 data["creator"] << this->creator; 33 data["reason"] << this->reason; 34 data["time"] << this->time; 35 } 36 37 Serializable* IgnoreDataImpl::Unserialize(Serializable *obj, Serialize::Data &data) 38 { 39 if (!ignore_service) 40 return NULL; 41 42 IgnoreDataImpl *ign; 43 if (obj) 44 ign = anope_dynamic_static_cast<IgnoreDataImpl *>(obj); 45 else 46 { 47 ign = new IgnoreDataImpl(); 48 ignore_service->AddIgnore(ign); 49 } 50 51 data["mask"] >> ign->mask; 52 data["creator"] >> ign->creator; 53 data["reason"] >> ign->reason; 54 data["time"] >> ign->time; 55 56 return ign; 57 } 58 59 60 class OSIgnoreService : public IgnoreService 61 { 62 Serialize::Checker<std::vector<IgnoreData *> > ignores; 63 64 public: 65 OSIgnoreService(Module *o) : IgnoreService(o), ignores("IgnoreData") { } 66 67 void AddIgnore(IgnoreData *ign) anope_override 68 { 69 ignores->push_back(ign); 70 } 71 72 void DelIgnore(IgnoreData *ign) anope_override 73 { 74 std::vector<IgnoreData *>::iterator it = std::find(ignores->begin(), ignores->end(), ign); 75 if (it != ignores->end()) 76 ignores->erase(it); 77 } 78 79 void ClearIgnores() anope_override 80 { 81 for (unsigned i = ignores->size(); i > 0; --i) 82 { 83 IgnoreData *ign = ignores->at(i - 1); 84 delete ign; 85 } 86 } 87 88 IgnoreData *Create() anope_override 89 { 90 return new IgnoreDataImpl(); 91 } 92 93 IgnoreData *Find(const Anope::string &mask) anope_override 94 { 95 User *u = User::Find(mask, true); 96 std::vector<IgnoreData *>::iterator ign = this->ignores->begin(), ign_end = this->ignores->end(); 97 98 if (u) 99 { 100 for (; ign != ign_end; ++ign) 101 { 102 Entry ignore_mask("", (*ign)->mask); 103 if (ignore_mask.Matches(u, true)) 104 break; 105 } 106 } 107 else 108 { 109 size_t user, host; 110 Anope::string tmp; 111 /* We didn't get a user.. generate a valid mask. */ 112 if ((host = mask.find('@')) != Anope::string::npos) 113 { 114 if ((user = mask.find('!')) != Anope::string::npos) 115 { 116 /* this should never happen */ 117 if (user > host) 118 return NULL; 119 tmp = mask; 120 } 121 else 122 /* We have user@host. Add nick wildcard. */ 123 tmp = "*!" + mask; 124 } 125 /* We only got a nick.. */ 126 else 127 tmp = mask + "!*@*"; 128 129 for (; ign != ign_end; ++ign) 130 if (Anope::Match(tmp, (*ign)->mask, false, true)) 131 break; 132 } 133 134 /* Check whether the entry has timed out */ 135 if (ign != ign_end) 136 { 137 IgnoreData *id = *ign; 138 139 if (id->time && !Anope::NoExpire && id->time <= Anope::CurTime) 140 { 141 Log(LOG_NORMAL, "expire/ignore", Config->GetClient("OperServ")) << "Expiring ignore entry " << id->mask; 142 delete id; 143 } 144 else 145 return id; 146 } 147 148 return NULL; 149 } 150 151 std::vector<IgnoreData *> &GetIgnores() anope_override 152 { 153 return *ignores; 154 } 155 }; 156 157 class CommandOSIgnore : public Command 158 { 159 private: 160 Anope::string RealMask(const Anope::string &mask) 161 { 162 /* If it s an existing user, we ignore the hostmask. */ 163 User *u = User::Find(mask, true); 164 if (u) 165 return "*!*@" + u->host; 166 167 size_t host = mask.find('@'); 168 /* Determine whether we get a nick or a mask. */ 169 if (host != Anope::string::npos) 170 { 171 size_t user = mask.find('!'); 172 /* Check whether we have a nick too.. */ 173 if (user != Anope::string::npos) 174 { 175 if (user > host) 176 /* this should never happen */ 177 return ""; 178 else 179 return mask; 180 } 181 else 182 /* We have user@host. Add nick wildcard. */ 183 return "*!" + mask; 184 } 185 186 /* We only got a nick.. */ 187 return mask + "!*@*"; 188 } 189 190 void DoAdd(CommandSource &source, const std::vector<Anope::string> ¶ms) 191 { 192 if (!ignore_service) 193 return; 194 195 const Anope::string &time = params.size() > 1 ? params[1] : ""; 196 const Anope::string &nick = params.size() > 2 ? params[2] : ""; 197 const Anope::string &reason = params.size() > 3 ? params[3] : ""; 198 199 if (time.empty() || nick.empty()) 200 { 201 this->OnSyntaxError(source, "ADD"); 202 return; 203 } 204 else 205 { 206 time_t t = Anope::DoTime(time); 207 208 if (t <= -1) 209 { 210 source.Reply(BAD_EXPIRY_TIME); 211 return; 212 } 213 214 Anope::string mask = RealMask(nick); 215 if (mask.empty()) 216 { 217 source.Reply(BAD_USERHOST_MASK); 218 return; 219 } 220 221 if (Anope::ReadOnly) 222 source.Reply(READ_ONLY_MODE); 223 224 IgnoreData *ign = new IgnoreDataImpl(); 225 ign->mask = mask; 226 ign->creator = source.GetNick(); 227 ign->reason = reason; 228 ign->time = t ? Anope::CurTime + t : 0; 229 230 ignore_service->AddIgnore(ign); 231 if (!t) 232 { 233 source.Reply(_("\002%s\002 will now permanently be ignored."), mask.c_str()); 234 Log(LOG_ADMIN, source, this) << "to add a permanent ignore for " << mask; 235 } 236 else 237 { 238 source.Reply(_("\002%s\002 will now be ignored for \002%s\002."), mask.c_str(), Anope::Duration(t, source.GetAccount()).c_str()); 239 Log(LOG_ADMIN, source, this) << "to add an ignore on " << mask << " for " << Anope::Duration(t); 240 } 241 } 242 } 243 244 void DoList(CommandSource &source) 245 { 246 if (!ignore_service) 247 return; 248 249 std::vector<IgnoreData *> &ignores = ignore_service->GetIgnores(); 250 for (unsigned i = ignores.size(); i > 0; --i) 251 { 252 IgnoreData *id = ignores[i - 1]; 253 254 if (id->time && !Anope::NoExpire && id->time <= Anope::CurTime) 255 { 256 Log(LOG_NORMAL, "expire/ignore", Config->GetClient("OperServ")) << "Expiring ignore entry " << id->mask; 257 delete id; 258 } 259 } 260 261 if (ignores.empty()) 262 source.Reply(_("Ignore list is empty.")); 263 else 264 { 265 ListFormatter list(source.GetAccount()); 266 list.AddColumn(_("Mask")).AddColumn(_("Creator")).AddColumn(_("Reason")).AddColumn(_("Expires")); 267 268 for (unsigned i = ignores.size(); i > 0; --i) 269 { 270 const IgnoreData *ignore = ignores[i - 1]; 271 272 ListFormatter::ListEntry entry; 273 entry["Mask"] = ignore->mask; 274 entry["Creator"] = ignore->creator; 275 entry["Reason"] = ignore->reason; 276 entry["Expires"] = Anope::Expires(ignore->time, source.GetAccount()); 277 list.AddEntry(entry); 278 } 279 280 source.Reply(_("Services ignore list:")); 281 282 std::vector<Anope::string> replies; 283 list.Process(replies); 284 285 for (unsigned i = 0; i < replies.size(); ++i) 286 source.Reply(replies[i]); 287 } 288 } 289 290 void DoDel(CommandSource &source, const std::vector<Anope::string> ¶ms) 291 { 292 if (!ignore_service) 293 return; 294 295 const Anope::string nick = params.size() > 1 ? params[1] : ""; 296 if (nick.empty()) 297 { 298 this->OnSyntaxError(source, "DEL"); 299 return; 300 } 301 302 Anope::string mask = RealMask(nick); 303 if (mask.empty()) 304 { 305 source.Reply(BAD_USERHOST_MASK); 306 return; 307 } 308 309 IgnoreData *ign = ignore_service->Find(mask); 310 if (ign) 311 { 312 if (Anope::ReadOnly) 313 source.Reply(READ_ONLY_MODE); 314 315 Log(LOG_ADMIN, source, this) << "to remove an ignore on " << mask; 316 source.Reply(_("\002%s\002 will no longer be ignored."), mask.c_str()); 317 delete ign; 318 } 319 else 320 source.Reply(_("\002%s\002 not found on ignore list."), mask.c_str()); 321 } 322 323 void DoClear(CommandSource &source) 324 { 325 if (!ignore_service) 326 return; 327 328 if (Anope::ReadOnly) 329 source.Reply(READ_ONLY_MODE); 330 331 ignore_service->ClearIgnores(); 332 Log(LOG_ADMIN, source, this) << "to CLEAR the list"; 333 source.Reply(_("Ignore list has been cleared.")); 334 335 return; 336 } 337 338 public: 339 CommandOSIgnore(Module *creator) : Command(creator, "operserv/ignore", 1, 4) 340 { 341 this->SetDesc(_("Modify the Services ignore list")); 342 this->SetSyntax(_("ADD \037expiry\037 {\037nick\037|\037mask\037} [\037reason\037]")); 343 this->SetSyntax(_("DEL {\037nick\037|\037mask\037}")); 344 this->SetSyntax("LIST"); 345 this->SetSyntax("CLEAR"); 346 } 347 348 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 349 { 350 const Anope::string &cmd = params[0]; 351 352 if (cmd.equals_ci("ADD")) 353 return this->DoAdd(source, params); 354 else if (cmd.equals_ci("LIST")) 355 return this->DoList(source); 356 else if (cmd.equals_ci("DEL")) 357 return this->DoDel(source, params); 358 else if (cmd.equals_ci("CLEAR")) 359 return this->DoClear(source); 360 else 361 this->OnSyntaxError(source, ""); 362 363 return; 364 } 365 366 bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override 367 { 368 this->SendSyntax(source); 369 source.Reply(" "); 370 source.Reply(_("Allows Services Operators to make Services ignore a nick or mask\n" 371 "for a certain time or until the next restart. The default\n" 372 "time format is seconds. You can specify it by using units.\n" 373 "Valid units are: \037s\037 for seconds, \037m\037 for minutes,\n" 374 "\037h\037 for hours and \037d\037 for days.\n" 375 "Combinations of these units are not permitted.\n" 376 "To make Services permanently ignore the user, type 0 as time.\n" 377 "When adding a \037mask\037, it should be in the format nick!user@host,\n" 378 "everything else will be considered a nick. Wildcards are permitted.\n" 379 " \n" 380 "Ignores will not be enforced on IRC Operators.")); 381 382 const Anope::string ®exengine = Config->GetBlock("options")->Get<const Anope::string>("regexengine"); 383 if (!regexengine.empty()) 384 { 385 source.Reply(" "); 386 source.Reply(_("Regex matches are also supported using the %s engine.\n" 387 "Enclose your pattern in // if this is desired."), regexengine.c_str()); 388 } 389 390 return true; 391 } 392 }; 393 394 class OSIgnore : public Module 395 { 396 Serialize::Type ignoredata_type; 397 OSIgnoreService osignoreservice; 398 CommandOSIgnore commandosignore; 399 400 public: 401 OSIgnore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), 402 ignoredata_type("IgnoreData", IgnoreDataImpl::Unserialize), osignoreservice(this), commandosignore(this) 403 { 404 405 } 406 407 EventReturn OnBotPrivmsg(User *u, BotInfo *bi, Anope::string &message) anope_override 408 { 409 if (!u->HasMode("OPER") && this->osignoreservice.Find(u->nick)) 410 return EVENT_STOP; 411 412 return EVENT_CONTINUE; 413 } 414 }; 415 416 MODULE_INIT(OSIgnore)