/*
 * Copyright (c) 2007 Jilles Tjoelker, et al
 * Rights to this code are as documented in doc/LICENSE.
 *
 * Per-channel userinfo thingie
 */

#include "atheme-compat.h"

static void
cs_cmd_userinfo(sourceinfo_t *si, int parc, char *parv[])
{
	mowgli_node_t *n;
	myuser_t *mu;
	mychan_t *mc;
	chanacs_t *ca;
	metadata_t *md;
	unsigned int restrictflags;

	if (parc < 1)
	{
		command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "USERINFO");
		command_fail(si, fault_needmoreparams, _("Syntax: USERINFO <channel> [target] [info]"));
		return;
	}

	mc = mychan_find(parv[0]);
	if (!mc)
	{
		command_fail(si, fault_nosuch_target, STR_IS_NOT_REGISTERED, parv[0]);
		return;
	}

	if (metadata_find(mc, "private:close:closer") && !has_priv(si, PRIV_CHAN_AUSPEX))
	{
		command_fail(si, fault_noprivs, _("\2%s\2 is closed."), mc->name);
		return;
	}

	restrictflags = chanacs_source_flags(mc, si);

	if (parc == 1)
	{
		if (!(restrictflags & CA_ACLVIEW))
		{
			command_fail(si, fault_noprivs, STR_NOT_AUTHORIZED);
			return;
		}
		command_success_nodata(si, _("Nickname            Info"));
		command_success_nodata(si, "------------------- ---------------");

		MOWGLI_ITER_FOREACH(n, mc->chanacs.head)
		{
			ca = n->data;
			if (ca->entity == NULL)
				continue;
			md = metadata_find(ca, "userinfo");
			if (md == NULL)
				continue;
			command_success_nodata(si, "%-19s %s", ca->entity->name, md->value);
		}

		command_success_nodata(si, "------------------- ---------------");
		command_success_nodata(si, _("End of \2%s\2 USERINFO listing."), mc->name);
		logcommand(si, CMDLOG_GET, "USERINFO:LIST: \2%s\2", mc->name);
	}
	else
	{
		if (!(restrictflags & CA_FLAGS))
		{
			command_fail(si, fault_noprivs, STR_NOT_AUTHORIZED);
			return;
		}
		mu = myuser_find_ext(parv[1]);
		if (mu == NULL)
		{
			command_fail(si, fault_nosuch_target, STR_IS_NOT_REGISTERED, parv[1]);
			return;
		}
		ca = chanacs_find_literal(mc, entity(mu), 0);
		if (ca == NULL || ca->level & CA_AKICK)
		{
			command_fail(si, fault_nosuch_target, _("\2%s\2 has no access to \2%s\2."), entity(mu)->name, mc->name);
			return;
		}
		if (ca->level & ~allow_flags(mc, restrictflags))
		{
			command_fail(si, fault_noprivs, _("You are not authorized to modify the access entry for \2%s\2 on \2%s\2."), entity(mu)->name, mc->name);
			return;
		}
		if (parc == 2)
		{
			metadata_delete(ca, "userinfo");
			command_success_nodata(si, _("Deleted userinfo for \2%s\2 on \2%s\2."),
						entity(mu)->name, mc->name);
			logcommand(si, CMDLOG_SET, "USERINFO:DEL: \2%s\2 on \2%s\2", entity(mu)->name, mc->name);
			return;
		}

		metadata_add(ca, "userinfo", parv[2]);
		command_success_nodata(si, _("Added userinfo for \2%s\2 on \2%s\2."),
					entity(mu)->name, mc->name);
		logcommand(si, CMDLOG_SET, "USERINFO:ADD: \2%s\2 on \2%s\2 (\2%s\2)", entity(mu)->name, mc->name, parv[2]);
	}
}

static void
userinfo_check_join(hook_channel_joinpart_t *hdata)
{
	chanuser_t *cu = hdata->cu;
	myuser_t *mu;
	mychan_t *mc;
	chanacs_t *ca;
	metadata_t *md;

	if (cu == NULL)
		return;
	if (!(cu->user->server->flags & SF_EOB))
		return;
	mu = cu->user->myuser;
	mc = mychan_from(cu->chan);
	if (mu == NULL || mc == NULL)
		return;
	ca = chanacs_find_literal(mc, entity(mu), 0);
	if (ca == NULL || ca->level & CA_AKICK)
		return;
	if (!(md = metadata_find(ca, "userinfo")))
		return;
	msg(chansvs.nick, cu->chan->name, "[%s] %s", cu->user->nick, md->value);
}

static command_t cs_userinfo = {
	"USERINFO",
	N_("Sets a userinfo message."),
	AC_NONE,
	3,
	&cs_cmd_userinfo,
	{ .path = "contrib/userinfo" },
};

static void
mod_init(module_t *const restrict m)
{
	hook_add_event("channel_join");
	hook_add_channel_join(userinfo_check_join);
	service_named_bind_command("chanserv", &cs_userinfo);
}

static void
mod_deinit(const module_unload_intent_t intent)
{
	hook_del_channel_join(userinfo_check_join);
	service_named_unbind_command("chanserv", &cs_userinfo);
}

SIMPLE_DECLARE_MODULE_V1("contrib/cs_userinfo", MODULE_UNLOAD_CAPABILITY_OK)
