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