diff options
Diffstat (limited to 'src/users.cpp')
-rw-r--r-- | src/users.cpp | 240 |
1 files changed, 137 insertions, 103 deletions
diff --git a/src/users.cpp b/src/users.cpp index 13a19c0ef..f6a4adb37 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -31,7 +31,8 @@ time_t MaxUserTime = 0; std::list<User *> User::quitting_users; -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) +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 std::vector<Anope::string> &smodeparams, const Anope::string &suid, NickCore *account) + : ip(uip) { if (snick.empty() || sident.empty() || shost.empty()) throw CoreException("Bad args passed to User::User"); @@ -40,7 +41,6 @@ User::User(const Anope::string &snick, const Anope::string &sident, const Anope: quit = false; server = NULL; invalid_pw_count = invalid_pw_time = lastmemosend = lastnickreg = lastmail = 0; - on_access = false; this->nick = snick; this->ident = sident; @@ -50,7 +50,7 @@ User::User(const Anope::string &snick, const Anope::string &sident, const Anope: this->server = sserver; this->realname = srealname; this->timestamp = this->signon = ts; - this->SetModesInternal(sserver, "%s", smodes.c_str()); + this->SetModesInternal(sserver, smodes, smodeparams); this->uid = suid; this->super_admin = false; this->nc = NULL; @@ -93,7 +93,7 @@ static void CollideKill(User *target, const Anope::string &reason) else { // Be sure my user is really dead - IRCD->SendQuit(target, "%s", reason.c_str()); + IRCD->SendQuit(target, reason); // Reintroduce my client if (BotInfo *bi = dynamic_cast<BotInfo *>(target)) @@ -111,7 +111,7 @@ static void Collide(User *u, const Anope::string &id, const Anope::string &type) CollideKill(u, type); } -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) +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, const std::vector<Anope::string> &smodeparams) { // How IRCds handle collisions varies a lot, for safety well just always kill both sides // With properly set qlines, this can almost never happen anyway @@ -133,7 +133,7 @@ User* User::OnIntroduce(const Anope::string &snick, const Anope::string &sident, } } - return new User(snick, sident, shost, svhost, sip, sserver, srealname, ts, smodes, suid, nc); + return new User(snick, sident, shost, svhost, sip, sserver, srealname, ts, smodes, smodeparams, suid, nc); } void User::ChangeNick(const Anope::string &newnick, time_t ts) @@ -153,14 +153,14 @@ void User::ChangeNick(const Anope::string &newnick, time_t ts) else { NickAlias *old_na = NickAlias::Find(this->nick); - if (old_na && (this->IsIdentified(true) || this->IsRecognized())) + if (old_na && this->IsIdentified(true)) old_na->last_seen = Anope::CurTime; UserListByNick.erase(this->nick); this->nick = newnick; - User* &other = UserListByNick[this->nick]; + User *&other = UserListByNick[this->nick]; if (other) { CollideKill(this, "Nick collision"); @@ -169,11 +169,7 @@ void User::ChangeNick(const Anope::string &newnick, time_t ts) } other = this; - on_access = false; NickAlias *na = NickAlias::Find(this->nick); - if (na) - on_access = na->nc->IsOnAccess(this); - if (na && na->nc == this->Account()) { na->last_seen = Anope::CurTime; @@ -282,7 +278,7 @@ void User::SetRealname(const Anope::string &srealname) this->realname = srealname; NickAlias *na = NickAlias::Find(this->nick); - if (na && (this->IsIdentified(true) || this->IsRecognized())) + if (na && this->IsIdentified(true)) na->last_realname = srealname; Log(this, "realname") << "changed realname to " << srealname; @@ -332,26 +328,52 @@ void User::SendMessage(BotInfo *source, const char *fmt, ...) va_end(args); } -void User::SendMessage(BotInfo *source, const Anope::string &msg) +void User::SendMessage(BotInfo *source, int count, const char *singular, const char *plural, ...) { - const char *translated_message = Language::Translate(this, msg.c_str()); + va_list args; + char buf[BUFSIZE] = ""; + + const char *translated_message = Language::Translate(this, count, singular, plural); - /* Send privmsg instead of notice if: - * - UsePrivmsg is enabled - * - The user is not registered and NSDefMsg is enabled - * - The user is registered and has set /ns set msg on - */ - bool send_privmsg = Config->UsePrivmsg && ((!this->nc && Config->DefPrivmsg) || (this->nc && this->nc->HasExt("MSG"))); - sepstream sep(translated_message, '\n', true); - for (Anope::string tok; sep.GetToken(tok);) + va_start(args, plural); + vsnprintf(buf, BUFSIZE - 1, translated_message, args); + + this->SendMessage(source, Anope::string(buf)); + + va_end(args); +} + +namespace +{ + void SendMessageInternal(BotInfo *source, User *target, const Anope::string &msg, const Anope::map<Anope::string> &tags) { - if (send_privmsg) - IRCD->SendPrivmsg(source, this->GetUID(), "%s", tok.c_str()); - else - IRCD->SendNotice(source, this->GetUID(), "%s", tok.c_str()); + const char *translated_message = Language::Translate(target, msg.c_str()); + + sepstream sep(translated_message, '\n', true); + for (Anope::string tok; sep.GetToken(tok);) + { + if (target->ShouldPrivmsg()) + IRCD->SendPrivmsg(source, target->GetUID(), tok, tags); + else + IRCD->SendNotice(source, target->GetUID(), tok, tags); + } } } +void User::SendMessage(BotInfo *source, const Anope::string &msg) +{ + SendMessageInternal(source, this, msg, {}); +} + +void User::SendMessage(CommandSource &source, const Anope::string &msg) +{ + Anope::map<Anope::string> tags; + if (!source.msgid.empty()) + tags["+draft/reply"] = source.msgid; + + SendMessageInternal(*source.service, this, msg, tags); +} + void User::Identify(NickAlias *na) { if (this->nick.equals_ci(na->nick)) @@ -372,17 +394,18 @@ void User::Identify(NickAlias *na) { if (!this->nc->o->ot->modes.empty()) { - this->SetModes(NULL, "%s", this->nc->o->ot->modes.c_str()); - this->SendMessage(NULL, "Changing your usermodes to \002%s\002", this->nc->o->ot->modes.c_str()); - UserMode *um = ModeManager::FindUserModeByName("OPER"); + auto *um = ModeManager::FindUserModeByName("OPER"); if (um && !this->HasMode("OPER") && this->nc->o->ot->modes.find(um->mchar) != Anope::string::npos) IRCD->SendOper(this); + + this->SetModes(NULL, this->nc->o->ot->modes); + this->SendMessage(NULL, _("Changing your usermodes to \002%s\002"), this->nc->o->ot->modes.c_str()); } if (IRCD->CanSetVHost && !this->nc->o->vhost.empty()) { - this->SendMessage(NULL, "Changing your vhost to \002%s\002", this->nc->o->vhost.c_str()); + this->SendMessage(NULL, _("Changing your vhost to \002%s\002"), this->nc->o->vhost.c_str()); this->SetDisplayedHost(this->nc->o->vhost); - IRCD->SendVhost(this, "", this->nc->o->vhost); + IRCD->SendVHost(this, "", this->nc->o->vhost); } } } @@ -424,6 +447,11 @@ NickCore *User::Account() const return this->nc; } +NickAlias *User::AccountNick() const +{ + return this->nc ? this->nc->na : nullptr; +} + bool User::IsIdentified(bool check_nick) const { if (check_nick && this->nc) @@ -432,56 +460,58 @@ bool User::IsIdentified(bool check_nick) const return na && *na->nc == *this->nc; } - return this->nc ? true : false; + return this->nc; } -bool User::IsRecognized(bool check_secure) const +bool User::IsSecurelyConnected() const { - if (check_secure && on_access) - { - const NickAlias *na = NickAlias::Find(this->nick); - - if (!na || na->nc->HasExt("NS_SECURE")) - return false; - } - - return on_access; + return HasMode("SSL") || HasExt("ssl"); } bool User::IsServicesOper() { if (!this->nc || !this->nc->IsServicesOper()) - // No opertype. - return false; - else if (this->nc->o->require_oper && !this->HasMode("OPER")) - return false; - else if (!this->nc->o->certfp.empty() && this->fingerprint != this->nc->o->certfp) - // Certfp mismatch - return false; - else if (!this->nc->o->hosts.empty()) + return false; // Account isn't a services oper. + + auto *oper = this->nc->o; + if (oper->require_oper && !this->HasMode("OPER")) + return false; // User isn't an ircd oper. + + if (!oper->certfp.empty()) + { + bool match = false; + for (const auto &certfp : oper->certfp) + { + if (this->fingerprint == certfp) + { + match = true; + break; + } + } + if (!match) + return false; // Wrong TLS fingerprint. + } + + if (!oper->hosts.empty()) { bool match = false; Anope::string match_host = this->GetIdent() + "@" + this->host; Anope::string match_ip = this->GetIdent() + "@" + this->ip.addr(); - for (unsigned i = 0; i < this->nc->o->hosts.size(); ++i) + for (const auto &userhost : oper->hosts) { - const Anope::string &userhost = this->nc->o->hosts[i]; if (Anope::Match(match_host, userhost) || Anope::Match(match_ip, userhost)) { match = true; break; } } - if (match == false) - return false; + if (!match) + return false; // Wrong user@host/ip. } EventReturn MOD_RESULT; FOREACH_RESULT(IsServicesOper, MOD_RESULT, (this)); - if (MOD_RESULT == EVENT_STOP) - return false; - - return true; + return MOD_RESULT != EVENT_STOP; } bool User::HasCommand(const Anope::string &command) @@ -504,11 +534,7 @@ void User::UpdateHost() return; NickAlias *na = NickAlias::Find(this->nick); - on_access = false; - if (na) - on_access = na->nc->IsOnAccess(this); - - if (na && (this->IsIdentified(true) || this->IsRecognized())) + if (na && this->IsIdentified(true)) { Anope::string last_usermask = this->GetIdent() + "@" + this->GetDisplayedHost(); Anope::string last_realhost = this->GetIdent() + "@" + this->host; @@ -539,17 +565,18 @@ void User::SetModeInternal(const MessageSource &source, UserMode *um, const Anop { if (!this->nc->o->ot->modes.empty()) { - this->SetModes(NULL, "%s", this->nc->o->ot->modes.c_str()); - this->SendMessage(NULL, "Changing your usermodes to \002%s\002", this->nc->o->ot->modes.c_str()); - UserMode *oper = ModeManager::FindUserModeByName("OPER"); + auto *oper = ModeManager::FindUserModeByName("OPER"); if (oper && !this->HasMode("OPER") && this->nc->o->ot->modes.find(oper->mchar) != Anope::string::npos) IRCD->SendOper(this); + + this->SetModes(NULL, this->nc->o->ot->modes); + this->SendMessage(NULL, _("Changing your usermodes to \002%s\002"), this->nc->o->ot->modes.c_str()); } if (IRCD->CanSetVHost && !this->nc->o->vhost.empty()) { - this->SendMessage(NULL, "Changing your vhost to \002%s\002", this->nc->o->vhost.c_str()); + this->SendMessage(NULL, _("Changing your vhost to \002%s\002"), this->nc->o->vhost.c_str()); this->SetDisplayedHost(this->nc->o->vhost); - IRCD->SendVhost(this, "", this->nc->o->vhost); + IRCD->SendVHost(this, "", this->nc->o->vhost); } } } @@ -616,19 +643,24 @@ void User::SetModes(BotInfo *bi, const char *umodes, ...) { char buf[BUFSIZE] = ""; va_list args; - Anope::string modebuf, sbuf; - int add = -1; va_start(args, umodes); vsnprintf(buf, BUFSIZE - 1, umodes, args); va_end(args); - spacesepstream sep(buf); + SetModes(bi, Anope::string(buf)); +} + +void User::SetModes(BotInfo *bi, const Anope::string &umodes) +{ + Anope::string modebuf, sbuf; + int add = -1; + spacesepstream sep(umodes); sep.GetToken(modebuf); - for (unsigned i = 0, end = modebuf.length(); i < end; ++i) + for (auto mode : modebuf) { UserMode *um; - switch (modebuf[i]) + switch (mode) { case '+': add = 1; @@ -639,7 +671,7 @@ void User::SetModes(BotInfo *bi, const char *umodes, ...) default: if (add == -1) continue; - um = ModeManager::FindUserModeByChar(modebuf[i]); + um = ModeManager::FindUserModeByChar(mode); if (!um) continue; } @@ -656,26 +688,18 @@ void User::SetModes(BotInfo *bi, const char *umodes, ...) } } -void User::SetModesInternal(const MessageSource &source, const char *umodes, ...) +void User::SetModesInternal(const MessageSource &source, const Anope::string &umodes, const std::vector<Anope::string> &umodeparams) { - char buf[BUFSIZE] = ""; - va_list args; - Anope::string modebuf, sbuf; - int add = -1; - va_start(args, umodes); - vsnprintf(buf, BUFSIZE - 1, umodes, args); - va_end(args); - - if (this->server && this->server->IsSynced() && Anope::string(buf) != "+") - Log(this, "mode") << "changes modes to " << buf; + if (this->server && this->server->IsSynced() && Anope::string(umodes) != "+") + Log(this, "mode") << "changes modes to " << umodes; - spacesepstream sep(buf); - sep.GetToken(modebuf); - for (unsigned i = 0, end = modebuf.length(); i < end; ++i) + int add = -1; + auto paramit = umodeparams.begin(); + for (const auto mode : umodes) { UserMode *um; - switch (modebuf[i]) + switch (mode) { case '+': add = 1; @@ -686,15 +710,16 @@ void User::SetModesInternal(const MessageSource &source, const char *umodes, ... default: if (add == -1) continue; - um = ModeManager::FindUserModeByChar(modebuf[i]); + um = ModeManager::FindUserModeByChar(mode); if (!um) continue; } if (add) { - if (um->type == MODE_PARAM && sep.GetToken(sbuf)) - this->SetModeInternal(source, um, sbuf); + Anope::string sbuf; + if (um->type == MODE_PARAM && paramit != umodeparams.end()) + this->SetModeInternal(source, um, *paramit++); else this->SetModeInternal(source, um); } @@ -707,16 +732,16 @@ Anope::string User::GetModes() const { Anope::string m, params; - for (ModeList::const_iterator it = this->modes.begin(), it_end = this->modes.end(); it != it_end; ++it) + for (const auto &[mode, value] : this->modes) { - UserMode *um = ModeManager::FindUserModeByName(it->first); + UserMode *um = ModeManager::FindUserModeByName(mode); if (um == NULL) continue; m += um->mchar; - if (!it->second.empty()) - params += " " + it->second; + if (!value.empty()) + params += " " + value; } return m + params; @@ -744,7 +769,7 @@ void User::Kill(const MessageSource &source, const Anope::string &reason) { Anope::string real_reason = source.GetName() + " (" + reason + ")"; - IRCD->SendSVSKill(source, this, "%s", real_reason.c_str()); + IRCD->SendSVSKill(source, this, real_reason); } void User::KillInternal(const MessageSource &source, const Anope::string &reason) @@ -810,14 +835,14 @@ Anope::string User::Mask() const bool User::BadPassword() { - if (!Config->GetBlock("options")->Get<int>("badpasslimit")) + if (!Config->GetBlock("options")->Get<unsigned int>("badpasslimit")) return false; 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")) this->invalid_pw_count = 0; ++this->invalid_pw_count; this->invalid_pw_time = Anope::CurTime; - if (this->invalid_pw_count >= Config->GetBlock("options")->Get<int>("badpasslimit")) + if (this->invalid_pw_count >= Config->GetBlock("options")->Get<unsigned int>("badpasslimit")) { this->Kill(Me, "Too many invalid passwords"); return true; @@ -826,7 +851,16 @@ bool User::BadPassword() return false; } -User* User::Find(const Anope::string &name, bool nick_only) +bool User::ShouldPrivmsg() const +{ + // Send a PRIVMSG instead of a NOTICE if: + // 1. The user is not registered and msg is in nickserv:defaults. + // 2. The user is registered and has set /ns set message on. + static ExtensibleRef<bool> msg("MSG"); + return (!nc && Config->DefPrivmsg) || (nc && msg && msg->HasExt(nc)); +} + +User *User::Find(const Anope::string &name, bool nick_only) { if (!nick_only && IRCD && IRCD->RequiresID) { @@ -847,7 +881,7 @@ User* User::Find(const Anope::string &name, bool nick_only) void User::QuitUsers() { - for (std::list<User *>::iterator it = quitting_users.begin(), it_end = quitting_users.end(); it != it_end; ++it) - delete *it; + for (const auto *quitting_user : quitting_users) + delete quitting_user; quitting_users.clear(); } |