anope

- supernets anope source code & configuration
git clone git://git.acid.vegas/anope.git
Log | Files | Refs | Archive | README

hs_request.cpp (11285B)

      1 /* hs_request.c - Add request and activate functionality to HostServ
      2  *
      3  * (C) 2003-2022 Anope Team
      4  * Contact us at team@anope.org
      5  *
      6  * Based on the original module by Rob <rob@anope.org>
      7  * Included in the Anope module pack since Anope 1.7.11
      8  * Anope Coder: GeniusDex <geniusdex@anope.org>
      9  *
     10  * Please read COPYING and README for further details.
     11  *
     12  * Send bug reports to the Anope Coder instead of the module
     13  * author, because any changes since the inclusion into anope
     14  * are not supported by the original author.
     15  */
     16 
     17 #include "module.h"
     18 
     19 static ServiceReference<MemoServService> memoserv("MemoServService", "MemoServ");
     20 
     21 static void req_send_memos(Module *me, CommandSource &source, const Anope::string &vIdent, const Anope::string &vHost);
     22 
     23 struct HostRequest : Serializable
     24 {
     25 	Anope::string nick;
     26 	Anope::string ident;
     27 	Anope::string host;
     28 	time_t time;
     29 
     30 	HostRequest(Extensible *) : Serializable("HostRequest") { }
     31 
     32 	void Serialize(Serialize::Data &data) const anope_override
     33 	{
     34 		data["nick"] << this->nick;
     35 		data["ident"] << this->ident;
     36 		data["host"] << this->host;
     37 		data.SetType("time", Serialize::Data::DT_INT); data["time"] << this->time;
     38 	}
     39 
     40 	static Serializable* Unserialize(Serializable *obj, Serialize::Data &data)
     41 	{
     42 		Anope::string snick;
     43 		data["nick"] >> snick;
     44 
     45 		NickAlias *na = NickAlias::Find(snick);
     46 		if (na == NULL)
     47 			return NULL;
     48 
     49 		HostRequest *req;
     50 		if (obj)
     51 			req = anope_dynamic_static_cast<HostRequest *>(obj);
     52 		else
     53 			req = na->Extend<HostRequest>("hostrequest");
     54 		if (req)
     55 		{
     56 			req->nick = na->nick;
     57 			data["ident"] >> req->ident;
     58 			data["host"] >> req->host;
     59 			data["time"] >> req->time;
     60 		}
     61 
     62 		return req;
     63 	}
     64 };
     65 
     66 class CommandHSRequest : public Command
     67 {
     68 	bool isvalidchar(char c)
     69 	{
     70 		if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '.' || c == '-')
     71 			return true;
     72 		return false;
     73 	}
     74 
     75  public:
     76 	CommandHSRequest(Module *creator) : Command(creator, "hostserv/request", 1, 1)
     77 	{
     78 		this->SetDesc(_("Request a vHost for your nick"));
     79 		this->SetSyntax(_("vhost"));
     80 	}
     81 
     82 	void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
     83 	{
     84 		if (Anope::ReadOnly)
     85 		{
     86 			source.Reply(READ_ONLY_MODE);
     87 			return;
     88 		}
     89 
     90 		User *u = source.GetUser();
     91 		NickAlias *na = NickAlias::Find(source.GetNick());
     92 		if (!na || na->nc != source.GetAccount())
     93 		{
     94 			source.Reply(ACCESS_DENIED);
     95 			return;
     96 		}
     97 
     98 		if (source.GetAccount()->HasExt("UNCONFIRMED"))
     99 		{
    100 			source.Reply(_("You must confirm your account before you may request a vhost."));
    101 			return;
    102 		}
    103 
    104 		Anope::string rawhostmask = params[0];
    105 
    106 		Anope::string user, host;
    107 		size_t a = rawhostmask.find('@');
    108 
    109 		if (a == Anope::string::npos)
    110 			host = rawhostmask;
    111 		else
    112 		{
    113 			user = rawhostmask.substr(0, a);
    114 			host = rawhostmask.substr(a + 1);
    115 		}
    116 
    117 		if (host.empty())
    118 		{
    119 			this->OnSyntaxError(source, "");
    120 			return;
    121 		}
    122 
    123 		if (!user.empty())
    124 		{
    125 			if (user.length() > Config->GetBlock("networkinfo")->Get<unsigned>("userlen"))
    126 			{
    127 				source.Reply(HOST_SET_IDENTTOOLONG, Config->GetBlock("networkinfo")->Get<unsigned>("userlen"));
    128 				return;
    129 			}
    130 			else if (!IRCD->CanSetVIdent)
    131 			{
    132 				source.Reply(HOST_NO_VIDENT);
    133 				return;
    134 			}
    135 			for (Anope::string::iterator s = user.begin(), s_end = user.end(); s != s_end; ++s)
    136 				if (!isvalidchar(*s))
    137 				{
    138 					source.Reply(HOST_SET_IDENT_ERROR);
    139 					return;
    140 				}
    141 		}
    142 
    143 		if (host.length() > Config->GetBlock("networkinfo")->Get<unsigned>("hostlen"))
    144 		{
    145 			source.Reply(HOST_SET_TOOLONG, Config->GetBlock("networkinfo")->Get<unsigned>("hostlen"));
    146 			return;
    147 		}
    148 
    149 		if (!IRCD->IsHostValid(host))
    150 		{
    151 			source.Reply(HOST_SET_ERROR);
    152 			return;
    153 		}
    154 
    155 		time_t send_delay = Config->GetModule("memoserv")->Get<time_t>("senddelay");
    156 		if (Config->GetModule(this->owner)->Get<bool>("memooper") && send_delay > 0 && u && u->lastmemosend + send_delay > Anope::CurTime)
    157 		{
    158 			source.Reply(_("Please wait %d seconds before requesting a new vHost."), send_delay);
    159 			u->lastmemosend = Anope::CurTime;
    160 			return;
    161 		}
    162 
    163 		HostRequest req(na);
    164 		req.nick = source.GetNick();
    165 		req.ident = user;
    166 		req.host = host;
    167 		req.time = Anope::CurTime;
    168 		na->Extend<HostRequest>("hostrequest", req);
    169 
    170 		source.Reply(_("Your vHost has been requested."));
    171 		req_send_memos(owner, source, user, host);
    172 		Log(LOG_COMMAND, source, this) << "to request new vhost " << (!user.empty() ? user + "@" : "") << host;
    173 	}
    174 
    175 	bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
    176 	{
    177 		this->SendSyntax(source);
    178 		source.Reply(" ");
    179 		source.Reply(_("Request the given vHost to be activated for your nick by the\n"
    180 			"network administrators. Please be patient while your request\n"
    181 			"is being considered."));
    182 		return true;
    183 	}
    184 };
    185 
    186 class CommandHSActivate : public Command
    187 {
    188  public:
    189 	CommandHSActivate(Module *creator) : Command(creator, "hostserv/activate", 1, 1)
    190 	{
    191 		this->SetDesc(_("Approve the requested vHost of a user"));
    192 		this->SetSyntax(_("\037nick\037"));
    193 	}
    194 
    195 	void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
    196 	{
    197 		if (Anope::ReadOnly)
    198 		{
    199 			source.Reply(READ_ONLY_MODE);
    200 			return;
    201 		}
    202 
    203 		const Anope::string &nick = params[0];
    204 
    205 		NickAlias *na = NickAlias::Find(nick);
    206 		HostRequest *req = na ? na->GetExt<HostRequest>("hostrequest") : NULL;
    207 		if (req)
    208 		{
    209 			na->SetVhost(req->ident, req->host, source.GetNick(), req->time);
    210 			FOREACH_MOD(OnSetVhost, (na));
    211 
    212 			if (Config->GetModule(this->owner)->Get<bool>("memouser") && memoserv)
    213 				memoserv->Send(source.service->nick, na->nick, _("[auto memo] Your requested vHost has been approved."), true);
    214 
    215 			source.Reply(_("vHost for %s has been activated."), na->nick.c_str());
    216 			Log(LOG_COMMAND, source, this) << "for " << na->nick << " for vhost " << (!req->ident.empty() ? req->ident + "@" : "") << req->host;
    217 			na->Shrink<HostRequest>("hostrequest");
    218 		}
    219 		else
    220 			source.Reply(_("No request for nick %s found."), nick.c_str());
    221 	}
    222 
    223 	bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
    224 	{
    225 		this->SendSyntax(source);
    226 		source.Reply(" ");
    227 		source.Reply(_("Activate the requested vHost for the given nick."));
    228 		if (Config->GetModule(this->owner)->Get<bool>("memouser"))
    229 			source.Reply(_("A memo informing the user will also be sent."));
    230 
    231 		return true;
    232 	}
    233 };
    234 
    235 class CommandHSReject : public Command
    236 {
    237  public:
    238 	CommandHSReject(Module *creator) : Command(creator, "hostserv/reject", 1, 2)
    239 	{
    240 		this->SetDesc(_("Reject the requested vHost of a user"));
    241 		this->SetSyntax(_("\037nick\037 [\037reason\037]"));
    242 	}
    243 
    244 	void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
    245 	{
    246 		if (Anope::ReadOnly)
    247 		{
    248 			source.Reply(READ_ONLY_MODE);
    249 			return;
    250 		}
    251 
    252 		const Anope::string &nick = params[0];
    253 		const Anope::string &reason = params.size() > 1 ? params[1] : "";
    254 
    255 		NickAlias *na = NickAlias::Find(nick);
    256 		HostRequest *req = na ? na->GetExt<HostRequest>("hostrequest") : NULL;
    257 		if (req)
    258 		{
    259 			na->Shrink<HostRequest>("hostrequest");
    260 
    261 			if (Config->GetModule(this->owner)->Get<bool>("memouser") && memoserv)
    262 			{
    263 				Anope::string message;
    264 				if (!reason.empty())
    265 					message = Anope::printf(_("[auto memo] Your requested vHost has been rejected. Reason: %s"), reason.c_str());
    266 				else
    267 					message = _("[auto memo] Your requested vHost has been rejected.");
    268 
    269 				memoserv->Send(source.service->nick, nick, Language::Translate(source.GetAccount(), message.c_str()), true);
    270 			}
    271 
    272 			source.Reply(_("vHost for %s has been rejected."), nick.c_str());
    273 			Log(LOG_COMMAND, source, this) << "to reject vhost for " << nick << " (" << (!reason.empty() ? reason : "no reason") << ")";
    274 		}
    275 		else
    276 			source.Reply(_("No request for nick %s found."), nick.c_str());
    277 	}
    278 
    279 	bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
    280 	{
    281 		this->SendSyntax(source);
    282 		source.Reply(" ");
    283 		source.Reply(_("Reject the requested vHost for the given nick."));
    284 		if (Config->GetModule(this->owner)->Get<bool>("memouser"))
    285 			source.Reply(_("A memo informing the user will also be sent, which includes the reason for the rejection if supplied."));
    286 
    287 		return true;
    288 	}
    289 };
    290 
    291 class CommandHSWaiting : public Command
    292 {
    293  public:
    294 	CommandHSWaiting(Module *creator) : Command(creator, "hostserv/waiting", 0, 0)
    295 	{
    296 		this->SetDesc(_("Retrieves the vhost requests"));
    297 	}
    298 
    299 	void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
    300 	{
    301 		unsigned counter = 0;
    302 		unsigned display_counter = 0, listmax = Config->GetModule(this->owner)->Get<unsigned>("listmax");
    303 		ListFormatter list(source.GetAccount());
    304 
    305 		list.AddColumn(_("Number")).AddColumn(_("Nick")).AddColumn(_("Vhost")).AddColumn(_("Created"));
    306 
    307 		for (nickalias_map::const_iterator it = NickAliasList->begin(), it_end = NickAliasList->end(); it != it_end; ++it)
    308 		{
    309 			const NickAlias *na = it->second;
    310 			HostRequest *hr = na->GetExt<HostRequest>("hostrequest");
    311 			if (!hr)
    312 				continue;
    313 
    314 			if (!listmax || display_counter < listmax)
    315 			{
    316 				++display_counter;
    317 
    318 				ListFormatter::ListEntry entry;
    319 				entry["Number"] = stringify(display_counter);
    320 				entry["Nick"] = it->first;
    321 				if (!hr->ident.empty())
    322 					entry["Vhost"] = hr->ident + "@" + hr->host;
    323 				else
    324 					entry["Vhost"] = hr->host;
    325 				entry["Created"] = Anope::strftime(hr->time, NULL, true);
    326 				list.AddEntry(entry);
    327 			}
    328 			++counter;
    329 		}
    330 
    331 		std::vector<Anope::string> replies;
    332 		list.Process(replies);
    333 
    334 		for (unsigned i = 0; i < replies.size(); ++i)
    335 			source.Reply(replies[i]);
    336 
    337 		source.Reply(_("Displayed \002%d\002 records (\002%d\002 total)."), display_counter, counter);
    338 	}
    339 
    340 	bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
    341 	{
    342 		this->SendSyntax(source);
    343 		source.Reply(" ");
    344 		source.Reply(_("This command retrieves the vhost requests."));
    345 
    346 		return true;
    347 	}
    348 };
    349 
    350 class HSRequest : public Module
    351 {
    352 	CommandHSRequest commandhsrequest;
    353 	CommandHSActivate commandhsactive;
    354 	CommandHSReject commandhsreject;
    355 	CommandHSWaiting commandhswaiting;
    356 	ExtensibleItem<HostRequest> hostrequest;
    357 	Serialize::Type request_type;
    358 
    359  public:
    360 	HSRequest(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
    361 		commandhsrequest(this), commandhsactive(this),
    362 		commandhsreject(this), commandhswaiting(this), hostrequest(this, "hostrequest"), request_type("HostRequest", HostRequest::Unserialize)
    363 	{
    364 		if (!IRCD || !IRCD->CanSetVHost)
    365 			throw ModuleException("Your IRCd does not support vhosts");
    366 	}
    367 };
    368 
    369 static void req_send_memos(Module *me, CommandSource &source, const Anope::string &vIdent, const Anope::string &vHost)
    370 {
    371 	Anope::string host;
    372 	std::list<std::pair<Anope::string, Anope::string> >::iterator it, it_end;
    373 
    374 	if (!vIdent.empty())
    375 		host = vIdent + "@" + vHost;
    376 	else
    377 		host = vHost;
    378 
    379 	if (Config->GetModule(me)->Get<bool>("memooper") && memoserv)
    380 		for (unsigned i = 0; i < Oper::opers.size(); ++i)
    381 		{
    382 			Oper *o = Oper::opers[i];
    383 
    384 			const NickAlias *na = NickAlias::Find(o->name);
    385 			if (!na)
    386 				continue;
    387 
    388 			Anope::string message = Anope::printf(_("[auto memo] vHost \002%s\002 has been requested by %s."), host.c_str(), source.GetNick().c_str());
    389 
    390 			memoserv->Send(source.service->nick, na->nick, message, true);
    391 		}
    392 }
    393 
    394 MODULE_INIT(HSRequest)