]> jfr.im git - irc/rqf/shadowircd.git/blame - modules/core/m_mode.c
[svn] Merge old trunk r2081:
[irc/rqf/shadowircd.git] / modules / core / m_mode.c
CommitLineData
212380e3 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 * $Id: m_mode.c 1006 2006-03-09 15:32:14Z nenolod $
25 */
26
27#include "stdinc.h"
28#include "tools.h"
29#include "balloc.h"
30#include "channel.h"
31#include "client.h"
32#include "hash.h"
33#include "irc_string.h"
34#include "ircd.h"
35#include "numeric.h"
36#include "s_user.h"
37#include "s_conf.h"
38#include "s_serv.h"
39#include "s_log.h"
40#include "send.h"
41#include "msg.h"
42#include "parse.h"
43#include "modules.h"
44#include "packet.h"
45#include "sprintf_irc.h"
46#include "s_newconf.h"
47
48static int m_mode(struct Client *, struct Client *, int, const char **);
49static int ms_mode(struct Client *, struct Client *, int, const char **);
50static int ms_tmode(struct Client *, struct Client *, int, const char **);
51static int ms_bmask(struct Client *, struct Client *, int, const char **);
52
53struct Message mode_msgtab = {
54 "MODE", 0, 0, 0, MFLG_SLOW,
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, MFLG_SLOW,
59 {mg_ignore, mg_ignore, {ms_tmode, 4}, {ms_tmode, 4}, mg_ignore, mg_ignore}
60};
61struct Message bmask_msgtab = {
62 "BMASK", 0, 0, 0, MFLG_SLOW,
63 {mg_ignore, mg_ignore, mg_ignore, {ms_bmask, 5}, mg_ignore, mg_ignore}
64};
65
66mapi_clist_av1 mode_clist[] = { &mode_msgtab, &tmode_msgtab, &bmask_msgtab, NULL };
67
68DECLARE_MODULE_AV1(mode, NULL, NULL, mode_clist, NULL, NULL, "$Revision: 1006 $");
69
70/*
71 * m_mode - MODE command handler
72 * parv[0] - sender
73 * parv[1] - channel
74 */
75static int
76m_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 if(is_deop(msptr))
140 return 0;
141
142 /* Finish the flood grace period... */
143 if(MyClient(source_p) && !IsFloodDone(source_p))
144 {
145 if(!((parc == 3) && (parv[2][0] == 'b') && (parv[2][1] == '\0')))
146 flood_endgrace(source_p);
147 }
148
149 set_channel_mode(client_p, source_p, chptr, msptr, parc - n, parv + n);
150 }
151
152 return 0;
153}
154
155static int
156ms_mode(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
157{
158 struct Channel *chptr;
159
160 chptr = find_channel(parv[1]);
161
162 if(chptr == NULL)
163 {
164 sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
165 form_str(ERR_NOSUCHCHANNEL), parv[1]);
166 return 0;
167 }
168
169 set_channel_mode(client_p, source_p, chptr, NULL, parc - 2, parv + 2);
170
171 return 0;
172}
173
174static int
175ms_tmode(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
176{
177 struct Channel *chptr = NULL;
178 struct membership *msptr;
179
180 /* Now, try to find the channel in question */
181 if(!IsChanPrefix(parv[2][0]) || !check_channel_name(parv[2]))
182 {
183 sendto_one_numeric(source_p, ERR_BADCHANNAME, form_str(ERR_BADCHANNAME), parv[2]);
184 return 0;
185 }
186
187 chptr = find_channel(parv[2]);
188
189 if(chptr == NULL)
190 {
191 sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
192 form_str(ERR_NOSUCHCHANNEL), parv[2]);
193 return 0;
194 }
195
196 /* TS is higher, drop it. */
197 if(atol(parv[1]) > chptr->channelts)
198 return 0;
199
200 if(IsServer(source_p))
201 {
202 set_channel_mode(client_p, source_p, chptr, NULL, parc - 3, parv + 3);
203 }
204 else
205 {
206 msptr = find_channel_membership(chptr, source_p);
207
208 /* this can still happen on a mixed ts network. */
209 if(is_deop(msptr))
210 return 0;
211
212 set_channel_mode(client_p, source_p, chptr, msptr, parc - 3, parv + 3);
213 }
214
215 return 0;
216}
217
218static int
219ms_bmask(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
220{
221 static char modebuf[BUFSIZE];
222 static char parabuf[BUFSIZE];
223 struct Channel *chptr;
224 dlink_list *banlist;
225 const char *s;
226 char *t;
227 char *mbuf;
228 char *pbuf;
229 long mode_type;
230 int mlen;
231 int plen = 0;
232 int tlen;
233 int arglen;
234 int modecount = 0;
235 int needcap = NOCAPS;
236 int mems;
237 struct Client *fakesource_p;
238
239 if(!IsChanPrefix(parv[2][0]) || !check_channel_name(parv[2]))
240 return 0;
241
242 if((chptr = find_channel(parv[2])) == NULL)
243 return 0;
244
245 /* TS is higher, drop it. */
246 if(atol(parv[1]) > chptr->channelts)
247 return 0;
248
249 switch (parv[3][0])
250 {
251 case 'b':
252 banlist = &chptr->banlist;
253 mode_type = CHFL_BAN;
254 mems = ALL_MEMBERS;
255 break;
256
257 case 'e':
258 banlist = &chptr->exceptlist;
259 mode_type = CHFL_EXCEPTION;
260 needcap = CAP_EX;
261 mems = ONLY_CHANOPS;
262 break;
263
264 case 'I':
265 banlist = &chptr->invexlist;
266 mode_type = CHFL_INVEX;
267 needcap = CAP_IE;
268 mems = ONLY_CHANOPS;
269 break;
270
271 case 'q':
272 banlist = &chptr->quietlist;
273 mode_type = CHFL_QUIET;
274 mems = ALL_MEMBERS;
275 break;
276
277 /* maybe we should just blindly propagate this? */
278 default:
279 return 0;
280 }
281
282 parabuf[0] = '\0';
283 s = LOCAL_COPY(parv[4]);
284
285 /* Hide connecting server on netburst -- jilles */
286 if (ConfigServerHide.flatten_links && !HasSentEob(source_p))
287 fakesource_p = &me;
288 else
289 fakesource_p = source_p;
290 mlen = ircsprintf(modebuf, ":%s MODE %s +", fakesource_p->name, chptr->chname);
291 mbuf = modebuf + mlen;
292 pbuf = parabuf;
293
294 while(*s == ' ')
295 s++;
296
297 /* next char isnt a space, point t to the next one */
298 if((t = strchr(s, ' ')) != NULL)
299 {
300 *t++ = '\0';
301
302 /* double spaces will break the parser */
303 while(*t == ' ')
304 t++;
305 }
306
307 /* couldve skipped spaces and got nothing.. */
308 while(!EmptyString(s))
309 {
310 /* ban with a leading ':' -- this will break the protocol */
311 if(*s == ':')
312 goto nextban;
313
314 tlen = strlen(s);
315
316 /* I dont even want to begin parsing this.. */
317 if(tlen > MODEBUFLEN)
318 break;
319
320 if(add_id(fakesource_p, chptr, s, banlist, mode_type))
321 {
322 /* this new one wont fit.. */
323 if(mlen + MAXMODEPARAMS + plen + tlen > BUFSIZE - 5 ||
324 modecount >= MAXMODEPARAMS)
325 {
326 *mbuf = '\0';
327 *(pbuf - 1) = '\0';
328 sendto_channel_local(mems, chptr, "%s %s", modebuf, parabuf);
329 sendto_server(client_p, chptr, needcap, CAP_TS6,
330 "%s %s", modebuf, parabuf);
331
332 mbuf = modebuf + mlen;
333 pbuf = parabuf;
334 plen = modecount = 0;
335 }
336
337 *mbuf++ = parv[3][0];
338 arglen = ircsprintf(pbuf, "%s ", s);
339 pbuf += arglen;
340 plen += arglen;
341 modecount++;
342 }
343
344 nextban:
345 s = t;
346
347 if(s != NULL)
348 {
349 if((t = strchr(s, ' ')) != NULL)
350 {
351 *t++ = '\0';
352
353 while(*t == ' ')
354 t++;
355 }
356 }
357 }
358
359 if(modecount)
360 {
361 *mbuf = '\0';
362 *(pbuf - 1) = '\0';
363 sendto_channel_local(mems, chptr, "%s %s", modebuf, parabuf);
364 sendto_server(client_p, chptr, needcap, CAP_TS6, "%s %s", modebuf, parabuf);
365 }
366
367 sendto_server(client_p, chptr, CAP_TS6 | needcap, NOCAPS, ":%s BMASK %ld %s %s :%s",
368 source_p->id, (long) chptr->channelts, chptr->chname, parv[3], parv[4]);
369 return 0;
370}
371