1 /*
2  * Copyright (c) 2005 Atheme Development Group
3  * Rights to this code are as documented in doc/LICENSE.
4  *
5  * This file contains code for the Memoserv FSEND function
6  *
7  */
8 
9 #include "atheme-compat.h"
10 
11 /* MEMOLEN + 8, so the "[FORCE] " string will fit */
12 #define FMEMOLEN 308
13 
14 DECLARE_MODULE_V1
15 (
16 	"contrib/ms_fsend", false, _modinit, _moddeinit,
17 	PACKAGE_STRING,
18 	VENDOR_STRING
19 );
20 
21 static void ms_cmd_fsend(sourceinfo_t *si, int parc, char *parv[]);
22 
23 /* MARK is prolly the most appropriate priv (that I can think of), if you can
24  * think of a better one, feel free to change it. --jdhore
25  */
26 command_t ms_fsend = { "FSEND", N_("Forcibly sends a memo to a user."),
27                         PRIV_MARK, 2, ms_cmd_fsend, { .path = "contrib/fsend" } };
28 
_modinit(module_t * m)29 void _modinit(module_t *m)
30 {
31         service_named_bind_command("memoserv", &ms_fsend);
32 }
33 
_moddeinit(module_unload_intent_t intent)34 void _moddeinit(module_unload_intent_t intent)
35 {
36 	service_named_unbind_command("memoserv", &ms_fsend);
37 }
38 
ms_cmd_fsend(sourceinfo_t * si,int parc,char * parv[])39 static void ms_cmd_fsend(sourceinfo_t *si, int parc, char *parv[])
40 {
41 	/* misc structs etc */
42 	user_t *tu;
43 	myuser_t *tmu;
44 	mowgli_node_t *n;
45 	mymemo_t *memo;
46 	service_t *memoserv;
47 
48 	/* Grab args */
49 	char *target = parv[0];
50 	char *m = parv[1];
51 
52 	/* Arg validation */
53 	if (!target || !m)
54 	{
55 		command_fail(si, fault_needmoreparams,
56 			STR_INSUFFICIENT_PARAMS, "FSEND");
57 
58 		command_fail(si, fault_needmoreparams,
59 			"Syntax: FSEND <user> <memo>");
60 
61 		return;
62 	}
63 
64 	if (!si->smu)
65         {
66                 command_fail(si, fault_noprivs, _("You are not logged in."));
67                 return;
68         }
69 
70 	/* rate limit it -- jilles */
71 	if (CURRTIME - si->smu->memo_ratelimit_time > MEMO_MAX_TIME)
72 		si->smu->memo_ratelimit_num = 0;
73 	if (si->smu->memo_ratelimit_num > MEMO_MAX_NUM && !has_priv(si, PRIV_FLOOD))
74 	{
75 		command_fail(si, fault_toomany, _("You have used this command too many times; please wait a while and try again."));
76 		return;
77 	}
78 
79 	/* Check for memo text length -- includes/common.h */
80 	if (strlen(m) >= MEMOLEN)
81 	{
82 		command_fail(si, fault_badparams,
83 			"Please make sure your memo is less than %d characters", MEMOLEN);
84 
85 		return;
86 	}
87 
88 	/* Check to make sure the memo doesn't contain hostile CTCP responses.
89 	 * realistically, we'll probably want to check the _entire_ message for this... --nenolod
90 	 */
91 	if (*m == '\001')
92 	{
93 		command_fail(si, fault_badparams, _("Your memo contains invalid characters."));
94 		return;
95 	}
96 
97 	memoserv = service_find("memoserv");
98 	if (memoserv == NULL)
99 		memoserv = si->service;
100 
101 	if (*target != '#' && *target != '!')
102 	{
103 		/* See if target is valid */
104 		if (!(tmu = myuser_find_ext(target)))
105 		{
106 			command_fail(si, fault_nosuch_target,
107 				"\2%s\2 is not registered.", target);
108 
109 			return;
110 		}
111 
112 		si->smu->memo_ratelimit_num++;
113 		si->smu->memo_ratelimit_time = CURRTIME;
114 
115 		/* Check to make sure target inbox not full */
116 		if (tmu->memos.count >= me.mdlimit)
117 		{
118 			command_fail(si, fault_toomany, _("%s's inbox is full"), target);
119 			logcommand(si, CMDLOG_SET, "failed SEND to \2%s\2 (target inbox full)", entity(tmu)->name);
120 			return;
121 		}
122 
123 		logcommand(si, CMDLOG_ADMIN, "FSEND: to \2%s\2", entity(tmu)->name);
124 
125 		/* Malloc and populate struct */
126 		memo = smalloc(sizeof(mymemo_t));
127 		memo->sent = CURRTIME;
128 		memo->status = 0;
129 		mowgli_strlcpy(memo->sender,entity(si->smu)->name,NICKLEN);
130 		mowgli_strlcpy(memo->text, "[FORCE] ", FMEMOLEN);
131 		mowgli_strlcat(memo->text, m, FMEMOLEN);
132 
133 		/* Create a linked list node and add to memos */
134 		n = mowgli_node_create();
135 		mowgli_node_add(memo, n, &tmu->memos);
136 		tmu->memoct_new++;
137 
138 		/* Should we email this? */
139 	        if (tmu->flags & MU_EMAILMEMOS)
140 		{
141 			compat_sendemail(si->su, tmu, EMAIL_MEMO, tmu->email, memo->text);
142 	        }
143 
144 		/* Note: do not disclose other nicks they're logged in with
145 		 * -- jilles
146 		 *
147 		 * Actually, I don't see the point in this at all. If they want this information,
148 		 * they should use WHOIS. --nenolod
149 		 */
150 		tu = user_find_named(target);
151 		if (tu != NULL && tu->myuser == tmu)
152 			command_success_nodata(si, _("%s is currently online, and you may talk directly, by sending a private message."), target);
153 
154 		/* Is the user online? If so, tell them about the new memo. */
155 		if (si->su == NULL || !irccasecmp(si->su->nick, entity(si->smu)->name))
156 			myuser_notice(memoserv->nick, tmu, "You have a new memo from %s (%zu).", entity(si->smu)->name, MOWGLI_LIST_LENGTH(&tmu->memos));
157 		else
158 			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));
159 		myuser_notice(memoserv->nick, tmu, _("To read it, type /%s%s READ %zu"),
160 					ircd->uses_rcommand ? "" : "msg ", memoserv->disp, MOWGLI_LIST_LENGTH(&tmu->memos));
161 
162 		/* Tell user memo sent */
163 		command_success_nodata(si, _("The memo has been successfully sent to \2%s\2."), target);
164 	}
165 	else if (*target == '#')
166 	{
167 		command_fail(si, fault_nosuch_target, _("Channel memos may not be forced."));
168 	}
169 	else
170 	{
171 		command_fail(si, fault_nosuch_target, _("Group memos may not be forced."));
172 	}
173 
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