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