]> jfr.im git - solanum.git/blame_incremental - modules/core/m_mode.c
add help for `chm_regmsg`
[solanum.git] / modules / core / m_mode.c
... / ...
CommitLineData
1/*
2 * ircd-ratbox: A slightly useful ircd.
3 * m_mode.c: Sets a user or channel mode.
4 *
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * USA
23 */
24
25#include "stdinc.h"
26#include "channel.h"
27#include "client.h"
28#include "hash.h"
29#include "match.h"
30#include "ircd.h"
31#include "numeric.h"
32#include "s_user.h"
33#include "s_conf.h"
34#include "s_serv.h"
35#include "logger.h"
36#include "send.h"
37#include "msg.h"
38#include "parse.h"
39#include "modules.h"
40#include "packet.h"
41#include "s_newconf.h"
42
43static const char mode_desc[] =
44 "Provides the MODE and MLOCK client and server commands, and TS6 server-to-server TMODE and BMASK commands";
45
46static void m_mode(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
47static void ms_mode(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
48static void ms_tmode(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
49static void ms_mlock(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
50static void ms_bmask(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
51static void ms_ebmask(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
52
53struct Message mode_msgtab = {
54 "MODE", 0, 0, 0, 0,
55 {mg_unreg, {m_mode, 2}, {m_mode, 3}, {ms_mode, 3}, mg_ignore, {m_mode, 2}}
56};
57struct Message tmode_msgtab = {
58 "TMODE", 0, 0, 0, 0,
59 {mg_ignore, mg_ignore, {ms_tmode, 4}, {ms_tmode, 4}, mg_ignore, mg_ignore}
60};
61struct Message mlock_msgtab = {
62 "MLOCK", 0, 0, 0, 0,
63 {mg_ignore, mg_ignore, {ms_mlock, 3}, {ms_mlock, 3}, mg_ignore, mg_ignore}
64};
65struct Message bmask_msgtab = {
66 "BMASK", 0, 0, 0, 0,
67 {mg_ignore, mg_ignore, mg_ignore, {ms_bmask, 5}, mg_ignore, mg_ignore}
68};
69struct Message ebmask_msgtab = {
70 "EBMASK", 0, 0, 0, 0,
71 {mg_ignore, mg_ignore, mg_ignore, {ms_ebmask, 5}, mg_ignore, mg_ignore}
72};
73
74mapi_clist_av1 mode_clist[] = { &mode_msgtab, &tmode_msgtab, &mlock_msgtab, &bmask_msgtab, &ebmask_msgtab, NULL };
75
76DECLARE_MODULE_AV2(mode, NULL, NULL, mode_clist, NULL, NULL, NULL, NULL, mode_desc);
77
78/*
79 * m_mode - MODE command handler
80 * parv[1] - channel
81 */
82static void
83m_mode(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
84{
85 struct Channel *chptr = NULL;
86 struct membership *msptr;
87 int n = 2;
88 const char *dest;
89 int operspy = 0;
90
91 dest = parv[1];
92
93 if(IsOperSpy(source_p) && *dest == '!')
94 {
95 dest++;
96 operspy = 1;
97
98 if(EmptyString(dest))
99 {
100 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
101 me.name, source_p->name, "MODE");
102 return;
103 }
104 }
105
106 /* Now, try to find the channel in question */
107 if(!IsChanPrefix(*dest))
108 {
109 /* if here, it has to be a non-channel name */
110 user_mode(client_p, source_p, parc, parv);
111 return;
112 }
113
114 if(!check_channel_name(dest))
115 {
116 sendto_one_numeric(source_p, ERR_BADCHANNAME, form_str(ERR_BADCHANNAME), parv[1]);
117 return;
118 }
119
120 chptr = find_channel(dest);
121
122 if(chptr == NULL)
123 {
124 sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
125 form_str(ERR_NOSUCHCHANNEL), parv[1]);
126 return;
127 }
128
129 /* Now know the channel exists */
130 if(parc < n + 1)
131 {
132 if(operspy)
133 report_operspy(source_p, "MODE", chptr->chname);
134
135 sendto_one(source_p, form_str(RPL_CHANNELMODEIS),
136 me.name, source_p->name, parv[1],
137 operspy ? channel_modes(chptr, &me) : channel_modes(chptr, source_p));
138
139 sendto_one(source_p, form_str(RPL_CREATIONTIME),
140 me.name, source_p->name, parv[1], (long long)chptr->channelts);
141 }
142 else
143 {
144 msptr = find_channel_membership(chptr, source_p);
145
146 set_channel_mode(client_p, source_p, chptr, msptr, parc - n, parv + n);
147 }
148}
149
150static void
151ms_mode(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
152{
153 struct Channel *chptr;
154
155 chptr = find_channel(parv[1]);
156
157 if(chptr == NULL)
158 {
159 sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
160 form_str(ERR_NOSUCHCHANNEL), parv[1]);
161 return;
162 }
163
164 set_channel_mode(client_p, source_p, chptr, NULL, parc - 2, parv + 2);
165}
166
167static void
168ms_tmode(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
169{
170 struct Channel *chptr = NULL;
171 struct membership *msptr;
172
173 /* Now, try to find the channel in question */
174 if(!IsChanPrefix(parv[2][0]) || !check_channel_name(parv[2]))
175 {
176 sendto_one_numeric(source_p, ERR_BADCHANNAME, form_str(ERR_BADCHANNAME), parv[2]);
177 return;
178 }
179
180 chptr = find_channel(parv[2]);
181
182 if(chptr == NULL)
183 {
184 sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
185 form_str(ERR_NOSUCHCHANNEL), parv[2]);
186 return;
187 }
188
189 /* TS is higher, drop it. */
190 if(atol(parv[1]) > chptr->channelts)
191 return;
192
193 if(IsServer(source_p))
194 {
195 set_channel_mode(client_p, source_p, chptr, NULL, parc - 3, parv + 3);
196 }
197 else
198 {
199 msptr = find_channel_membership(chptr, source_p);
200
201 set_channel_mode(client_p, source_p, chptr, msptr, parc - 3, parv + 3);
202 }
203}
204
205static void
206ms_mlock(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
207{
208 struct Channel *chptr = NULL;
209
210 /* Now, try to find the channel in question */
211 if(!IsChanPrefix(parv[2][0]) || !check_channel_name(parv[2]))
212 {
213 sendto_one_numeric(source_p, ERR_BADCHANNAME, form_str(ERR_BADCHANNAME), parv[2]);
214 return;
215 }
216
217 chptr = find_channel(parv[2]);
218
219 if(chptr == NULL)
220 {
221 sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
222 form_str(ERR_NOSUCHCHANNEL), parv[2]);
223 return;
224 }
225
226 /* TS is higher, drop it. */
227 if(atol(parv[1]) > chptr->channelts)
228 return;
229
230 if(IsServer(source_p))
231 set_channel_mlock(client_p, source_p, chptr, parv[3], true);
232}
233
234static void
235possibly_remove_lower_forward(struct Client *fakesource_p, int mems,
236 struct Channel *chptr, rb_dlink_list *banlist, int mchar,
237 const char *mask, const char *forward)
238{
239 struct Ban *actualBan;
240 rb_dlink_node *ptr;
241
242 RB_DLINK_FOREACH(ptr, banlist->head)
243 {
244 actualBan = ptr->data;
245 if(!irccmp(actualBan->banstr, mask) &&
246 (actualBan->forward == NULL ||
247 irccmp(actualBan->forward, forward) < 0))
248 {
249 sendto_channel_local(fakesource_p, mems, chptr, ":%s MODE %s -%c %s%s%s",
250 fakesource_p->name,
251 chptr->chname,
252 mchar,
253 actualBan->banstr,
254 actualBan->forward ? "$" : "",
255 actualBan->forward ? actualBan->forward : "");
256 rb_dlinkDelete(&actualBan->node, banlist);
257 free_ban(actualBan);
258 return;
259 }
260 }
261}
262
263static void
264do_bmask(bool extended, struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
265{
266 static char output[BUFSIZE];
267 static char parabuf[BUFSIZE];
268 static char degrade[BUFSIZE];
269 static char squitreason[120];
270 struct Channel *chptr;
271 struct Ban *banptr;
272 rb_dlink_list *banlist;
273 char *s, *mask, *forward, *who;
274 char *output_ptr;
275 char *param_ptr;
276 char *degrade_ptr;
277 long mode_type;
278 int mlen;
279 int plen = 0;
280 int tlen;
281 int arglen;
282 int modecount = 0;
283 int needcap = NOCAPS;
284 int mems;
285 time_t when = (long)rb_current_time();
286 struct Client *fakesource_p;
287
288 if(!IsChanPrefix(parv[2][0]) || !check_channel_name(parv[2]))
289 return;
290
291 if((chptr = find_channel(parv[2])) == NULL)
292 return;
293
294 /* TS is higher, drop it. */
295 if(atol(parv[1]) > chptr->channelts)
296 return;
297
298 switch (parv[3][0])
299 {
300 case 'b':
301 banlist = &chptr->banlist;
302 mode_type = CHFL_BAN;
303 mems = ALL_MEMBERS;
304 break;
305
306 case 'e':
307 banlist = &chptr->exceptlist;
308 mode_type = CHFL_EXCEPTION;
309 needcap = CAP_EX;
310 mems = ONLY_CHANOPS;
311 break;
312
313 case 'I':
314 banlist = &chptr->invexlist;
315 mode_type = CHFL_INVEX;
316 needcap = CAP_IE;
317 mems = ONLY_CHANOPS;
318 break;
319
320 case 'q':
321 banlist = &chptr->quietlist;
322 mode_type = CHFL_QUIET;
323 mems = ALL_MEMBERS;
324 break;
325
326 /* maybe we should just blindly propagate this? */
327 default:
328 return;
329 }
330
331 parabuf[0] = '\0';
332 s = LOCAL_COPY(parv[4]);
333
334 /* Hide connecting server on netburst -- jilles */
335 if (ConfigServerHide.flatten_links && !HasSentEob(source_p))
336 fakesource_p = &me;
337 else
338 fakesource_p = source_p;
339 who = fakesource_p->name;
340
341 mlen = sprintf(output, ":%s MODE %s +", fakesource_p->name, chptr->chname);
342 output_ptr = output + mlen;
343 param_ptr = parabuf;
344 degrade_ptr = degrade;
345
346 while(*s == ' ')
347 s++;
348
349 s = strtok(s, " ");
350
351 while(!EmptyString(s))
352 {
353 if(*s == ':')
354 {
355 /* ban with a leading ':' -- this will break the protocol */
356 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
357 "Link %s dropped, invalid BMASK mask (%s)", source_p->name, s);
358 snprintf(squitreason, sizeof squitreason, "Invalid BMASK mask (%s)", s);
359 exit_client(client_p, client_p, client_p, squitreason);
360 return;
361 }
362
363 tlen = strlen(s);
364
365 /* I dont even want to begin parsing this.. */
366 if(tlen > MODEBUFLEN)
367 break;
368
369 if((forward = strchr(s+1, '$')) != NULL)
370 {
371 *forward++ = '\0';
372 if(*forward == '\0')
373 tlen--, forward = NULL;
374 else
375 possibly_remove_lower_forward(fakesource_p,
376 mems, chptr, banlist,
377 parv[3][0], s, forward);
378 }
379
380 mask = s;
381 if (extended) {
382 when = atol(strtok(NULL, " "));
383 who = strtok(NULL, " ");
384 if (who == NULL)
385 {
386 /* EBMASK params don't divide by 3, so we have an incomplete chunk */
387 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
388 "Link %s dropped, invalid EBMASK chunk", source_p->name);
389 snprintf(squitreason, sizeof squitreason, "Invalid EBMASK chunk");
390 exit_client(client_p, client_p, client_p, squitreason);
391 return;
392 }
393
394 arglen = sprintf(degrade_ptr, "%s ", mask);
395 degrade_ptr += arglen;
396 }
397
398 if((banptr = add_id(fakesource_p, chptr, mask, forward, banlist, mode_type)) != NULL)
399 {
400 banptr->when = when;
401 rb_free(banptr->who);
402 banptr->who = rb_strdup(who);
403
404 /* this new one wont fit.. */
405 if(mlen + MAXMODEPARAMS + plen + tlen > BUFSIZE - 5 ||
406 modecount >= MAXMODEPARAMS)
407 {
408 *output_ptr = '\0';
409 *(param_ptr - 1) = '\0';
410 sendto_channel_local(fakesource_p, mems, chptr, "%s %s", output, parabuf);
411
412 output_ptr = output + mlen;
413 param_ptr = parabuf;
414 plen = modecount = 0;
415 }
416
417 if (forward != NULL)
418 forward[-1] = '$';
419
420 *output_ptr++ = parv[3][0];
421 arglen = sprintf(param_ptr, "%s ", mask);
422 param_ptr += arglen;
423 plen += arglen;
424 modecount++;
425 }
426
427 s = strtok(NULL, " ");
428 }
429
430 if(modecount)
431 {
432 *output_ptr = '\0';
433 *(param_ptr - 1) = '\0';
434 sendto_channel_local(fakesource_p, mems, chptr, "%s %s", output, parabuf);
435 }
436
437 if (extended) {
438 *(degrade_ptr - 1) = '\0';
439 sendto_server(client_p, chptr, CAP_EBMASK | CAP_TS6 | needcap, NOCAPS, ":%s EBMASK %ld %s %s :%s",
440 source_p->id, (long) chptr->channelts, chptr->chname, parv[3], parv[4]);
441 sendto_server(client_p, chptr, CAP_TS6 | needcap, CAP_EBMASK, ":%s BMASK %ld %s %s :%s",
442 source_p->id, (long) chptr->channelts, chptr->chname, parv[3], degrade);
443 }
444 else
445 sendto_server(client_p, chptr, CAP_TS6 | needcap, NOCAPS, ":%s BMASK %ld %s %s :%s",
446 source_p->id, (long) chptr->channelts, chptr->chname, parv[3], parv[4]);
447}
448
449static void
450ms_bmask(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
451{
452 do_bmask(false, msgbuf_p, client_p, source_p, parc, parv);
453}
454static void
455ms_ebmask(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
456{
457 do_bmask(true, msgbuf_p, client_p, source_p, parc, parv);
458}
459