1 /*
2  * Copyright (c) 2005-2007 Atheme Development Group
3  * Rights to this code are as documented in doc/LICENSE.
4  *
5  * This file contains code for the Memoserv SENDOPS function
6  *
7  */
8 
9 #include "atheme.h"
10 
11 DECLARE_MODULE_V1
12 (
13 	"memoserv/sendops", false, _modinit, _moddeinit,
14 	PACKAGE_STRING,
15 	VENDOR_STRING
16 );
17 
18 static void ms_cmd_sendops(sourceinfo_t *si, int parc, char *parv[]);
19 
20 command_t ms_sendops = { "SENDOPS", N_("Sends a memo to all ops on a channel."),
21                           AC_AUTHENTICATED, 2, ms_cmd_sendops, { .path = "memoserv/sendops" } };
22 static unsigned int *maxmemos;
23 
_modinit(module_t * m)24 void _modinit(module_t *m)
25 {
26         service_named_bind_command("memoserv", &ms_sendops);
27         MODULE_TRY_REQUEST_SYMBOL(m, maxmemos, "memoserv/main", "maxmemos");
28 }
29 
_moddeinit(module_unload_intent_t intent)30 void _moddeinit(module_unload_intent_t intent)
31 {
32 	service_named_unbind_command("memoserv", &ms_sendops);
33 }
34 
ms_cmd_sendops(sourceinfo_t * si,int parc,char * parv[])35 static void ms_cmd_sendops(sourceinfo_t *si, int parc, char *parv[])
36 {
37 	/* misc structs etc */
38 	myuser_t *tmu;
39 	mowgli_node_t *n, *tn;
40 	mymemo_t *memo;
41 	mychan_t *mc;
42 	int sent = 0, tried = 0;
43 	bool ignored, operoverride = false;
44 	service_t *memoserv;
45 
46 	/* Grab args */
47 	char *target = parv[0];
48 	char *m = parv[1];
49 
50 	/* Arg validation */
51 	if (!target || !m)
52 	{
53 		command_fail(si, fault_needmoreparams,
54 			STR_INSUFFICIENT_PARAMS, "SENDOPS");
55 
56 		command_fail(si, fault_needmoreparams,
57 			"Syntax: SENDOPS <channel> <memo>");
58 
59 		return;
60 	}
61 
62 	if (si->smu->flags & MU_WAITAUTH)
63 	{
64 		command_fail(si, fault_notverified, _("You need to verify your email address before you may send memos."));
65 		return;
66 	}
67 
68 	/* rate limit it -- jilles */
69 	if (CURRTIME - si->smu->memo_ratelimit_time > MEMO_MAX_TIME)
70 		si->smu->memo_ratelimit_num = 0;
71 	if (si->smu->memo_ratelimit_num > MEMO_MAX_NUM && !has_priv(si, PRIV_FLOOD))
72 	{
73 		command_fail(si, fault_toomany, _("You have used this command too many times; please wait a while and try again."));
74 		return;
75 	}
76 
77 	/* Check for memo text length -- includes/common.h */
78 	if (strlen(m) >= MEMOLEN)
79 	{
80 		command_fail(si, fault_badparams,
81 			"Please make sure your memo is less than %d characters", MEMOLEN);
82 
83 		return;
84 	}
85 
86 	/* Check to make sure the memo doesn't contain hostile CTCP responses.
87 	 * realistically, we'll probably want to check the _entire_ message for this... --nenolod
88 	 */
89 	if (*m == '\001')
90 	{
91 		command_fail(si, fault_badparams, _("Your memo contains invalid characters."));
92 		return;
93 	}
94 
95 	mc = mychan_find(target);
96 
97 	if (mc == NULL)
98 	{
99 		command_fail(si, fault_nosuch_target, "Channel \2%s\2 is not registered.", target);
100 		return;
101 	}
102 
103 	if (!(mc->flags & MC_PUBACL) && !chanacs_user_has_flag(mc, si->su, CA_ACLVIEW))
104 	{
105 		if (has_priv(si, PRIV_CHAN_ADMIN))
106 			operoverride = true;
107 		else
108 		{
109 			command_fail(si, fault_noprivs, _("You are not authorized to perform this operation."));
110 			return;
111 		}
112 	}
113 
114 	si->smu->memo_ratelimit_num++;
115 	si->smu->memo_ratelimit_time = CURRTIME;
116 
117 	MOWGLI_ITER_FOREACH(tn, mc->chanacs.head)
118 	{
119 		chanacs_t *ca = (chanacs_t *) tn->data;
120 		tmu = isuser(ca->entity) ? user(ca->entity) : NULL;	/* XXX */
121 
122 		if (!(ca->level & (CA_OP | CA_AUTOOP)) || tmu == NULL || tmu == si->smu)
123 			continue;
124 
125 		tried++;
126 
127 		/* Does the user allow memos? --pfish */
128 		if (tmu->flags & MU_NOMEMO)
129 			continue;
130 
131 		/* Check to make sure target inbox not full */
132 		if (tmu->memos.count >= *maxmemos)
133 			continue;
134 
135 		/* As in SEND to a single user, make ignore fail silently */
136 		sent++;
137 
138 		/* Make sure we're not on ignore */
139 		ignored = false;
140 		MOWGLI_ITER_FOREACH(n, tmu->memo_ignores.head)
141 		{
142 			mynick_t *mn;
143 			myuser_t *mu;
144 
145 			if (nicksvs.no_nick_ownership)
146 				mu = myuser_find((const char *)n->data);
147 			else
148 			{
149 				mn = mynick_find((const char *)n->data);
150 				mu = mn != NULL ? mn->owner : NULL;
151 			}
152 			if (mu == si->smu)
153 				ignored = true;
154 		}
155 		if (ignored)
156 			continue;
157 
158 		/* Malloc and populate struct */
159 		memo = smalloc(sizeof(mymemo_t));
160 		memo->sent = CURRTIME;
161 		memo->status = MEMO_CHANNEL;
162 		mowgli_strlcpy(memo->sender,entity(si->smu)->name,NICKLEN);
163 		snprintf(memo->text, MEMOLEN, "%s %s", mc->name, m);
164 
165 		/* Create a linked list node and add to memos */
166 		n = mowgli_node_create();
167 		mowgli_node_add(memo, n, &tmu->memos);
168 		tmu->memoct_new++;
169 
170 		/* Should we email this? */
171 		if (tmu->flags & MU_EMAILMEMOS)
172 		{
173 			sendemail(si->su, tmu, EMAIL_MEMO, tmu->email, memo->text);
174 		}
175 
176 		memoserv = service_find("memoserv");
177 		if (memoserv == NULL)
178 			memoserv = si->service;
179 
180 		/* Is the user online? If so, tell them about the new memo. */
181 		if (si->su == NULL || !irccasecmp(si->su->nick, entity(si->smu)->name))
182 			myuser_notice(memoserv->nick, tmu, "You have a new memo from %s (%zu).", entity(si->smu)->name, MOWGLI_LIST_LENGTH(&tmu->memos));
183 		else
184 			myuser_notice(memoserv->nick, tmu, "You have a new memo from %s (nick: %s) (%zu).", entity(si->smu)->name, si->su->nick, MOWGLI_LIST_LENGTH(&tmu->memos));
185 		myuser_notice(memoserv->nick, tmu, _("To read it, type /%s%s READ %zu"),
186 					ircd->uses_rcommand ? "" : "msg ", memoserv->disp, MOWGLI_LIST_LENGTH(&tmu->memos));
187 	}
188 
189 	/* Tell user memo sent, return */
190 	if (sent > 4)
191 		command_add_flood(si, FLOOD_HEAVY);
192 	else if (sent > 1)
193 		command_add_flood(si, FLOOD_MODERATE);
194 	if (operoverride)
195 		logcommand(si, CMDLOG_ADMIN, "SENDOPS: to \2%s\2 (%d/%d sent) (oper override)", mc->name, sent, tried);
196 	else
197 		logcommand(si, CMDLOG_SET, "SENDOPS: to \2%s\2 (%d/%d sent)", mc->name, sent, tried);
198 	command_success_nodata(si, _("The memo has been successfully sent to %d ops on \2%s\2."), sent, mc->name);
199 	return;
200 }
201 
202 /* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
203  * vim:ts=8
204  * vim:sw=8
205  * vim:noexpandtab
206  */
207