ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/channel_mode.c
Revision: 9387
Committed: Sun May 10 09:46:21 2020 UTC (5 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 28789 byte(s)
Log Message:
- Style corrections

File Contents

# User Rev Content
1 adx 30 /*
2 michael 2916 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 adx 30 *
4 michael 9101 * Copyright (c) 1997-2020 ircd-hybrid development team
5 adx 30 *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18 michael 4565 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 adx 30 * USA
20     */
21    
22 michael 2916 /*! \file channel_mode.c
23     * \brief Controls modes on channels.
24     * \version $Id$
25     */
26    
27 adx 30 #include "stdinc.h"
28 michael 1011 #include "list.h"
29 adx 30 #include "channel.h"
30     #include "channel_mode.h"
31     #include "client.h"
32 michael 1632 #include "conf.h"
33 michael 371 #include "hostmask.h"
34 adx 30 #include "irc_string.h"
35     #include "ircd.h"
36     #include "numeric.h"
37 michael 3347 #include "server.h"
38 adx 30 #include "send.h"
39     #include "memory.h"
40 michael 1243 #include "parse.h"
41 michael 9234 #include "extban.h"
42 adx 30
43    
44     static struct ChModeChange mode_changes[IRCD_BUFSIZE];
45 michael 3057 static unsigned int mode_count;
46     static unsigned int mode_limit; /* number of modes set other than simple */
47     static unsigned int simple_modes_mask; /* bit mask of simple modes already set */
48 adx 30
49    
50     /* check_string()
51     *
52     * inputs - string to check
53     * output - pointer to modified string
54     * side effects - Fixes a string so that the first white space found
55     * becomes an end of string marker (`\0`).
56     * returns the 'fixed' string or "*" if the string
57     * was NULL length or a NULL pointer.
58     */
59 michael 9234 static void
60 adx 30 check_string(char *s)
61     {
62 michael 9234 char *str = s;
63 adx 30
64 michael 9234 assert(s);
65 adx 30
66     for (; *s; ++s)
67     {
68     if (IsSpace(*s))
69     {
70     *s = '\0';
71     break;
72     }
73     }
74    
75 michael 9234 if (EmptyString(str))
76     strcpy(str, "*");
77 adx 30 }
78    
79 michael 9234 static const char *
80     get_mask(const struct Ban *ban)
81     {
82     static char buf[MODEBUFLEN];
83     const unsigned int i = extban_format(ban->extban, buf);
84    
85     assert(i <= sizeof(buf));
86    
87     /* Matching extbans only use ban->host */
88     if (ban->extban & extban_matching_mask())
89     strlcpy(buf + i, ban->host, sizeof(buf) - i);
90     else
91     snprintf(buf + i, sizeof(buf) - i, "%s!%s@%s", ban->name, ban->user, ban->host);
92    
93     return buf;
94     }
95    
96 adx 30 /*
97 michael 5583 * Ban functions to work with mode +b/e/I
98 adx 30 */
99 michael 2892 /* add the specified ID to the channel.
100     * -is 8/9/00
101 adx 30 */
102    
103 michael 9234 const char *
104 michael 9250 add_id(struct Client *client, struct Channel *channel, const char *banid, dlink_list *list, unsigned int type)
105 adx 30 {
106 michael 7797 dlink_node *node;
107 michael 9234 char mask[MODEBUFLEN];
108     char *maskptr = mask;
109     unsigned int extbans, offset;
110 adx 30
111 michael 9234 strlcpy(mask, banid, sizeof(mask));
112    
113 michael 9250 if (MyClient(client))
114 adx 30 {
115 michael 9081 unsigned int num_mask = dlink_list_length(&channel->banlist) +
116     dlink_list_length(&channel->exceptlist) +
117     dlink_list_length(&channel->invexlist);
118 adx 30
119 michael 8046 /* Don't let local clients overflow the b/e/I lists */
120 michael 9081 if (num_mask >= ((HasCMode(channel, MODE_EXTLIMIT)) ? ConfigChannel.max_bans_large :
121 michael 9234 ConfigChannel.max_bans))
122 adx 30 {
123 michael 9250 sendto_one_numeric(client, &me, ERR_BANLISTFULL, channel->name, banid);
124 michael 8658 return false;
125 adx 30 }
126    
127 michael 9234 collapse(mask);
128 adx 30 }
129    
130 michael 9234 enum extban_type etype = extban_parse(mask, &extbans, &offset);
131     maskptr += offset;
132 adx 30
133 michael 9250 if (MyClient(client))
134 michael 9234 {
135     if (etype == EXTBAN_INVALID)
136     {
137 michael 9250 sendto_one_numeric(client, &me, ERR_INVALIDBAN, channel->name, mask);
138 michael 9234 return NULL;
139     }
140 michael 593
141 michael 9234 if (etype != EXTBAN_NONE && ConfigChannel.enable_extbans == 0)
142     {
143 michael 9250 sendto_one_numeric(client, &me, ERR_INVALIDBAN, channel->name, mask);
144 michael 9234 return NULL;
145     }
146 michael 593
147 michael 9234 unsigned int extban_acting = extbans & extban_acting_mask();
148     if (extban_acting)
149     {
150     const struct Extban *extban = extban_find_flag(extban_acting);
151 adx 30
152 michael 9234 if (extban == NULL || !(extban->types & type))
153     {
154 michael 9250 sendto_one_numeric(client, &me, ERR_INVALIDBAN, channel->name, mask);
155 michael 9234 return NULL;
156     }
157     }
158    
159     unsigned extban_matching = extbans & extban_matching_mask();
160     if (extban_matching)
161     {
162     const struct Extban *extban = extban_find_flag(extban_matching);
163    
164     if (extban == NULL || !(extban->types & type))
165     {
166 michael 9250 sendto_one_numeric(client, &me, ERR_INVALIDBAN, channel->name, mask);
167 michael 9234 return NULL;
168     }
169     }
170     }
171    
172     /* Don't allow empty bans */
173     if (EmptyString(maskptr))
174     return NULL;
175    
176     struct Ban *ban = xcalloc(sizeof(*ban));
177     ban->extban = extbans;
178     ban->when = event_base->time.sec_real;
179    
180     check_string(maskptr);
181    
182     if (etype == EXTBAN_MATCHING)
183     /* Matching extbans have their own format, don't try to parse it */
184     strlcpy(ban->host, maskptr, sizeof(ban->host));
185     else
186     {
187     struct split_nuh_item nuh;
188    
189     nuh.nuhmask = maskptr;
190     nuh.nickptr = ban->name;
191     nuh.userptr = ban->user;
192     nuh.hostptr = ban->host;
193    
194     nuh.nicksize = sizeof(ban->name);
195     nuh.usersize = sizeof(ban->user);
196     nuh.hostsize = sizeof(ban->host);
197    
198     split_nuh(&nuh);
199    
200     ban->type = parse_netmask(ban->host, &ban->addr, &ban->bits);
201     }
202    
203 michael 9250 if (MyClient(client))
204 michael 9234 ban->banstr_len = strlcpy(ban->banstr, get_mask(ban), sizeof(ban->banstr));
205     else
206 michael 9358 ban->banstr_len = strlcpy(ban->banstr, banid, sizeof(ban->banstr));
207 michael 9234
208 michael 4800 DLINK_FOREACH(node, list->head)
209 adx 30 {
210 michael 9234 const struct Ban *tmp = node->data;
211 michael 2892
212 michael 9234 if (irccmp(tmp->banstr, ban->banstr) == 0)
213     {
214     xfree(ban);
215     return NULL;
216     }
217 adx 30 }
218    
219 michael 9081 clear_ban_cache_list(&channel->members_local);
220 michael 8647
221 michael 9250 if (IsClient(client))
222     snprintf(ban->who, sizeof(ban->who), "%s!%s@%s", client->name,
223     client->username, client->host);
224     else if (IsHidden(client) || ConfigServerHide.hide_servers)
225 michael 5757 strlcpy(ban->who, me.name, sizeof(ban->who));
226 adx 30 else
227 michael 9250 strlcpy(ban->who, client->name, sizeof(ban->who));
228 adx 30
229 michael 4815 dlinkAdd(ban, &ban->node, list);
230 adx 30
231 michael 9234 return ban->banstr;
232 adx 30 }
233    
234     /*
235     * inputs - pointer to channel
236     * - pointer to ban id
237     * - type of ban, i.e. ban, exception, invex
238     * output - 0 for failure, 1 for success
239     * side effects -
240     */
241 michael 9234 static const char *
242 michael 9250 del_id(struct Client *client, struct Channel *channel, const char *banid, dlink_list *list, unsigned int type)
243 adx 30 {
244 michael 9234 static char mask[MODEBUFLEN];
245 michael 7797 dlink_node *node;
246 michael 2892 assert(banid);
247 adx 30
248 michael 9234 /* TBD: n!u@h formatting fo local clients */
249 adx 30
250 michael 4800 DLINK_FOREACH(node, list->head)
251 adx 30 {
252 michael 4815 struct Ban *ban = node->data;
253 adx 30
254 michael 9234 if (irccmp(banid, ban->banstr) == 0)
255 adx 30 {
256 michael 9234 strlcpy(mask, ban->banstr, sizeof(mask)); /* caSe might be different in 'banid' */
257 michael 9081 clear_ban_cache_list(&channel->members_local);
258 michael 4815 remove_ban(ban, list);
259 michael 9234
260     return mask;
261 adx 30 }
262     }
263    
264 michael 9234 return NULL;
265 adx 30 }
266    
267     /* channel_modes()
268     *
269     * inputs - pointer to channel
270     * - pointer to client
271     * - pointer to mode buf
272     * - pointer to parameter buf
273     * output - NONE
274     * side effects - write the "simple" list of channel modes for channel
275 michael 9081 * channel onto buffer mbuf with the parameters in pbuf.
276 adx 30 */
277     void
278 michael 9250 channel_modes(const struct Channel *channel, const struct Client *client, char *mbuf, char *pbuf)
279 adx 30 {
280     *mbuf++ = '+';
281     *pbuf = '\0';
282    
283 michael 8227 for (const struct chan_mode *tab = cmode_tab; tab->letter; ++tab)
284 michael 9081 if (tab->mode && HasCMode(channel, tab->mode))
285 michael 1175 *mbuf++ = tab->letter;
286 adx 30
287 michael 9081 if (channel->mode.limit)
288 adx 30 {
289     *mbuf++ = 'l';
290    
291 michael 9250 if (IsServer(client) || IsMember(client, channel))
292 michael 9081 pbuf += sprintf(pbuf, "%u ", channel->mode.limit);
293 adx 30 }
294    
295 michael 9081 if (channel->mode.key[0])
296 adx 30 {
297     *mbuf++ = 'k';
298    
299 michael 9250 if (IsServer(client) || IsMember(client, channel))
300 michael 9081 sprintf(pbuf, "%s ", channel->mode.key);
301 adx 30 }
302    
303     *mbuf = '\0';
304     }
305    
306     /* fix_key()
307 michael 2892 *
308 adx 30 * inputs - pointer to key to clean up
309     * output - pointer to cleaned up key
310     * side effects - input string is modified
311     *
312     * stolen from Undernet's ircd -orabidoo
313     */
314     static char *
315     fix_key(char *arg)
316     {
317 michael 9387 unsigned char *s = (unsigned char *)arg;
318     unsigned char *t = (unsigned char *)arg;
319 adx 30
320 michael 9387 for (unsigned char c; (c = *s) && s - (unsigned char *)arg < KEYLEN; ++s)
321 adx 30 {
322     c &= 0x7f;
323 michael 2892
324 adx 30 if (c != ':' && c > ' ' && c != ',')
325     *t++ = c;
326     }
327    
328     *t = '\0';
329 michael 2892 return arg;
330 adx 30 }
331    
332 michael 3149 /*
333     * inputs - pointer to channel
334     * output - none
335     * side effects - clear ban cache
336     */
337     void
338 michael 7764 clear_ban_cache_list(dlink_list *list)
339 michael 3149 {
340 michael 7764 dlink_node *node;
341 michael 3149
342 michael 7764 DLINK_FOREACH(node, list->head)
343 michael 3149 {
344 michael 9081 struct ChannelMember *member = node->data;
345 michael 9234 member->flags &= ~(CHFL_BAN_SILENCED | CHFL_BAN_CHECKED | CHFL_MUTE_CHECKED);
346 michael 3149 }
347     }
348    
349 michael 3634 /*
350 michael 8431 * Bitmasks for various error returns that channel_mode_set should only return
351 adx 30 * once per call -orabidoo
352     */
353 michael 3634 enum
354     {
355     SM_ERR_NOOPS = 1 << 0, /* No chan ops */
356     SM_ERR_UNKNOWN = 1 << 1,
357     SM_ERR_RPL_B = 1 << 2,
358     SM_ERR_RPL_E = 1 << 3,
359     SM_ERR_RPL_I = 1 << 4,
360     SM_ERR_NOTONCHANNEL = 1 << 5, /* Client is not on channel */
361 michael 8051 SM_ERR_NOTOPER = 1 << 6, /* Only irc-operators can change that mode */
362     SM_ERR_ONLYSERVER = 1 << 7 /* Only servers or services can change that mode */
363 michael 3634 };
364 adx 30
365     /* Mode functions handle mode changes for a particular mode... */
366     static void
367 michael 9250 chm_nosuch(struct Client *client, struct Channel *channel, int parc, int *parn, char **parv,
368 michael 8095 int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
369 adx 30 {
370     if (*errors & SM_ERR_UNKNOWN)
371     return;
372    
373     *errors |= SM_ERR_UNKNOWN;
374 michael 9250 sendto_one_numeric(client, &me, ERR_UNKNOWNMODE, c);
375 adx 30 }
376    
377     static void
378 michael 9250 chm_simple(struct Client *client, struct Channel *channel, int parc, int *parn, char **parv,
379 michael 8095 int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
380 adx 30 {
381 michael 8091 if (mode->only_opers)
382 adx 30 {
383 michael 9250 if (MyClient(client) && !HasUMode(client, UMODE_OPER))
384 michael 8091 {
385     if (!(*errors & SM_ERR_NOTOPER))
386 michael 9250 sendto_one_numeric(client, &me, ERR_NOPRIVILEGES);
387 michael 4884
388 michael 8091 *errors |= SM_ERR_NOTOPER;
389     return;
390     }
391 adx 30 }
392    
393 michael 8091 if (mode->only_servers)
394 adx 30 {
395 michael 9250 if (!IsServer(client) && !HasFlag(client, FLAGS_SERVICE))
396 michael 8091 {
397     if (!(*errors & SM_ERR_ONLYSERVER))
398 michael 9250 sendto_one_numeric(client, &me,
399 michael 8091 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
400 michael 9081 ERR_ONLYSERVERSCANCHANGE, channel->name);
401 adx 30
402 michael 8091 *errors |= SM_ERR_ONLYSERVER;
403     return;
404     }
405 adx 30 }
406    
407 michael 8649 if (alev < mode->required_oplevel)
408 michael 1150 {
409     if (!(*errors & SM_ERR_NOOPS))
410 michael 9250 sendto_one_numeric(client, &me,
411 michael 3109 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
412 michael 9081 ERR_CHANOPRIVSNEEDED, channel->name);
413 michael 3648
414 michael 1150 *errors |= SM_ERR_NOOPS;
415     return;
416     }
417 michael 3648
418 michael 1150 /* If have already dealt with this simple mode, ignore it */
419 michael 8091 if (simple_modes_mask & mode->mode)
420 michael 1150 return;
421    
422 michael 8091 simple_modes_mask |= mode->mode;
423 michael 1150
424 michael 8097 if (dir == MODE_ADD) /* setting + */
425 michael 1150 {
426 michael 9250 if (MyClient(client) && HasCMode(channel, mode->mode))
427 michael 8097 return;
428    
429 michael 9081 AddCMode(channel, mode->mode);
430 michael 1150 }
431 michael 8097 else if (dir == MODE_DEL) /* setting - */
432 michael 1150 {
433 michael 9250 if (MyClient(client) && !HasCMode(channel, mode->mode))
434 michael 8097 return;
435    
436 michael 9081 DelCMode(channel, mode->mode);
437 michael 8097 }
438 michael 1150
439 michael 8097 mode_changes[mode_count].letter = mode->letter;
440     mode_changes[mode_count].arg = NULL;
441     mode_changes[mode_count].id = NULL;
442     mode_changes[mode_count].flags = 0;
443     mode_changes[mode_count++].dir = dir;
444 michael 1150 }
445    
446     static void
447 michael 9250 chm_mask(struct Client *client, struct Channel *channel, int parc, int *parn, char **parv,
448 michael 8646 int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
449 adx 30 {
450 michael 9234 const char *ret = NULL;
451 michael 8646 dlink_list *list;
452     enum irc_numerics rpl_list = 0, rpl_endlist = 0;
453     int errtype = 0;
454 adx 30
455 michael 8646 switch (mode->flag)
456 adx 30 {
457 michael 8646 case CHFL_BAN:
458     errtype = SM_ERR_RPL_B;
459 michael 9081 list = &channel->banlist;
460 michael 8646 rpl_list = RPL_BANLIST;
461     rpl_endlist = RPL_ENDOFBANLIST;
462     break;
463     case CHFL_EXCEPTION:
464     errtype = SM_ERR_RPL_E;
465 michael 9081 list = &channel->exceptlist;
466 michael 8646 rpl_list = RPL_EXCEPTLIST;
467     rpl_endlist = RPL_ENDOFEXCEPTLIST;
468     break;
469     case CHFL_INVEX:
470     errtype = SM_ERR_RPL_I;
471 michael 9081 list = &channel->invexlist;
472 michael 8646 rpl_list = RPL_INVEXLIST;
473     rpl_endlist = RPL_ENDOFINVEXLIST;
474     break;
475     default:
476     list = NULL; /* Let it crash */
477 adx 30 }
478    
479     if (dir == MODE_QUERY || parc <= *parn)
480     {
481 michael 7797 dlink_node *node;
482 adx 30
483 michael 8646 if (*errors & errtype)
484 adx 30 return;
485    
486 michael 8646 *errors |= errtype;
487 adx 30
488 michael 8646 DLINK_FOREACH(node, list->head)
489 adx 30 {
490 michael 4815 const struct Ban *ban = node->data;
491 michael 8040
492 michael 9081 if (!HasCMode(channel, MODE_HIDEBMASKS) || alev >= mode->required_oplevel)
493 michael 9250 sendto_one_numeric(client, &me, rpl_list, channel->name,
494 michael 9234 ban->banstr, ban->who, ban->when);
495 adx 30 }
496    
497 michael 9250 sendto_one_numeric(client, &me, rpl_endlist, channel->name);
498 adx 30 return;
499     }
500    
501 michael 8646 if (alev < mode->required_oplevel)
502 michael 3841 {
503     if (!(*errors & SM_ERR_NOOPS))
504 michael 9250 sendto_one_numeric(client, &me,
505 michael 3841 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
506 michael 9081 ERR_CHANOPRIVSNEEDED, channel->name);
507 michael 4884
508 michael 3841 *errors |= SM_ERR_NOOPS;
509     return;
510     }
511    
512 michael 9250 if (MyClient(client) && (++mode_limit > MAXMODEPARAMS))
513 adx 30 return;
514    
515 michael 9234 char *mask = parv[*parn];
516 michael 4791 ++(*parn);
517 adx 30
518 michael 9250 if (*mask == ':' || (!MyConnect(client) && strchr(mask, ' ')))
519 michael 5031 return;
520 adx 30
521 michael 8160 if (dir == MODE_ADD) /* setting + */
522 adx 30 {
523 michael 9250 ret = add_id(client, channel, mask, list, mode->flag);
524 michael 9234 if (ret == NULL)
525 michael 8160 return;
526 adx 30 }
527 michael 8160 else if (dir == MODE_DEL) /* setting - */
528     {
529 michael 9250 ret = del_id(client, channel, mask, list, mode->flag);
530 michael 9234 if (ret == NULL)
531 michael 8160 return;
532     }
533 adx 30
534 michael 9234 static char buf[MAXPARA][MODEBUFLEN];
535     mask = buf[(*parn) - 1];
536     strlcpy(mask, ret, sizeof(buf[(*parn) - 1]));
537    
538 michael 8091 mode_changes[mode_count].letter = mode->letter;
539 michael 9234 mode_changes[mode_count].arg = mask; /* At this point 'mask' is no longer than MODEBUFLEN */
540 michael 3734 mode_changes[mode_count].id = NULL;
541 michael 9081 if (HasCMode(channel, MODE_HIDEBMASKS))
542 michael 8040 mode_changes[mode_count].flags = CHFL_CHANOP | CHFL_HALFOP;
543     else
544     mode_changes[mode_count].flags = 0;
545 michael 4799 mode_changes[mode_count++].dir = dir;
546 adx 30 }
547    
548     static void
549 michael 9250 chm_flag(struct Client *client, struct Channel *channel, int parc, int *parn, char **parv,
550 michael 8640 int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
551 adx 30 {
552 michael 8640 if (alev < mode->required_oplevel)
553 adx 30 {
554     if (!(*errors & SM_ERR_NOOPS))
555 michael 9250 sendto_one_numeric(client, &me,
556 michael 3109 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
557 michael 9081 ERR_CHANOPRIVSNEEDED, channel->name);
558 michael 4884
559 adx 30 *errors |= SM_ERR_NOOPS;
560     return;
561     }
562    
563 michael 3671 if (dir == MODE_QUERY || parc <= *parn)
564 adx 30 return;
565    
566 michael 9250 struct Client *client_target = find_chasing(client, parv[(*parn)++]);
567     if (client_target == NULL)
568 michael 3737 return; /* find_chasing sends ERR_NOSUCHNICK */
569 adx 30
570 michael 9250 struct ChannelMember *member = find_channel_link(client_target, channel);
571     if (member == NULL)
572 adx 30 {
573     if (!(*errors & SM_ERR_NOTONCHANNEL))
574 michael 9250 sendto_one_numeric(client, &me, ERR_USERNOTINCHANNEL, client_target->name, channel->name);
575 michael 4884
576 adx 30 *errors |= SM_ERR_NOTONCHANNEL;
577     return;
578     }
579    
580 michael 9250 if (MyClient(client) && (++mode_limit > MAXMODEPARAMS))
581 adx 30 return;
582    
583 michael 8160 if (dir == MODE_ADD) /* setting + */
584 michael 6930 {
585 michael 8640 if (has_member_flags(member, mode->flag))
586 michael 8160 return; /* No redundant mode changes */
587 michael 4884
588 michael 8640 AddMemberFlag(member, mode->flag);
589 michael 8160 }
590     else if (dir == MODE_DEL) /* setting - */
591     {
592 michael 8640 if (has_member_flags(member, mode->flag) == 0)
593 michael 8160 return; /* No redundant mode changes */
594 adx 30
595 michael 8640 DelMemberFlag(member, mode->flag);
596 michael 6930 }
597    
598 michael 8091 mode_changes[mode_count].letter = mode->letter;
599 michael 9250 mode_changes[mode_count].arg = client_target->name;
600     mode_changes[mode_count].id = client_target->id;
601 michael 8040 mode_changes[mode_count].flags = 0;
602 michael 4799 mode_changes[mode_count++].dir = dir;
603 adx 30 }
604    
605     static void
606 michael 9250 chm_limit(struct Client *client, struct Channel *channel, int parc, int *parn, char **parv,
607 michael 8095 int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
608 adx 30 {
609 michael 8649 if (alev < mode->required_oplevel)
610 adx 30 {
611     if (!(*errors & SM_ERR_NOOPS))
612 michael 9250 sendto_one_numeric(client, &me,
613 michael 3109 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
614 michael 9081 ERR_CHANOPRIVSNEEDED, channel->name);
615 adx 30 *errors |= SM_ERR_NOOPS;
616     return;
617     }
618    
619     if (dir == MODE_QUERY)
620     return;
621    
622 michael 3671 if (dir == MODE_ADD && parc > *parn)
623 adx 30 {
624 michael 4833 char *const lstr = parv[(*parn)++];
625 michael 6947 int limit = 0;
626 adx 30
627 michael 3153 if (EmptyString(lstr) || (limit = atoi(lstr)) <= 0)
628 adx 30 return;
629    
630 michael 1793 sprintf(lstr, "%d", limit);
631 adx 30
632 michael 3151 /* If somebody sets MODE #channel +ll 1 2, accept latter --fl */
633 michael 3671 for (unsigned int i = 0; i < mode_count; ++i)
634 michael 8091 if (mode_changes[i].letter == mode->letter && mode_changes[i].dir == MODE_ADD)
635 adx 30 mode_changes[i].letter = 0;
636    
637 michael 8091 mode_changes[mode_count].letter = mode->letter;
638 michael 3734 mode_changes[mode_count].arg = lstr;
639 adx 30 mode_changes[mode_count].id = NULL;
640 michael 8040 mode_changes[mode_count].flags = 0;
641 michael 4799 mode_changes[mode_count++].dir = dir;
642 adx 30
643 michael 9081 channel->mode.limit = limit;
644 adx 30 }
645     else if (dir == MODE_DEL)
646     {
647 michael 9081 if (channel->mode.limit == 0)
648 adx 30 return;
649    
650 michael 9081 channel->mode.limit = 0;
651 adx 30
652 michael 8091 mode_changes[mode_count].letter = mode->letter;
653 michael 3734 mode_changes[mode_count].arg = NULL;
654 adx 30 mode_changes[mode_count].id = NULL;
655 michael 8040 mode_changes[mode_count].flags = 0;
656 michael 4799 mode_changes[mode_count++].dir = dir;
657 adx 30 }
658     }
659    
660     static void
661 michael 9250 chm_key(struct Client *client, struct Channel *channel, int parc, int *parn, char **parv,
662 michael 8095 int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
663 adx 30 {
664 michael 8649 if (alev < mode->required_oplevel)
665 adx 30 {
666     if (!(*errors & SM_ERR_NOOPS))
667 michael 9250 sendto_one_numeric(client, &me,
668 michael 3109 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
669 michael 9081 ERR_CHANOPRIVSNEEDED, channel->name);
670 adx 30 *errors |= SM_ERR_NOOPS;
671     return;
672     }
673    
674     if (dir == MODE_QUERY)
675     return;
676    
677 michael 3671 if (dir == MODE_ADD && parc > *parn)
678 adx 30 {
679 michael 4833 char *const key = fix_key(parv[(*parn)++]);
680 adx 30
681 michael 3153 if (EmptyString(key))
682 adx 30 return;
683    
684     assert(key[0] != ' ');
685 michael 9081 strlcpy(channel->mode.key, key, sizeof(channel->mode.key));
686 adx 30
687 michael 3151 /* If somebody does MODE #channel +kk a b, accept latter --fl */
688 michael 3671 for (unsigned int i = 0; i < mode_count; ++i)
689 michael 8091 if (mode_changes[i].letter == mode->letter && mode_changes[i].dir == MODE_ADD)
690 adx 30 mode_changes[i].letter = 0;
691    
692 michael 8091 mode_changes[mode_count].letter = mode->letter;
693 michael 8022 mode_changes[mode_count].arg = key;
694 adx 30 mode_changes[mode_count].id = NULL;
695 michael 8040 mode_changes[mode_count].flags = 0;
696 michael 4799 mode_changes[mode_count++].dir = dir;
697 adx 30 }
698     else if (dir == MODE_DEL)
699     {
700     if (parc > *parn)
701 michael 4791 ++(*parn);
702 adx 30
703 michael 9081 if (channel->mode.key[0] == '\0')
704 adx 30 return;
705    
706 michael 9081 channel->mode.key[0] = '\0';
707 adx 30
708 michael 8091 mode_changes[mode_count].letter = mode->letter;
709 michael 3734 mode_changes[mode_count].arg = "*";
710 adx 30 mode_changes[mode_count].id = NULL;
711 michael 8040 mode_changes[mode_count].flags = 0;
712 michael 4799 mode_changes[mode_count++].dir = dir;
713 adx 30 }
714     }
715    
716     /* get_channel_access()
717     *
718     * inputs - pointer to Client struct
719     * - pointer to Membership struct
720     * output - CHACCESS_CHANOP if we should let them have
721     * chanop level access, 0 for peon level access.
722     * side effects - NONE
723     */
724     static int
725 michael 9250 get_channel_access(const struct Client *client,
726 michael 9081 const struct ChannelMember *member)
727 adx 30 {
728     /* Let hacked servers in for now... */
729 michael 9250 if (!MyClient(client))
730 michael 4102 return CHACCESS_REMOTE;
731 adx 30
732 michael 8620 if (member == NULL)
733 adx 30 return CHACCESS_NOTONCHAN;
734    
735 michael 3374 /* Just to be sure.. */
736 michael 9250 assert(client == member->client);
737 adx 30
738     if (has_member_flags(member, CHFL_CHANOP))
739     return CHACCESS_CHANOP;
740    
741     if (has_member_flags(member, CHFL_HALFOP))
742     return CHACCESS_HALFOP;
743    
744     return CHACCESS_PEON;
745     }
746    
747 michael 3151 /* send_mode_changes_server()
748 michael 9250 * Input: the source client(client),
749 michael 9081 * the channel to send mode changes for(channel)
750 adx 30 * Output: None.
751 michael 3151 * Side-effects: Sends the appropriate mode changes to servers.
752 adx 30 *
753     */
754     static void
755 michael 9250 send_mode_changes_server(struct Client *client, struct Channel *channel)
756 adx 30 {
757 michael 8016 char modebuf[IRCD_BUFSIZE] = "";
758     char parabuf[IRCD_BUFSIZE] = "";
759     char *parptr = parabuf;
760 michael 8042 unsigned int mbl = 0, pbl = 0, arglen = 0, modecount = 0, paracount = 0;
761     unsigned int dir = MODE_QUERY;
762 adx 30
763 michael 8016 mbl = snprintf(modebuf, sizeof(modebuf), ":%s TMODE %ju %s ",
764 michael 9250 client->id, channel->creation_time, channel->name);
765 adx 30
766 michael 3374 /* Loop the list of modes we have */
767 michael 5545 for (unsigned int i = 0; i < mode_count; ++i)
768 adx 30 {
769 michael 3668 if (mode_changes[i].letter == 0)
770 adx 30 continue;
771    
772 michael 8016 const char *arg;
773 michael 3141 if (mode_changes[i].id)
774     arg = mode_changes[i].id;
775     else
776     arg = mode_changes[i].arg;
777 adx 30
778 michael 3215 if (arg)
779 michael 3141 arglen = strlen(arg);
780     else
781     arglen = 0;
782    
783 michael 3136 /*
784     * If we're creeping past the buf size, we need to send it and make
785 adx 30 * another line for the other modes
786     */
787 michael 8014 if ((paracount == MAXMODEPARAMS) ||
788 michael 8016 ((arglen + mbl + pbl + 2 /* +2 for /r/n */ ) > IRCD_BUFSIZE))
789 adx 30 {
790 michael 8014 if (modecount)
791 michael 9250 sendto_server(client, 0, 0, "%s %s", modebuf, parabuf);
792 michael 3215
793 michael 8014 modecount = 0;
794     paracount = 0;
795 adx 30
796 michael 8016 mbl = snprintf(modebuf, sizeof(modebuf), ":%s TMODE %ju %s ",
797 michael 9250 client->id, channel->creation_time, channel->name);
798 adx 30
799     pbl = 0;
800     parabuf[0] = '\0';
801     parptr = parabuf;
802     dir = MODE_QUERY;
803     }
804    
805     if (dir != mode_changes[i].dir)
806     {
807     modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
808     dir = mode_changes[i].dir;
809     }
810    
811     modebuf[mbl++] = mode_changes[i].letter;
812     modebuf[mbl] = '\0';
813 michael 8014 ++modecount;
814 adx 30
815 michael 3215 if (arg)
816 adx 30 {
817 michael 8016 int len = sprintf(parptr, (pbl == 0) ? "%s" : " %s", arg);
818 adx 30 pbl += len;
819     parptr += len;
820 michael 8014 ++paracount;
821 adx 30 }
822     }
823    
824 michael 8014 if (modecount)
825 michael 9250 sendto_server(client, 0, 0, "%s %s", modebuf, parabuf);
826 adx 30 }
827    
828 michael 9250 /* void send_mode_changes(struct Client *client,
829     * struct Client *client,
830 michael 9081 * struct Channel *channel)
831 michael 9250 * Input: The client sending(client), the source client(client),
832 michael 9081 * the channel to send mode changes for(channel),
833 adx 30 * mode change globals.
834     * Output: None.
835     * Side-effects: Sends the appropriate mode changes to other clients
836     * and propagates to servers.
837     */
838     static void
839 michael 9250 send_mode_changes_client(struct Client *client, struct Channel *channel)
840 adx 30 {
841 michael 8040 unsigned int flags = 0;
842 adx 30
843 michael 8040 for (unsigned int pass = 2; pass--; flags = CHFL_CHANOP | CHFL_HALFOP)
844 adx 30 {
845 michael 8040 char modebuf[IRCD_BUFSIZE] = "";
846     char parabuf[IRCD_BUFSIZE] = "";
847     char *parptr = parabuf;
848 michael 8042 unsigned int mbl = 0, pbl = 0, arglen = 0, modecount = 0, paracount = 0;
849     unsigned int dir = MODE_QUERY;
850 adx 30
851 michael 9250 if (IsClient(client))
852     mbl = snprintf(modebuf, sizeof(modebuf), ":%s!%s@%s MODE %s ", client->name,
853     client->username, client->host, channel->name);
854 michael 8431 else
855 michael 9250 mbl = snprintf(modebuf, sizeof(modebuf), ":%s MODE %s ", (IsHidden(client) ||
856 michael 8040 ConfigServerHide.hide_servers) ?
857 michael 9250 me.name : client->name, channel->name);
858 adx 30
859 michael 8040 for (unsigned int i = 0; i < mode_count; ++i)
860 adx 30 {
861 michael 8040 if (mode_changes[i].letter == 0 || mode_changes[i].flags != flags)
862     continue;
863 adx 30
864 michael 8040 const char *arg = mode_changes[i].arg;
865     if (arg)
866     arglen = strlen(arg);
867 adx 30 else
868 michael 8040 arglen = 0;
869 adx 30
870 michael 8040 if ((paracount == MAXMODEPARAMS) ||
871     ((arglen + mbl + pbl + 2 /* +2 for /r/n */ ) > IRCD_BUFSIZE))
872     {
873     if (modecount)
874 michael 9081 sendto_channel_local(NULL, channel, flags, 0, 0, "%s %s", modebuf, parabuf);
875 adx 30
876 michael 8040 modecount = 0;
877     paracount = 0;
878 adx 30
879 michael 9250 if (IsClient(client))
880     mbl = snprintf(modebuf, sizeof(modebuf), ":%s!%s@%s MODE %s ", client->name,
881     client->username, client->host, channel->name);
882 michael 8431 else
883 michael 9250 mbl = snprintf(modebuf, sizeof(modebuf), ":%s MODE %s ", (IsHidden(client) ||
884 michael 8040 ConfigServerHide.hide_servers) ?
885 michael 9250 me.name : client->name, channel->name);
886 adx 30
887 michael 8040 pbl = 0;
888     parabuf[0] = '\0';
889     parptr = parabuf;
890     dir = MODE_QUERY;
891     }
892    
893     if (dir != mode_changes[i].dir)
894     {
895     modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
896     dir = mode_changes[i].dir;
897     }
898    
899     modebuf[mbl++] = mode_changes[i].letter;
900     modebuf[mbl] = '\0';
901     ++modecount;
902    
903     if (arg)
904     {
905     int len = sprintf(parptr, (pbl == 0) ? "%s" : " %s", arg);
906     pbl += len;
907     parptr += len;
908     ++paracount;
909     }
910 adx 30 }
911 michael 8040
912     if (modecount)
913 michael 9081 sendto_channel_local(NULL, channel, flags, 0, 0, "%s %s", modebuf, parabuf);
914 adx 30 }
915     }
916    
917 michael 8091 const struct chan_mode *cmode_map[256];
918     const struct chan_mode cmode_tab[] =
919 michael 8089 {
920 michael 8649 { .letter = 'b', .flag = CHFL_BAN, .required_oplevel = CHACCESS_HALFOP, .func = chm_mask },
921     { .letter = 'c', .mode = MODE_NOCTRL, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
922     { .letter = 'e', .flag = CHFL_EXCEPTION, .required_oplevel = CHACCESS_HALFOP, .func = chm_mask },
923 michael 8640 { .letter = 'h', .flag = CHFL_HALFOP, .required_oplevel = CHACCESS_CHANOP, .func = chm_flag },
924 michael 8649 { .letter = 'i', .mode = MODE_INVITEONLY, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
925     { .letter = 'k', .func = chm_key, .required_oplevel = CHACCESS_HALFOP },
926     { .letter = 'l', .func = chm_limit, .required_oplevel = CHACCESS_HALFOP },
927     { .letter = 'm', .mode = MODE_MODERATED, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
928     { .letter = 'n', .mode = MODE_NOPRIVMSGS, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
929 michael 8640 { .letter = 'o', .flag = CHFL_CHANOP, .required_oplevel = CHACCESS_CHANOP, .func = chm_flag },
930 michael 8649 { .letter = 'p', .mode = MODE_PRIVATE, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
931     { .letter = 'r', .mode = MODE_REGISTERED, .required_oplevel = CHACCESS_REMOTE, .only_servers = true, .func = chm_simple },
932     { .letter = 's', .mode = MODE_SECRET, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
933     { .letter = 't', .mode = MODE_TOPICLIMIT, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
934     { .letter = 'u', .mode = MODE_HIDEBMASKS, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
935     { .letter = 'v', .flag = CHFL_VOICE, .required_oplevel = CHACCESS_HALFOP, .func = chm_flag },
936     { .letter = 'C', .mode = MODE_NOCTCP, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
937     { .letter = 'I', .flag = CHFL_INVEX, .required_oplevel = CHACCESS_HALFOP, .func = chm_mask },
938     { .letter = 'L', .mode = MODE_EXTLIMIT, .required_oplevel = CHACCESS_HALFOP, .only_opers = true, .func = chm_simple },
939     { .letter = 'M', .mode = MODE_MODREG, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
940     { .letter = 'N', .mode = MODE_NONICKCHANGE, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
941     { .letter = 'O', .mode = MODE_OPERONLY, .required_oplevel = CHACCESS_HALFOP, .only_opers = true, .func = chm_simple },
942     { .letter = 'R', .mode = MODE_REGONLY, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
943 michael 9157 { .letter = 'S', .mode = MODE_SECUREONLY, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
944 michael 8649 { .letter = 'T', .mode = MODE_NONOTICE, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
945 michael 8092 { .letter = '\0', .mode = 0 }
946 michael 8089 };
947    
948     void
949     channel_mode_init(void)
950     {
951 michael 8091 for (const struct chan_mode *tab = cmode_tab; tab->letter; ++tab)
952 michael 8089 cmode_map[tab->letter] = tab;
953     }
954    
955 michael 3671 /*
956 michael 3159 * Input: The the client this originated
957 adx 30 * from, the channel, the parameter count starting at the modes,
958     * the parameters, the channel name.
959     * Output: None.
960     * Side-effects: Changes the channel membership and modes appropriately,
961     * sends the appropriate MODE messages to the appropriate
962     * clients.
963     */
964     void
965 michael 9250 channel_mode_set(struct Client *client, struct Channel *channel,
966 michael 9081 struct ChannelMember *member, int parc, char *parv[])
967 adx 30 {
968     int dir = MODE_ADD;
969     int parn = 1;
970 michael 3671 int alevel = 0, errors = 0;
971 adx 30
972     mode_count = 0;
973     mode_limit = 0;
974     simple_modes_mask = 0;
975    
976 michael 9250 alevel = get_channel_access(client, member);
977 adx 30
978 michael 3283 for (const char *ml = parv[0]; *ml; ++ml)
979 adx 30 {
980 michael 3250 switch (*ml)
981 adx 30 {
982     case '+':
983     dir = MODE_ADD;
984     break;
985     case '-':
986     dir = MODE_DEL;
987     break;
988     case '=':
989     dir = MODE_QUERY;
990     break;
991     default:
992 michael 2939 {
993 michael 8091 const struct chan_mode *mode = cmode_map[(unsigned char)*ml];
994 michael 2939
995 michael 8089 if (mode)
996 michael 9250 mode->func(client, channel, parc, &parn, parv, &errors, alevel, dir, *ml, mode);
997 michael 8089 else
998 michael 9250 chm_nosuch(client, channel, parc, &parn, parv, &errors, alevel, dir, *ml, NULL);
999 adx 30 break;
1000 michael 2939 }
1001 adx 30 }
1002     }
1003    
1004 michael 5749 /* Bail out if we have nothing to do... */
1005 michael 8447 if (mode_count == 0)
1006 michael 5749 return;
1007    
1008 michael 9250 send_mode_changes_client(client, channel);
1009     send_mode_changes_server(client, channel);
1010 adx 30 }

Properties

Name Value
svn:eol-style native
svn:keywords Id