anope- supernets anope source code & configuration |
git clone git://git.acid.vegas/anope.git |
Log | Files | Refs | Archive | README |
users.cpp (20057B)
1 /* Routines to maintain a list of online users. 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 "services.h" 13 #include "modules.h" 14 #include "users.h" 15 #include "account.h" 16 #include "protocol.h" 17 #include "servers.h" 18 #include "channels.h" 19 #include "bots.h" 20 #include "config.h" 21 #include "opertype.h" 22 #include "language.h" 23 #include "sockets.h" 24 #include "uplink.h" 25 26 user_map UserListByNick, UserListByUID; 27 28 int OperCount = 0; 29 unsigned MaxUserCount = 0; 30 time_t MaxUserTime = 0; 31 32 std::list<User *> User::quitting_users; 33 34 User::User(const Anope::string &snick, const Anope::string &sident, const Anope::string &shost, const Anope::string &svhost, const Anope::string &uip, Server *sserver, const Anope::string &srealname, time_t ts, const Anope::string &smodes, const Anope::string &suid, NickCore *account) : ip(uip) 35 { 36 if (snick.empty() || sident.empty() || shost.empty()) 37 throw CoreException("Bad args passed to User::User"); 38 39 /* we used to do this by calloc, no more. */ 40 quit = false; 41 server = NULL; 42 invalid_pw_count = invalid_pw_time = lastmemosend = lastnickreg = lastmail = 0; 43 on_access = false; 44 45 this->nick = snick; 46 this->ident = sident; 47 this->host = shost; 48 this->vhost = svhost; 49 this->chost = svhost; 50 this->server = sserver; 51 this->realname = srealname; 52 this->timestamp = this->signon = ts; 53 this->SetModesInternal(sserver, "%s", smodes.c_str()); 54 this->uid = suid; 55 this->super_admin = false; 56 this->nc = NULL; 57 58 size_t old = UserListByNick.size(); 59 UserListByNick[snick] = this; 60 if (!suid.empty()) 61 UserListByUID[suid] = this; 62 if (old == UserListByNick.size()) 63 Log(LOG_DEBUG) << "Duplicate user " << snick << " in user table?"; 64 65 this->Login(account); 66 this->UpdateHost(); 67 68 if (sserver) // Our bots are introduced on startup with no server 69 { 70 ++sserver->users; 71 if (server->IsSynced()) 72 Log(this, "connect") << (!vhost.empty() && vhost != host ? "(" + vhost + ") " : "") << "(" << srealname << ") " << (!uip.empty() && uip != host ? "[" + uip + "] " : "") << "connected to the network (" << sserver->GetName() << ")"; 73 } 74 75 if (UserListByNick.size() > MaxUserCount) 76 { 77 MaxUserCount = UserListByNick.size(); 78 MaxUserTime = Anope::CurTime; 79 if (sserver && sserver->IsSynced()) 80 Log(this, "maxusers") << "connected - new maximum user count: " << UserListByNick.size(); 81 } 82 83 bool exempt = false; 84 if (server && server->IsULined()) 85 exempt = true; 86 FOREACH_MOD(OnUserConnect, (this, exempt)); 87 } 88 89 static void CollideKill(User *target, const Anope::string &reason) 90 { 91 if (target->server != Me) 92 target->Kill(Me, reason); 93 else 94 { 95 // Be sure my user is really dead 96 IRCD->SendQuit(target, "%s", reason.c_str()); 97 98 // Reintroduce my client 99 if (BotInfo *bi = dynamic_cast<BotInfo *>(target)) 100 bi->OnKill(); 101 else 102 target->Quit(reason); 103 } 104 } 105 106 static void Collide(User *u, const Anope::string &id, const Anope::string &type) 107 { 108 // Kill incoming user 109 IRCD->SendKill(Me, id, type); 110 // Quit colliding user 111 CollideKill(u, type); 112 } 113 114 User* User::OnIntroduce(const Anope::string &snick, const Anope::string &sident, const Anope::string &shost, const Anope::string &svhost, const Anope::string &sip, Server *sserver, const Anope::string &srealname, time_t ts, const Anope::string &smodes, const Anope::string &suid, NickCore *nc) 115 { 116 // How IRCds handle collisions varies a lot, for safety well just always kill both sides 117 // With properly set qlines, this can almost never happen anyway 118 119 User *u = User::Find(snick, true); 120 if (u) 121 { 122 Collide(u, !suid.empty() ? suid : snick, "Nick collision"); 123 return NULL; 124 } 125 126 if (!suid.empty()) 127 { 128 u = User::Find(suid); 129 if (u) 130 { 131 Collide(u, suid, "ID collision"); 132 return NULL; 133 } 134 } 135 136 return new User(snick, sident, shost, svhost, sip, sserver, srealname, ts, smodes, suid, nc); 137 } 138 139 void User::ChangeNick(const Anope::string &newnick, time_t ts) 140 { 141 /* Sanity check to make sure we don't segfault */ 142 if (newnick.empty()) 143 throw CoreException("User::ChangeNick() got a bad argument"); 144 145 this->super_admin = false; 146 Log(this, "nick") << "(" << this->realname << ") changed nick to " << newnick; 147 148 Anope::string old = this->nick; 149 this->timestamp = ts; 150 151 if (this->nick.equals_ci(newnick)) 152 this->nick = newnick; 153 else 154 { 155 NickAlias *old_na = NickAlias::Find(this->nick); 156 if (old_na && (this->IsIdentified(true) || this->IsRecognized())) 157 old_na->last_seen = Anope::CurTime; 158 159 UserListByNick.erase(this->nick); 160 161 this->nick = newnick; 162 163 User* &other = UserListByNick[this->nick]; 164 if (other) 165 { 166 CollideKill(this, "Nick collision"); 167 CollideKill(other, "Nick collision"); 168 return; 169 } 170 other = this; 171 172 on_access = false; 173 NickAlias *na = NickAlias::Find(this->nick); 174 if (na) 175 on_access = na->nc->IsOnAccess(this); 176 177 if (na && na->nc == this->Account()) 178 { 179 na->last_seen = Anope::CurTime; 180 this->UpdateHost(); 181 } 182 } 183 184 FOREACH_MOD(OnUserNickChange, (this, old)); 185 } 186 187 void User::SetDisplayedHost(const Anope::string &shost) 188 { 189 if (shost.empty()) 190 throw CoreException("empty host? in MY services? it seems it's more likely than I thought."); 191 192 this->vhost = shost; 193 194 Log(this, "host") << "changed vhost to " << shost; 195 196 FOREACH_MOD(OnSetDisplayedHost, (this)); 197 198 this->UpdateHost(); 199 } 200 201 const Anope::string &User::GetDisplayedHost() const 202 { 203 if (!this->vhost.empty()) 204 return this->vhost; 205 else if (this->HasMode("CLOAK") && !this->GetCloakedHost().empty()) 206 return this->GetCloakedHost(); 207 else 208 return this->host; 209 } 210 211 void User::SetCloakedHost(const Anope::string &newhost) 212 { 213 if (newhost.empty()) 214 throw CoreException("empty host in User::SetCloakedHost"); 215 216 chost = newhost; 217 218 Log(this, "host") << "changed cloaked host to " << newhost; 219 220 this->UpdateHost(); 221 } 222 223 const Anope::string &User::GetCloakedHost() const 224 { 225 return chost; 226 } 227 228 const Anope::string &User::GetUID() const 229 { 230 if (!this->uid.empty() && IRCD->RequiresID) 231 return this->uid; 232 else 233 return this->nick; 234 } 235 236 void User::SetVIdent(const Anope::string &sident) 237 { 238 this->vident = sident; 239 240 Log(this, "ident") << "changed vident to " << sident; 241 242 this->UpdateHost(); 243 } 244 245 const Anope::string &User::GetVIdent() const 246 { 247 if (!this->vident.empty()) 248 return this->vident; 249 else 250 return this->ident; 251 } 252 253 void User::SetIdent(const Anope::string &sident) 254 { 255 this->ident = sident; 256 257 Log(this, "ident") << "changed real ident to " << sident; 258 259 this->UpdateHost(); 260 } 261 262 const Anope::string &User::GetIdent() const 263 { 264 return this->ident; 265 } 266 267 Anope::string User::GetMask() const 268 { 269 return this->nick + "!" + this->ident + "@" + this->host; 270 } 271 272 Anope::string User::GetDisplayedMask() const 273 { 274 return this->nick + "!" + this->GetVIdent() + "@" + this->GetDisplayedHost(); 275 } 276 277 void User::SetRealname(const Anope::string &srealname) 278 { 279 if (srealname.empty()) 280 throw CoreException("realname empty in SetRealname"); 281 282 this->realname = srealname; 283 NickAlias *na = NickAlias::Find(this->nick); 284 285 if (na && (this->IsIdentified(true) || this->IsRecognized())) 286 na->last_realname = srealname; 287 288 Log(this, "realname") << "changed realname to " << srealname; 289 } 290 291 User::~User() 292 { 293 UnsetExtensibles(); 294 295 if (this->server != NULL) 296 { 297 if (this->server->IsSynced()) 298 Log(this, "disconnect") << "(" << this->realname << ") disconnected from the network (" << this->server->GetName() << ")"; 299 --this->server->users; 300 } 301 302 FOREACH_MOD(OnPreUserLogoff, (this)); 303 304 ModeManager::StackerDel(this); 305 this->Logout(); 306 307 if (this->HasMode("OPER")) 308 --OperCount; 309 310 while (!this->chans.empty()) 311 this->chans.begin()->second->chan->DeleteUser(this); 312 313 UserListByNick.erase(this->nick); 314 if (!this->uid.empty()) 315 UserListByUID.erase(this->uid); 316 317 FOREACH_MOD(OnPostUserLogoff, (this)); 318 } 319 320 void User::SendMessage(BotInfo *source, const char *fmt, ...) 321 { 322 va_list args; 323 char buf[BUFSIZE] = ""; 324 325 const char *translated_message = Language::Translate(this, fmt); 326 327 va_start(args, fmt); 328 vsnprintf(buf, BUFSIZE - 1, translated_message, args); 329 330 this->SendMessage(source, Anope::string(buf)); 331 332 va_end(args); 333 } 334 335 void User::SendMessage(BotInfo *source, const Anope::string &msg) 336 { 337 const char *translated_message = Language::Translate(this, msg.c_str()); 338 339 /* Send privmsg instead of notice if: 340 * - UsePrivmsg is enabled 341 * - The user is not registered and NSDefMsg is enabled 342 * - The user is registered and has set /ns set msg on 343 */ 344 bool send_privmsg = Config->UsePrivmsg && ((!this->nc && Config->DefPrivmsg) || (this->nc && this->nc->HasExt("MSG"))); 345 sepstream sep(translated_message, '\n', true); 346 for (Anope::string tok; sep.GetToken(tok);) 347 { 348 if (send_privmsg) 349 IRCD->SendPrivmsg(source, this->GetUID(), "%s", tok.c_str()); 350 else 351 IRCD->SendNotice(source, this->GetUID(), "%s", tok.c_str()); 352 } 353 } 354 355 void User::Identify(NickAlias *na) 356 { 357 if (this->nick.equals_ci(na->nick)) 358 { 359 na->last_usermask = this->GetIdent() + "@" + this->GetDisplayedHost(); 360 na->last_realhost = this->GetIdent() + "@" + this->host; 361 na->last_realname = this->realname; 362 na->last_seen = Anope::CurTime; 363 } 364 365 IRCD->SendLogin(this, na); 366 367 this->Login(na->nc); 368 369 FOREACH_MOD(OnNickIdentify, (this)); 370 371 if (this->IsServicesOper()) 372 { 373 if (!this->nc->o->ot->modes.empty()) 374 { 375 this->SetModes(NULL, "%s", this->nc->o->ot->modes.c_str()); 376 this->SendMessage(NULL, "Changing your usermodes to \002%s\002", this->nc->o->ot->modes.c_str()); 377 UserMode *um = ModeManager::FindUserModeByName("OPER"); 378 if (um && !this->HasMode("OPER") && this->nc->o->ot->modes.find(um->mchar) != Anope::string::npos) 379 IRCD->SendOper(this); 380 } 381 if (IRCD->CanSetVHost && !this->nc->o->vhost.empty()) 382 { 383 this->SendMessage(NULL, "Changing your vhost to \002%s\002", this->nc->o->vhost.c_str()); 384 this->SetDisplayedHost(this->nc->o->vhost); 385 IRCD->SendVhost(this, "", this->nc->o->vhost); 386 } 387 } 388 } 389 390 391 void User::Login(NickCore *core) 392 { 393 if (!core || core == this->nc) 394 return; 395 396 this->Logout(); 397 this->nc = core; 398 core->users.push_back(this); 399 400 this->UpdateHost(); 401 402 if (this->server->IsSynced()) 403 Log(this, "account") << "is now identified as " << this->nc->display; 404 405 FOREACH_MOD(OnUserLogin, (this)); 406 } 407 408 void User::Logout() 409 { 410 if (!this->nc) 411 return; 412 413 Log(this, "account") << "is no longer identified as " << this->nc->display; 414 415 std::list<User *>::iterator it = std::find(this->nc->users.begin(), this->nc->users.end(), this); 416 if (it != this->nc->users.end()) 417 this->nc->users.erase(it); 418 419 this->nc = NULL; 420 } 421 422 NickCore *User::Account() const 423 { 424 return this->nc; 425 } 426 427 bool User::IsIdentified(bool check_nick) const 428 { 429 if (check_nick && this->nc) 430 { 431 NickAlias *na = NickAlias::Find(this->nick); 432 return na && *na->nc == *this->nc; 433 } 434 435 return this->nc ? true : false; 436 } 437 438 bool User::IsRecognized(bool check_secure) const 439 { 440 if (check_secure && on_access) 441 { 442 const NickAlias *na = NickAlias::Find(this->nick); 443 444 if (!na || na->nc->HasExt("NS_SECURE")) 445 return false; 446 } 447 448 return on_access; 449 } 450 451 bool User::IsServicesOper() 452 { 453 if (!this->nc || !this->nc->IsServicesOper()) 454 // No opertype. 455 return false; 456 else if (this->nc->o->require_oper && !this->HasMode("OPER")) 457 return false; 458 else if (!this->nc->o->certfp.empty() && this->fingerprint != this->nc->o->certfp) 459 // Certfp mismatch 460 return false; 461 else if (!this->nc->o->hosts.empty()) 462 { 463 bool match = false; 464 Anope::string match_host = this->GetIdent() + "@" + this->host; 465 for (unsigned i = 0; i < this->nc->o->hosts.size(); ++i) 466 if (Anope::Match(match_host, this->nc->o->hosts[i])) 467 match = true; 468 if (match == false) 469 return false; 470 } 471 472 EventReturn MOD_RESULT; 473 FOREACH_RESULT(IsServicesOper, MOD_RESULT, (this)); 474 if (MOD_RESULT == EVENT_STOP) 475 return false; 476 477 return true; 478 } 479 480 bool User::HasCommand(const Anope::string &command) 481 { 482 if (this->IsServicesOper()) 483 return this->nc->o->ot->HasCommand(command); 484 return false; 485 } 486 487 bool User::HasPriv(const Anope::string &priv) 488 { 489 if (this->IsServicesOper()) 490 return this->nc->o->ot->HasPriv(priv); 491 return false; 492 } 493 494 void User::UpdateHost() 495 { 496 if (this->host.empty()) 497 return; 498 499 NickAlias *na = NickAlias::Find(this->nick); 500 on_access = false; 501 if (na) 502 on_access = na->nc->IsOnAccess(this); 503 504 if (na && (this->IsIdentified(true) || this->IsRecognized())) 505 { 506 Anope::string last_usermask = this->GetIdent() + "@" + this->GetDisplayedHost(); 507 Anope::string last_realhost = this->GetIdent() + "@" + this->host; 508 na->last_usermask = last_usermask; 509 na->last_realhost = last_realhost; 510 // This is called on signon, and if users are introduced with an account it won't update 511 na->last_realname = this->realname; 512 } 513 } 514 515 bool User::HasMode(const Anope::string &mname) const 516 { 517 return this->modes.count(mname); 518 } 519 520 void User::SetModeInternal(const MessageSource &source, UserMode *um, const Anope::string ¶m) 521 { 522 if (!um) 523 return; 524 525 this->modes[um->name] = param; 526 527 if (um->name == "OPER") 528 { 529 ++OperCount; 530 531 if (this->IsServicesOper()) 532 { 533 if (!this->nc->o->ot->modes.empty()) 534 { 535 this->SetModes(NULL, "%s", this->nc->o->ot->modes.c_str()); 536 this->SendMessage(NULL, "Changing your usermodes to \002%s\002", this->nc->o->ot->modes.c_str()); 537 UserMode *oper = ModeManager::FindUserModeByName("OPER"); 538 if (oper && !this->HasMode("OPER") && this->nc->o->ot->modes.find(oper->mchar) != Anope::string::npos) 539 IRCD->SendOper(this); 540 } 541 if (IRCD->CanSetVHost && !this->nc->o->vhost.empty()) 542 { 543 this->SendMessage(NULL, "Changing your vhost to \002%s\002", this->nc->o->vhost.c_str()); 544 this->SetDisplayedHost(this->nc->o->vhost); 545 IRCD->SendVhost(this, "", this->nc->o->vhost); 546 } 547 } 548 } 549 550 if (um->name == "CLOAK" || um->name == "VHOST") 551 this->UpdateHost(); 552 553 FOREACH_MOD(OnUserModeSet, (source, this, um->name)); 554 } 555 556 void User::RemoveModeInternal(const MessageSource &source, UserMode *um) 557 { 558 if (!um) 559 return; 560 561 this->modes.erase(um->name); 562 563 if (um->name == "OPER") 564 { 565 --OperCount; 566 567 // Don't let people de-oper and remain a SuperAdmin 568 this->super_admin = false; 569 } 570 571 if (um->name == "CLOAK" || um->name == "VHOST") 572 { 573 this->vhost.clear(); 574 this->UpdateHost(); 575 } 576 577 FOREACH_MOD(OnUserModeUnset, (source, this, um->name)); 578 } 579 580 void User::SetMode(BotInfo *bi, UserMode *um, const Anope::string ¶m) 581 { 582 if (!um || HasMode(um->name)) 583 return; 584 585 ModeManager::StackerAdd(bi, this, um, true, param); 586 SetModeInternal(bi, um, param); 587 } 588 589 void User::SetMode(BotInfo *bi, const Anope::string &uname, const Anope::string ¶m) 590 { 591 SetMode(bi, ModeManager::FindUserModeByName(uname), param); 592 } 593 594 void User::RemoveMode(BotInfo *bi, UserMode *um, const Anope::string ¶m) 595 { 596 if (!um || !HasMode(um->name)) 597 return; 598 599 ModeManager::StackerAdd(bi, this, um, false, param); 600 RemoveModeInternal(bi, um); 601 } 602 603 void User::RemoveMode(BotInfo *bi, const Anope::string &name, const Anope::string ¶m) 604 { 605 RemoveMode(bi, ModeManager::FindUserModeByName(name), param); 606 } 607 608 void User::SetModes(BotInfo *bi, const char *umodes, ...) 609 { 610 char buf[BUFSIZE] = ""; 611 va_list args; 612 Anope::string modebuf, sbuf; 613 int add = -1; 614 va_start(args, umodes); 615 vsnprintf(buf, BUFSIZE - 1, umodes, args); 616 va_end(args); 617 618 spacesepstream sep(buf); 619 sep.GetToken(modebuf); 620 for (unsigned i = 0, end = modebuf.length(); i < end; ++i) 621 { 622 UserMode *um; 623 624 switch (modebuf[i]) 625 { 626 case '+': 627 add = 1; 628 continue; 629 case '-': 630 add = 0; 631 continue; 632 default: 633 if (add == -1) 634 continue; 635 um = ModeManager::FindUserModeByChar(modebuf[i]); 636 if (!um) 637 continue; 638 } 639 640 if (add) 641 { 642 if (um->type == MODE_PARAM && sep.GetToken(sbuf)) 643 this->SetMode(bi, um, sbuf); 644 else 645 this->SetMode(bi, um); 646 } 647 else 648 this->RemoveMode(bi, um); 649 } 650 } 651 652 void User::SetModesInternal(const MessageSource &source, const char *umodes, ...) 653 { 654 char buf[BUFSIZE] = ""; 655 va_list args; 656 Anope::string modebuf, sbuf; 657 int add = -1; 658 va_start(args, umodes); 659 vsnprintf(buf, BUFSIZE - 1, umodes, args); 660 va_end(args); 661 662 if (this->server && this->server->IsSynced() && Anope::string(buf) != "+") 663 Log(this, "mode") << "changes modes to " << buf; 664 665 spacesepstream sep(buf); 666 sep.GetToken(modebuf); 667 for (unsigned i = 0, end = modebuf.length(); i < end; ++i) 668 { 669 UserMode *um; 670 671 switch (modebuf[i]) 672 { 673 case '+': 674 add = 1; 675 continue; 676 case '-': 677 add = 0; 678 continue; 679 default: 680 if (add == -1) 681 continue; 682 um = ModeManager::FindUserModeByChar(modebuf[i]); 683 if (!um) 684 continue; 685 } 686 687 if (add) 688 { 689 if (um->type == MODE_PARAM && sep.GetToken(sbuf)) 690 this->SetModeInternal(source, um, sbuf); 691 else 692 this->SetModeInternal(source, um); 693 } 694 else 695 this->RemoveModeInternal(source, um); 696 } 697 } 698 699 Anope::string User::GetModes() const 700 { 701 Anope::string m, params; 702 703 for (ModeList::const_iterator it = this->modes.begin(), it_end = this->modes.end(); it != it_end; ++it) 704 { 705 UserMode *um = ModeManager::FindUserModeByName(it->first); 706 if (um == NULL) 707 continue; 708 709 m += um->mchar; 710 711 if (!it->second.empty()) 712 params += " " + it->second; 713 } 714 715 return m + params; 716 } 717 718 const User::ModeList &User::GetModeList() const 719 { 720 return modes; 721 } 722 723 ChanUserContainer *User::FindChannel(Channel *c) const 724 { 725 User::ChanUserList::const_iterator it = this->chans.find(c); 726 if (it != this->chans.end()) 727 return it->second; 728 return NULL; 729 } 730 731 bool User::IsProtected() 732 { 733 return this->HasMode("PROTECTED") || this->HasMode("GOD") || this->HasPriv("protected") || (this->server && this->server->IsULined()); 734 } 735 736 void User::Kill(const MessageSource &source, const Anope::string &reason) 737 { 738 Anope::string real_reason = source.GetName() + " (" + reason + ")"; 739 740 IRCD->SendSVSKill(source, this, "%s", real_reason.c_str()); 741 } 742 743 void User::KillInternal(const MessageSource &source, const Anope::string &reason) 744 { 745 if (this->quit) 746 { 747 Log(LOG_DEBUG) << "Duplicate quit for " << this->nick; 748 return; 749 } 750 751 Log(this, "killed") << "was killed by " << source.GetName() << " (Reason: " << reason << ")"; 752 753 this->Quit(reason); 754 } 755 756 void User::Quit(const Anope::string &reason) 757 { 758 if (this->quit) 759 { 760 Log(LOG_DEBUG) << "Duplicate quit for " << this->nick; 761 return; 762 } 763 764 FOREACH_MOD(OnUserQuit, (this, reason)); 765 766 this->quit = true; 767 quitting_users.push_back(this); 768 } 769 770 bool User::Quitting() const 771 { 772 return this->quit; 773 } 774 775 Anope::string User::Mask() const 776 { 777 Anope::string mask; 778 const Anope::string &mident = this->GetIdent(); 779 const Anope::string &mhost = this->GetDisplayedHost(); 780 781 if (mident[0] == '~') 782 mask = "*" + mident + "@"; 783 else 784 mask = mident + "@"; 785 786 sockaddrs addr(mhost); 787 if (addr.valid() && addr.sa.sa_family == AF_INET) 788 { 789 size_t dot = mhost.rfind('.'); 790 mask += mhost.substr(0, dot) + (dot == Anope::string::npos ? "" : ".*"); 791 } 792 else 793 { 794 size_t dot = mhost.find('.'); 795 if (dot != Anope::string::npos && mhost.find('.', dot + 1) != Anope::string::npos) 796 mask += "*" + mhost.substr(dot); 797 else 798 mask += mhost; 799 } 800 801 return mask; 802 } 803 804 bool User::BadPassword() 805 { 806 if (!Config->GetBlock("options")->Get<int>("badpasslimit")) 807 return false; 808 809 if (Config->GetBlock("options")->Get<time_t>("badpasstimeout") > 0 && this->invalid_pw_time > 0 && this->invalid_pw_time < Anope::CurTime - Config->GetBlock("options")->Get<time_t>("badpasstimeout")) 810 this->invalid_pw_count = 0; 811 ++this->invalid_pw_count; 812 this->invalid_pw_time = Anope::CurTime; 813 if (this->invalid_pw_count >= Config->GetBlock("options")->Get<int>("badpasslimit")) 814 { 815 this->Kill(Me, "Too many invalid passwords"); 816 return true; 817 } 818 819 return false; 820 } 821 822 User* User::Find(const Anope::string &name, bool nick_only) 823 { 824 if (!nick_only && IRCD && IRCD->RequiresID) 825 { 826 user_map::iterator it = UserListByUID.find(name); 827 if (it != UserListByUID.end()) 828 return it->second; 829 830 if (IRCD->AmbiguousID) 831 return NULL; 832 } 833 834 user_map::iterator it = UserListByNick.find(name); 835 if (it != UserListByNick.end()) 836 return it->second; 837 838 return NULL; 839 } 840 841 void User::QuitUsers() 842 { 843 for (std::list<User *>::iterator it = quitting_users.begin(), it_end = quitting_users.end(); it != it_end; ++it) 844 delete *it; 845 quitting_users.clear(); 846 }