users.cpp

Go to the documentation of this file.
00001 /* Routines to maintain a list of online users.
00002  *
00003  * (C) 2003-2013 Anope Team
00004  * Contact us at team@anope.org
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church.
00010  *
00011  */
00012 
00013 
00014 #include "services.h"
00015 #include "modules.h"
00016 #include "users.h"
00017 #include "account.h"
00018 #include "protocol.h"
00019 #include "servers.h"
00020 #include "channels.h"
00021 #include "bots.h"
00022 #include "config.h"
00023 #include "opertype.h"
00024 #include "nickserv.h"
00025 #include "language.h"
00026 
00027 user_map UserListByNick, UserListByUID;
00028 
00029 int OperCount = 0;
00030 unsigned MaxUserCount = 0;
00031 time_t MaxUserTime = 0;
00032 
00033 std::list<User *> User::quitting_users;
00034 
00035 User::User(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 ssignon, const Anope::string &smodes, const Anope::string &suid)
00036 {
00037         if (snick.empty() || sident.empty() || shost.empty())
00038                 throw CoreException("Bad args passed to User::User");
00039 
00040         /* we used to do this by calloc, no more. */
00041         quit = false;
00042         server = NULL;
00043         invalid_pw_count = invalid_pw_time = lastmemosend = lastnickreg = lastmail = 0;
00044         on_access = false;
00045 
00046         this->nick = snick;
00047         this->ident = sident;
00048         this->host = shost;
00049         this->vhost = svhost;
00050         if (!svhost.empty())
00051                 this->SetCloakedHost(svhost);
00052         this->ip = sip;
00053         this->server = sserver;
00054         this->realname = srealname;
00055         this->timestamp = this->signon = ssignon;
00056         this->SetModesInternal("%s", smodes.c_str());
00057         this->uid = suid;
00058         this->super_admin = false;
00059 
00060         size_t old = UserListByNick.size();
00061         UserListByNick[snick] = this;
00062         if (!suid.empty())
00063                 UserListByUID[suid] = this;
00064         if (old == UserListByNick.size())
00065                 Log(LOG_DEBUG) << "Duplicate user " << snick << " in user table?";
00066 
00067         this->nc = NULL;
00068 
00069         if (sserver) // Our bots are introduced on startup with no server
00070         {
00071                 ++sserver->users;
00072                 Log(this, "connect") << (!svhost.empty() ? Anope::string("(") + svhost + ") " : "") << "(" << srealname << ") " << sip << " connected to the network (" << sserver->GetName() << ")";
00073         }
00074 
00075         if (UserListByNick.size() > MaxUserCount)
00076         {
00077                 MaxUserCount = UserListByNick.size();
00078                 MaxUserTime = Anope::CurTime;
00079                 Log(this, "maxusers") << "connected - new maximum user count: " << UserListByNick.size();
00080         }
00081 
00082         bool exempt = false;
00083         if (server && server->IsULined())
00084                 exempt = true;
00085         FOREACH_MOD(I_OnUserConnect, OnUserConnect(this, exempt));
00086 }
00087 
00088 void User::ChangeNick(const Anope::string &newnick, time_t ts)
00089 {
00090         /* Sanity check to make sure we don't segfault */
00091         if (newnick.empty())
00092                 throw CoreException("User::ChangeNick() got a bad argument");
00093         
00094         this->super_admin = false;
00095         Log(this, "nick") << "(" << this->realname << ") changed nick to " << newnick;
00096 
00097         Anope::string old = this->nick;
00098         this->timestamp = ts;
00099 
00100         if (this->nick.equals_ci(newnick))
00101                 this->nick = newnick;
00102         else
00103         {
00104                 NickAlias *old_na = NickAlias::Find(this->nick);
00105                 if (old_na && (this->IsIdentified(true) || this->IsRecognized()))
00106                         old_na->last_seen = Anope::CurTime;
00107                 
00108                 UserListByNick.erase(this->nick);
00109                 this->nick = newnick;
00110                 UserListByNick[this->nick] = this;
00111 
00112                 on_access = false;
00113                 NickAlias *na = NickAlias::Find(this->nick);
00114                 if (na)
00115                         on_access = na->nc->IsOnAccess(this);
00116 
00117                 if (na && na->nc == this->Account())
00118                 {
00119                         na->last_seen = Anope::CurTime;
00120                         this->UpdateHost();
00121                 }
00122         }
00123 
00124         FOREACH_MOD(I_OnUserNickChange, OnUserNickChange(this, old));
00125 }
00126 
00127 void User::SetDisplayedHost(const Anope::string &shost)
00128 {
00129         if (shost.empty())
00130                 throw CoreException("empty host? in MY services? it seems it's more likely than I thought.");
00131 
00132         this->vhost = shost;
00133 
00134         Log(this, "host") << "changed vhost to " << shost;
00135 
00136         this->UpdateHost();
00137 }
00138 
00139 const Anope::string &User::GetDisplayedHost() const
00140 {
00141         if (!this->vhost.empty())
00142                 return this->vhost;
00143         else if (this->HasMode("CLOAK") && !this->GetCloakedHost().empty())
00144                 return this->GetCloakedHost();
00145         else
00146                 return this->host;
00147 }
00148 
00149 void User::SetCloakedHost(const Anope::string &newhost)
00150 {
00151         if (newhost.empty())
00152                 throw "empty host in User::SetCloakedHost";
00153 
00154         chost = newhost;
00155 
00156         Log(this, "host") << "changed cloaked host to " << newhost;
00157 
00158         this->UpdateHost();
00159 }
00160 
00161 const Anope::string &User::GetCloakedHost() const
00162 {
00163         return chost;
00164 }
00165 
00166 const Anope::string &User::GetUID() const
00167 {
00168         if (!this->uid.empty() && IRCD->RequiresID)
00169                 return this->uid;
00170         else
00171                 return this->nick;
00172 }
00173 
00174 void User::SetVIdent(const Anope::string &sident)
00175 {
00176         this->vident = sident;
00177 
00178         Log(this, "ident") << "changed vident to " << sident;
00179 
00180         this->UpdateHost();
00181 }
00182 
00183 const Anope::string &User::GetVIdent() const
00184 {
00185         if (!this->vident.empty())
00186                 return this->vident;
00187         else
00188                 return this->ident;
00189 }
00190 
00191 void User::SetIdent(const Anope::string &sident)
00192 {
00193         this->ident = sident;
00194 
00195         Log(this, "ident") << "changed real ident to " << sident;
00196 
00197         this->UpdateHost();
00198 }
00199 
00200 const Anope::string &User::GetIdent() const
00201 {
00202         return this->ident;
00203 }
00204 
00205 Anope::string User::GetMask() const
00206 {
00207         return this->nick + "!" + this->ident + "@" + this->host;
00208 }
00209 
00210 Anope::string User::GetDisplayedMask() const
00211 {
00212         return this->nick + "!" + this->GetVIdent() + "@" + this->GetDisplayedHost();
00213 }
00214 
00215 void User::SetRealname(const Anope::string &srealname)
00216 {
00217         if (srealname.empty())
00218                 throw CoreException("realname empty in SetRealname");
00219 
00220         this->realname = srealname;
00221         NickAlias *na = NickAlias::Find(this->nick);
00222 
00223         if (na && (this->IsIdentified(true) || this->IsRecognized()))
00224                 na->last_realname = srealname;
00225 
00226         Log(this, "realname") << "changed realname to " << srealname;
00227 }
00228 
00229 User::~User()
00230 {
00231         if (this->server != NULL)
00232         {
00233                 Log(this, "disconnect") << "(" << this->realname << ") disconnected from the network (" << this->server->GetName() << ")";
00234                 --this->server->users;
00235         }
00236 
00237         FOREACH_MOD(I_OnPreUserLogoff, OnPreUserLogoff(this));
00238 
00239         ModeManager::StackerDel(this);
00240         this->Logout();
00241 
00242         if (this->HasMode("OPER"))
00243                 --OperCount;
00244 
00245         while (!this->chans.empty())
00246                 this->chans.front()->chan->DeleteUser(this);
00247 
00248         UserListByNick.erase(this->nick);
00249         if (!this->uid.empty())
00250                 UserListByUID.erase(this->uid);
00251 
00252         FOREACH_MOD(I_OnPostUserLogoff, OnPostUserLogoff(this));
00253 }
00254 
00255 void User::SendMessage(const BotInfo *source, const char *fmt, ...)
00256 {
00257         va_list args;
00258         char buf[BUFSIZE] = "";
00259 
00260         const char *translated_message = Language::Translate(this, fmt);
00261 
00262         va_start(args, fmt);
00263         vsnprintf(buf, BUFSIZE - 1, translated_message, args);
00264 
00265         this->SendMessage(source, Anope::string(buf));
00266 
00267         va_end(args);
00268 }
00269 
00270 void User::SendMessage(const BotInfo *source, const Anope::string &msg)
00271 {
00272         const char *translated_message = Language::Translate(this, msg.c_str());
00273 
00274         /* Send privmsg instead of notice if:
00275         * - UsePrivmsg is enabled
00276         * - The user is not registered and NSDefMsg is enabled
00277         * - The user is registered and has set /ns set msg on
00278         */
00279         sepstream sep(translated_message, '\n');
00280         Anope::string tok;
00281         while (sep.GetToken(tok))
00282         {
00283                 if (Config->UsePrivmsg && ((!this->nc && Config->NSDefFlags.count("msg")) || (this->nc && this->nc->HasExt("MSG"))))
00284                         IRCD->SendPrivmsg(source, this->GetUID(), "%s", tok.c_str());
00285                 else
00286                         IRCD->SendNotice(source, this->GetUID(), "%s", tok.c_str());
00287         }
00288 }
00289 
00346 void User::Collide(NickAlias *na)
00347 {
00348         if (na)
00349                 na->Extend("COLLIDED");
00350 
00351         if (IRCD->CanSVSNick)
00352         {
00353                 Anope::string guestnick;
00354 
00355                 int i = 0;
00356                 do
00357                 {
00358                         guestnick = Config->NSGuestNickPrefix + stringify(static_cast<uint16_t>(rand()));
00359                 } while (User::Find(guestnick) && i++ < 10);
00360 
00361                 if (i == 11)
00362                         this->Kill(Config->NickServ, "Services nickname-enforcer kill");
00363                 else
00364                 {
00365                         if (NickServ)
00366                                 this->SendMessage(NickServ, _("Your nickname is now being changed to \002%s\002"), guestnick.c_str());
00367                         IRCD->SendForceNickChange(this, guestnick, Anope::CurTime);
00368                 }
00369         }
00370         else
00371                 this->Kill(Config->NickServ, "Services nickname-enforcer kill");
00372 }
00373 
00374 void User::Identify(NickAlias *na)
00375 {
00376         if (!na)
00377         {
00378                 Log() << "User::Identify() called with NULL pointer";
00379                 return;
00380         }
00381 
00382         if (this->nick.equals_ci(na->nick))
00383         {
00384                 Anope::string last_usermask = this->GetIdent() + "@" + this->GetDisplayedHost();
00385                 Anope::string last_realhost = this->GetIdent() + "@" + this->host;
00386                 na->last_usermask = last_usermask;
00387                 na->last_realhost = last_realhost;
00388                 na->last_realname = this->realname;
00389                 na->last_seen = Anope::CurTime;
00390         }
00391 
00392         this->Login(na->nc);
00393         IRCD->SendLogin(this);
00394 
00395         const NickAlias *this_na = NickAlias::Find(this->nick);
00396         if (!Config->NoNicknameOwnership && this_na && this_na->nc == *na->nc && na->nc->HasExt("UNCONFIRMED") == false)
00397                 this->SetMode(NickServ, "REGISTERED");
00398 
00399         FOREACH_MOD(I_OnNickIdentify, OnNickIdentify(this));
00400 
00401         if (this->IsServicesOper())
00402         {
00403                 if (!this->nc->o->ot->modes.empty())
00404                 {
00405                         this->SetModes(OperServ, "%s", this->nc->o->ot->modes.c_str());
00406                         if (OperServ)
00407                                 this->SendMessage(OperServ, "Changing your usermodes to \002%s\002", this->nc->o->ot->modes.c_str());
00408                         UserMode *um = ModeManager::FindUserModeByName("OPER");
00409                         if (um && !this->HasMode("OPER") && this->nc->o->ot->modes.find(um->mchar) != Anope::string::npos)
00410                                 IRCD->SendOper(this);
00411                 }
00412                 if (IRCD->CanSetVHost && !this->nc->o->vhost.empty())
00413                 {
00414                         if (OperServ)
00415                                 this->SendMessage(OperServ, "Changing your vhost to \002%s\002", this->nc->o->vhost.c_str());
00416                         this->SetDisplayedHost(this->nc->o->vhost);
00417                         IRCD->SendVhost(this, "", this->nc->o->vhost);
00418                 }
00419         }
00420 }
00421 
00422 
00423 void User::Login(NickCore *core)
00424 {
00425         this->Logout();
00426         this->nc = core;
00427         core->users.push_back(this);
00428 
00429         this->UpdateHost();
00430 
00431         if (this->server->IsSynced())
00432                 Log(this, "account") << "is now identified as " << this->nc->display;
00433 }
00434 
00435 void User::Logout()
00436 {
00437         if (!this->nc)
00438                 return;
00439         
00440         Log(this, "account") << "is no longer identified as " << this->nc->display;
00441 
00442         std::list<User *>::iterator it = std::find(this->nc->users.begin(), this->nc->users.end(), this);
00443         if (it != this->nc->users.end())
00444                 this->nc->users.erase(it);
00445 
00446         this->nc = NULL;
00447 }
00448 
00449 NickCore *User::Account() const
00450 {
00451         return this->nc;
00452 }
00453 
00454 bool User::IsIdentified(bool CheckNick) const
00455 {
00456         if (CheckNick && this->nc)
00457         {
00458                 NickAlias *na = NickAlias::Find(this->nc->display);
00459 
00460                 if (na && *na->nc == *this->nc)
00461                         return true;
00462 
00463                 return false;
00464         }
00465 
00466         return this->nc ? true : false;
00467 }
00468 
00469 bool User::IsRecognized(bool CheckSecure) const
00470 {
00471         if (CheckSecure && on_access)
00472         {
00473                 const NickAlias *na = NickAlias::Find(this->nick);
00474 
00475                 if (!na || na->nc->HasExt("SECURE"))
00476                         return false;
00477         }
00478 
00479         return on_access;
00480 }
00481 
00482 bool User::IsServicesOper()
00483 {
00484         if (!this->nc || !this->nc->IsServicesOper())
00485                 // No opertype.
00486                 return false;
00487         else if (this->nc->o->require_oper && !this->HasMode("OPER"))
00488                 return false;
00489         else if (!this->nc->o->certfp.empty() && this->fingerprint != this->nc->o->certfp)
00490                 // Certfp mismatch
00491                 return false;
00492         else if (!this->nc->o->hosts.empty())
00493         {
00494                 bool match = false;
00495                 Anope::string match_host = this->GetIdent() + "@" + this->host;
00496                 for (unsigned i = 0; i < this->nc->o->hosts.size(); ++i)
00497                         if (Anope::Match(match_host, this->nc->o->hosts[i]))
00498                                 match = true;
00499                 if (match == false)
00500                         return false;
00501         }
00502 
00503         EventReturn MOD_RESULT;
00504         FOREACH_RESULT(I_IsServicesOper, IsServicesOper(this));
00505         if (MOD_RESULT == EVENT_STOP)
00506                 return false;
00507 
00508         return true;
00509 }
00510 
00511 bool User::HasCommand(const Anope::string &command)
00512 {
00513         if (this->IsServicesOper())
00514                 return this->nc->o->ot->HasCommand(command);
00515         return false;
00516 }
00517 
00518 bool User::HasPriv(const Anope::string &priv)
00519 {
00520         if (this->IsServicesOper())
00521                 return this->nc->o->ot->HasPriv(priv);
00522         return false;
00523 }
00524 
00525 void User::UpdateHost()
00526 {
00527         if (this->host.empty())
00528                 return;
00529 
00530         NickAlias *na = NickAlias::Find(this->nick);
00531         on_access = false;
00532         if (na)
00533                 on_access = na->nc->IsOnAccess(this);
00534 
00535         if (na && (this->IsIdentified(true) || this->IsRecognized()))
00536         {
00537                 Anope::string last_usermask = this->GetIdent() + "@" + this->GetDisplayedHost();
00538                 Anope::string last_realhost = this->GetIdent() + "@" + this->host;
00539                 na->last_usermask = last_usermask;
00540                 na->last_realhost = last_realhost;
00541         }
00542 }
00543 
00544 bool User::HasMode(const Anope::string &mname) const
00545 {
00546         return this->modes.count(mname);
00547 }
00548 
00549 void User::SetModeInternal(UserMode *um, const Anope::string &param)
00550 {
00551         if (!um)
00552                 return;
00553 
00554         this->modes[um->name] = param;
00555 
00556         FOREACH_MOD(I_OnUserModeSet, OnUserModeSet(this, um->name));
00557 }
00558 
00559 void User::RemoveModeInternal(UserMode *um)
00560 {
00561         if (!um)
00562                 return;
00563 
00564         this->modes.erase(um->name);
00565 
00566         FOREACH_MOD(I_OnUserModeUnset, OnUserModeUnset(this, um->name));
00567 }
00568 
00569 void User::SetMode(const BotInfo *bi, UserMode *um, const Anope::string &Param)
00570 {
00571         if (!um || HasMode(um->name))
00572                 return;
00573 
00574         ModeManager::StackerAdd(bi, this, um, true, Param);
00575         SetModeInternal(um, Param);
00576 }
00577 
00578 void User::SetMode(const BotInfo *bi, const Anope::string &uname, const Anope::string &Param)
00579 {
00580         SetMode(bi, ModeManager::FindUserModeByName(uname), Param);
00581 }
00582 
00583 void User::RemoveMode(const BotInfo *bi, UserMode *um)
00584 {
00585         if (!um || !HasMode(um->name))
00586                 return;
00587 
00588         ModeManager::StackerAdd(bi, this, um, false);
00589         RemoveModeInternal(um);
00590 }
00591 
00592 void User::RemoveMode(const BotInfo *bi, const Anope::string &name)
00593 {
00594         RemoveMode(bi, ModeManager::FindUserModeByName(name));
00595 }
00596 
00597 void User::SetModes(const BotInfo *bi, const char *umodes, ...)
00598 {
00599         char buf[BUFSIZE] = "";
00600         va_list args;
00601         Anope::string modebuf, sbuf;
00602         int add = -1;
00603         va_start(args, umodes);
00604         vsnprintf(buf, BUFSIZE - 1, umodes, args);
00605         va_end(args);
00606 
00607         spacesepstream sep(buf);
00608         sep.GetToken(modebuf);
00609         for (unsigned i = 0, end = modebuf.length(); i < end; ++i)
00610         {
00611                 UserMode *um;
00612 
00613                 switch (modebuf[i])
00614                 {
00615                         case '+':
00616                                 add = 1;
00617                                 continue;
00618                         case '-':
00619                                 add = 0;
00620                                 continue;
00621                         default:
00622                                 if (add == -1)
00623                                         continue;
00624                                 um = ModeManager::FindUserModeByChar(modebuf[i]);
00625                                 if (!um)
00626                                         continue;
00627                 }
00628 
00629                 if (add)
00630                 {
00631                         if (um->type == MODE_PARAM && sep.GetToken(sbuf))
00632                                 this->SetMode(bi, um, sbuf);
00633                         else
00634                                 this->SetMode(bi, um);
00635                 }
00636                 else
00637                         this->RemoveMode(bi, um);
00638         }
00639 }
00640 
00641 void User::SetModesInternal(const char *umodes, ...)
00642 {
00643         char buf[BUFSIZE] = "";
00644         va_list args;
00645         Anope::string modebuf, sbuf;
00646         int add = -1;
00647         va_start(args, umodes);
00648         vsnprintf(buf, BUFSIZE - 1, umodes, args);
00649         va_end(args);
00650 
00651         Log(this, "mode") << "changes modes to " << buf;
00652 
00653         spacesepstream sep(buf);
00654         sep.GetToken(modebuf);
00655         for (unsigned i = 0, end = modebuf.length(); i < end; ++i)
00656         {
00657                 UserMode *um;
00658 
00659                 switch (modebuf[i])
00660                 {
00661                         case '+':
00662                                 add = 1;
00663                                 continue;
00664                         case '-':
00665                                 add = 0;
00666                                 continue;
00667                         default:
00668                                 if (add == -1)
00669                                         continue;
00670                                 um = ModeManager::FindUserModeByChar(modebuf[i]);
00671                                 if (!um)
00672                                         continue;
00673                 }
00674 
00675                 if (add)
00676                 {
00677                         if (um->type == MODE_PARAM && sep.GetToken(sbuf))
00678                                 this->SetModeInternal(um, sbuf);
00679                         else
00680                                 this->SetModeInternal(um);
00681                 }
00682                 else
00683                         this->RemoveModeInternal(um);
00684 
00685                 if (um->name == "OPER")
00686                 {
00687                         if (add)
00688                                 ++OperCount;
00689                         else
00690                                 --OperCount;
00691                 }
00692                 else if (um->name == "CLOAK" || um->name == "VHOST")
00693                 {
00694                         if (!add && !this->vhost.empty())
00695                                 this->vhost.clear();
00696                         this->UpdateHost();
00697                 }
00698         }
00699 }
00700 
00701 Anope::string User::GetModes() const
00702 {
00703         Anope::string m, params;
00704 
00705         typedef std::map<Anope::string, Anope::string> mode_map;
00706         for (mode_map::const_iterator it = this->modes.begin(), it_end = this->modes.end(); it != it_end; ++it)
00707         {
00708                 UserMode *um = ModeManager::FindUserModeByName(it->first);
00709                 if (um == NULL)
00710                         continue;
00711 
00712                 m += um->mchar;
00713 
00714                 if (!it->second.empty())
00715                         params += " " + it->second;
00716         }
00717 
00718         return m + params;
00719 }
00720 
00721 ChanUserContainer *User::FindChannel(const Channel *c) const
00722 {
00723         for (User::ChanUserList::const_iterator it = this->chans.begin(), it_end = this->chans.end(); it != it_end; ++it)
00724                 if ((*it)->chan == c)
00725                         return *it;
00726         return NULL;
00727 }
00728 
00729 bool User::IsProtected() const
00730 {
00731         if (this->HasMode("PROTECTED") || this->HasMode("GOD"))
00732                 return true;
00733 
00734         return false;
00735 }
00736 
00737 void User::Kill(const Anope::string &source, const Anope::string &reason)
00738 {
00739         Anope::string real_source = source.empty() ? Config->ServerName : source;
00740         Anope::string real_reason = real_source + " (" + reason + ")";
00741 
00742         IRCD->SendSVSKill(BotInfo::Find(source), this, "%s", real_reason.c_str());
00743 }
00744 
00745 void User::KillInternal(const Anope::string &source, const Anope::string &reason)
00746 {
00747         if (this->quit)
00748         {
00749                 Log(LOG_DEBUG) << "Duplicate quit for " << this->nick;
00750                 return;
00751         }
00752 
00753         Log(this, "killed") << "was killed by " << source << " (Reason: " << reason << ")";
00754 
00755         NickAlias *na = NickAlias::Find(this->nick);
00756         if (na && !na->nc->HasExt("SUSPENDED") && (this->IsRecognized() || this->IsIdentified(true)))
00757         {
00758                 na->last_seen = Anope::CurTime;
00759                 na->last_quit = reason;
00760         }
00761 
00762         this->quit = true;
00763         quitting_users.push_back(this);
00764 }
00765 
00766 void User::Quit(const Anope::string &reason)
00767 {
00768         if (this->quit)
00769         {
00770                 Log(LOG_DEBUG) << "Duplicate quit for " << this->nick;
00771                 return;
00772         }
00773 
00774         this->quit = true;
00775         quitting_users.push_back(this);
00776 }
00777 
00778 bool User::Quitting() const
00779 {
00780         return this->quit;
00781 }
00782 
00783 Anope::string User::Mask() const
00784 {
00785         Anope::string mask;
00786         Anope::string mident = this->GetIdent();
00787         Anope::string mhost = this->GetDisplayedHost();
00788 
00789         if (mident[0] == '~')
00790                 mask = "*" + mident + "@";
00791         else
00792                 mask = mident + "@";
00793 
00794         size_t dot;
00795         /* To make sure this is an IP, make sure the host contains only numbers and dots, and check to make sure it only contains 3 dots */
00796         if (mhost.find_first_not_of("0123456789.") == Anope::string::npos && (dot = mhost.find('.')) != Anope::string::npos && (dot = mhost.find('.', dot + 1)) != Anope::string::npos && (dot = mhost.find('.', dot + 1)) != Anope::string::npos && mhost.find('.', dot + 1) == Anope::string::npos)
00797         { /* IP addr */
00798                 dot = mhost.find('.');
00799                 mask += mhost.substr(0, dot) + ".*";
00800         }
00801         else
00802         {
00803                 if ((dot = mhost.find('.')) != Anope::string::npos && mhost.find('.', dot + 1) != Anope::string::npos)
00804                         mask += "*" + mhost.substr(dot);
00805                 else
00806                         mask += mhost;
00807         }
00808 
00809         return mask;
00810 }
00811 
00812 bool User::BadPassword()
00813 {
00814         if (!Config->BadPassLimit)
00815                 return false;
00816 
00817         if (Config->BadPassTimeout > 0 && this->invalid_pw_time > 0 && this->invalid_pw_time < Anope::CurTime - Config->BadPassTimeout)
00818                 this->invalid_pw_count = 0;
00819         ++this->invalid_pw_count;
00820         this->invalid_pw_time = Anope::CurTime;
00821         if (this->invalid_pw_count >= Config->BadPassLimit)
00822         {
00823                 this->Kill(Config->ServerName, "Too many invalid passwords");
00824                 return true;
00825         }
00826 
00827         return false;
00828 }
00829 
00830 User* User::Find(const Anope::string &name, bool nick_only)
00831 {
00832         if (!nick_only && isdigit(name[0]) && IRCD->RequiresID)
00833         {
00834                 user_map::iterator it = UserListByUID.find(name);
00835                 if (it != UserListByUID.end())
00836                         return it->second;
00837         }
00838         else
00839         {
00840                 user_map::iterator it = UserListByNick.find(name);
00841                 if (it != UserListByNick.end())
00842                         return it->second;
00843         }
00844 
00845         return NULL;
00846 }
00847 
00848 void User::QuitUsers()
00849 {
00850         for (std::list<User *>::iterator it = quitting_users.begin(), it_end = quitting_users.end(); it != it_end; ++it)
00851                 delete *it;
00852         quitting_users.clear();
00853 }
00854