]> jfr.im git - solanum.git/blob - modules/core/m_mode.c
Migrate remaining modules to AV2
[solanum.git] / modules / core / m_mode.c
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
43 static int m_mode(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
44 static int ms_mode(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
45 static int ms_tmode(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
46 static int ms_mlock(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
47 static int ms_bmask(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
48
49 struct Message mode_msgtab = {
50 "MODE", 0, 0, 0, 0,
51 {mg_unreg, {m_mode, 2}, {m_mode, 3}, {ms_mode, 3}, mg_ignore, {m_mode, 2}}
52 };
53 struct Message tmode_msgtab = {
54 "TMODE", 0, 0, 0, 0,
55 {mg_ignore, mg_ignore, {ms_tmode, 4}, {ms_tmode, 4}, mg_ignore, mg_ignore}
56 };
57 struct Message mlock_msgtab = {
58 "MLOCK", 0, 0, 0, 0,
59 {mg_ignore, mg_ignore, {ms_mlock, 3}, {ms_mlock, 3}, mg_ignore, mg_ignore}
60 };
61 struct Message bmask_msgtab = {
62 "BMASK", 0, 0, 0, 0,
63 {mg_ignore, mg_ignore, mg_ignore, {ms_bmask, 5}, mg_ignore, mg_ignore}
64 };
65
66 mapi_clist_av1 mode_clist[] = { &mode_msgtab, &tmode_msgtab, &mlock_msgtab, &bmask_msgtab, NULL };
67
68 DECLARE_MODULE_AV2(mode, NULL, NULL, mode_clist, NULL, NULL, NULL, NULL, NULL);
69
70 /*
71 * m_mode - MODE command handler
72 * parv[1] - channel
73 */
74 static int
75 m_mode(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
76 {
77 struct Channel *chptr = NULL;
78 struct membership *msptr;
79 int n = 2;
80 const char *dest;
81 int operspy = 0;
82
83 dest = parv[1];
84
85 if(IsOperSpy(source_p) && *dest == '!')
86 {
87 dest++;
88 operspy = 1;
89
90 if(EmptyString(dest))
91 {
92 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
93 me.name, source_p->name, "MODE");
94 return 0;
95 }
96 }
97
98 /* Now, try to find the channel in question */
99 if(!IsChanPrefix(*dest))
100 {
101 /* if here, it has to be a non-channel name */
102 user_mode(client_p, source_p, parc, parv);
103 return 0;
104 }
105
106 if(!check_channel_name(dest))
107 {
108 sendto_one_numeric(source_p, ERR_BADCHANNAME, form_str(ERR_BADCHANNAME), parv[1]);
109 return 0;
110 }
111
112 chptr = find_channel(dest);
113
114 if(chptr == NULL)
115 {
116 sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
117 form_str(ERR_NOSUCHCHANNEL), parv[1]);
118 return 0;
119 }
120
121 /* Now know the channel exists */
122 if(parc < n + 1)
123 {
124 if(operspy)
125 report_operspy(source_p, "MODE", chptr->chname);
126
127 sendto_one(source_p, form_str(RPL_CHANNELMODEIS),
128 me.name, source_p->name, parv[1],
129 operspy ? channel_modes(chptr, &me) : channel_modes(chptr, source_p));
130
131 sendto_one(source_p, form_str(RPL_CREATIONTIME),
132 me.name, source_p->name, parv[1], chptr->channelts);
133 }
134 else
135 {
136 msptr = find_channel_membership(chptr, source_p);
137
138 /* Finish the flood grace period... */
139 if(MyClient(source_p) && !IsFloodDone(source_p))
140 {
141 if(!((parc == 3) && (parv[2][0] == 'b' || parv[2][0] == 'q') && (parv[2][1] == '\0')))
142 flood_endgrace(source_p);
143 }
144
145 set_channel_mode(client_p, source_p, chptr, msptr, parc - n, parv + n);
146 }
147
148 return 0;
149 }
150
151 static int
152 ms_mode(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
153 {
154 struct Channel *chptr;
155
156 chptr = find_channel(parv[1]);
157
158 if(chptr == NULL)
159 {
160 sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
161 form_str(ERR_NOSUCHCHANNEL), parv[1]);
162 return 0;
163 }
164
165 set_channel_mode(client_p, source_p, chptr, NULL, parc - 2, parv + 2);
166
167 return 0;
168 }
169
170 static int
171 ms_tmode(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
172 {
173 struct Channel *chptr = NULL;
174 struct membership *msptr;
175
176 /* Now, try to find the channel in question */
177 if(!IsChanPrefix(parv[2][0]) || !check_channel_name(parv[2]))
178 {
179 sendto_one_numeric(source_p, ERR_BADCHANNAME, form_str(ERR_BADCHANNAME), parv[2]);
180 return 0;
181 }
182
183 chptr = find_channel(parv[2]);
184
185 if(chptr == NULL)
186 {
187 sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
188 form_str(ERR_NOSUCHCHANNEL), parv[2]);
189 return 0;
190 }
191
192 /* TS is higher, drop it. */
193 if(atol(parv[1]) > chptr->channelts)
194 return 0;
195
196 if(IsServer(source_p))
197 {
198 set_channel_mode(client_p, source_p, chptr, NULL, parc - 3, parv + 3);
199 }
200 else
201 {
202 msptr = find_channel_membership(chptr, source_p);
203
204 set_channel_mode(client_p, source_p, chptr, msptr, parc - 3, parv + 3);
205 }
206
207 return 0;
208 }
209
210 static int
211 ms_mlock(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
212 {
213 struct Channel *chptr = NULL;
214
215 /* Now, try to find the channel in question */
216 if(!IsChanPrefix(parv[2][0]) || !check_channel_name(parv[2]))
217 {
218 sendto_one_numeric(source_p, ERR_BADCHANNAME, form_str(ERR_BADCHANNAME), parv[2]);
219 return 0;
220 }
221
222 chptr = find_channel(parv[2]);
223
224 if(chptr == NULL)
225 {
226 sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
227 form_str(ERR_NOSUCHCHANNEL), parv[2]);
228 return 0;
229 }
230
231 /* TS is higher, drop it. */
232 if(atol(parv[1]) > chptr->channelts)
233 return 0;
234
235 if(IsServer(source_p))
236 set_channel_mlock(client_p, source_p, chptr, parv[3], TRUE);
237
238 return 0;
239 }
240
241 static void
242 possibly_remove_lower_forward(struct Client *fakesource_p, int mems,
243 struct Channel *chptr, rb_dlink_list *banlist, int mchar,
244 const char *mask, const char *forward)
245 {
246 struct Ban *actualBan;
247 rb_dlink_node *ptr;
248
249 RB_DLINK_FOREACH(ptr, banlist->head)
250 {
251 actualBan = ptr->data;
252 if(!irccmp(actualBan->banstr, mask) &&
253 (actualBan->forward == NULL ||
254 irccmp(actualBan->forward, forward) < 0))
255 {
256 sendto_channel_local(mems, chptr, ":%s MODE %s -%c %s%s%s",
257 fakesource_p->name,
258 chptr->chname,
259 mchar,
260 actualBan->banstr,
261 actualBan->forward ? "$" : "",
262 actualBan->forward ? actualBan->forward : "");
263 rb_dlinkDelete(&actualBan->node, banlist);
264 free_ban(actualBan);
265 return;
266 }
267 }
268 }
269
270 static int
271 ms_bmask(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
272 {
273 static char modebuf[BUFSIZE];
274 static char parabuf[BUFSIZE];
275 struct Channel *chptr;
276 rb_dlink_list *banlist;
277 char *s, *forward;
278 char *t;
279 char *mbuf;
280 char *pbuf;
281 long mode_type;
282 int mlen;
283 int plen = 0;
284 int tlen;
285 int arglen;
286 int modecount = 0;
287 int needcap = NOCAPS;
288 int mems;
289 struct Client *fakesource_p;
290
291 if(!IsChanPrefix(parv[2][0]) || !check_channel_name(parv[2]))
292 return 0;
293
294 if((chptr = find_channel(parv[2])) == NULL)
295 return 0;
296
297 /* TS is higher, drop it. */
298 if(atol(parv[1]) > chptr->channelts)
299 return 0;
300
301 switch (parv[3][0])
302 {
303 case 'b':
304 banlist = &chptr->banlist;
305 mode_type = CHFL_BAN;
306 mems = ALL_MEMBERS;
307 break;
308
309 case 'e':
310 banlist = &chptr->exceptlist;
311 mode_type = CHFL_EXCEPTION;
312 needcap = CAP_EX;
313 mems = ONLY_CHANOPS;
314 break;
315
316 case 'I':
317 banlist = &chptr->invexlist;
318 mode_type = CHFL_INVEX;
319 needcap = CAP_IE;
320 mems = ONLY_CHANOPS;
321 break;
322
323 case 'q':
324 banlist = &chptr->quietlist;
325 mode_type = CHFL_QUIET;
326 mems = ALL_MEMBERS;
327 break;
328
329 /* maybe we should just blindly propagate this? */
330 default:
331 return 0;
332 }
333
334 parabuf[0] = '\0';
335 s = LOCAL_COPY(parv[4]);
336
337 /* Hide connecting server on netburst -- jilles */
338 if (ConfigServerHide.flatten_links && !HasSentEob(source_p))
339 fakesource_p = &me;
340 else
341 fakesource_p = source_p;
342 mlen = sprintf(modebuf, ":%s MODE %s +", fakesource_p->name, chptr->chname);
343 mbuf = modebuf + mlen;
344 pbuf = parabuf;
345
346 while(*s == ' ')
347 s++;
348
349 /* next char isnt a space, point t to the next one */
350 if((t = strchr(s, ' ')) != NULL)
351 {
352 *t++ = '\0';
353
354 /* double spaces will break the parser */
355 while(*t == ' ')
356 t++;
357 }
358
359 /* couldve skipped spaces and got nothing.. */
360 while(!EmptyString(s))
361 {
362 /* ban with a leading ':' -- this will break the protocol */
363 if(*s == ':')
364 goto nextban;
365
366 tlen = strlen(s);
367
368 /* I dont even want to begin parsing this.. */
369 if(tlen > MODEBUFLEN)
370 break;
371
372 if((forward = strchr(s+1, '$')) != NULL)
373 {
374 *forward++ = '\0';
375 if(*forward == '\0')
376 tlen--, forward = NULL;
377 else
378 possibly_remove_lower_forward(fakesource_p,
379 mems, chptr, banlist,
380 parv[3][0], s, forward);
381 }
382
383 if(add_id(fakesource_p, chptr, s, forward, banlist, mode_type))
384 {
385 /* this new one wont fit.. */
386 if(mlen + MAXMODEPARAMS + plen + tlen > BUFSIZE - 5 ||
387 modecount >= MAXMODEPARAMS)
388 {
389 *mbuf = '\0';
390 *(pbuf - 1) = '\0';
391 sendto_channel_local(mems, chptr, "%s %s", modebuf, parabuf);
392
393 mbuf = modebuf + mlen;
394 pbuf = parabuf;
395 plen = modecount = 0;
396 }
397
398 if (forward != NULL)
399 forward[-1] = '$';
400
401 *mbuf++ = parv[3][0];
402 arglen = sprintf(pbuf, "%s ", s);
403 pbuf += arglen;
404 plen += arglen;
405 modecount++;
406 }
407
408 nextban:
409 s = t;
410
411 if(s != NULL)
412 {
413 if((t = strchr(s, ' ')) != NULL)
414 {
415 *t++ = '\0';
416
417 while(*t == ' ')
418 t++;
419 }
420 }
421 }
422
423 if(modecount)
424 {
425 *mbuf = '\0';
426 *(pbuf - 1) = '\0';
427 sendto_channel_local(mems, chptr, "%s %s", modebuf, parabuf);
428 }
429
430 sendto_server(client_p, chptr, CAP_TS6 | needcap, NOCAPS, ":%s BMASK %ld %s %s :%s",
431 source_p->id, (long) chptr->channelts, chptr->chname, parv[3], parv[4]);
432 return 0;
433 }