aboutsummaryrefslogtreecommitdiff
/*       +------------------------------------+
 *       | Inspire Internet Relay Chat Daemon |
 *       +------------------------------------+
 *
 *  InspIRCd: (C) 2002-2011 InspIRCd Development Team
 * See: http://wiki.inspircd.org/Credits
 *
 * This program is free but copyrighted software; see
 *            the file COPYING for details.
 *
 * ---------------------------------------------------
 */

#include "inspircd.h"
#include "account.h"

/* $ModDesc: Allow vhosts to be set on accounts */

static dynamic_reference<AccountProvider> account("account");
static dynamic_reference<AccountDBProvider> db("accountdb");

/** Handle /ACCTVHOST
 */
class CommandAcctvhost : public Command
{
	char* hostmap;

	void UpdateVhosts(irc::string acctname, std::string new_vhost)
	{
		for (user_hash::const_iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); ++i)
		{
			if(!IS_LOCAL(i->second) || acctname != account->GetAccountName(i->second))
				continue;
			i->second->ChangeDisplayedHost(new_vhost.c_str());
		}
	}

 public:
	TSStringExtItem vhost;
	CommandAcctvhost(Module* Creator, char* hmap) : Command(Creator,"ACCTVHOST", 1, 2), hostmap(hmap), vhost("Vhost", "", Creator)
	{
		flags_needed = 'o'; syntax = "<account name> [vhost]";
	}

	CmdResult Handle (const std::vector<std::string>& parameters, User *user)
	{
		AccountDBEntry* entry = db->GetAccount(parameters[0], false);
		if(!entry)
		{
			user->WriteServ("NOTICE %s :No such account", user->nick.c_str());
			return CMD_FAILURE;
		}
		if(parameters.size() > 1 && !parameters[1].empty())
		{
			if(IS_LOCAL(user))
			{
				size_t len = 0;
				for (std::string::const_iterator x = parameters[1].begin(); x != parameters[1].end(); ++x, ++len)
				{
					if (!hostmap[(const unsigned char)*x])
					{
						user->WriteServ("NOTICE %s :Invalid characters in hostname", user->nick.c_str());
						return CMD_FAILURE;
					}
				}
				if (len > 64)
				{
					user->WriteServ("NOTICE %s :Host too long", user->nick.c_str());
					return CMD_FAILURE;
				}
				vhost.set(entry, parameters[1]);
				db->SendUpdate(entry, "Vhost");
				ServerInstance->SNO->WriteGlobalSno('a', "%s used ACCTVHOST to set the vhost of account %s to %s", user->nick.c_str(), entry->name.c_str(), parameters[1].c_str());
				user->WriteServ("NOTICE %s :Account %s vhost set to %s", user->nick.c_str(), entry->name.c_str(), parameters[1].c_str());
			}
			UpdateVhosts(entry->name, parameters[1]);
		}
		else if(IS_LOCAL(user))
		{
			vhost.set(entry, "");
			db->SendUpdate(entry, "Vhost");
			ServerInstance->SNO->WriteGlobalSno('a', "%s used ACCTVHOST to remove the vhost of account %s", user->nick.c_str(), entry->name.c_str());
			user->WriteServ("NOTICE %s :Account %s vhost removed", user->nick.c_str(), entry->name.c_str());
		}
		return CMD_SUCCESS;
	}

	RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
	{
		return ROUTE_OPT_BCAST;
	}
};

class ModuleAccountVhost : public Module
{
	char hostmap[256];
	CommandAcctvhost cmd_acctvhost;

 public:
	ModuleAccountVhost() : cmd_acctvhost(this, hostmap)
	{
	}

	void init()
	{
		if(!db) throw ModuleException("m_account_vhost requires that m_account be loaded");
		ServerInstance->Modules->AddService(cmd_acctvhost);
		ServerInstance->Modules->AddService(cmd_acctvhost.vhost);
		Implementation eventlist[] = { I_OnEvent, I_OnUserConnect };
		ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
	}

	void ReadConfig(ConfigReadStatus&)
	{
		std::string hmap = ServerInstance->Config->GetTag("hostname")->getString("charmap");

		if (hmap.empty())
			hmap = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-_/0123456789";

		memset(hostmap, 0, sizeof(hostmap));
		for (std::string::iterator n = hmap.begin(); n != hmap.end(); n++)
			hostmap[(unsigned char)*n] = 1;
	}

	void OnEvent(Event& event)
	{
		if(event.id == "account_login"){
			AccountEvent& acct_event = static_cast<AccountEvent&>(event);
			if(!IS_LOCAL(acct_event.user) || acct_event.user->registered != REG_ALL)
				return;
			AccountDBEntry* entry = db->GetAccount(acct_event.account, false);
			if(!entry)
				return;
			std::string* vhost = cmd_acctvhost.vhost.get_value(entry);
			if(vhost && !vhost->empty())
				acct_event.user->ChangeDisplayedHost(vhost->c_str());
		}
	}

	virtual void OnUserConnect(LocalUser* user)
	{
		if(!account->IsRegistered(user))
			return;
		AccountDBEntry* entry = db->GetAccount(account->GetAccountName(user), false);
		if(!entry)
			return;
		std::string* vhost = cmd_acctvhost.vhost.get_value(entry);
		if(vhost && !vhost->empty())
			user->ChangeDisplayedHost(vhost->c_str());
	}

	void Prioritize()
	{
		ServerInstance->Modules->SetPriority(this, I_ModuleInit, PRIORITY_AFTER, ServerInstance->Modules->Find("m_account.so"));
		ServerInstance->Modules->SetPriority(this, I_OnUserConnect, PRIORITY_AFTER, ServerInstance->Modules->Find("m_hostchange.so"));
	}

	Version GetVersion()
	{
		return Version("Allow vhosts to be set on accounts", VF_VENDOR|VF_OPTCOMMON);
	}
};

MODULE_INIT(ModuleAccountVhost)