Exemple #1
0
	void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
	{
		if (Anope::ReadOnly)
		{
			source.Reply(_("Services are in read-only mode."));
			return;
		}

		const Anope::string &mask = params[0];
		std::vector<HostServ::VHost *> vhosts = source.GetAccount()->GetRefs<HostServ::VHost *>();

		if (vhosts.empty())
		{
			source.Reply(_("You do not have any vhosts associated with your account."));
			return;
		}

		HostServ::VHost *vhost = HostServ::FindVHost(source.GetAccount(), mask);
		if (vhost == nullptr)
		{
			source.Reply(_("You do not have the vhost \002{0}\002."), mask);
			return;
		}

		/* Disable default on all vhosts */
		for (HostServ::VHost *v : vhosts)
			v->SetDefault(false);

		/* Set default on chose vhost */
		vhost->SetDefault(true);

		source.Reply(_("Your default vhost is now \002{0}\002."), vhost->Mask());
	}
Exemple #2
0
	void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
	{
		const Anope::string &nick = !params.empty() ? params[0] : "";
		NickServ::Account *nc;

		if (!nick.empty() && source.IsServicesOper())
		{
			NickServ::Nick *na = NickServ::FindNick(nick);
			if (!na)
			{
				source.Reply(_("\002{0}\002 isn't registered."), nick);
				return;
			}

			nc = na->GetAccount();
		}
		else
			nc = source.GetAccount();

		ListFormatter list(source.GetAccount());
		list.AddColumn(_("Nick")).AddColumn(_("Expires"));
		time_t nickserv_expire = Config->GetModule("nickserv")->Get<time_t>("expire", "21d"),
		       unconfirmed_expire = Config->GetModule("nickserv")->Get<time_t>("unconfirmedexpire", "1d");
		for (NickServ::Nick *na2 : nc->GetRefs<NickServ::Nick *>())
		{
			Anope::string expires;
			if (na2->HasFieldS("NS_NO_EXPIRE"))
				expires = _("Does not expire");
			else if (!nickserv_expire || Anope::NoExpire)
				;
			else if (na2->GetAccount()->HasFieldS("UNCONFIRMED") && unconfirmed_expire)
				expires = Anope::strftime(na2->GetTimeRegistered() + unconfirmed_expire, source.GetAccount());
			else
				expires = Anope::strftime(na2->GetLastSeen() + nickserv_expire, source.GetAccount());

			ListFormatter::ListEntry entry;
			entry["Nick"] = na2->GetNick();
			entry["Expires"] = expires;
			list.AddEntry(entry);
		}

		source.Reply(nc != source.GetAccount() ? _("List of nicknames in the group of \002%s\002:") : _("List of nicknames in your group:"), nc->GetDisplay().c_str());
		std::vector<Anope::string> replies;
		list.Process(replies);

		for (unsigned i = 0; i < replies.size(); ++i)
			source.Reply(replies[i]);

		source.Reply(_("%d nickname(s) in the group."), replies.size());
	}
Exemple #3
0
	void DoList(CommandSource &source, NickServ::Account *nc)
	{
		std::vector<AutoJoin *> channels = nc->GetRefs<AutoJoin *>();

		if (channels.empty())
		{
			source.Reply(_("The auto join list of \002{0}\002 is empty."), nc->GetDisplay());
			return;
		}

		ListFormatter list(source.GetAccount());
		list.AddColumn(_("Number")).AddColumn(_("Channel")).AddColumn(_("Key"));
		for (unsigned i = 0; i < channels.size(); ++i)
		{
			AutoJoin *aj = channels[i];
			ListFormatter::ListEntry entry;
			entry["Number"] = stringify(i + 1);
			entry["Channel"] = aj->GetChannel();
			entry["Key"] = aj->GetKey();
			list.AddEntry(entry);
		}

		source.Reply(_("Auto join list of \002{0}\002:"), nc->GetDisplay());

		std::vector<Anope::string> replies;
		list.Process(replies);

		for (unsigned i = 0; i < replies.size(); ++i)
			source.Reply(replies[i]);
	}
Exemple #4
0
	void DoDel(CommandSource &source, NickServ::Account *nc, const Anope::string &mask)
	{
		if (mask.empty())
		{
			this->OnSyntaxError(source, "DEL");
			return;
		}

		if (Anope::ReadOnly)
		{
			source.Reply(_("Services are in read-only mode."));
			return;
		}

		for (NickAccess *a : nc->GetRefs<NickAccess *>(nsaccess))
			if (a->GetMask().equals_ci(mask))
			{
				a->Delete();
				Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to DELETE mask " << mask << " from " << nc->GetDisplay();
				source.Reply(_("\002{0}\002 deleted from the access list of \002{1}\002."), mask, nc->GetDisplay());
				return;
			}


		source.Reply(_("\002{0}\002 not found on the access list of \002{1}\002."), mask, nc->GetDisplay());
	}
Exemple #5
0
    void DoDel(CommandSource &source, NickServ::Account *nc, Anope::string certfp)
    {
        std::vector<NSCertEntry *> cl = nc->GetRefs<NSCertEntry *>(certentry);

        if (certfp.empty())
        {
            User *u = source.GetUser();
            if (u)
                certfp = u->fingerprint;
        }

        if (certfp.empty())
        {
            this->OnSyntaxError(source, "DEL");
            return;
        }

        NSCertEntry *cert = FindCert(cl, certfp);
        if (!cert)
        {
            source.Reply(_("\002{0}\002 not found on the certificate list of \002{1}\002."), certfp, nc->GetDisplay());
            return;
        }

        cert->Delete();

        Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to DELETE certificate fingerprint " << certfp << " from " << nc->GetDisplay();
        source.Reply(_("\002{0}\002 deleted from the access list of \002{1}\002."), certfp, nc->GetDisplay());
    }
Exemple #6
0
	void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
	{
		if (!MemoServ::service)
			return;

		const Anope::string &nick = params[0];
		const Anope::string &text = params[1];

		if (Anope::ReadOnly && !source.IsOper())
		{
			source.Reply(_("Sorry, memo sending is temporarily disabled."));
			return;
		}

		if (source.GetAccount()->HasFieldS("UNCONFIRMED"))
		{
			source.Reply(_("You must confirm your account before you may send a memo."));
			return;
		}

		MemoServ::MemoServService::MemoResult result = MemoServ::service->Send(source.GetNick(), nick, text);
		if (result == MemoServ::MemoServService::MEMO_SUCCESS)
		{
			source.Reply(_("Memo sent to \002%s\002."), nick.c_str());
			Log(LOG_COMMAND, source, this) << "to send a memo to " << nick;
		}
		else if (result == MemoServ::MemoServService::MEMO_INVALID_TARGET)
			source.Reply(_("\002{0}\002 is not a registered unforbidden nick or channel."), nick);
		else if (result == MemoServ::MemoServService::MEMO_TOO_FAST)
			source.Reply(_("Please wait \002{0}\002 seconds before using the \002{1}\002 command again."), Config->GetModule("memoserv")->Get<time_t>("senddelay"), source.command);
		else if (result == MemoServ::MemoServService::MEMO_TARGET_FULL)
			source.Reply(_("Sorry, \002{0}\002 currently has too many memos and cannot receive more."), nick);
	}
Exemple #7
0
	void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
	{
		unsigned count = 0;
		ListFormatter list(source.GetAccount());

		list.AddColumn(_("Nick")).AddColumn(_("Mask"));

		for (BotInfo *bi : Serialize::GetObjects<BotInfo *>())
		{
			if (source.HasPriv("botserv/administration") || !bi->GetOperOnly())
			{
				++count;
				ListFormatter::ListEntry entry;
				entry["Nick"] = (bi->GetOperOnly() ? "* " : "") + bi->GetNick();
				entry["Mask"] = bi->GetUser() + "@" + bi->GetHost();
				list.AddEntry(entry);
			}
		}

		std::vector<Anope::string> replies;
		list.Process(replies);

		if (!count)
		{
			source.Reply(_("There are no bots available"));
			return;
		}

		source.Reply(_("Bot list:"));

		for (unsigned i = 0; i < replies.size(); ++i)
			source.Reply(replies[i]);

		source.Reply(_("{0} bots available."), count);
	}
Exemple #8
0
	void DoList(CommandSource &source, NewsType ntype, const char **msgs)
	{
		std::vector<NewsItem *> list = Serialize::GetObjects<NewsItem *>();

		if (list.empty())
		{
			source.Reply(msgs[MSG_LIST_NONE]);
			return;
		}

		ListFormatter lflist(source.GetAccount());
		lflist.AddColumn(_("Number")).AddColumn(_("Creator")).AddColumn(_("Created")).AddColumn(_("Text"));

		unsigned int i = 1;
		for (NewsItem *n : list)
		{
			ListFormatter::ListEntry entry;
			entry["Number"] = stringify(i++ + 1);
			entry["Creator"] = n->GetWho();
			entry["Created"] = Anope::strftime(n->GetTime(), NULL, true);
			entry["Text"] = n->GetText();
			lflist.AddEntry(entry);
		}

		source.Reply(msgs[MSG_LIST_HEADER]);

		std::vector<Anope::string> replies;
		lflist.Process(replies);

		for (i = 0; i < replies.size(); ++i)
			source.Reply(replies[i]);

		source.Reply(_("End of news list."));
	}
Exemple #9
0
	void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
	{
		unsigned counter = 0;
		unsigned display_counter = 0, listmax = Config->GetModule(this->GetOwner())->Get<unsigned>("listmax");
		ListFormatter list(source.GetAccount());

		list.AddColumn(_("Number")).AddColumn(_("Nick")).AddColumn(_("Vhost")).AddColumn(_("Created"));

		for (HostRequest *hr : Serialize::GetObjects<HostRequest *>())
		{
			if (!listmax || display_counter < listmax)
			{
				++display_counter;

				ListFormatter::ListEntry entry;
				entry["Number"] = stringify(display_counter);
				entry["Nick"] = hr->GetNick()->GetNick();
				if (!hr->GetIdent().empty())
					entry["Vhost"] = hr->GetIdent() + "@" + hr->GetHost();
				else
					entry["Vhost"] = hr->GetHost();
				entry["Created"] = Anope::strftime(hr->GetTime(), NULL, true);
				list.AddEntry(entry);
			}
			++counter;
		}

		std::vector<Anope::string> replies;
		list.Process(replies);

		for (unsigned i = 0; i < replies.size(); ++i)
			source.Reply(replies[i]);

		source.Reply(_("Displayed \002{0}\002 records (\002{1}\002 total)."), display_counter, counter);
	}
Exemple #10
0
	void OnNickInfo(CommandSource &source, NickServ::Nick *na, InfoFormatter &info, bool show_hidden) override
	{
		NSSuspendInfo *s = na->GetAccount()->GetRef<NSSuspendInfo *>();
		if (!s)
			return;

		if (show_hidden || Show(source, "suspended"))
			info[_("Suspended")] = _("This nickname is \002suspended\002.");
		if (!s->GetBy().empty() && (show_hidden || Show(source, "by")))
			info[_("Suspended by")] = s->GetBy();
		if (!s->GetReason().empty() && (show_hidden || Show(source, "reason")))
			info[_("Suspend reason")] = s->GetReason();
		if (s->GetWhen() && (show_hidden || Show(source, "on")))
			info[_("Suspended on")] = Anope::strftime(s->GetWhen(), source.GetAccount());
		if (s->GetExpires() && (show_hidden || Show(source, "expires")))
			info[_("Suspension expires")] = Anope::strftime(s->GetExpires(), source.GetAccount());
	}
Exemple #11
0
	void DoStatsUptime(CommandSource &source)
	{
		Stats *stats = Serialize::GetObject<Stats *>();
		time_t uptime = Anope::CurTime - Anope::StartTime;
		
		source.Reply(_("Current users: \002{0}\002 (\002{1}\002 ops)"), UserListByNick.size(), OperCount);
		source.Reply(_("Maximum users: \002{0}\002 ({1})"), stats->GetMaxUserCount(), Anope::strftime(stats->GetMaxUserTime(), source.GetAccount()));
		source.Reply(_("Services up \002{0}\002."), Anope::Duration(uptime, source.GetAccount()));
	}
Exemple #12
0
    void DoAdd(CommandSource &source, NickServ::Account *nc, Anope::string certfp)
    {
        std::vector<NSCertEntry *> cl = nc->GetRefs<NSCertEntry *>(certentry);
        unsigned max = Config->GetModule(this->owner)->Get<unsigned>("max", "5");

        if (cl.size() >= max)
        {
            source.Reply(_("Sorry, the maximum of \002{0}\002 certificate entries has been reached."), max);
            return;
        }

        if (source.GetAccount() == nc)
        {
            User *u = source.GetUser();

            if (!u || u->fingerprint.empty())
            {
                source.Reply(_("You are not using a client certificate."));
                return;
            }

            certfp = u->fingerprint;
        }

        if (FindCert(cl, certfp))
        {
            source.Reply(_("Fingerprint \002{0}\002 already present on the certificate list of \002{0}\002."), certfp, nc->GetDisplay());
            return;
        }

        if (certmap.find(certfp) != certmap.end())
        {
            source.Reply(_("Fingerprint \002{0}\002 is already in use."), certfp);
            return;
        }

        NSCertEntry *e = certentry.Create();
        e->SetAccount(nc);
        e->SetCert(certfp);

        Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to ADD certificate fingerprint " << certfp << " to " << nc->GetDisplay();
        source.Reply(_("\002{0}\002 added to the certificate list of \002{1}\002."), certfp, nc->GetDisplay());
    }
Exemple #13
0
	void DoList(CommandSource &source)
	{
		std::vector<Ignore *> ignores = Serialize::GetObjects<Ignore *>();

		for (Ignore *id : ignores)
		{
			if (id->GetTime() && !Anope::NoExpire && id->GetTime() <= Anope::CurTime)
			{
				Log(LOG_NORMAL, "expire/ignore", Config->GetClient("OperServ")) << "Expiring ignore entry " << id->GetMask();
				id->Delete();
			}
		}

		ignores = Serialize::GetObjects<Ignore *>();
		if (ignores.empty())
		{
			source.Reply(_("Ignore list is empty."));
			return;
		}

		ListFormatter list(source.GetAccount());
		list.AddColumn(_("Mask")).AddColumn(_("Creator")).AddColumn(_("Reason")).AddColumn(_("Expires"));

		for (Ignore *ignore : ignores)
		{
			ListFormatter::ListEntry entry;
			entry["Mask"] = ignore->GetMask();
			entry["Creator"] = ignore->GetCreator();
			entry["Reason"] = ignore->GetReason();
			entry["Expires"] = Anope::Expires(ignore->GetTime(), source.GetAccount());
			list.AddEntry(entry);
		}

		source.Reply(_("Services ignore list:"));

		std::vector<Anope::string> replies;
		list.Process(replies);

		for (const Anope::string &r : replies)
			source.Reply(r);
	}
Exemple #14
0
	void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
	{
		const Anope::string &nick = params[0];
		const Anope::string &pass = params.size() > 1 ? params[1] : "";

		User *user = User::Find(nick, true);

		if (user && source.GetUser() == user)
		{
			source.Reply(_("You can't %s yourself!"), source.command.lower().c_str());
			return;
		}

		NickServ::Nick *na = NickServ::FindNick(nick);

		if (!na)
		{
			source.Reply(_("\002{0}\002 isn't registered."), nick);
			return;
		}

		if (na->GetAccount()->HasFieldS("NS_SUSPENDED"))
		{
			source.Reply(_("\002{0}\002 is suspended."), na->GetNick());
			return;
		}

		bool ok = false;
		if (source.GetAccount() == na->GetAccount())
			ok = true;
		else if (!na->GetAccount()->HasFieldS("NS_SECURE") && source.GetUser() && na->GetAccount()->IsOnAccess(source.GetUser()))
			ok = true;

		if (certservice && source.GetUser() && certservice->Matches(source.GetUser(), na->GetAccount()))
			ok = true;

		if (ok == false && !pass.empty())
		{
			NickServ::IdentifyRequest *req = NickServ::service->CreateIdentifyRequest(new NSRecoverRequestListener(source, this, na->GetNick(), pass), owner, na->GetNick(), pass);
			Event::OnCheckAuthentication(&Event::CheckAuthentication::OnCheckAuthentication, source.GetUser(), req);
			req->Dispatch();
		}
		else
		{
			NSRecoverRequestListener req(source, this, na->GetNick(), pass);

			if (ok)
				req.OnSuccess(nullptr);
			else
				req.OnFail(nullptr);
		}
	}
Exemple #15
0
void Command::SendSyntax(CommandSource &source)
{
	Anope::string s = Language::Translate(source.GetAccount(), _("Syntax"));
	if (!this->syntax.empty())
	{
		source.Reply("%s: \002%s %s\002", s.c_str(), source.command.c_str(), Language::Translate(source.GetAccount(), this->syntax[0].c_str()));
		Anope::string spaces(s.length(), ' ');
		for (unsigned i = 1, j = this->syntax.size(); i < j; ++i)
			source.Reply("%s  \002%s %s\002", spaces.c_str(), source.command.c_str(), Language::Translate(source.GetAccount(), this->syntax[i].c_str()));
	}
	else
		source.Reply("%s: \002%s\002", s.c_str(), source.command.c_str());
}
Exemple #16
0
	void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
	{
#warning "this is completely disabled"
#if 0
		if (!MemoServ::service)
			return;

		if (Anope::ReadOnly && !source.IsOper())
		{
			source.Reply(_("Sorry, memo sending is temporarily disabled."));
			return;
		}

		const Anope::string &nick = params[0];
		const Anope::string &text = params[1];
		const NickServ::Nick *na = NULL;

		/* prevent user from rsend to themselves */
		if ((na = NickServ::FindNick(nick)) && na->GetAccount() == source.GetAccount())
		{
			source.Reply(_("You can not request a receipt when sending a memo to yourself."));
			return;
		}

		if (Config->GetModule(this->GetOwner())->Get<bool>("operonly") && !source.IsServicesOper())
			source.Reply(_("Access denied. This command is for operators only."));
		else
		{
			MemoServ::MemoServService::MemoResult result = MemoServ::service->Send(source.GetNick(), nick, text);
			if (result == MemoServ::MemoServService::MEMO_INVALID_TARGET)
				source.Reply(_("\002{0}\002 isn't registered."), nick);
			else if (result == MemoServ::MemoServService::MEMO_TOO_FAST)
				source.Reply(_("Please wait \002{0}\002 seconds before using the \002{1}\002 command again."), Config->GetModule("memoserv/main")->Get<time_t>("senddelay"), source.command);
			else if (result == MemoServ::MemoServService::MEMO_TARGET_FULL)
				source.Reply(_("Sorry, \002{0}\002 currently has too many memos and cannot receive more."), nick);
			else
			{
				source.Reply(_("Memo sent to \002{0}\002."), nick);

				bool ischan, isregistered;
				MemoServ::MemoInfo *mi = MemoServ::service->GetMemoInfo(nick, ischan, isregistered, false);
				if (mi == NULL)
					throw CoreException("NULL mi in ms_rsend");
				MemoServ::Memo *m = (mi->memos->size() ? mi->GetMemo(mi->memos->size() - 1) : NULL);
				if (m != NULL)
					m->receipt = true;
			}
		}
#endif
	}
Exemple #17
0
	void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
	{
		const Anope::string &cmd = params[0];
		Anope::string nick, mask;

		if (cmd.equals_ci("LIST"))
			nick = params.size() > 1 ? params[1] : "";
		else
		{
			nick = params.size() == 3 ? params[1] : "";
			mask = params.size() > 1 ? params[params.size() - 1] : "";
		}

		NickServ::Account *nc;
		if (!nick.empty() && source.HasPriv("nickserv/access"))
		{
			NickServ::Nick *na = NickServ::FindNick(nick);
			if (na == NULL)
			{
				source.Reply(_("\002{0}\002 isn't registered."), nick);
				return;
			}

			if (Config->GetModule("nickserv")->Get<bool>("secureadmins", "yes") && source.GetAccount() != na->GetAccount() && na->GetAccount()->IsServicesOper() && !cmd.equals_ci("LIST"))
			{
				source.Reply(_("You may view but not modify the access list of other Services Operators."));
				return;
			}

			nc = na->GetAccount();
		}
		else
			nc = source.nc;

		if (!mask.empty() && (mask.find('@') == Anope::string::npos || mask.find('!') != Anope::string::npos))
		{
			source.Reply(_("Mask must be in the form \037user\037@\037host\037."));
			source.Reply(_("\002%s%s HELP %s\002 for more information."), Config->StrictPrivmsg, source.service->nick, source.command); // XXX
		}
		else if (cmd.equals_ci("LIST"))
			return this->DoList(source, nc, mask);
		else if (nc->HasFieldS("NS_SUSPENDED"))
			source.Reply(_("\002{0}\002 is suspended."), nc->GetDisplay());
		else if (cmd.equals_ci("ADD"))
			return this->DoAdd(source, nc, mask);
		else if (cmd.equals_ci("DEL"))
			return this->DoDel(source, nc, mask);
		else
			this->OnSyntaxError(source, "");
	}
Exemple #18
0
	EventReturn OnPreCommand(CommandSource &source, Command *command, std::vector<Anope::string> &params) override
	{
		if (source.IsOper())
			return EVENT_CONTINUE;

		if (command->GetName() == "nickserv/register")
		{
			if (this->CheckLimitReached(source, params.size() > 1 ? params[1] : ""))
				return EVENT_STOP;
		}
		else if (command->GetName() == "nickserv/set/email")
		{
			if (this->CheckLimitReached(source, params.size() > 0 ? params[0] : ""))
				return EVENT_STOP;
		}
		else if (command->GetName() == "nickserv/ungroup" && source.GetAccount())
		{
			if (this->CheckLimitReached(source, source.GetAccount()->GetEmail()))
				return EVENT_STOP;
		}

		return EVENT_CONTINUE;
	}
Exemple #19
0
	void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
	{
		User *u = source.GetUser();
		NickServ::Nick *na = NickServ::FindNick(u->nick);

		if (!na || !na->HasVhost() || na->GetAccount() != source.GetAccount())
		{
			source.Reply(_("There is no vhost assigned to this nickname."));
			return;
		}

		u->vhost.clear();
		IRCD->SendVhostDel(u);
		Log(LOG_COMMAND, source, this) << "to disable their vhost";
		source.Reply(_("Your vhost was removed and the normal cloaking restored."));
	}
Exemple #20
0
    void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
    {
        const Anope::string &cmd = params[0];
        Anope::string nick, certfp;

        if (cmd.equals_ci("LIST"))
            nick = params.size() > 1 ? params[1] : "";
        else
        {
            nick = params.size() == 3 ? params[1] : "";
            certfp = params.size() > 1 ? params[params.size() - 1] : "";
        }

        NickServ::Account *nc;
        if (!nick.empty() && source.HasPriv("nickserv/access"))
        {
            NickServ::Nick *na = NickServ::FindNick(nick);
            if (na == NULL)
            {
                source.Reply(_("\002{0}\002 isn't registered."), nick);
                return;
            }

            if (Config->GetModule("nickserv")->Get<bool>("secureadmins", "yes") && source.GetAccount() != na->GetAccount() && na->GetAccount()->IsServicesOper() && !cmd.equals_ci("LIST"))
            {
                source.Reply(_("You may view, but not modify, the certificate list of other Services Operators."));
                return;
            }

            nc = na->GetAccount();
        }
        else
            nc = source.nc;

        if (cmd.equals_ci("LIST"))
            return this->DoList(source, nc);
        else if (nc->HasFieldS("NS_SUSPENDED"))
            source.Reply(_("\002{0}\002 is suspended."), nc->GetDisplay());
        else if (Anope::ReadOnly)
            source.Reply(_("Services are in read-only mode."));
        else if (cmd.equals_ci("ADD"))
            return this->DoAdd(source, nc, certfp);
        else if (cmd.equals_ci("DEL"))
            return this->DoDel(source, nc, certfp);
        else
            this->OnSyntaxError(source, "");
    }
Exemple #21
0
	void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
	{
		if (Anope::ReadOnly)
		{
			source.Reply(_("Services are in read-only mode."));
			return;
		}

		const Anope::string &nick = params[0];
		const Anope::string &reason = params.size() > 1 ? params[1] : "";

		NickServ::Nick *na = NickServ::FindNick(nick);
		if (!na)
		{
			source.Reply(_("\002{0}\002 isn't registered."), nick);
			return;
		}

		HostRequest *req = na->GetExt<HostRequest>("hostrequest");
		if (!req)
		{
			source.Reply(_("\002{0}\002 does not have a pending vhost request."), na->GetNick());
			return;
		}

		req->Delete();

		if (Config->GetModule(this->GetOwner())->Get<bool>("memouser") && memoserv)
		{
			Anope::string message;
			if (!reason.empty())
				message = Anope::printf(_("[auto memo] Your requested vHost has been rejected. Reason: %s"), reason.c_str());
			else
				message = _("[auto memo] Your requested vHost has been rejected.");

			memoserv->Send(source.service->nick, nick, Language::Translate(source.GetAccount(), message.c_str()), true);
		}

		source.Reply(_("Vhost for \002{0}\002 has been rejected."), na->GetNick());
		Log(LOG_COMMAND, source, this) << "to reject vhost for " << nick << " (" << (!reason.empty() ? reason : "no reason") << ")";
	}
Exemple #22
0
	bool OnHelp(CommandSource &source, const Anope::string &subcommand) override
	{
		this->SendSyntax(source);
		source.Reply(" ");
		source.Reply(_("Available options:"));
		// XXX this entire thing is dup
		Anope::string this_name = source.command;
		bool hide_privileged_commands = Config->GetBlock("options")->Get<bool>("hideprivilegedcommands"),
		     hide_registered_commands = Config->GetBlock("options")->Get<bool>("hideregisteredcommands");
		for (CommandInfo::map::const_iterator it = source.service->commands.begin(), it_end = source.service->commands.end(); it != it_end; ++it)
		{
			const Anope::string &c_name = it->first;
			const CommandInfo &info = it->second;
			if (c_name.find_ci(this_name + " ") == 0)
			{
				ServiceReference<Command> c(info.name);

				// XXX dup
				if (!c)
					continue;
				else if (hide_registered_commands && !c->AllowUnregistered() && !source.GetAccount())
					continue;
				else if (hide_privileged_commands && !info.permission.empty() && !source.HasCommand(info.permission))
					continue;

				source.command = it->first;
				c->OnServHelp(source);
			}
		}

		CommandInfo *help = source.service->FindCommand("generic/help");
		if (help)
			source.Reply(_("Type \002{0}{1} {2} {3} \037option\037\002 for more information on a particular option."),
			               Config->StrictPrivmsg, source.service->nick, help->cname, this_name);

		return true;
	}
Exemple #23
0
	void DoAdd(CommandSource &source, NickServ::Account *nc, const Anope::string &mask)
	{
		if (mask.empty())
		{
			this->OnSyntaxError(source, "ADD");
			return;
		}

		if (Anope::ReadOnly)
		{
			source.Reply(_("Services are in read-only mode."));
			return;
		}

		std::vector<NickAccess *> access = nc->GetRefs<NickAccess *>(nsaccess);

		if (access.size() >= Config->GetModule(this->owner)->Get<unsigned>("accessmax", "32"))
		{
			source.Reply(_("Sorry, the maximum of \002{0}\002 access entries has been reached."), Config->GetModule(this->owner)->Get<unsigned>("accessmax"));
			return;
		}

		for (NickAccess *a : access)
			if (a->GetMask().equals_ci(mask))
			{
				source.Reply(_("Mask \002{0}\002 already present on the access list of \002{1}\002."), mask, nc->GetDisplay());
				return;
			}

		NickAccess *a = nsaccess.Create();
		a->SetAccount(nc);
		a->SetMask(mask);

		Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to ADD mask " << mask << " to " << nc->GetDisplay();
		source.Reply(_("\002{0}\002 added to the access list of \002{1}\002."), mask, nc->GetDisplay());
	}
Exemple #24
0
	void DoDel(CommandSource &source, NickServ::Account *nc, const Anope::string &chans)
	{
		std::vector<AutoJoin *> channels = nc->GetRefs<AutoJoin *>();
		Anope::string delchans;
		Anope::string notfoundchans;
		commasepstream sep(chans);

		for (Anope::string chan; sep.GetToken(chan);)
		{
			unsigned i = 0;
			for (; i < channels.size(); ++i)
				if (channels[i]->GetChannel().equals_ci(chan))
					break;

			if (i == channels.size())
				notfoundchans += chan + ", ";
			else
			{
				delete channels[i];
				delchans += chan + ", ";
			}
		}

		if (!notfoundchans.empty())
		{
			notfoundchans = notfoundchans.substr(0, notfoundchans.length() - 2);
			source.Reply(_("\002{0}\002 was not found on the auto join list of \002{1}\002."), notfoundchans, nc->GetDisplay());
		}

		if (delchans.empty())
			return;

		delchans = delchans.substr(0, delchans.length() - 2);
		Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to DELETE channel " << delchans << " from " << nc->GetDisplay();
		source.Reply(_("\002{0}\002 was removed from the auto join list of \002{1}\002."), delchans, nc->GetDisplay());
	}
Exemple #25
0
	void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
	{
		if (Anope::ReadOnly)
		{
			source.Reply(_("Services are in read-only mode."));
			return;
		}

		User *u = source.GetUser();
		NickServ::Nick *na = NickServ::FindNick(source.GetNick());
		if (!na || na->GetAccount() != source.GetAccount())
		{
			source.Reply(_("Access denied.")); //XXX with nonickownership this should be allowed.
			return;
		}

		if (source.GetAccount()->HasFieldS("UNCONFIRMED"))
		{
			source.Reply(_("You must confirm your account before you may request a vhost."));
			return;
		}

		Anope::string rawhostmask = params[0];

		Anope::string user, host;
		size_t a = rawhostmask.find('@');

		if (a == Anope::string::npos)
			host = rawhostmask;
		else
		{
			user = rawhostmask.substr(0, a);
			host = rawhostmask.substr(a + 1);
		}

		if (host.empty())
		{
			this->OnSyntaxError(source, "");
			return;
		}

		if (!user.empty())
		{
			if (user.length() > Config->GetBlock("networkinfo")->Get<unsigned>("userlen"))
			{
				source.Reply(_("The username \002{0}\002 is too long, please use a username shorter than %d characters."), Config->GetBlock("networkinfo")->Get<unsigned>("userlen"));
				return;
			}

			if (!IRCD->CanSetVIdent)
			{
				source.Reply(_("Vhosts may not contain a username."));
				return;
			}

			if (!IRCD->IsIdentValid(user))
			{
				source.Reply(_("The requested username is not valid."));
				return;
			}
		}

		if (host.length() > Config->GetBlock("networkinfo")->Get<unsigned>("hostlen"))
		{
			source.Reply(_("The requested vhost is too long, please use a hostname no longer than {0} characters."), Config->GetBlock("networkinfo")->Get<unsigned>("hostlen"));
			return;
		}

		if (!IRCD->IsHostValid(host))
		{
			source.Reply(_("The requested hostname is not valid."));
			return;
		}

		time_t send_delay = Config->GetModule("memoserv")->Get<time_t>("senddelay");
		if (Config->GetModule(this->GetOwner())->Get<bool>("memooper") && send_delay > 0 && u && u->lastmemosend + send_delay > Anope::CurTime)
		{
			source.Reply(_("Please wait %d seconds before requesting a new vHost."), send_delay);
			u->lastmemosend = Anope::CurTime;
			return;
		}

		HostRequest *req = Serialize::New<HostRequest *>();
		req->SetNick(na);
		req->SetIdent(user);
		req->SetHost(host);
		req->SetTime(Anope::CurTime);

		source.Reply(_("Your vhost has been requested."));
		this->SendMemos(source, user, host);
		Log(LOG_COMMAND, source, this) << "to request new vhost " << (!user.empty() ? user + "@" : "") << host;
	}
Exemple #26
0
	void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
	{
		const Anope::string &channel = params[0];

		ChanServ::Channel *ci = ChanServ::Find(channel);
		if (ci == NULL)
		{
			source.Reply(_("Channel \002{0}\002 isn't registered."), channel);
			return;
		}

		if (!source.AccessFor(ci).HasPriv("SET") && !source.HasOverridePriv("chanserv/administration"))
		{
			source.Reply(_("Access denied. You do not have privilege \002{0}\002 on \002{1}\002."), "SET", ci->GetName());
			return;
		}

		if (params.size() == 1)
		{
			std::vector<LogSetting *> ls = ci->GetRefs<LogSetting *>();
			if (ls.empty())
			{
				source.Reply(_("There currently are no logging configurations for \002{0}\002."), ci->GetName());
				return;
			}

			ListFormatter list(source.GetAccount());
			list.AddColumn(_("Number")).AddColumn(_("Service")).AddColumn(_("Command")).AddColumn(_("Method")).AddColumn("");

			for (unsigned i = 0; i < ls.size(); ++i)
			{
				LogSetting *log = ls[i];

				ListFormatter::ListEntry entry;
				entry["Number"] = stringify(i + 1);
				entry["Service"] = log->GetCommandService();
				entry["Command"] = !log->GetCommandName().empty() ? log->GetCommandName() : log->GetServiceName();
				entry["Method"] = log->GetMethod();
				entry[""] = log->GetExtra();
				list.AddEntry(entry);
			}

			source.Reply(_("Log list for \002{0}\002:"), ci->GetName());

			std::vector<Anope::string> replies;
			list.Process(replies);

			for (unsigned i = 0; i < replies.size(); ++i)
				source.Reply(replies[i]);
		}
		else if (params.size() > 2)
		{
			if (Anope::ReadOnly)
			{
				source.Reply(_("Services are in read-only mode."));
				return;
			}

			const Anope::string &command = params[1];
			const Anope::string &method = params[2];
			const Anope::string &extra = params.size() > 3 ? params[3] : "";

			size_t sl = command.find('/');
			if (sl == Anope::string::npos)
			{
				source.Reply(_("\002{0}\002 is not a valid command."), command);
				return;
			}

			Anope::string service = command.substr(0, sl),
				command_name = command.substr(sl + 1);
			ServiceBot *bi = ServiceBot::Find(service, true);

			Anope::string service_name;

			/* Allow either a command name or a service name. */
			if (bi && bi->commands.count(command_name))
			{
				/* Get service name from command */
				service_name = bi->commands[command_name].name;
			}
			else if (ServiceReference<Command>(command.lower()))
			{
				/* This is the service name, don't use any specific command */
				service_name = command;
				bi = NULL;
				command_name.clear();
			}
			else
			{
				source.Reply(_("\002{0}\002 is not a valid command."), command);
				return;
			}

			if (!method.equals_ci("MESSAGE") && !method.equals_ci("NOTICE") && !method.equals_ci("MEMO"))
			{
				source.Reply(_("\002%s\002 is not a valid logging method."));
				return;
			}

			for (unsigned i = 0; i < extra.length(); ++i)
				if (ModeManager::GetStatusChar(extra[i]) == 0)
				{
					source.Reply(_("\002%c\002 is an unknown status mode."), extra[i]);
					return;
				}

			std::vector<LogSetting *> ls = ci->GetRefs<LogSetting *>();
			for (unsigned i = ls.size(); i > 0; --i)
			{
				LogSetting *log = ls[i - 1];

				if (log->GetServiceName() == service_name && log->GetMethod().equals_ci(method) && command_name.equals_ci(log->GetCommandName()))
				{
					if (log->GetExtra() == extra)
					{
						logger.Command(source, ci, _("{source} used {command} on {channel} to remove logging for {0} with method {1}"),
							command, method + (extra.empty() ? "" : (" " + extra)));

						source.Reply(_("Logging for command \002{0}\002 on \002{1}\002 with log method \002{2}{3}{4}\002 has been removed."),
								!log->GetCommandName().empty() ? log->GetCommandName() : log->GetServiceName(),
								!log->GetCommandService().empty() ? log->GetCommandService() : "any service", method, extra.empty() ? "" : " ", extra);
						log->Delete();
					}
					else
					{
						log->SetExtra(extra);

						logger.Command(source, ci, _("{source} used {command} on {channel} to change logging for {0} to method {1}"),
							command, method + (extra.empty() ? "" : (" " + extra)));

						source.Reply(_("Logging changed for command \002{0}\002 on \002{1}\002, now using log method \002{2}{3}{4]\002."),
								!log->GetCommandName().empty() ? log->GetCommandName() : log->GetServiceName(),
								!log->GetCommandService().empty() ? log->GetCommandService() : "any service", method, extra.empty() ? "" : " ", extra);
					}
					return;
				}
			}

			LogSetting *log = Serialize::New<LogSetting *>();
			log->SetChannel(ci);
			log->SetServiceName(service_name);
			if (bi)
				log->SetCommandService(bi->nick);
			log->SetCommandName(command_name);
			log->SetMethod(method);
			log->SetExtra(extra);
			log->SetCreated(Anope::CurTime);
			log->SetCreator(source.GetNick());

			logger.Command(source, ci,
					_("{source} used {command} on {channel} to log {0} to method {1}"), command, method + (extra.empty() ? "" : (" " + extra)));

			source.Reply(_("Logging is now active for command \002{0}\002 on \002{1}\002, using log method \002{2}{3}{4}\002."),
					!command_name.empty() ? command_name : service_name, bi ? bi->nick : "any service", method, extra.empty() ? "" : " ", extra);
		}
		else
		{
			this->OnSyntaxError(source, "");
		}
	}
Exemple #27
0
	static void DoRead(CommandSource &source, MemoServ::MemoInfo *mi, ChanServ::Channel *ci, unsigned index)
	{
		MemoServ::Memo *m = mi->GetMemo(index);
		if (!m)
			return;

		if (ci)
			source.Reply(_("Memo \002{0}\002 from \002{1}\002 (\002{2}\002)."), index + 1, m->GetSender(), Anope::strftime(m->GetTime(), source.GetAccount()));
		else
			source.Reply(_("Memo \002{0}\002 from \002{1}\002 (\002{2}\002)."), index + 1, m->GetSender(), Anope::strftime(m->GetTime(), source.GetAccount()));

		ServiceBot *bi;
		Anope::string cmd;
		if (Command::FindCommandFromService("memoserv/del", bi, cmd))
		{
			if (ci)
				source.Reply(_("To delete, use \002{0}{1} {2} {3} {4}\002"), Config->StrictPrivmsg, bi->nick, cmd, ci->GetName(), index + 1);
			else
				source.Reply(_("To delete, use \002{0}{1} {2} {3}\002"), Config->StrictPrivmsg, bi->nick, cmd, index + 1);
		}

		source.Reply(m->GetText());
		m->SetUnread(false);

		/* Check if a receipt notification was requested */
		if (m->GetReceipt())
			rsend_notify(source, mi, m, ci ? ci->GetName() : source.GetNick());
	}
Exemple #28
0
	void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
	{

		Anope::string param = !params.empty() ? params[0] : "", chan;
		ChanServ::Channel *ci = NULL;
		MemoServ::MemoInfo *mi;

		if (!param.empty() && param[0] == '#')
		{
			chan = param;
			param = params.size() > 1 ? params[1] : "";

			ci = ChanServ::Find(chan);
			if (!ci)
			{
				source.Reply(_("Channel \002{0}\002 isn't registered."), chan);
				return;
			}

			if (!source.AccessFor(ci).HasPriv("MEMO"))
			{
				source.Reply(_("Access denied. You do not have privilege \002{0}\002 on \002{1}\002."), "MEMO", ci->GetName());
				return;
			}

			mi = ci->GetMemos();
		}
		else
		{
			mi = source.nc->GetMemos();
		}

		if (!param.empty() && !isdigit(param[0]) && !param.equals_ci("NEW"))
		{
			this->OnSyntaxError(source);
			return;
		}

		if (!mi)
			return;

		auto memos = mi->GetMemos();

		if (!memos.size())
		{
			if (!chan.empty())
				source.Reply(_("\002{0}\002 has no memos."), chan);
			else
				source.Reply(_("You have no memos."));
			return;
		}

		ListFormatter list(source.GetAccount());

		list.AddColumn(_("Number")).AddColumn(_("Sender")).AddColumn(_("Date/Time"));

		if (!param.empty() && isdigit(param[0]))
		{
			NumberList(param, false,
				[&](unsigned int number)
				{
					if (!number || number > memos.size())
						return;

					MemoServ::Memo *m = mi->GetMemo(number - 1);

					ListFormatter::ListEntry entry;
					entry["Number"] = (m->GetUnread() ? "* " : "  ") + stringify(number);
					entry["Sender"] = m->GetSender();
					entry["Date/Time"] = Anope::strftime(m->GetTime(), source.GetAccount());
					list.AddEntry(entry);
				},
				[]{});
		}
		else
		{
			if (!param.empty())
			{
				unsigned i, end;
				for (i = 0, end = memos.size(); i < end; ++i)
					if (mi->GetMemo(i)->GetUnread())
						break;
				if (i == end)
				{
					if (!chan.empty())
						source.Reply(_("\002{0}\002 has no new memos."), chan);
					else
						source.Reply(_("You have no new memos."));
					return;
				}
			}

			for (unsigned i = 0, end = memos.size(); i < end; ++i)
			{
				if (!param.empty() && !mi->GetMemo(i)->GetUnread())
					continue;

				MemoServ::Memo *m = mi->GetMemo(i);

				ListFormatter::ListEntry entry;
				entry["Number"] = (m->GetUnread() ? "* " : "  ") + stringify(i + 1);
				entry["Sender"] = m->GetSender();
				entry["Date/Time"] = Anope::strftime(m->GetTime(), source.GetAccount());
				list.AddEntry(entry);
			}
		}

		std::vector<Anope::string> replies;
		list.Process(replies);

		source.Reply(_("Memos for \002{0}\002:"), ci ? ci->GetName().c_str() : source.GetNick().c_str());
		for (unsigned i = 0; i < replies.size(); ++i)
			source.Reply(replies[i]);
	}
Exemple #29
0
	void DoAdd(CommandSource &source, const std::vector<Anope::string> &params)
	{
		const Anope::string &time = params.size() > 1 ? params[1] : "";
		const Anope::string &nick = params.size() > 2 ? params[2] : "";
		const Anope::string &reason = params.size() > 3 ? params[3] : "";

		if (time.empty() || nick.empty())
		{
			this->OnSyntaxError(source, "ADD");
			return;
		}

		time_t t = Anope::DoTime(time);

		if (t <= -1)
		{
			source.Reply(_("Invalid expiry time \002{0}\002."), time);
			return;
		}

		Anope::string mask = RealMask(nick);
		if (mask.empty())
		{
			source.Reply(_("Mask must be in the form \037user\037@\037host\037."));
			return;
		}

		if (Anope::ReadOnly)
			source.Reply(_("Services are in read-only mode. Any changes made may not persist."));

		Ignore *ign = Serialize::New<Ignore *>();
		ign->SetMask(mask);
		ign->SetCreator(source.GetNick());
		ign->SetReason(reason);
		ign->SetTime(t ? Anope::CurTime + t : 0);

		if (!t)
		{
			source.Reply(_("\002{0}\002 will now permanently be ignored."), mask);
			Log(LOG_ADMIN, source, this) << "to add a permanent ignore for " << mask;
		}
		else
		{
			source.Reply(_("\002{0}\002 will now be ignored for \002{1}\002."), mask, Anope::Duration(t, source.GetAccount()));
			Log(LOG_ADMIN, source, this) << "to add an ignore on " << mask << " for " << Anope::Duration(t);
		}
	}
Exemple #30
0
	void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
	{
		if (!this->fs)
			return;

		const Anope::string &command = params[0];
		const Anope::string &subcommand = params.size() > 1 ? params[1] : "";

		ForbidType ftype = FT_SIZE;
		if (subcommand.equals_ci("NICK"))
			ftype = FT_NICK;
		else if (subcommand.equals_ci("CHAN"))
			ftype = FT_CHAN;
		else if (subcommand.equals_ci("EMAIL"))
			ftype = FT_EMAIL;
		else if (subcommand.equals_ci("REGISTER"))
			ftype = FT_REGISTER;

		if (command.equals_ci("ADD") && params.size() > 3 && ftype != FT_SIZE)
		{
			const Anope::string &expiry = params[2][0] == '+' ? params[2] : "";
			const Anope::string &entry = !expiry.empty() ? params[3] : params[2];
			Anope::string reason;
			if (expiry.empty())
				reason = params[3] + " ";
			if (params.size() > 4)
				reason += params[4];
			reason.trim();

			if (entry.replace_all_cs("?*", "").empty())
			{
				source.Reply(_("The mask must contain at least one non wildcard character."));
				return;
			}

			time_t expiryt = 0;

			if (!expiry.empty())
			{
				expiryt = Anope::DoTime(expiry);
				if (expiryt == -1)
				{
					source.Reply(_("Invalid expiry time \002{0}\002."), expiry);
					return;
				}
				else if (expiryt)
					expiryt += Anope::CurTime;
			}

			NickServ::Nick *target = NickServ::FindNick(entry);
			if (target != NULL && Config->GetModule("nickserv")->Get<bool>("secureadmins", "yes") && target->GetAccount()->IsServicesOper())
			{
				source.Reply(_("Access denied."));
				return;
			}

			ForbidData *d = this->fs->FindForbid(entry, ftype);
			bool created = false;
			if (d == NULL)
			{
				d = Serialize::New<ForbidData *>();
				created = true;
			}

			d->SetMask(entry);
			d->SetCreator(source.GetNick());
			d->SetReason(reason);
			d->SetCreated(Anope::CurTime);
			d->SetExpires(expiryt);
			d->SetType(ftype);

			if (Anope::ReadOnly)
				source.Reply(_("Services are in read-only mode. Any changes made may not persist."));

			Log(LOG_ADMIN, source, this) << "to add a forbid on " << entry << " of type " << subcommand;
			source.Reply(_("Added a forbid on \002{0}\002 of type \002{1}\002 to expire on \002{2}\002."), entry, subcommand.lower(), expiryt ? Anope::strftime(expiryt, source.GetAccount()) : "never");

			/* apply forbid */
			switch (ftype)
			{
				case FT_NICK:
				{
					int na_matches = 0;

					for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it)
						this->OnUserNickChange(it->second);

					for (auto it = NickServ::service->GetNickList().begin(); it != NickServ::service->GetNickList().end();)
					{
						NickServ::Nick *na = *it;
						++it;

						d = this->fs->FindForbid(na->GetNick(), FT_NICK);
						if (d == NULL)
							continue;

						++na_matches;

						delete na;
					}

					source.Reply(_("\002{0}\002 nickname(s) dropped."), na_matches);
					break;
				}
				case FT_CHAN:
				{
					int chan_matches = 0, ci_matches = 0;

					for (channel_map::const_iterator it = ChannelList.begin(), it_end = ChannelList.end(); it != it_end;)
					{
						Channel *c = it->second;
						++it;

						d = this->fs->FindForbid(c->name, FT_CHAN);
						if (d == NULL)
							continue;

						ServiceBot *OperServ = Config->GetClient("OperServ");
						if (IRCD->CanSQLineChannel && OperServ)
						{
							time_t inhabit = Config->GetModule("chanserv")->Get<time_t>("inhabit", "15s");
#warning "xline allocated on stack"
#if 0
							XLine x(c->name, OperServ->nick, Anope::CurTime + inhabit, d->GetReason());
							IRCD->SendSQLine(NULL, &x);
#endif
						}
						else if (ChanServ::service)
						{
							ChanServ::service->Hold(c);
						}

						++chan_matches;

						for (Channel::ChanUserList::const_iterator cit = c->users.begin(), cit_end = c->users.end(); cit != cit_end;)
						{
							User *u = cit->first;
							++cit;

							if (u->server == Me || u->HasMode("OPER"))
								continue;

							reason = Anope::printf(Language::Translate(u, _("This channel has been forbidden: \002%s\002")), d->GetReason().c_str());

							c->Kick(source.service, u, "%s", reason.c_str());
						}
					}

					for (auto it = ChanServ::service->GetChannels().begin(); it != ChanServ::service->GetChannels().end();)
					{
						ChanServ::Channel *ci = it->second;
						++it;

						d = this->fs->FindForbid(ci->GetName(), FT_CHAN);
						if (d == NULL)
							continue;

						++ci_matches;

						delete ci;
					}

					source.Reply(_("\002{0}\002 channel(s) cleared, and \002{1}\002 channel(s) dropped."), chan_matches, ci_matches);

					break;
				}
				default:
					break;
			}

		}
		else if (command.equals_ci("DEL") && params.size() > 2 && ftype != FT_SIZE)
		{
			const Anope::string &entry = params[2];

			ForbidData *d = this->fs->FindForbid(entry, ftype);
			if (d == nullptr)
			{
				source.Reply(_("Forbid on \002{0}\002 was not found."), entry);
				return;
			}

			if (Anope::ReadOnly)
				source.Reply(_("Services are in read-only mode. Any changes made may not persist."));

			Log(LOG_ADMIN, source, this) << "to remove forbid on " << d->GetMask() << " of type " << subcommand;
			source.Reply(_("\002{0}\002 deleted from the \002{1}\002 forbid list."), d->GetMask(), subcommand);
			d->Delete();
		}
		else if (command.equals_ci("LIST"))
		{
			const std::vector<ForbidData *> &forbids = this->fs->GetForbids();
			if (forbids.empty())
			{
				source.Reply(_("Forbid list is empty."));
				return;
			}

			ListFormatter list(source.GetAccount());
			list.AddColumn(_("Mask")).AddColumn(_("Type")).AddColumn(_("Creator")).AddColumn(_("Expires")).AddColumn(_("Reason"));

			unsigned shown = 0;
			for (unsigned i = 0; i < forbids.size(); ++i)
			{
				ForbidData *d = forbids[i];

				if (ftype != FT_SIZE && ftype != d->GetType())
					continue;

				Anope::string stype;
				if (d->GetType() == FT_NICK)
					stype = "NICK";
				else if (d->GetType() == FT_CHAN)
					stype = "CHAN";
				else if (d->GetType() == FT_EMAIL)
					stype = "EMAIL";
				else if (d->GetType() == FT_REGISTER)
					stype = "REGISTER";
				else
					continue;

				ListFormatter::ListEntry entry;
				entry["Mask"] = d->GetMask();
				entry["Type"] = stype;
				entry["Creator"] = d->GetCreator();
				entry["Expires"] = d->GetExpires() ? Anope::strftime(d->GetExpires(), NULL, true).c_str() : Language::Translate(source.GetAccount(), _("Never"));
				entry["Reason"] = d->GetReason();
				list.AddEntry(entry);
				++shown;
			}

			if (!shown)
			{
				source.Reply(_("There are no forbids of type \002{0}\002."), subcommand.upper());
				return;
			}

			source.Reply(_("Forbid list:"));

			std::vector<Anope::string> replies;
			list.Process(replies);

			for (unsigned i = 0; i < replies.size(); ++i)
				source.Reply(replies[i]);

			if (shown >= forbids.size())
				source.Reply(_("End of forbid list."));
			else
				source.Reply(_("End of forbid list - \002{0}\002/\002{1}\002 entries shown."), shown, forbids.size());
		}
		else
			this->OnSyntaxError(source, command);
	}