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 FORWARD function
6  *
7  */
8 
9 #include "atheme.h"
10 
11 DECLARE_MODULE_V1
12 (
13 	"memoserv/forward", false, _modinit, _moddeinit,
14 	PACKAGE_STRING,
15 	VENDOR_STRING
16 );
17 
18 static void ms_cmd_forward(sourceinfo_t *si, int parc, char *parv[]);
19 
20 command_t ms_forward = { "FORWARD", N_(N_("Forwards a memo.")),
21                         AC_AUTHENTICATED, 2, ms_cmd_forward, { .path = "memoserv/forward" } };
22 
_modinit(module_t * m)23 void _modinit(module_t *m)
24 {
25         service_named_bind_command("memoserv", &ms_forward);
26 }
27 
_moddeinit(module_unload_intent_t intent)28 void _moddeinit(module_unload_intent_t intent)
29 {
30 	service_named_unbind_command("memoserv", &ms_forward);
31 }
32 
ms_cmd_forward(sourceinfo_t * si,int parc,char * parv[])33 static void ms_cmd_forward(sourceinfo_t *si, int parc, char *parv[])
34 {
35 	/* Misc structs etc */
36 	user_t *tu;
37 	myuser_t *tmu;
38 	mymemo_t *memo, *newmemo;
39 	mowgli_node_t *n, *temp;
40 	unsigned int i = 1, memonum = 0;
41 
42 	/* Grab args */
43 	char *target = parv[0];
44 	char *arg = parv[1];
45 
46 	/* Arg validator */
47 	if (!target || !arg)
48 	{
49 		command_fail(si, fault_needmoreparams,
50 			STR_INSUFFICIENT_PARAMS, "FORWARD");
51 
52 		command_fail(si, fault_needmoreparams,
53 			"Syntax: FORWARD <account> <memo number>");
54 
55 		return;
56 	}
57 	else
58 		memonum = atoi(arg);
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 	/* Check to see if any memos */
67 	if (!si->smu->memos.count)
68 	{
69 		command_fail(si, fault_nosuch_key, _("You have no memos to forward."));
70 		return;
71 	}
72 
73 	/* Check to see if target user exists */
74 	if (!(tmu = myuser_find_ext(target)))
75 	{
76 		command_fail(si, fault_nosuch_target, _("\2%s\2 is not registered."), target);
77 		return;
78 	}
79 
80 	/* Make sure target isn't sender */
81 	if (si->smu == tmu)
82 	{
83 		command_fail(si, fault_noprivs, _("You cannot send yourself a memo."));
84 		return;
85 	}
86 
87 	/* Make sure arg is an int */
88 	if (!memonum)
89 	{
90 		command_fail(si, fault_badparams, _("Invalid message index."));
91 		return;
92 	}
93 
94 	/* check if targetuser has nomemo set */
95 	if (tmu->flags & MU_NOMEMO)
96 	{
97 		command_fail(si, fault_noprivs,
98 			"\2%s\2 does not wish to receive memos.", target);
99 
100 		return;
101 	}
102 
103 	/* Check to see if memo n exists */
104 	if (memonum > si->smu->memos.count)
105 	{
106 		command_fail(si, fault_nosuch_key, _("Invalid memo number."));
107 		return;
108 	}
109 
110 	/* Check to make sure target inbox not full */
111 	if (tmu->memos.count >= me.mdlimit)
112 	{
113 		command_fail(si, fault_toomany, _("Target inbox is full."));
114 		logcommand(si, CMDLOG_SET, "failed FORWARD to \2%s\2 (target inbox full)", entity(tmu)->name);
115 		return;
116 	}
117 
118 	/* rate limit it -- jilles */
119 	if (CURRTIME - si->smu->memo_ratelimit_time > MEMO_MAX_TIME)
120 		si->smu->memo_ratelimit_num = 0;
121 	if (si->smu->memo_ratelimit_num > MEMO_MAX_NUM && !has_priv(si, PRIV_FLOOD))
122 	{
123 		command_fail(si, fault_toomany, _("Too many memos; please wait a while and try again"));
124 		return;
125 	}
126 	si->smu->memo_ratelimit_num++;
127 	si->smu->memo_ratelimit_time = CURRTIME;
128 
129 	/* Make sure we're not on ignore */
130 	MOWGLI_ITER_FOREACH(n, tmu->memo_ignores.head)
131 	{
132 		mynick_t *mn;
133 		myuser_t *mu;
134 
135 		if (nicksvs.no_nick_ownership)
136 			mu = myuser_find((const char *)n->data);
137 		else
138 		{
139 			mn = mynick_find((const char *)n->data);
140 			mu = mn != NULL ? mn->owner : NULL;
141 		}
142 		if (mu == si->smu)
143 		{
144 			/* Lie... change this if you want it to fail silent */
145 			logcommand(si, CMDLOG_SET, "failed FORWARD to \2%s\2 (on ignore list)", entity(tmu)->name);
146 			command_success_nodata(si, _("The memo has been successfully forwarded to \2%s\2."), target);
147 			return;
148 		}
149 	}
150 	logcommand(si, CMDLOG_SET, "FORWARD: to \2%s\2", entity(tmu)->name);
151 
152 	/* Go to forwarding memos */
153 	MOWGLI_ITER_FOREACH(n, si->smu->memos.head)
154 	{
155 		if (i == memonum)
156 		{
157 			/* should have some function for send here...  ask nenolod*/
158 			memo = (mymemo_t *)n->data;
159 			newmemo = smalloc(sizeof(mymemo_t));
160 
161 			/* Create memo */
162 			newmemo->sent = CURRTIME;
163 			newmemo->status = 0;
164 			mowgli_strlcpy(newmemo->sender,entity(si->smu)->name,NICKLEN);
165 			mowgli_strlcpy(newmemo->text,memo->text,MEMOLEN);
166 
167 			/* Create node, add to their linked list of memos */
168 			temp = mowgli_node_create();
169 			mowgli_node_add(newmemo, temp, &tmu->memos);
170 			tmu->memoct_new++;
171 
172 			/* Should we email this? */
173 			if (tmu->flags & MU_EMAILMEMOS)
174 			{
175 				sendemail(si->su, tmu, EMAIL_MEMO, tmu->email, memo->text);
176 			}
177 		}
178 		i++;
179 	}
180 
181 	/* Note: do not disclose other nicks they're logged in with
182 	 * -- jilles */
183 	tu = user_find_named(target);
184 	if (tu != NULL && tu->myuser == tmu)
185 	{
186 		command_success_nodata(si, _("%s is currently online, and you may talk directly, by sending a private message."), target);
187 	}
188 	if (si->su == NULL || !irccasecmp(si->su->nick, entity(si->smu)->name))
189 		myuser_notice(si->service->nick, tmu, "You have a new forwarded memo from %s (%zu).", entity(si->smu)->name, MOWGLI_LIST_LENGTH(&tmu->memos));
190 	else
191 		myuser_notice(si->service->nick, tmu, "You have a new forwarded memo from %s (nick: %s) (%zu).", entity(si->smu)->name, si->su->nick, MOWGLI_LIST_LENGTH(&tmu->memos));
192 	myuser_notice(si->service->nick, tmu, _("To read it, type /%s%s READ %zu"),
193 				ircd->uses_rcommand ? "" : "msg ", si->service->disp, MOWGLI_LIST_LENGTH(&tmu->memos));
194 
195 	command_success_nodata(si, _("The memo has been successfully forwarded to \2%s\2."), target);
196 	return;
197 }
198 
199 /* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
200  * vim:ts=8
201  * vim:sw=8
202  * vim:noexpandtab
203  */
204