1 |
/* |
2 |
* ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). |
3 |
* m_resv.c: Reserves(jupes) a nickname or channel. |
4 |
* |
5 |
* Copyright (C) 2001-2002 Hybrid Development Team |
6 |
* |
7 |
* This program is free software; you can redistribute it and/or modify |
8 |
* it under the terms of the GNU General Public License as published by |
9 |
* the Free Software Foundation; either version 2 of the License, or |
10 |
* (at your option) any later version. |
11 |
* |
12 |
* This program is distributed in the hope that it will be useful, |
13 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 |
* GNU General Public License for more details. |
16 |
* |
17 |
* You should have received a copy of the GNU General Public License |
18 |
* along with this program; if not, write to the Free Software |
19 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
20 |
* USA |
21 |
* |
22 |
* $Id$ |
23 |
*/ |
24 |
|
25 |
#include "stdinc.h" |
26 |
#include "conf/conf.h" |
27 |
#include "handlers.h" |
28 |
#include "client.h" |
29 |
#include "channel.h" |
30 |
#include "ircd.h" |
31 |
#include "numeric.h" |
32 |
#include "s_serv.h" |
33 |
#include "send.h" |
34 |
#include "msg.h" |
35 |
#include "parse.h" |
36 |
#include "parse_aline.h" |
37 |
#include "hash.h" |
38 |
#include "s_user.h" |
39 |
|
40 |
static void mo_resv(struct Client *, struct Client *, int, char *[]); |
41 |
static void me_resv(struct Client *, struct Client *, int, char *[]); |
42 |
static void ms_resv(struct Client *, struct Client *, int, char *[]); |
43 |
static void mo_unresv(struct Client *, struct Client *, int, char *[]); |
44 |
static void ms_unresv(struct Client *, struct Client *, int, char *[]); |
45 |
|
46 |
static void parse_resv(struct Client *, char *, int, char *); |
47 |
static void remove_resv(struct Client *, const char *); |
48 |
|
49 |
struct Message resv_msgtab = { |
50 |
"RESV", 0, 0, 3, 0, MFLG_SLOW, 0, |
51 |
{ m_ignore, m_not_oper, ms_resv, me_resv, mo_resv, m_ignore } |
52 |
}; |
53 |
|
54 |
struct Message unresv_msgtab = { |
55 |
"UNRESV", 0, 0, 2, 0, MFLG_SLOW, 0, |
56 |
{ m_ignore, m_not_oper, ms_unresv, m_ignore, mo_unresv, m_ignore } |
57 |
}; |
58 |
|
59 |
INIT_MODULE(m_resv, "$Revision$") |
60 |
{ |
61 |
mod_add_cmd(&resv_msgtab); |
62 |
mod_add_cmd(&unresv_msgtab); |
63 |
} |
64 |
|
65 |
CLEANUP_MODULE |
66 |
{ |
67 |
mod_del_cmd(&unresv_msgtab); |
68 |
mod_del_cmd(&resv_msgtab); |
69 |
} |
70 |
|
71 |
/* mo_resv() |
72 |
* parv[0] = sender prefix |
73 |
* parv[1] = channel/nick to forbid |
74 |
*/ |
75 |
static void |
76 |
mo_resv(struct Client *client_p, struct Client *source_p, |
77 |
int parc, char *parv[]) |
78 |
{ |
79 |
char *resv = NULL; |
80 |
char *reason = NULL; |
81 |
char *target_server = NULL; |
82 |
time_t tkline_time = 0; |
83 |
|
84 |
/* RESV #channel ON irc.server.com :abuse |
85 |
* RESV kiddie ON irc.server.com :abuse |
86 |
*/ |
87 |
if (parse_aline("RESV", source_p, parc, parv, |
88 |
AWILD, &resv, NULL, &tkline_time, &target_server, &reason) < 0) |
89 |
return; |
90 |
|
91 |
if (target_server != NULL) |
92 |
{ |
93 |
// if a given expire time is given, ENCAP it |
94 |
if (tkline_time != 0) |
95 |
sendto_match_servs(source_p, target_server, CAP_ENCAP, |
96 |
"ENCAP %s RESV %d %s 0 :%s", |
97 |
target_server, (int)tkline_time, resv, reason); |
98 |
else |
99 |
sendto_match_servs(source_p, target_server, CAP_CLUSTER, |
100 |
"RESV %s %s :%s", |
101 |
target_server, resv, reason); |
102 |
// Allow ON to apply local resv as well if it matches |
103 |
if (!match(target_server, me.name)) |
104 |
return; |
105 |
} |
106 |
else |
107 |
{ |
108 |
/* RESV #channel :abuse |
109 |
* RESV kiddie :abuse |
110 |
*/ |
111 |
if (tkline_time != 0) |
112 |
cluster_a_line(source_p, "ENCAP", CAP_ENCAP, SHARED_RESV, |
113 |
"RESV %d %s 0 : %s", (int)tkline_time, resv, reason); |
114 |
else |
115 |
cluster_a_line(source_p, "RESV", CAP_KLN, SHARED_RESV, |
116 |
"%s : %s", resv, reason); |
117 |
} |
118 |
|
119 |
parse_resv(source_p, resv, (int)tkline_time, reason); |
120 |
} |
121 |
|
122 |
/* me_resv() |
123 |
* |
124 |
* inputs - server |
125 |
* - client (oper) |
126 |
* - parc number of arguments |
127 |
* - parv list of arguments |
128 |
* via parv[] |
129 |
* parv[0] = client name applying resv |
130 |
* parv[1] = tkline_time |
131 |
* parv[2] = name |
132 |
* parv[3] = 0 |
133 |
* parv[4] = reason |
134 |
* parc should be 5 |
135 |
* |
136 |
* outputs - NONE |
137 |
* side effects - |
138 |
*/ |
139 |
static void |
140 |
me_resv(struct Client *client_p, struct Client *source_p, |
141 |
int parc, char *parv[]) |
142 |
{ |
143 |
if (parc != 5 || !IsClient(source_p)) |
144 |
return; |
145 |
|
146 |
parse_resv(source_p, parv[2], atoi(parv[1]), parv[4]); |
147 |
} |
148 |
|
149 |
/* ms_resv() |
150 |
* parv[0] = sender prefix |
151 |
* parv[1] = target server |
152 |
* parv[2] = channel/nick to resv |
153 |
* parv[3] = reason |
154 |
*/ |
155 |
static void |
156 |
ms_resv(struct Client *client_p, struct Client *source_p, |
157 |
int parc, char *parv[]) |
158 |
{ |
159 |
if ((parc != 4) || EmptyString(parv[3])) |
160 |
return; |
161 |
|
162 |
sendto_match_servs(source_p, parv[1], CAP_CLUSTER, |
163 |
"RESV %s %s :%s", |
164 |
parv[1], parv[2], parv[3]); |
165 |
|
166 |
if (!IsClient(source_p) || !match(parv[1], me.name)) |
167 |
return; |
168 |
|
169 |
if (find_shared(source_p->servptr->name, source_p->username, source_p->host, |
170 |
source_p->sockhost, SHARED_RESV)) |
171 |
parse_resv(source_p, parv[2], 0, parv[3]); |
172 |
} |
173 |
|
174 |
/* mo_unresv() |
175 |
* parv[0] = sender prefix |
176 |
* parv[1] = channel/nick to unforbid |
177 |
*/ |
178 |
static void |
179 |
mo_unresv(struct Client *client_p, struct Client *source_p, |
180 |
int parc, char *parv[]) |
181 |
{ |
182 |
char *resv = NULL; |
183 |
char *reason = NULL; |
184 |
char *target_server = NULL; |
185 |
|
186 |
// UNRESV #channel ON irc.server.com |
187 |
// UNRESV kiddie ON irc.server.com |
188 |
if (parse_aline("UNRESV", source_p, parc, parv, |
189 |
0, &resv, NULL, NULL, &target_server, &reason) < 0) |
190 |
return; |
191 |
|
192 |
if (target_server != NULL) |
193 |
{ |
194 |
sendto_match_servs(source_p, target_server, CAP_CLUSTER, |
195 |
"UNRESV %s %s", |
196 |
target_server, resv); |
197 |
|
198 |
// Allow ON to apply local unresv as well if it matches |
199 |
if (!match(target_server, me.name)) |
200 |
return; |
201 |
} |
202 |
else |
203 |
cluster_a_line(source_p, "UNRESV", CAP_KLN, SHARED_UNRESV, resv); |
204 |
|
205 |
remove_resv(source_p, resv); |
206 |
} |
207 |
|
208 |
/* ms_unresv() |
209 |
* parv[0] = sender prefix |
210 |
* parv[1] = target server |
211 |
* parv[2] = resv to remove |
212 |
*/ |
213 |
static void |
214 |
ms_unresv(struct Client *client_p, struct Client *source_p, |
215 |
int parc, char *parv[]) |
216 |
{ |
217 |
if ((parc != 3) || EmptyString(parv[2])) |
218 |
return; |
219 |
|
220 |
sendto_match_servs(source_p, parv[1], CAP_CLUSTER, |
221 |
"UNRESV %s %s", |
222 |
parv[1], parv[2]); |
223 |
|
224 |
if (!IsClient(source_p) || !match(parv[1], me.name)) |
225 |
return; |
226 |
|
227 |
if (find_shared(source_p->servptr->name, source_p->username, source_p->host, |
228 |
source_p->sockhost, SHARED_UNRESV)) |
229 |
remove_resv(source_p, parv[2]); |
230 |
} |
231 |
|
232 |
/* parse_resv() |
233 |
* |
234 |
* inputs - source_p, NULL supported |
235 |
* - thing to resv |
236 |
* - time_t if tkline |
237 |
* - reason |
238 |
* outputs - none |
239 |
* side effects - parse resv, create if valid |
240 |
*/ |
241 |
static void |
242 |
parse_resv(struct Client *source_p, char *name, int tkline_time, char *reason) |
243 |
{ |
244 |
struct ResvConf *conf = NULL; |
245 |
FBFILE *out = NULL; |
246 |
|
247 |
if (!IsAdmin(source_p) && has_wildcards(name, IsChanPrefix(*name))) |
248 |
{ |
249 |
sendto_one(source_p, ":%s NOTICE %s :You must be an admin to perform a " |
250 |
"wildcard RESV", me.name, source_p->name); |
251 |
return; |
252 |
} |
253 |
|
254 |
if (IsChanPrefix(*name)) |
255 |
{ |
256 |
if (find_channel_resv(name)) |
257 |
{ |
258 |
sendto_one(source_p, |
259 |
":%s NOTICE %s :A RESV has already been placed on channel: %s", |
260 |
me.name, source_p->name, name); |
261 |
return; |
262 |
} |
263 |
|
264 |
conf = MyMalloc(sizeof(*conf)); |
265 |
DupString(conf->mask, name); |
266 |
DupString(conf->reason, reason); |
267 |
if (has_wildcards(name, YES)) |
268 |
{ |
269 |
unsigned int hashv = hash_text(name, RHSIZE); |
270 |
conf->hnext = cresv_hash[hashv]; |
271 |
cresv_hash[hashv] = conf; |
272 |
num_hashed_resvs++; |
273 |
} |
274 |
else |
275 |
dlinkAdd(conf, &conf->node, &cresv_confs); |
276 |
|
277 |
if (tkline_time != 0) |
278 |
{ |
279 |
sendto_one(source_p, |
280 |
":%s NOTICE %s :A %d minute %s RESV has been placed on " |
281 |
"channel: %s", me.name, source_p->name, tkline_time/60, |
282 |
(MyClient(source_p) ? "local" : "remote"), name); |
283 |
sendto_realops_flags(UMODE_ALL, L_ALL, |
284 |
"%s has placed a %d minute %s RESV on " |
285 |
"channel: %s [%s]", get_oper_name(source_p), |
286 |
tkline_time/60, (MyClient(source_p) ? |
287 |
"local" : "remote"), conf->mask, conf->reason); |
288 |
ilog(L_TRACE, "%s added temporary %d min. RESV for [%s] [%s]", |
289 |
get_oper_name(source_p), (int)tkline_time/60, |
290 |
conf->mask, conf->reason); |
291 |
conf->expires = CurrentTime + tkline_time; |
292 |
} |
293 |
else |
294 |
{ |
295 |
sendto_one(source_p, |
296 |
":%s NOTICE %s :A %s RESV has been placed on channel %s", |
297 |
me.name, source_p->name, |
298 |
(MyClient(source_p) ? "local" : "remote"), name); |
299 |
sendto_realops_flags(UMODE_ALL, L_ALL, |
300 |
"%s has placed a %s RESV on channel %s : [%s]", |
301 |
get_oper_name(source_p), (MyClient(source_p) ? |
302 |
"local" : "remote"), conf->mask, conf->reason); |
303 |
// TBD - don't keep the *line in memory if we cannot open the conf file |
304 |
if ((out = fbopen(ServerState.cresvfile, "a")) == NULL) |
305 |
sendto_realops_flags(UMODE_ALL, L_ALL, |
306 |
"*** Problem opening %s", ServerState.cresvfile); |
307 |
else |
308 |
write_csv_line(out, "%s%s", |
309 |
conf->mask, conf->reason); |
310 |
} |
311 |
} |
312 |
else |
313 |
{ |
314 |
if (!valid_wild_card_simple(name)) |
315 |
{ |
316 |
sendto_one(source_p, ":%s NOTICE %s :Please include at least %d non-wildcard characters with the resv", |
317 |
me.name, source_p->name, General.min_nonwildcard_simple); |
318 |
return; |
319 |
} |
320 |
|
321 |
if (find_nick_resv(name)) |
322 |
{ |
323 |
sendto_one(source_p, |
324 |
":%s NOTICE %s :A RESV has already been placed on nick %s", |
325 |
me.name, source_p->name, name); |
326 |
return; |
327 |
} |
328 |
|
329 |
conf = MyMalloc(sizeof(*conf)); |
330 |
DupString(conf->mask, name); |
331 |
DupString(conf->reason, reason); |
332 |
if (has_wildcards(name, NO)) |
333 |
{ |
334 |
unsigned int hashv = hash_text(name, RHSIZE); |
335 |
conf->hnext = nresv_hash[hashv]; |
336 |
nresv_hash[hashv] = conf; |
337 |
num_hashed_resvs++; |
338 |
} |
339 |
else |
340 |
dlinkAdd(conf, &conf->node, &nresv_confs); |
341 |
|
342 |
if (tkline_time != 0) |
343 |
{ |
344 |
sendto_one(source_p, |
345 |
":%s NOTICE %s :A %d minute %s RESV has been placed on nick " |
346 |
"%s : [%s]", me.name, source_p->name, tkline_time/60, |
347 |
(MyClient(source_p) ? "local" : "remote"), |
348 |
conf->mask, conf->reason); |
349 |
sendto_realops_flags(UMODE_ALL, L_ALL, |
350 |
"%s has placed a %d minute %s RESV on nick %s : " |
351 |
"[%s]", get_oper_name(source_p), tkline_time/60, |
352 |
(MyClient(source_p) ? "local" : "remote"), |
353 |
conf->mask, conf->reason); |
354 |
ilog(L_TRACE, "%s added temporary %d min. RESV for [%s] [%s]", |
355 |
get_oper_name(source_p), (int)tkline_time/60, |
356 |
conf->mask, conf->reason); |
357 |
conf->expires = CurrentTime + tkline_time; |
358 |
} |
359 |
else |
360 |
{ |
361 |
sendto_one(source_p, |
362 |
":%s NOTICE %s :A %s RESV has been placed on nick %s : [%s]", |
363 |
me.name, source_p->name, |
364 |
(MyClient(source_p) ? "local" : "remote"), |
365 |
conf->mask, conf->reason); |
366 |
sendto_realops_flags(UMODE_ALL, L_ALL, |
367 |
"%s has placed a %s RESV on nick %s : [%s]", |
368 |
get_oper_name(source_p), (MyClient(source_p) ? |
369 |
"local" : "remote"), conf->mask, conf->reason); |
370 |
if ((out = fbopen(ServerState.nresvfile, "a")) == NULL) |
371 |
sendto_realops_flags(UMODE_ALL, L_ALL, |
372 |
"*** Problem opening %s", ServerState.nresvfile); |
373 |
else |
374 |
write_csv_line(out, "%s%s", |
375 |
conf->mask, conf->reason); |
376 |
} |
377 |
} |
378 |
} |
379 |
|
380 |
static void |
381 |
remove_resv(struct Client *source_p, const char *name) |
382 |
{ |
383 |
struct ResvConf *conf, *prev; |
384 |
|
385 |
if (IsChanPrefix(*name)) |
386 |
{ |
387 |
if (!(conf = do_find_resv(&cresv_confs, cresv_hash, name, irccmp))) |
388 |
{ |
389 |
sendto_one(source_p, |
390 |
":%s NOTICE %s :A RESV does not exist for channel: %s", |
391 |
me.name, source_p->name, name); |
392 |
return; |
393 |
} |
394 |
|
395 |
if (has_wildcards(conf->mask, YES)) |
396 |
{ |
397 |
unsigned int hashv = hash_text(conf->mask, RHSIZE); |
398 |
if (cresv_hash[hashv] == conf) |
399 |
cresv_hash[hashv] = conf->hnext; |
400 |
else |
401 |
{ |
402 |
// make it core if not found |
403 |
for (prev = cresv_hash[hashv]; prev->hnext != conf; prev = prev->hnext) |
404 |
; |
405 |
prev->hnext = conf->hnext; |
406 |
} |
407 |
num_hashed_resvs--; |
408 |
} |
409 |
else |
410 |
dlinkDelete(&conf->node, &cresv_confs); |
411 |
|
412 |
if (!conf->expires) |
413 |
remove_conf_line(123, source_p, name, NULL); |
414 |
|
415 |
MyFree(conf->mask); |
416 |
MyFree(conf->reason); |
417 |
MyFree(conf); |
418 |
|
419 |
sendto_one(source_p, |
420 |
":%s NOTICE %s :The RESV has been removed on channel: %s", |
421 |
me.name, source_p->name, name); |
422 |
sendto_realops_flags(UMODE_ALL, L_ALL, |
423 |
"%s has removed the RESV for channel: %s", |
424 |
get_oper_name(source_p), name); |
425 |
} |
426 |
else |
427 |
{ |
428 |
if (!(conf = do_find_resv(&nresv_confs, nresv_hash, name, irccmp))) |
429 |
{ |
430 |
sendto_one(source_p, ":%s NOTICE %s :A RESV does not exist for nick: %s", |
431 |
me.name, source_p->name, name); |
432 |
return; |
433 |
} |
434 |
|
435 |
if (has_wildcards(conf->mask, NO)) |
436 |
{ |
437 |
unsigned int hashv = hash_text(conf->mask, RHSIZE); |
438 |
if (nresv_hash[hashv] == conf) |
439 |
nresv_hash[hashv] = conf->hnext; |
440 |
else |
441 |
{ |
442 |
// make it core if not found |
443 |
for (prev = nresv_hash[hashv]; prev->hnext != conf; prev = prev->hnext) |
444 |
; |
445 |
prev->hnext = conf->hnext; |
446 |
} |
447 |
num_hashed_resvs--; |
448 |
} |
449 |
else |
450 |
dlinkDelete(&conf->node, &nresv_confs); |
451 |
|
452 |
if (!conf->expires) |
453 |
remove_conf_line(456, source_p, name, NULL); |
454 |
|
455 |
MyFree(conf->mask); |
456 |
MyFree(conf->reason); |
457 |
MyFree(conf); |
458 |
|
459 |
sendto_one(source_p, ":%s NOTICE %s :The RESV has been removed on nick: %s", |
460 |
me.name, source_p->name, name); |
461 |
sendto_realops_flags(UMODE_ALL, L_ALL, |
462 |
"%s has removed the RESV for nick: %s", |
463 |
get_oper_name(source_p), name); |
464 |
} |
465 |
} |