ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/channel_mode.c
Revision: 2892
Committed: Tue Jan 21 18:30:02 2014 UTC (12 years, 8 months ago) by michael
Content type: text/x-csrc
File size: 48952 byte(s)
Log Message:
- channel_mode.c: fixed indentation, removed whitespaces/tabs,
  removed unused header includes

File Contents

# User Rev Content
1 adx 30 /*
2     * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3     * channel_mode.c: Controls modes on channels.
4     *
5     * Copyright (C) 2005 by the past and present ircd coders, and others.
6     *
7     * This program is free software; you can redistribute it and/or modify
8     * it under the terms of the GNU General Public License as published by
9     * the Free Software Foundation; either version 2 of the License, or
10     * (at your option) any later version.
11     *
12     * This program is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     * GNU General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with this program; if not, write to the Free Software
19     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20     * USA
21     *
22 knight 31 * $Id$
23 adx 30 */
24    
25     #include "stdinc.h"
26 michael 1011 #include "list.h"
27 adx 30 #include "channel.h"
28     #include "channel_mode.h"
29     #include "client.h"
30 michael 1632 #include "conf.h"
31 michael 371 #include "hostmask.h"
32 adx 30 #include "irc_string.h"
33     #include "ircd.h"
34     #include "numeric.h"
35 michael 2892 #include "s_serv.h"
36 adx 30 #include "s_user.h"
37     #include "send.h"
38     #include "memory.h"
39 michael 1654 #include "mempool.h"
40 michael 1243 #include "parse.h"
41 adx 30
42     /* 10 is a magic number in hybrid 6 NFI where it comes from -db */
43 michael 2892 #define BAN_FUDGE 10
44 adx 30 #define NCHCAPS (sizeof(channel_capabs)/sizeof(int))
45     #define NCHCAP_COMBOS (1 << NCHCAPS)
46    
47 michael 2892
48 michael 388 static char nuh_mask[MAXPARA][IRCD_BUFSIZE];
49 adx 30 /* some buffers for rebuilding channel/nick lists with ,'s */
50     static char modebuf[IRCD_BUFSIZE];
51     static char parabuf[MODEBUFLEN];
52     static struct ChModeChange mode_changes[IRCD_BUFSIZE];
53     static int mode_count;
54 michael 2892 static int mode_limit; /* number of modes set other than simple */
55     static int simple_modes_mask; /* bit mask of simple modes already set */
56 adx 356 #ifdef HALFOPS
57     static int channel_capabs[] = { CAP_EX, CAP_IE, CAP_TS6, CAP_HOPS };
58     #else
59 adx 30 static int channel_capabs[] = { CAP_EX, CAP_IE, CAP_TS6 };
60 adx 356 #endif
61 adx 30 static struct ChCapCombo chcap_combos[NCHCAP_COMBOS];
62 michael 1654 extern mp_pool_t *ban_pool;
63 adx 30
64    
65     /* check_string()
66     *
67     * inputs - string to check
68     * output - pointer to modified string
69     * side effects - Fixes a string so that the first white space found
70     * becomes an end of string marker (`\0`).
71     * returns the 'fixed' string or "*" if the string
72     * was NULL length or a NULL pointer.
73     */
74     static char *
75     check_string(char *s)
76     {
77     char *str = s;
78     static char star[] = "*";
79    
80 michael 1772 if (EmptyString(str))
81 michael 593 return star;
82 adx 30
83     for (; *s; ++s)
84     {
85     if (IsSpace(*s))
86     {
87     *s = '\0';
88     break;
89     }
90     }
91    
92 michael 1772 return EmptyString(str) ? star : str;
93 adx 30 }
94    
95     /*
96     * Ban functions to work with mode +b/e/d/I
97     */
98 michael 2892 /* add the specified ID to the channel.
99     * -is 8/9/00
100 adx 30 */
101    
102     int
103     add_id(struct Client *client_p, struct Channel *chptr, char *banid, int type)
104     {
105 michael 593 dlink_list *list = NULL;
106     dlink_node *ban = NULL;
107 adx 30 size_t len = 0;
108 michael 593 struct Ban *ban_p = NULL;
109 adx 30 unsigned int num_mask;
110 michael 1431 char name[NICKLEN + 1];
111 michael 593 char user[USERLEN + 1];
112     char host[HOSTLEN + 1];
113     struct split_nuh_item nuh;
114 adx 30
115     /* dont let local clients overflow the b/e/I lists */
116     if (MyClient(client_p))
117     {
118     num_mask = dlink_list_length(&chptr->banlist) +
119     dlink_list_length(&chptr->exceptlist) +
120     dlink_list_length(&chptr->invexlist);
121    
122     if (num_mask >= ConfigChannel.max_bans)
123     {
124 michael 1834 sendto_one(client_p, form_str(ERR_BANLISTFULL),
125 adx 30 me.name, client_p->name, chptr->chname, banid);
126     return 0;
127     }
128    
129     collapse(banid);
130     }
131    
132 michael 593 nuh.nuhmask = check_string(banid);
133     nuh.nickptr = name;
134     nuh.userptr = user;
135     nuh.hostptr = host;
136 adx 30
137 michael 593 nuh.nicksize = sizeof(name);
138     nuh.usersize = sizeof(user);
139     nuh.hostsize = sizeof(host);
140    
141     split_nuh(&nuh);
142    
143 adx 30 /*
144 michael 593 * Re-assemble a new n!u@h and print it back to banid for sending
145 adx 30 * the mode to the channel.
146     */
147 michael 1793 len = sprintf(banid, "%s!%s@%s", name, user, host);
148 adx 30
149     switch (type)
150     {
151     case CHFL_BAN:
152     list = &chptr->banlist;
153     clear_ban_cache(chptr);
154     break;
155     case CHFL_EXCEPTION:
156     list = &chptr->exceptlist;
157     clear_ban_cache(chptr);
158     break;
159     case CHFL_INVEX:
160     list = &chptr->invexlist;
161     break;
162     default:
163     assert(0);
164     return 0;
165     }
166    
167     DLINK_FOREACH(ban, list->head)
168     {
169 michael 593 ban_p = ban->data;
170 michael 2892
171 michael 593 if (!irccmp(ban_p->name, name) &&
172 michael 2296 !irccmp(ban_p->user, user) &&
173 michael 593 !irccmp(ban_p->host, host))
174 adx 30 return 0;
175     }
176    
177 michael 1654 ban_p = mp_pool_get(ban_pool);
178     memset(ban_p, 0, sizeof(*ban_p));
179 michael 1646 ban_p->name = xstrdup(name);
180 michael 2296 ban_p->user = xstrdup(user);
181 michael 1646 ban_p->host = xstrdup(host);
182 michael 593 ban_p->when = CurrentTime;
183 michael 2892 ban_p->len = len - 2; /* -2 for @ and ! */
184 michael 593 ban_p->type = parse_netmask(host, &ban_p->addr, &ban_p->bits);
185    
186 adx 30 if (IsClient(client_p))
187     {
188 michael 593 ban_p->who = MyMalloc(strlen(client_p->name) +
189     strlen(client_p->username) +
190     strlen(client_p->host) + 3);
191 michael 1793 sprintf(ban_p->who, "%s!%s@%s", client_p->name,
192 michael 2296 client_p->username, client_p->host);
193 adx 30 }
194 michael 2242 else if (IsHidden(client_p) || (IsServer(client_p) && ConfigServerHide.hide_servers))
195     ban_p->who = xstrdup(me.name);
196 adx 30 else
197 michael 1646 ban_p->who = xstrdup(client_p->name);
198 adx 30
199 michael 593 dlinkAdd(ban_p, &ban_p->node, list);
200 adx 30
201     return 1;
202     }
203    
204     /*
205     * inputs - pointer to channel
206     * - pointer to ban id
207     * - type of ban, i.e. ban, exception, invex
208     * output - 0 for failure, 1 for success
209     * side effects -
210     */
211     static int
212     del_id(struct Channel *chptr, char *banid, int type)
213     {
214     dlink_list *list;
215     dlink_node *ban;
216     struct Ban *banptr;
217 michael 1431 char name[NICKLEN + 1];
218 michael 593 char user[USERLEN + 1];
219     char host[HOSTLEN + 1];
220     struct split_nuh_item nuh;
221 adx 30
222 michael 2892 assert(banid);
223 adx 30
224 michael 593 nuh.nuhmask = check_string(banid);
225     nuh.nickptr = name;
226     nuh.userptr = user;
227     nuh.hostptr = host;
228 adx 30
229 michael 593 nuh.nicksize = sizeof(name);
230     nuh.usersize = sizeof(user);
231     nuh.hostsize = sizeof(host);
232    
233     split_nuh(&nuh);
234    
235 adx 30 /*
236 michael 593 * Re-assemble a new n!u@h and print it back to banid for sending
237 adx 30 * the mode to the channel.
238     */
239 michael 1793 sprintf(banid, "%s!%s@%s", name, user, host);
240 adx 30
241     switch (type)
242     {
243     case CHFL_BAN:
244     list = &chptr->banlist;
245     clear_ban_cache(chptr);
246     break;
247     case CHFL_EXCEPTION:
248     list = &chptr->exceptlist;
249     clear_ban_cache(chptr);
250     break;
251     case CHFL_INVEX:
252     list = &chptr->invexlist;
253     break;
254     default:
255 michael 2892 assert(0);
256 michael 593 return 0;
257 adx 30 }
258    
259     DLINK_FOREACH(ban, list->head)
260     {
261     banptr = ban->data;
262    
263     if (!irccmp(name, banptr->name) &&
264 michael 2296 !irccmp(user, banptr->user) &&
265 michael 593 !irccmp(host, banptr->host))
266 adx 30 {
267     remove_ban(banptr, list);
268     return 1;
269     }
270     }
271    
272     return 0;
273     }
274    
275 michael 2892 const struct mode_letter chan_modes[] =
276     {
277 michael 1937 { MODE_NOCTRL, 'c' },
278 adx 30 { MODE_INVITEONLY, 'i' },
279     { MODE_MODERATED, 'm' },
280     { MODE_NOPRIVMSGS, 'n' },
281     { MODE_PRIVATE, 'p' },
282 michael 1167 { MODE_REGISTERED, 'r' },
283 adx 30 { MODE_SECRET, 's' },
284     { MODE_TOPICLIMIT, 't' },
285 michael 1954 { MODE_MODREG, 'M' },
286 michael 1150 { MODE_OPERONLY, 'O' },
287 michael 1175 { MODE_REGONLY, 'R' },
288 michael 1150 { MODE_SSLONLY, 'S' },
289 adx 30 { 0, '\0' }
290     };
291    
292     /* channel_modes()
293     *
294     * inputs - pointer to channel
295     * - pointer to client
296     * - pointer to mode buf
297     * - pointer to parameter buf
298     * output - NONE
299     * side effects - write the "simple" list of channel modes for channel
300     * chptr onto buffer mbuf with the parameters in pbuf.
301     */
302     void
303     channel_modes(struct Channel *chptr, struct Client *client_p,
304     char *mbuf, char *pbuf)
305     {
306 michael 1175 const struct mode_letter *tab = chan_modes;
307 adx 30
308     *mbuf++ = '+';
309     *pbuf = '\0';
310    
311 michael 1175 for (; tab->mode; ++tab)
312     if (chptr->mode.mode & tab->mode)
313     *mbuf++ = tab->letter;
314 adx 30
315     if (chptr->mode.limit)
316     {
317     *mbuf++ = 'l';
318    
319 michael 1219 if (IsServer(client_p) || HasFlag(client_p, FLAGS_SERVICE) || IsMember(client_p, chptr))
320 michael 1793 pbuf += sprintf(pbuf, "%d ", chptr->mode.limit);
321 adx 30 }
322    
323     if (chptr->mode.key[0])
324     {
325     *mbuf++ = 'k';
326    
327 michael 1219 if (IsServer(client_p) || HasFlag(client_p, FLAGS_SERVICE) || IsMember(client_p, chptr))
328 michael 1793 sprintf(pbuf, "%s ", chptr->mode.key);
329 adx 30 }
330    
331     *mbuf = '\0';
332     }
333    
334     /* fix_key()
335 michael 2892 *
336 adx 30 * inputs - pointer to key to clean up
337     * output - pointer to cleaned up key
338     * side effects - input string is modified
339     *
340     * stolen from Undernet's ircd -orabidoo
341     */
342     static char *
343     fix_key(char *arg)
344     {
345     unsigned char *s, *t, c;
346    
347     for (s = t = (unsigned char *)arg; (c = *s); s++)
348     {
349     c &= 0x7f;
350 michael 2892
351 adx 30 if (c != ':' && c > ' ' && c != ',')
352     *t++ = c;
353     }
354    
355     *t = '\0';
356 michael 2892 return arg;
357 adx 30 }
358    
359     /* fix_key_old()
360 michael 2892 *
361 adx 30 * inputs - pointer to key to clean up
362     * output - pointer to cleaned up key
363 michael 2892 * side effects - input string is modifed
364 adx 30 *
365     * Here we attempt to be compatible with older non-hybrid servers.
366     * We can't back down from the ':' issue however. --Rodder
367     */
368     static char *
369     fix_key_old(char *arg)
370     {
371     unsigned char *s, *t, c;
372    
373     for (s = t = (unsigned char *)arg; (c = *s); s++)
374     {
375     c &= 0x7f;
376 michael 2892
377     if ((c != 0x0a) && (c != ':') &&
378     (c != 0x0d) && (c != ','))
379 adx 30 *t++ = c;
380     }
381    
382     *t = '\0';
383 michael 2892 return arg;
384 adx 30 }
385    
386     /* bitmasks for various error returns that set_channel_mode should only return
387     * once per call -orabidoo
388     */
389    
390     #define SM_ERR_NOTS 0x00000001 /* No TS on channel */
391     #define SM_ERR_NOOPS 0x00000002 /* No chan ops */
392     #define SM_ERR_UNKNOWN 0x00000004
393     #define SM_ERR_RPL_B 0x00000008
394     #define SM_ERR_RPL_E 0x00000010
395     #define SM_ERR_NOTONCHANNEL 0x00000020 /* Not on channel */
396     #define SM_ERR_RPL_I 0x00000040
397 michael 1150 #define SM_ERR_NOTOPER 0x00000080
398 michael 1167 #define SM_ERR_ONLYSERVER 0x00000100
399 adx 30
400     /* Now lets do some stuff to keep track of what combinations of
401     * servers exist...
402     * Note that the number of combinations doubles each time you add
403     * something to this list. Each one is only quick if no servers use that
404     * combination, but if the numbers get too high here MODE will get too
405     * slow. I suggest if you get more than 7 here, you consider getting rid
406     * of some and merging or something. If it wasn't for irc+cs we would
407     * probably not even need to bother about most of these, but unfortunately
408     * we do. -A1kmm
409     */
410    
411     /* void init_chcap_usage_counts(void)
412     *
413     * Inputs - none
414     * Output - none
415     * Side-effects - Initialises the usage counts to zero. Fills in the
416     * chcap_yes and chcap_no combination tables.
417     */
418     void
419     init_chcap_usage_counts(void)
420     {
421     unsigned long m, c, y, n;
422    
423     memset(chcap_combos, 0, sizeof(chcap_combos));
424    
425     /* For every possible combination */
426     for (m = 0; m < NCHCAP_COMBOS; m++)
427     {
428     /* Check each capab */
429     for (c = y = n = 0; c < NCHCAPS; c++)
430     {
431     if ((m & (1 << c)) == 0)
432     n |= channel_capabs[c];
433     else
434     y |= channel_capabs[c];
435     }
436 michael 2892
437 adx 30 chcap_combos[m].cap_yes = y;
438     chcap_combos[m].cap_no = n;
439     }
440     }
441    
442     /* void set_chcap_usage_counts(struct Client *serv_p)
443     * Input: serv_p; The client whose capabs to register.
444     * Output: none
445     * Side-effects: Increments the usage counts for the correct capab
446     * combination.
447     */
448     void
449     set_chcap_usage_counts(struct Client *serv_p)
450     {
451     int n;
452    
453     for (n = 0; n < NCHCAP_COMBOS; n++)
454     {
455     if (((serv_p->localClient->caps & chcap_combos[n].cap_yes) ==
456     chcap_combos[n].cap_yes) &&
457     ((serv_p->localClient->caps & chcap_combos[n].cap_no) == 0))
458     {
459     chcap_combos[n].count++;
460     return;
461     }
462     }
463    
464     /* This should be impossible -A1kmm. */
465     assert(0);
466     }
467    
468     /* void set_chcap_usage_counts(struct Client *serv_p)
469     *
470     * Inputs - serv_p; The client whose capabs to register.
471     * Output - none
472     * Side-effects - Decrements the usage counts for the correct capab
473     * combination.
474     */
475     void
476     unset_chcap_usage_counts(struct Client *serv_p)
477     {
478     int n;
479    
480     for (n = 0; n < NCHCAP_COMBOS; n++)
481     {
482     if ((serv_p->localClient->caps & chcap_combos[n].cap_yes) ==
483     chcap_combos[n].cap_yes &&
484     (serv_p->localClient->caps & chcap_combos[n].cap_no) == 0)
485     {
486     /* Hopefully capabs can't change dynamically or anything... */
487     assert(chcap_combos[n].count > 0);
488     chcap_combos[n].count--;
489     return;
490     }
491     }
492    
493     /* This should be impossible -A1kmm. */
494     assert(0);
495     }
496    
497     /* Mode functions handle mode changes for a particular mode... */
498     static void
499     chm_nosuch(struct Client *client_p, struct Client *source_p,
500     struct Channel *chptr, int parc, int *parn,
501     char **parv, int *errors, int alev, int dir, char c, void *d,
502     const char *chname)
503     {
504     if (*errors & SM_ERR_UNKNOWN)
505     return;
506    
507     *errors |= SM_ERR_UNKNOWN;
508 michael 1834 sendto_one(source_p, form_str(ERR_UNKNOWNMODE), me.name,
509 adx 30 source_p->name, c);
510     }
511    
512     static void
513     chm_simple(struct Client *client_p, struct Client *source_p, struct Channel *chptr,
514     int parc, int *parn, char **parv, int *errors, int alev, int dir,
515     char c, void *d, const char *chname)
516     {
517 michael 2892 long mode_type = (long)d;
518 adx 30
519     if ((alev < CHACCESS_HALFOP) ||
520     ((mode_type == MODE_PRIVATE) && (alev < CHACCESS_CHANOP)))
521     {
522     if (!(*errors & SM_ERR_NOOPS))
523 michael 1834 sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
524     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
525 adx 30 me.name, source_p->name, chname);
526     *errors |= SM_ERR_NOOPS;
527     return;
528     }
529    
530     /* If have already dealt with this simple mode, ignore it */
531     if (simple_modes_mask & mode_type)
532     return;
533    
534     simple_modes_mask |= mode_type;
535    
536     /* setting + */
537 michael 2892 /* Apparently, (though no one has ever told the hybrid group directly)
538     * admins don't like redundant mode checking. ok. It would have been nice
539     * if you had have told us directly. I've left the original code snippets
540     * in place.
541     *
542     * -Dianora
543     */
544 michael 2534 if (dir == MODE_ADD) /* && !(chptr->mode.mode & mode_type)) */
545 adx 30 {
546     chptr->mode.mode |= mode_type;
547    
548     mode_changes[mode_count].letter = c;
549     mode_changes[mode_count].dir = MODE_ADD;
550     mode_changes[mode_count].caps = 0;
551     mode_changes[mode_count].nocaps = 0;
552     mode_changes[mode_count].id = NULL;
553     mode_changes[mode_count].mems = ALL_MEMBERS;
554     mode_changes[mode_count++].arg = NULL;
555     }
556 michael 2534 else if (dir == MODE_DEL) /* && (chptr->mode.mode & mode_type)) */
557 adx 30 {
558     /* setting - */
559    
560     chptr->mode.mode &= ~mode_type;
561    
562     mode_changes[mode_count].letter = c;
563     mode_changes[mode_count].dir = MODE_DEL;
564     mode_changes[mode_count].caps = 0;
565     mode_changes[mode_count].nocaps = 0;
566     mode_changes[mode_count].mems = ALL_MEMBERS;
567     mode_changes[mode_count].id = NULL;
568     mode_changes[mode_count++].arg = NULL;
569     }
570     }
571    
572     static void
573 michael 1167 chm_registered(struct Client *client_p, struct Client *source_p, struct Channel *chptr,
574     int parc, int *parn, char **parv, int *errors, int alev, int dir,
575     char c, void *d, const char *chname)
576     {
577 michael 2892 long mode_type = (long)d;
578 michael 1167
579    
580 michael 1219 if (!IsServer(source_p) && !HasFlag(source_p, FLAGS_SERVICE))
581 michael 1167 {
582     if (!(*errors & SM_ERR_ONLYSERVER))
583 michael 1834 sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
584     ERR_NOTONCHANNEL : ERR_ONLYSERVERSCANCHANGE),
585 michael 1167 me.name, source_p->name, chname);
586     *errors |= SM_ERR_ONLYSERVER;
587     return;
588     }
589    
590     /* If have already dealt with this simple mode, ignore it */
591     if (simple_modes_mask & mode_type)
592     return;
593    
594     simple_modes_mask |= mode_type;
595    
596     /* setting + */
597 michael 2892 /* Apparently, (though no one has ever told the hybrid group directly)
598     * admins don't like redundant mode checking. ok. It would have been nice
599     * if you had have told us directly. I've left the original code snippets
600     * in place.
601     *
602     * -Dianora
603 michael 1167 */
604 michael 2534 if (dir == MODE_ADD) /* && !(chptr->mode.mode & mode_type)) */
605 michael 1167 {
606     chptr->mode.mode |= mode_type;
607    
608     mode_changes[mode_count].letter = c;
609     mode_changes[mode_count].dir = MODE_ADD;
610     mode_changes[mode_count].caps = 0;
611     mode_changes[mode_count].nocaps = 0;
612     mode_changes[mode_count].id = NULL;
613     mode_changes[mode_count].mems = ALL_MEMBERS;
614     mode_changes[mode_count++].arg = NULL;
615     }
616 michael 2534 else if (dir == MODE_DEL) /* && (chptr->mode.mode & mode_type)) */
617 michael 1167 {
618     /* setting - */
619    
620     chptr->mode.mode &= ~mode_type;
621    
622     mode_changes[mode_count].letter = c;
623     mode_changes[mode_count].dir = MODE_DEL;
624     mode_changes[mode_count].caps = 0;
625     mode_changes[mode_count].nocaps = 0;
626     mode_changes[mode_count].mems = ALL_MEMBERS;
627     mode_changes[mode_count].id = NULL;
628     mode_changes[mode_count++].arg = NULL;
629     }
630     }
631    
632     static void
633 michael 1150 chm_operonly(struct Client *client_p, struct Client *source_p, struct Channel *chptr,
634     int parc, int *parn, char **parv, int *errors, int alev, int dir,
635     char c, void *d, const char *chname)
636     {
637 michael 2892 long mode_type = (long)d;
638 michael 1150
639     if ((alev < CHACCESS_HALFOP) ||
640     ((mode_type == MODE_PRIVATE) && (alev < CHACCESS_CHANOP)))
641     {
642     if (!(*errors & SM_ERR_NOOPS))
643 michael 1834 sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
644     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
645 michael 1150 me.name, source_p->name, chname);
646     *errors |= SM_ERR_NOOPS;
647     return;
648     }
649 michael 1219 else if (MyClient(source_p) && !HasUMode(source_p, UMODE_OPER))
650 michael 1150 {
651     if (!(*errors & SM_ERR_NOTOPER))
652     {
653     if (alev == CHACCESS_NOTONCHAN)
654 michael 1834 sendto_one(source_p, form_str(ERR_NOTONCHANNEL),
655 michael 1150 me.name, source_p->name, chname);
656     else
657 michael 1834 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
658 michael 1150 me.name, source_p->name);
659     }
660    
661     *errors |= SM_ERR_NOTOPER;
662     return;
663     }
664    
665     /* If have already dealt with this simple mode, ignore it */
666     if (simple_modes_mask & mode_type)
667     return;
668    
669     simple_modes_mask |= mode_type;
670    
671 michael 2534 if (dir == MODE_ADD) /* && !(chptr->mode.mode & mode_type)) */
672 michael 1150 {
673     chptr->mode.mode |= mode_type;
674    
675     mode_changes[mode_count].letter = c;
676     mode_changes[mode_count].dir = MODE_ADD;
677     mode_changes[mode_count].caps = 0;
678     mode_changes[mode_count].nocaps = 0;
679     mode_changes[mode_count].id = NULL;
680     mode_changes[mode_count].mems = ALL_MEMBERS;
681     mode_changes[mode_count].mems = ALL_MEMBERS;
682     mode_changes[mode_count++].arg = NULL;
683     }
684 michael 2534 else if (dir == MODE_DEL) /* && (chptr->mode.mode & mode_type)) */
685 michael 1150 {
686     /* setting - */
687    
688     chptr->mode.mode &= ~mode_type;
689    
690     mode_changes[mode_count].letter = c;
691     mode_changes[mode_count].dir = MODE_DEL;
692     mode_changes[mode_count].caps = 0;
693     mode_changes[mode_count].nocaps = 0;
694     mode_changes[mode_count].mems = ALL_MEMBERS;
695     mode_changes[mode_count].id = NULL;
696     mode_changes[mode_count++].arg = NULL;
697     }
698     }
699    
700     static void
701 adx 30 chm_ban(struct Client *client_p, struct Client *source_p,
702     struct Channel *chptr, int parc, int *parn,
703     char **parv, int *errors, int alev, int dir, char c, void *d,
704     const char *chname)
705     {
706     char *mask = NULL;
707    
708     if (dir == MODE_QUERY || parc <= *parn)
709     {
710     dlink_node *ptr = NULL;
711    
712     if (*errors & SM_ERR_RPL_B)
713     return;
714    
715     *errors |= SM_ERR_RPL_B;
716    
717     DLINK_FOREACH(ptr, chptr->banlist.head)
718     {
719     const struct Ban *banptr = ptr->data;
720 michael 1834 sendto_one(client_p, form_str(RPL_BANLIST),
721 adx 30 me.name, client_p->name, chname,
722 michael 2296 banptr->name, banptr->user, banptr->host,
723 michael 2892 banptr->who, banptr->when);
724 adx 30 }
725    
726 michael 1834 sendto_one(source_p, form_str(RPL_ENDOFBANLIST), me.name,
727 adx 30 source_p->name, chname);
728     return;
729     }
730    
731     if (alev < CHACCESS_HALFOP)
732     {
733     if (!(*errors & SM_ERR_NOOPS))
734 michael 1834 sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
735     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
736 adx 30 me.name, source_p->name, chname);
737     *errors |= SM_ERR_NOOPS;
738     return;
739     }
740    
741     if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
742     return;
743    
744 michael 388 mask = nuh_mask[*parn];
745     memcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
746     ++*parn;
747    
748 adx 30 if (IsServer(client_p))
749     if (strchr(mask, ' '))
750     return;
751    
752     switch (dir)
753     {
754     case MODE_ADD:
755     if (!add_id(source_p, chptr, mask, CHFL_BAN))
756     return;
757     break;
758     case MODE_DEL:
759     if (!del_id(chptr, mask, CHFL_BAN))
760     return;
761     break;
762     default:
763     assert(0);
764     }
765    
766     mode_changes[mode_count].letter = c;
767     mode_changes[mode_count].dir = dir;
768     mode_changes[mode_count].caps = 0;
769     mode_changes[mode_count].nocaps = 0;
770     mode_changes[mode_count].mems = ALL_MEMBERS;
771     mode_changes[mode_count].id = NULL;
772     mode_changes[mode_count++].arg = mask;
773     }
774    
775     static void
776     chm_except(struct Client *client_p, struct Client *source_p,
777     struct Channel *chptr, int parc, int *parn,
778     char **parv, int *errors, int alev, int dir, char c, void *d,
779     const char *chname)
780     {
781     char *mask = NULL;
782    
783     if (alev < CHACCESS_HALFOP)
784     {
785     if (!(*errors & SM_ERR_NOOPS))
786 michael 1834 sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
787     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
788 adx 30 me.name, source_p->name, chname);
789     *errors |= SM_ERR_NOOPS;
790     return;
791     }
792    
793     if (dir == MODE_QUERY || parc <= *parn)
794     {
795     dlink_node *ptr = NULL;
796    
797     if (*errors & SM_ERR_RPL_E)
798     return;
799    
800     *errors |= SM_ERR_RPL_E;
801    
802     DLINK_FOREACH(ptr, chptr->exceptlist.head)
803     {
804     const struct Ban *banptr = ptr->data;
805 michael 1834 sendto_one(client_p, form_str(RPL_EXCEPTLIST),
806 adx 30 me.name, client_p->name, chname,
807 michael 2296 banptr->name, banptr->user, banptr->host,
808 michael 2892 banptr->who, banptr->when);
809 adx 30 }
810    
811 michael 1834 sendto_one(source_p, form_str(RPL_ENDOFEXCEPTLIST), me.name,
812 adx 30 source_p->name, chname);
813     return;
814     }
815    
816     if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
817     return;
818    
819 michael 388 mask = nuh_mask[*parn];
820     memcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
821     ++*parn;
822 adx 30
823     if (IsServer(client_p))
824     if (strchr(mask, ' '))
825     return;
826    
827     switch (dir)
828     {
829     case MODE_ADD:
830     if (!add_id(source_p, chptr, mask, CHFL_EXCEPTION))
831     return;
832     break;
833     case MODE_DEL:
834     if (!del_id(chptr, mask, CHFL_EXCEPTION))
835     return;
836     break;
837     default:
838     assert(0);
839     }
840    
841     mode_changes[mode_count].letter = c;
842     mode_changes[mode_count].dir = dir;
843 michael 1684 mode_changes[mode_count].caps = 0;
844 adx 30 mode_changes[mode_count].nocaps = 0;
845 michael 1495 mode_changes[mode_count].mems = ONLY_CHANOPS;
846 adx 30 mode_changes[mode_count].id = NULL;
847     mode_changes[mode_count++].arg = mask;
848     }
849    
850     static void
851     chm_invex(struct Client *client_p, struct Client *source_p,
852     struct Channel *chptr, int parc, int *parn,
853     char **parv, int *errors, int alev, int dir, char c, void *d,
854     const char *chname)
855     {
856     char *mask = NULL;
857    
858     if (alev < CHACCESS_HALFOP)
859     {
860     if (!(*errors & SM_ERR_NOOPS))
861 michael 1834 sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
862     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
863 adx 30 me.name, source_p->name, chname);
864     *errors |= SM_ERR_NOOPS;
865     return;
866     }
867    
868     if (dir == MODE_QUERY || parc <= *parn)
869     {
870     dlink_node *ptr = NULL;
871    
872     if (*errors & SM_ERR_RPL_I)
873     return;
874    
875     *errors |= SM_ERR_RPL_I;
876    
877     DLINK_FOREACH(ptr, chptr->invexlist.head)
878     {
879     const struct Ban *banptr = ptr->data;
880 michael 1834 sendto_one(client_p, form_str(RPL_INVITELIST), me.name,
881 adx 30 client_p->name, chname,
882 michael 2892 banptr->name, banptr->user, banptr->host,
883 adx 30 banptr->who, banptr->when);
884     }
885    
886 michael 1834 sendto_one(source_p, form_str(RPL_ENDOFINVITELIST), me.name,
887 adx 30 source_p->name, chname);
888     return;
889     }
890    
891     if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
892     return;
893    
894 michael 388 mask = nuh_mask[*parn];
895     memcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
896     ++*parn;
897 adx 30
898     if (IsServer(client_p))
899     if (strchr(mask, ' '))
900     return;
901    
902     switch (dir)
903     {
904     case MODE_ADD:
905     if (!add_id(source_p, chptr, mask, CHFL_INVEX))
906     return;
907     break;
908     case MODE_DEL:
909     if (!del_id(chptr, mask, CHFL_INVEX))
910     return;
911     break;
912     default:
913     assert(0);
914     }
915    
916     mode_changes[mode_count].letter = c;
917     mode_changes[mode_count].dir = dir;
918 michael 1684 mode_changes[mode_count].caps = 0;
919 adx 30 mode_changes[mode_count].nocaps = 0;
920 michael 1495 mode_changes[mode_count].mems = ONLY_CHANOPS;
921 adx 30 mode_changes[mode_count].id = NULL;
922     mode_changes[mode_count++].arg = mask;
923     }
924    
925     /*
926     * inputs - pointer to channel
927     * output - none
928     * side effects - clear ban cache
929     */
930     void
931     clear_ban_cache(struct Channel *chptr)
932     {
933     dlink_node *ptr = NULL;
934    
935 michael 572 DLINK_FOREACH(ptr, chptr->members.head)
936 adx 30 {
937     struct Membership *ms = ptr->data;
938 michael 572
939     if (MyConnect(ms->client_p))
940     ms->flags &= ~(CHFL_BAN_SILENCED|CHFL_BAN_CHECKED);
941 adx 30 }
942     }
943    
944 michael 759 void
945     clear_ban_cache_client(struct Client *client_p)
946     {
947     dlink_node *ptr = NULL;
948    
949 michael 760 DLINK_FOREACH(ptr, client_p->channel.head)
950 michael 759 {
951     struct Membership *ms = ptr->data;
952     ms->flags &= ~(CHFL_BAN_SILENCED|CHFL_BAN_CHECKED);
953     }
954     }
955    
956 adx 30 static void
957     chm_op(struct Client *client_p, struct Client *source_p,
958     struct Channel *chptr, int parc, int *parn,
959     char **parv, int *errors, int alev, int dir, char c, void *d,
960     const char *chname)
961     {
962 michael 2892 const char *opnick = NULL;
963 adx 30 struct Client *targ_p;
964     struct Membership *member;
965 adx 356 int caps = 0;
966 adx 30
967     if (alev < CHACCESS_CHANOP)
968     {
969     if (!(*errors & SM_ERR_NOOPS))
970 michael 1834 sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
971     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
972 adx 30 me.name, source_p->name, chname);
973     *errors |= SM_ERR_NOOPS;
974     return;
975     }
976    
977     if ((dir == MODE_QUERY) || (parc <= *parn))
978     return;
979    
980     opnick = parv[(*parn)++];
981    
982 michael 2475 if ((targ_p = find_chasing(source_p, opnick, NULL)) == NULL)
983 adx 30 return;
984     if (!IsClient(targ_p))
985     return;
986    
987     if ((member = find_channel_link(targ_p, chptr)) == NULL)
988     {
989     if (!(*errors & SM_ERR_NOTONCHANNEL))
990 michael 1834 sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
991 adx 30 me.name, source_p->name, opnick, chname);
992     *errors |= SM_ERR_NOTONCHANNEL;
993     return;
994     }
995    
996     if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
997     return;
998    
999     /* no redundant mode changes */
1000     if (dir == MODE_ADD && has_member_flags(member, CHFL_CHANOP))
1001     return;
1002     if (dir == MODE_DEL && !has_member_flags(member, CHFL_CHANOP))
1003 adx 356 {
1004     #ifdef HALFOPS
1005     if (has_member_flags(member, CHFL_HALFOP))
1006 db 931 {
1007     --*parn;
1008 adx 356 chm_hop(client_p, source_p, chptr, parc, parn, parv, errors, alev,
1009     dir, c, d, chname);
1010 db 931 }
1011 adx 356 #endif
1012 adx 30 return;
1013 adx 356 }
1014 adx 30
1015 adx 356 #ifdef HALFOPS
1016     if (dir == MODE_ADD && has_member_flags(member, CHFL_HALFOP))
1017     {
1018     /* promoting from % to @ is visible only to CAP_HOPS servers */
1019     mode_changes[mode_count].letter = 'h';
1020     mode_changes[mode_count].dir = MODE_DEL;
1021     mode_changes[mode_count].caps = caps = CAP_HOPS;
1022     mode_changes[mode_count].nocaps = 0;
1023     mode_changes[mode_count].mems = ALL_MEMBERS;
1024     mode_changes[mode_count].id = NULL;
1025     mode_changes[mode_count].arg = targ_p->name;
1026     mode_changes[mode_count++].client = targ_p;
1027     }
1028     #endif
1029    
1030 adx 30 mode_changes[mode_count].letter = 'o';
1031     mode_changes[mode_count].dir = dir;
1032 adx 356 mode_changes[mode_count].caps = caps;
1033 adx 30 mode_changes[mode_count].nocaps = 0;
1034     mode_changes[mode_count].mems = ALL_MEMBERS;
1035     mode_changes[mode_count].id = targ_p->id;
1036     mode_changes[mode_count].arg = targ_p->name;
1037     mode_changes[mode_count++].client = targ_p;
1038    
1039     if (dir == MODE_ADD)
1040     {
1041     AddMemberFlag(member, CHFL_CHANOP);
1042 adx 356 DelMemberFlag(member, CHFL_DEOPPED | CHFL_HALFOP);
1043 adx 30 }
1044     else
1045     DelMemberFlag(member, CHFL_CHANOP);
1046     }
1047    
1048     #ifdef HALFOPS
1049     static void
1050     chm_hop(struct Client *client_p, struct Client *source_p,
1051     struct Channel *chptr, int parc, int *parn,
1052     char **parv, int *errors, int alev, int dir, char c, void *d,
1053     const char *chname)
1054     {
1055 michael 2892 const char *opnick = NULL;
1056 adx 30 struct Client *targ_p;
1057     struct Membership *member;
1058    
1059     /* *sigh* - dont allow halfops to set +/-h, they could fully control a
1060     * channel if there were no ops - it doesnt solve anything.. MODE_PRIVATE
1061     * when used with MODE_SECRET is paranoid - cant use +p
1062     *
1063     * it needs to be optional per channel - but not via +p, that or remove
1064     * paranoid.. -- fl_
1065     *
1066     * +p means paranoid, it is useless for anything else on modern IRC, as
1067     * list isn't really usable. If you want to have a private channel these
1068     * days, you set it +s. Halfops can no longer remove simple modes when
1069     * +p is set (although they can set +p) so it is safe to use this to
1070     * control whether they can (de)halfop...
1071     */
1072     if (alev <
1073     ((chptr->mode.mode & MODE_PRIVATE) ? CHACCESS_CHANOP : CHACCESS_HALFOP))
1074     {
1075     if (!(*errors & SM_ERR_NOOPS))
1076 michael 1834 sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
1077     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
1078 adx 30 me.name, source_p->name, chname);
1079     *errors |= SM_ERR_NOOPS;
1080     return;
1081     }
1082    
1083     if ((dir == MODE_QUERY) || (parc <= *parn))
1084     return;
1085    
1086     opnick = parv[(*parn)++];
1087    
1088 michael 2475 if ((targ_p = find_chasing(source_p, opnick, NULL)) == NULL)
1089 adx 30 return;
1090     if (!IsClient(targ_p))
1091     return;
1092    
1093     if ((member = find_channel_link(targ_p, chptr)) == NULL)
1094     {
1095     if (!(*errors & SM_ERR_NOTONCHANNEL))
1096 michael 1834 sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
1097 adx 30 me.name, source_p->name, opnick, chname);
1098     *errors |= SM_ERR_NOTONCHANNEL;
1099     return;
1100     }
1101    
1102     if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
1103     return;
1104    
1105     /* no redundant mode changes */
1106 adx 356 if (dir == MODE_ADD && has_member_flags(member, CHFL_HALFOP | CHFL_CHANOP))
1107 adx 30 return;
1108     if (dir == MODE_DEL && !has_member_flags(member, CHFL_HALFOP))
1109     return;
1110    
1111     mode_changes[mode_count].letter = 'h';
1112     mode_changes[mode_count].dir = dir;
1113 adx 356 mode_changes[mode_count].caps = CAP_HOPS;
1114 adx 30 mode_changes[mode_count].nocaps = 0;
1115     mode_changes[mode_count].mems = ALL_MEMBERS;
1116     mode_changes[mode_count].id = targ_p->id;
1117     mode_changes[mode_count].arg = targ_p->name;
1118     mode_changes[mode_count++].client = targ_p;
1119    
1120 adx 356 mode_changes[mode_count].letter = 'o';
1121     mode_changes[mode_count].dir = dir;
1122     mode_changes[mode_count].caps = 0;
1123     mode_changes[mode_count].nocaps = CAP_HOPS;
1124     mode_changes[mode_count].mems = ONLY_SERVERS;
1125     mode_changes[mode_count].id = targ_p->id;
1126     mode_changes[mode_count].arg = targ_p->name;
1127     mode_changes[mode_count++].client = targ_p;
1128    
1129 adx 30 if (dir == MODE_ADD)
1130     {
1131     AddMemberFlag(member, CHFL_HALFOP);
1132     DelMemberFlag(member, CHFL_DEOPPED);
1133     }
1134     else
1135     DelMemberFlag(member, CHFL_HALFOP);
1136     }
1137     #endif
1138    
1139     static void
1140     chm_voice(struct Client *client_p, struct Client *source_p,
1141     struct Channel *chptr, int parc, int *parn,
1142     char **parv, int *errors, int alev, int dir, char c, void *d,
1143     const char *chname)
1144     {
1145 michael 2892 const char *opnick = NULL;
1146 adx 30 struct Client *targ_p;
1147     struct Membership *member;
1148    
1149     if (alev < CHACCESS_HALFOP)
1150     {
1151     if (!(*errors & SM_ERR_NOOPS))
1152 michael 1834 sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
1153     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
1154 adx 30 me.name, source_p->name, chname);
1155     *errors |= SM_ERR_NOOPS;
1156     return;
1157     }
1158    
1159     if ((dir == MODE_QUERY) || parc <= *parn)
1160     return;
1161    
1162     opnick = parv[(*parn)++];
1163    
1164 michael 2475 if ((targ_p = find_chasing(source_p, opnick, NULL)) == NULL)
1165 adx 30 return;
1166     if (!IsClient(targ_p))
1167     return;
1168    
1169     if ((member = find_channel_link(targ_p, chptr)) == NULL)
1170     {
1171     if (!(*errors & SM_ERR_NOTONCHANNEL))
1172 michael 1834 sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
1173 adx 30 me.name, source_p->name, opnick, chname);
1174     *errors |= SM_ERR_NOTONCHANNEL;
1175     return;
1176     }
1177    
1178     if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
1179     return;
1180    
1181     /* no redundant mode changes */
1182     if (dir == MODE_ADD && has_member_flags(member, CHFL_VOICE))
1183     return;
1184     if (dir == MODE_DEL && !has_member_flags(member, CHFL_VOICE))
1185     return;
1186    
1187     mode_changes[mode_count].letter = 'v';
1188     mode_changes[mode_count].dir = dir;
1189     mode_changes[mode_count].caps = 0;
1190     mode_changes[mode_count].nocaps = 0;
1191     mode_changes[mode_count].mems = ALL_MEMBERS;
1192     mode_changes[mode_count].id = targ_p->id;
1193     mode_changes[mode_count].arg = targ_p->name;
1194     mode_changes[mode_count++].client = targ_p;
1195    
1196     if (dir == MODE_ADD)
1197     AddMemberFlag(member, CHFL_VOICE);
1198     else
1199     DelMemberFlag(member, CHFL_VOICE);
1200     }
1201    
1202     static void
1203     chm_limit(struct Client *client_p, struct Client *source_p,
1204     struct Channel *chptr, int parc, int *parn,
1205     char **parv, int *errors, int alev, int dir, char c, void *d,
1206     const char *chname)
1207     {
1208     int i, limit;
1209     char *lstr;
1210    
1211     if (alev < CHACCESS_HALFOP)
1212     {
1213     if (!(*errors & SM_ERR_NOOPS))
1214 michael 1834 sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
1215     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
1216 adx 30 me.name, source_p->name, chname);
1217     *errors |= SM_ERR_NOOPS;
1218     return;
1219     }
1220    
1221     if (dir == MODE_QUERY)
1222     return;
1223    
1224     if ((dir == MODE_ADD) && parc > *parn)
1225     {
1226     lstr = parv[(*parn)++];
1227    
1228     if ((limit = atoi(lstr)) <= 0)
1229     return;
1230    
1231 michael 1793 sprintf(lstr, "%d", limit);
1232 adx 30
1233     /* if somebody sets MODE #channel +ll 1 2, accept latter --fl */
1234     for (i = 0; i < mode_count; i++)
1235     if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
1236     mode_changes[i].letter = 0;
1237    
1238     mode_changes[mode_count].letter = c;
1239     mode_changes[mode_count].dir = MODE_ADD;
1240     mode_changes[mode_count].caps = 0;
1241     mode_changes[mode_count].nocaps = 0;
1242     mode_changes[mode_count].mems = ALL_MEMBERS;
1243     mode_changes[mode_count].id = NULL;
1244     mode_changes[mode_count++].arg = lstr;
1245    
1246     chptr->mode.limit = limit;
1247     }
1248     else if (dir == MODE_DEL)
1249     {
1250     if (!chptr->mode.limit)
1251     return;
1252    
1253     chptr->mode.limit = 0;
1254    
1255     mode_changes[mode_count].letter = c;
1256     mode_changes[mode_count].dir = MODE_DEL;
1257     mode_changes[mode_count].caps = 0;
1258     mode_changes[mode_count].nocaps = 0;
1259     mode_changes[mode_count].mems = ALL_MEMBERS;
1260     mode_changes[mode_count].id = NULL;
1261     mode_changes[mode_count++].arg = NULL;
1262     }
1263     }
1264    
1265     static void
1266     chm_key(struct Client *client_p, struct Client *source_p,
1267     struct Channel *chptr, int parc, int *parn,
1268     char **parv, int *errors, int alev, int dir, char c, void *d,
1269     const char *chname)
1270     {
1271     int i;
1272     char *key;
1273    
1274     if (alev < CHACCESS_HALFOP)
1275     {
1276     if (!(*errors & SM_ERR_NOOPS))
1277 michael 1834 sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
1278     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
1279 adx 30 me.name, source_p->name, chname);
1280     *errors |= SM_ERR_NOOPS;
1281     return;
1282     }
1283    
1284     if (dir == MODE_QUERY)
1285     return;
1286    
1287     if ((dir == MODE_ADD) && parc > *parn)
1288     {
1289     key = parv[(*parn)++];
1290    
1291     if (MyClient(source_p))
1292     fix_key(key);
1293     else
1294     fix_key_old(key);
1295    
1296     if (*key == '\0')
1297     return;
1298    
1299     assert(key[0] != ' ');
1300     strlcpy(chptr->mode.key, key, sizeof(chptr->mode.key));
1301    
1302     /* if somebody does MODE #channel +kk a b, accept latter --fl */
1303     for (i = 0; i < mode_count; i++)
1304     if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
1305     mode_changes[i].letter = 0;
1306    
1307     mode_changes[mode_count].letter = c;
1308     mode_changes[mode_count].dir = MODE_ADD;
1309     mode_changes[mode_count].caps = 0;
1310     mode_changes[mode_count].nocaps = 0;
1311     mode_changes[mode_count].mems = ALL_MEMBERS;
1312     mode_changes[mode_count].id = NULL;
1313     mode_changes[mode_count++].arg = chptr->mode.key;
1314     }
1315     else if (dir == MODE_DEL)
1316     {
1317     if (parc > *parn)
1318     (*parn)++;
1319    
1320     if (chptr->mode.key[0] == '\0')
1321     return;
1322    
1323     chptr->mode.key[0] = '\0';
1324    
1325     mode_changes[mode_count].letter = c;
1326     mode_changes[mode_count].dir = MODE_DEL;
1327     mode_changes[mode_count].caps = 0;
1328     mode_changes[mode_count].nocaps = 0;
1329     mode_changes[mode_count].mems = ALL_MEMBERS;
1330     mode_changes[mode_count].id = NULL;
1331     mode_changes[mode_count++].arg = "*";
1332     }
1333     }
1334    
1335     struct ChannelMode
1336     {
1337     void (*func) (struct Client *client_p, struct Client *source_p,
1338     struct Channel *chptr, int parc, int *parn, char **parv,
1339     int *errors, int alev, int dir, char c, void *d,
1340     const char *chname);
1341     void *d;
1342     };
1343    
1344     static struct ChannelMode ModeTable[255] =
1345     {
1346     {chm_nosuch, NULL},
1347     {chm_nosuch, NULL}, /* A */
1348     {chm_nosuch, NULL}, /* B */
1349     {chm_nosuch, NULL}, /* C */
1350     {chm_nosuch, NULL}, /* D */
1351     {chm_nosuch, NULL}, /* E */
1352     {chm_nosuch, NULL}, /* F */
1353     {chm_nosuch, NULL}, /* G */
1354     {chm_nosuch, NULL}, /* H */
1355     {chm_invex, NULL}, /* I */
1356     {chm_nosuch, NULL}, /* J */
1357     {chm_nosuch, NULL}, /* K */
1358     {chm_nosuch, NULL}, /* L */
1359 michael 1954 {chm_simple, (void *)MODE_MODREG}, /* M */
1360 adx 30 {chm_nosuch, NULL}, /* N */
1361 michael 1150 {chm_operonly, (void *) MODE_OPERONLY}, /* O */
1362 adx 30 {chm_nosuch, NULL}, /* P */
1363     {chm_nosuch, NULL}, /* Q */
1364 michael 1175 {chm_simple, (void *) MODE_REGONLY}, /* R */
1365 michael 1150 {chm_simple, (void *) MODE_SSLONLY}, /* S */
1366 adx 30 {chm_nosuch, NULL}, /* T */
1367     {chm_nosuch, NULL}, /* U */
1368     {chm_nosuch, NULL}, /* V */
1369     {chm_nosuch, NULL}, /* W */
1370     {chm_nosuch, NULL}, /* X */
1371     {chm_nosuch, NULL}, /* Y */
1372     {chm_nosuch, NULL}, /* Z */
1373     {chm_nosuch, NULL},
1374     {chm_nosuch, NULL},
1375     {chm_nosuch, NULL},
1376     {chm_nosuch, NULL},
1377     {chm_nosuch, NULL},
1378     {chm_nosuch, NULL},
1379 michael 2892 {chm_nosuch, NULL}, /* a */
1380 adx 30 {chm_ban, NULL}, /* b */
1381 michael 1937 {chm_simple, (void *) MODE_NOCTRL}, /* c */
1382 adx 30 {chm_nosuch, NULL}, /* d */
1383     {chm_except, NULL}, /* e */
1384     {chm_nosuch, NULL}, /* f */
1385     {chm_nosuch, NULL}, /* g */
1386     #ifdef HALFOPS
1387     {chm_hop, NULL}, /* h */
1388     #else
1389 michael 2892 {chm_nosuch, NULL}, /* h */
1390 adx 30 #endif
1391     {chm_simple, (void *) MODE_INVITEONLY}, /* i */
1392     {chm_nosuch, NULL}, /* j */
1393     {chm_key, NULL}, /* k */
1394     {chm_limit, NULL}, /* l */
1395     {chm_simple, (void *) MODE_MODERATED}, /* m */
1396     {chm_simple, (void *) MODE_NOPRIVMSGS}, /* n */
1397     {chm_op, NULL}, /* o */
1398     {chm_simple, (void *) MODE_PRIVATE}, /* p */
1399     {chm_nosuch, NULL}, /* q */
1400 michael 1167 {chm_registered, (void *) MODE_REGISTERED}, /* r */
1401 adx 30 {chm_simple, (void *) MODE_SECRET}, /* s */
1402     {chm_simple, (void *) MODE_TOPICLIMIT}, /* t */
1403     {chm_nosuch, NULL}, /* u */
1404     {chm_voice, NULL}, /* v */
1405     {chm_nosuch, NULL}, /* w */
1406     {chm_nosuch, NULL}, /* x */
1407     {chm_nosuch, NULL}, /* y */
1408     {chm_nosuch, NULL}, /* z */
1409     };
1410    
1411     /* get_channel_access()
1412     *
1413     * inputs - pointer to Client struct
1414     * - pointer to Membership struct
1415     * output - CHACCESS_CHANOP if we should let them have
1416     * chanop level access, 0 for peon level access.
1417     * side effects - NONE
1418     */
1419     static int
1420     get_channel_access(struct Client *source_p, struct Membership *member)
1421     {
1422     /* Let hacked servers in for now... */
1423     if (!MyClient(source_p))
1424     return CHACCESS_CHANOP;
1425    
1426     if (member == NULL)
1427     return CHACCESS_NOTONCHAN;
1428    
1429     /* just to be sure.. */
1430     assert(source_p == member->client_p);
1431    
1432     if (has_member_flags(member, CHFL_CHANOP))
1433     return CHACCESS_CHANOP;
1434    
1435     #ifdef HALFOPS
1436     if (has_member_flags(member, CHFL_HALFOP))
1437     return CHACCESS_HALFOP;
1438     #endif
1439    
1440     return CHACCESS_PEON;
1441     }
1442    
1443     /* void send_cap_mode_changes(struct Client *client_p,
1444     * struct Client *source_p,
1445     * struct Channel *chptr, int cap, int nocap)
1446     * Input: The client sending(client_p), the source client(source_p),
1447     * the channel to send mode changes for(chptr)
1448     * Output: None.
1449     * Side-effects: Sends the appropriate mode changes to capable servers.
1450     *
1451     * send_cap_mode_changes() will loop the server list itself, because
1452     * at this point in time we have 4 capabs for channels, CAP_IE, CAP_EX,
1453     * and a server could support any number of these..
1454     * so we make the modebufs per server, tailoring them to each servers
1455     * specific demand. Its not very pretty, but its one of the few realistic
1456     * ways to handle having this many capabs for channel modes.. --fl_
1457     *
1458     * Reverted back to my original design, except that we now keep a count
1459     * of the number of servers which each combination as an optimisation, so
1460     * the capabs combinations which are not needed are not worked out. -A1kmm
1461     */
1462     /* rewritten to ensure parabuf < MODEBUFLEN -db */
1463    
1464     static void
1465     send_cap_mode_changes(struct Client *client_p, struct Client *source_p,
1466 michael 1015 struct Channel *chptr, unsigned int cap, unsigned int nocap)
1467 adx 30 {
1468     int i, mbl, pbl, arglen, nc, mc;
1469     int len;
1470     const char *arg = NULL;
1471     char *parptr;
1472     int dir = MODE_QUERY;
1473    
1474     mc = 0;
1475     nc = 0;
1476     pbl = 0;
1477    
1478     parabuf[0] = '\0';
1479     parptr = parabuf;
1480    
1481     if ((cap & CAP_TS6) && source_p->id[0] != '\0')
1482 michael 1793 mbl = sprintf(modebuf, ":%s TMODE %lu %s ", source_p->id,
1483 michael 2892 (unsigned long)chptr->channelts, chptr->chname);
1484 adx 30 else
1485 michael 1793 mbl = sprintf(modebuf, ":%s MODE %s ", source_p->name,
1486 michael 2892 chptr->chname);
1487 adx 30
1488     /* loop the list of - modes we have */
1489     for (i = 0; i < mode_count; i++)
1490     {
1491     /* if they dont support the cap we need, or they do support a cap they
1492     * cant have, then dont add it to the modebuf.. that way they wont see
1493     * the mode
1494     */
1495     if ((mode_changes[i].letter == 0) ||
1496 michael 2892 ((cap & mode_changes[i].caps) != mode_changes[i].caps) ||
1497     ((nocap & mode_changes[i].nocaps) != mode_changes[i].nocaps))
1498 adx 30 continue;
1499    
1500     arg = "";
1501    
1502     if ((cap & CAP_TS6) && mode_changes[i].id)
1503     arg = mode_changes[i].id;
1504     if (*arg == '\0')
1505     arg = mode_changes[i].arg;
1506    
1507     /* if we're creeping past the buf size, we need to send it and make
1508     * another line for the other modes
1509     * XXX - this could give away server topology with uids being
1510     * different lengths, but not much we can do, except possibly break
1511     * them as if they were the longest of the nick or uid at all times,
1512     * which even then won't work as we don't always know the uid -A1kmm.
1513     */
1514     if (arg != NULL)
1515     arglen = strlen(arg);
1516     else
1517     arglen = 0;
1518    
1519     if ((mc == MAXMODEPARAMS) ||
1520     ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) ||
1521     (pbl + arglen + BAN_FUDGE) >= MODEBUFLEN)
1522     {
1523     if (nc != 0)
1524 michael 2892 sendto_server(client_p, cap, nocap, "%s %s", modebuf, parabuf);
1525 adx 30 nc = 0;
1526     mc = 0;
1527    
1528     if ((cap & CAP_TS6) && source_p->id[0] != '\0')
1529 michael 1793 mbl = sprintf(modebuf, ":%s MODE %s ", source_p->id,
1530     chptr->chname);
1531 adx 30 else
1532 michael 1793 mbl = sprintf(modebuf, ":%s MODE %s ", source_p->name,
1533     chptr->chname);
1534 adx 30
1535     pbl = 0;
1536     parabuf[0] = '\0';
1537     parptr = parabuf;
1538     dir = MODE_QUERY;
1539     }
1540    
1541     if (dir != mode_changes[i].dir)
1542     {
1543     modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1544     dir = mode_changes[i].dir;
1545     }
1546    
1547     modebuf[mbl++] = mode_changes[i].letter;
1548     modebuf[mbl] = '\0';
1549     nc++;
1550    
1551     if (arg != NULL)
1552     {
1553 michael 1793 len = sprintf(parptr, "%s ", arg);
1554 adx 30 pbl += len;
1555     parptr += len;
1556     mc++;
1557     }
1558     }
1559    
1560     if (pbl && parabuf[pbl - 1] == ' ')
1561     parabuf[pbl - 1] = 0;
1562    
1563     if (nc != 0)
1564 michael 2892 sendto_server(client_p, cap, nocap, "%s %s", modebuf, parabuf);
1565 adx 30 }
1566    
1567     /* void send_mode_changes(struct Client *client_p,
1568     * struct Client *source_p,
1569     * struct Channel *chptr)
1570     * Input: The client sending(client_p), the source client(source_p),
1571     * the channel to send mode changes for(chptr),
1572     * mode change globals.
1573     * Output: None.
1574     * Side-effects: Sends the appropriate mode changes to other clients
1575     * and propagates to servers.
1576     */
1577     /* ensure parabuf < MODEBUFLEN -db */
1578     static void
1579     send_mode_changes(struct Client *client_p, struct Client *source_p,
1580     struct Channel *chptr, char *chname)
1581     {
1582     int i, mbl, pbl, arglen, nc, mc;
1583     int len;
1584     const char *arg = NULL;
1585     char *parptr;
1586     int dir = MODE_QUERY;
1587    
1588     /* bail out if we have nothing to do... */
1589     if (!mode_count)
1590     return;
1591    
1592     if (IsServer(source_p))
1593 michael 1793 mbl = sprintf(modebuf, ":%s MODE %s ", (IsHidden(source_p) ||
1594     ConfigServerHide.hide_servers) ?
1595     me.name : source_p->name, chname);
1596 adx 30 else
1597 michael 1793 mbl = sprintf(modebuf, ":%s!%s@%s MODE %s ", source_p->name,
1598     source_p->username, source_p->host, chname);
1599 adx 30
1600     mc = 0;
1601     nc = 0;
1602     pbl = 0;
1603    
1604     parabuf[0] = '\0';
1605     parptr = parabuf;
1606    
1607     for (i = 0; i < mode_count; i++)
1608     {
1609     if (mode_changes[i].letter == 0 ||
1610     mode_changes[i].mems == NON_CHANOPS ||
1611     mode_changes[i].mems == ONLY_SERVERS)
1612     continue;
1613    
1614     arg = mode_changes[i].arg;
1615     if (arg != NULL)
1616     arglen = strlen(arg);
1617     else
1618     arglen = 0;
1619    
1620 michael 2892 if ((mc == MAXMODEPARAMS) ||
1621 adx 30 ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) ||
1622 michael 2892 ((arglen + pbl + BAN_FUDGE) >= MODEBUFLEN))
1623 adx 30 {
1624     if (mbl && modebuf[mbl - 1] == '-')
1625     modebuf[mbl - 1] = '\0';
1626    
1627     if (nc != 0)
1628 michael 1243 sendto_channel_local(ALL_MEMBERS, 0, chptr, "%s %s", modebuf, parabuf);
1629 adx 30
1630     nc = 0;
1631     mc = 0;
1632    
1633     if (IsServer(source_p))
1634 michael 2557 mbl = sprintf(modebuf, ":%s MODE %s ", (IsHidden(source_p) ||
1635     ConfigServerHide.hide_servers) ?
1636     me.name : source_p->name, chname);
1637 adx 30 else
1638 michael 1793 mbl = sprintf(modebuf, ":%s!%s@%s MODE %s ", source_p->name,
1639     source_p->username, source_p->host, chname);
1640 adx 30
1641     pbl = 0;
1642     parabuf[0] = '\0';
1643     parptr = parabuf;
1644     dir = MODE_QUERY;
1645     }
1646    
1647     if (dir != mode_changes[i].dir)
1648     {
1649     modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1650     dir = mode_changes[i].dir;
1651     }
1652    
1653     modebuf[mbl++] = mode_changes[i].letter;
1654     modebuf[mbl] = '\0';
1655     nc++;
1656    
1657     if (arg != NULL)
1658     {
1659 michael 1793 len = sprintf(parptr, "%s ", arg);
1660 adx 30 pbl += len;
1661     parptr += len;
1662     mc++;
1663     }
1664     }
1665    
1666     if (pbl && parabuf[pbl - 1] == ' ')
1667     parabuf[pbl - 1] = 0;
1668    
1669     if (nc != 0)
1670 michael 1243 sendto_channel_local(ALL_MEMBERS, 0, chptr, "%s %s", modebuf, parabuf);
1671 adx 30
1672     nc = 0;
1673     mc = 0;
1674    
1675     /* Now send to servers... */
1676     for (i = 0; i < NCHCAP_COMBOS; i++)
1677     if (chcap_combos[i].count != 0)
1678     send_cap_mode_changes(client_p, source_p, chptr,
1679     chcap_combos[i].cap_yes,
1680     chcap_combos[i].cap_no);
1681     }
1682    
1683     /* void set_channel_mode(struct Client *client_p, struct Client *source_p,
1684     * struct Channel *chptr, int parc, char **parv,
1685     * char *chname)
1686     * Input: The client we received this from, the client this originated
1687     * from, the channel, the parameter count starting at the modes,
1688     * the parameters, the channel name.
1689     * Output: None.
1690     * Side-effects: Changes the channel membership and modes appropriately,
1691     * sends the appropriate MODE messages to the appropriate
1692     * clients.
1693     */
1694     void
1695     set_channel_mode(struct Client *client_p, struct Client *source_p, struct Channel *chptr,
1696     struct Membership *member, int parc, char *parv[], char *chname)
1697     {
1698     int dir = MODE_ADD;
1699     int parn = 1;
1700     int alevel, errors = 0;
1701     char *ml = parv[0], c;
1702     int table_position;
1703    
1704     mode_count = 0;
1705     mode_limit = 0;
1706     simple_modes_mask = 0;
1707    
1708     alevel = get_channel_access(source_p, member);
1709    
1710 michael 2892 for (; (c = *ml) != '\0'; ml++)
1711 adx 30 {
1712     switch (c)
1713     {
1714     case '+':
1715     dir = MODE_ADD;
1716     break;
1717     case '-':
1718     dir = MODE_DEL;
1719     break;
1720     case '=':
1721     dir = MODE_QUERY;
1722     break;
1723     default:
1724     if (c < 'A' || c > 'z')
1725     table_position = 0;
1726     else
1727     table_position = c - 'A' + 1;
1728     ModeTable[table_position].func(client_p, source_p, chptr,
1729     parc, &parn,
1730     parv, &errors, alevel, dir, c,
1731     ModeTable[table_position].d,
1732     chname);
1733     break;
1734     }
1735     }
1736    
1737     send_mode_changes(client_p, source_p, chptr, chname);
1738     }

Properties

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