File: clear_users.c

package info (click to toggle)
atheme-services 7.2.12-2.1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 17,256 kB
  • sloc: ansic: 95,899; sh: 8,462; php: 5,032; perl: 3,327; makefile: 1,279; sed: 16; ruby: 15; python: 3
file content (143 lines) | stat: -rw-r--r-- 3,924 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
 * Copyright (c) 2005 William Pitcock, et al.
 * Rights to this code are as documented in doc/LICENSE.
 *
 * This file contains code for the ChanServ CLEAR USERS function.
 *
 */

#include "atheme.h"

DECLARE_MODULE_V1
(
	"chanserv/clear_users", false, _modinit, _moddeinit,
	PACKAGE_STRING,
	VENDOR_STRING
);

static void cs_cmd_clear_users(sourceinfo_t *si, int parc, char *parv[]);

command_t cs_clear_users = { "USERS", N_("Kicks all users from a channel."),
	AC_NONE, 2, cs_cmd_clear_users, { .path = "cservice/clear_users" } };

mowgli_patricia_t **cs_clear_cmds;

void _modinit(module_t *m)
{
	MODULE_TRY_REQUEST_SYMBOL(m, cs_clear_cmds, "chanserv/clear", "cs_clear_cmds");

	command_add(&cs_clear_users, *cs_clear_cmds);
}

void _moddeinit(module_unload_intent_t intent)
{
	command_delete(&cs_clear_users, *cs_clear_cmds);
}

static void cs_cmd_clear_users(sourceinfo_t *si, int parc, char *parv[])
{
	char fullreason[200];
	channel_t *c;
	char *channel = parv[0];
	mychan_t *mc = mychan_find(channel);
	chanuser_t *cu;
	mowgli_node_t *n, *tn;
	int oldlimit;
	unsigned int nmembers;

	if (parc >= 2)
		snprintf(fullreason, sizeof fullreason, "CLEAR USERS used by %s: %s", get_source_name(si), parv[1]);
	else
		snprintf(fullreason, sizeof fullreason, "CLEAR USERS used by %s", get_source_name(si));

	if (!mc)
	{
		command_fail(si, fault_nosuch_target, _("Channel \2%s\2 is not registered."), channel);
		return;
	}

	if (!(c = channel_find(channel)))
	{
		command_fail(si, fault_nosuch_target, _("\2%s\2 is currently empty."), channel);
		return;
	}

	if (!chanacs_source_has_flag(mc, si, CA_RECOVER))
	{
		command_fail(si, fault_noprivs, _("You are not authorized to perform this operation."));
		return;
	}

	if (metadata_find(mc, "private:close:closer"))
	{
		command_fail(si, fault_noprivs, _("\2%s\2 is closed."), channel);
		return;
	}

	command_add_flood(si, MOWGLI_LIST_LENGTH(&c->members) > 3 ? FLOOD_HEAVY : FLOOD_MODERATE);

	/* stop a race condition where users can rejoin */
	oldlimit = c->limit;
	if (oldlimit != 1)
		modestack_mode_limit(chansvs.nick, c, MTYPE_ADD, 1);
	modestack_flush_channel(c);

	MOWGLI_ITER_FOREACH_SAFE(n, tn, c->members.head)
	{
		cu = n->data;

		/* don't kick the user who requested the masskick */
		if (cu->user == si->su || is_internal_client(cu->user))
			continue;

		nmembers = MOWGLI_LIST_LENGTH(&c->members);
		try_kick(chansvs.me->me, c, cu->user, fullreason);
		/* If there are only two users remaining before the kick,
		 * it is possible that the last user is chanserv which will
		 * part if leave_chans is enabled. If it is a permanent
		 * channel this will leave an empty channel, otherwise the
		 * channel will have been destroyed. In either case, it is
		 * not safe to continue.
		 *
		 * Kicking the last user is safe, tn will be NULL and
		 * MOWGLI_ITER_FOREACH_SAFE will stop without touching any part
		 * of the channel structure.
		 */
		if (nmembers == 2 && ((c = channel_find(channel)) == NULL ||
					MOWGLI_LIST_LENGTH(&c->members) == 0))
			break;
	}

	/* the channel may be empty now, so our pointer may be bogus! */
	c = channel_find(channel);
	if (c != NULL)
	{
		if ((mc->flags & MC_GUARD) && !config_options.leave_chans
				&& c != NULL &&
				(si->su == NULL || !chanuser_find(c, si->su)))
		{
			/* Always cycle it if the requester is not on channel
			 * -- jilles */
			part(channel, chansvs.nick);
		}
		/* could be permanent channel, blah */
		c = channel_find(channel);
		if (c != NULL)
		{
			if (oldlimit == 0)
				modestack_mode_limit(chansvs.nick, c, MTYPE_DEL, 0);
			else if (oldlimit != 1)
				modestack_mode_limit(chansvs.nick, c, MTYPE_ADD, oldlimit);
		}
	}

	logcommand(si, CMDLOG_DO, "CLEAR:USERS: \2%s\2", mc->name);

	command_success_nodata(si, _("Cleared users from \2%s\2."), channel);
}

/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
 * vim:ts=8
 * vim:sw=8
 * vim:noexpandtab
 */