ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/channel_mode.c
Revision: 759
Committed: Fri Aug 18 14:29:45 2006 UTC (17 years, 7 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-7.2/src/channel_mode.c
File size: 48372 byte(s)
Log Message:
- Fixed ban cache as reported by ThaPrince

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

Properties

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