ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/channel_mode.c
Revision: 593
Committed: Fri May 12 05:47:32 2006 UTC (19 years, 3 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-7.2/src/channel_mode.c
File size: 48138 byte(s)
Log Message:
- Backported RKLINE fix so the user and host portion of a banmask don't get
  cut off after 10 and 63 chars, respectively.
  A split_nuh() rewrite was required for this.
- Removed now unused xstrldup() function

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     static void
906     chm_op(struct Client *client_p, struct Client *source_p,
907     struct Channel *chptr, int parc, int *parn,
908     char **parv, int *errors, int alev, int dir, char c, void *d,
909     const char *chname)
910     {
911     char *opnick;
912     struct Client *targ_p;
913     struct Membership *member;
914 adx 356 int caps = 0;
915 adx 30
916     if (alev < CHACCESS_CHANOP)
917     {
918     if (!(*errors & SM_ERR_NOOPS))
919     sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
920     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
921     me.name, source_p->name, chname);
922     *errors |= SM_ERR_NOOPS;
923     return;
924     }
925    
926     if ((dir == MODE_QUERY) || (parc <= *parn))
927     return;
928    
929     opnick = parv[(*parn)++];
930    
931     if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL)
932     return;
933     if (!IsClient(targ_p))
934     return;
935    
936     if ((member = find_channel_link(targ_p, chptr)) == NULL)
937     {
938     if (!(*errors & SM_ERR_NOTONCHANNEL))
939     sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
940     me.name, source_p->name, opnick, chname);
941     *errors |= SM_ERR_NOTONCHANNEL;
942     return;
943     }
944    
945     if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
946     return;
947    
948     /* no redundant mode changes */
949     if (dir == MODE_ADD && has_member_flags(member, CHFL_CHANOP))
950     return;
951     if (dir == MODE_DEL && !has_member_flags(member, CHFL_CHANOP))
952 adx 356 {
953     #ifdef HALFOPS
954     if (has_member_flags(member, CHFL_HALFOP))
955     chm_hop(client_p, source_p, chptr, parc, parn, parv, errors, alev,
956     dir, c, d, chname);
957     #endif
958 adx 30 return;
959 adx 356 }
960 adx 30
961 adx 356 #ifdef HALFOPS
962     if (dir == MODE_ADD && has_member_flags(member, CHFL_HALFOP))
963     {
964     /* promoting from % to @ is visible only to CAP_HOPS servers */
965     mode_changes[mode_count].letter = 'h';
966     mode_changes[mode_count].dir = MODE_DEL;
967     mode_changes[mode_count].caps = caps = CAP_HOPS;
968     mode_changes[mode_count].nocaps = 0;
969     mode_changes[mode_count].mems = ALL_MEMBERS;
970     mode_changes[mode_count].id = NULL;
971     mode_changes[mode_count].arg = targ_p->name;
972     mode_changes[mode_count++].client = targ_p;
973     }
974     #endif
975    
976 adx 30 mode_changes[mode_count].letter = 'o';
977     mode_changes[mode_count].dir = dir;
978 adx 356 mode_changes[mode_count].caps = caps;
979 adx 30 mode_changes[mode_count].nocaps = 0;
980     mode_changes[mode_count].mems = ALL_MEMBERS;
981     mode_changes[mode_count].id = targ_p->id;
982     mode_changes[mode_count].arg = targ_p->name;
983     mode_changes[mode_count++].client = targ_p;
984    
985     if (dir == MODE_ADD)
986     {
987     AddMemberFlag(member, CHFL_CHANOP);
988 adx 356 DelMemberFlag(member, CHFL_DEOPPED | CHFL_HALFOP);
989 adx 30 }
990     else
991     DelMemberFlag(member, CHFL_CHANOP);
992     }
993    
994     #ifdef HALFOPS
995     static void
996     chm_hop(struct Client *client_p, struct Client *source_p,
997     struct Channel *chptr, int parc, int *parn,
998     char **parv, int *errors, int alev, int dir, char c, void *d,
999     const char *chname)
1000     {
1001     char *opnick;
1002     struct Client *targ_p;
1003     struct Membership *member;
1004    
1005     /* *sigh* - dont allow halfops to set +/-h, they could fully control a
1006     * channel if there were no ops - it doesnt solve anything.. MODE_PRIVATE
1007     * when used with MODE_SECRET is paranoid - cant use +p
1008     *
1009     * it needs to be optional per channel - but not via +p, that or remove
1010     * paranoid.. -- fl_
1011     *
1012     * +p means paranoid, it is useless for anything else on modern IRC, as
1013     * list isn't really usable. If you want to have a private channel these
1014     * days, you set it +s. Halfops can no longer remove simple modes when
1015     * +p is set (although they can set +p) so it is safe to use this to
1016     * control whether they can (de)halfop...
1017     */
1018     if (alev <
1019     ((chptr->mode.mode & MODE_PRIVATE) ? CHACCESS_CHANOP : CHACCESS_HALFOP))
1020     {
1021     if (!(*errors & SM_ERR_NOOPS))
1022     sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
1023     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
1024     me.name, source_p->name, chname);
1025     *errors |= SM_ERR_NOOPS;
1026     return;
1027     }
1028    
1029     if ((dir == MODE_QUERY) || (parc <= *parn))
1030     return;
1031    
1032     opnick = parv[(*parn)++];
1033    
1034     if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL)
1035     return;
1036     if (!IsClient(targ_p))
1037     return;
1038    
1039     if ((member = find_channel_link(targ_p, chptr)) == NULL)
1040     {
1041     if (!(*errors & SM_ERR_NOTONCHANNEL))
1042     sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
1043     me.name, source_p->name, opnick, chname);
1044     *errors |= SM_ERR_NOTONCHANNEL;
1045     return;
1046     }
1047    
1048     if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
1049     return;
1050    
1051     /* no redundant mode changes */
1052 adx 356 if (dir == MODE_ADD && has_member_flags(member, CHFL_HALFOP | CHFL_CHANOP))
1053 adx 30 return;
1054     if (dir == MODE_DEL && !has_member_flags(member, CHFL_HALFOP))
1055     return;
1056    
1057     mode_changes[mode_count].letter = 'h';
1058     mode_changes[mode_count].dir = dir;
1059 adx 356 mode_changes[mode_count].caps = CAP_HOPS;
1060 adx 30 mode_changes[mode_count].nocaps = 0;
1061     mode_changes[mode_count].mems = ALL_MEMBERS;
1062     mode_changes[mode_count].id = targ_p->id;
1063     mode_changes[mode_count].arg = targ_p->name;
1064     mode_changes[mode_count++].client = targ_p;
1065    
1066 adx 356 mode_changes[mode_count].letter = 'o';
1067     mode_changes[mode_count].dir = dir;
1068     mode_changes[mode_count].caps = 0;
1069     mode_changes[mode_count].nocaps = CAP_HOPS;
1070     mode_changes[mode_count].mems = ONLY_SERVERS;
1071     mode_changes[mode_count].id = targ_p->id;
1072     mode_changes[mode_count].arg = targ_p->name;
1073     mode_changes[mode_count++].client = targ_p;
1074    
1075 adx 30 if (dir == MODE_ADD)
1076     {
1077     AddMemberFlag(member, CHFL_HALFOP);
1078     DelMemberFlag(member, CHFL_DEOPPED);
1079     }
1080     else
1081     DelMemberFlag(member, CHFL_HALFOP);
1082     }
1083     #endif
1084    
1085     static void
1086     chm_voice(struct Client *client_p, struct Client *source_p,
1087     struct Channel *chptr, int parc, int *parn,
1088     char **parv, int *errors, int alev, int dir, char c, void *d,
1089     const char *chname)
1090     {
1091     char *opnick;
1092     struct Client *targ_p;
1093     struct Membership *member;
1094    
1095     if (alev < CHACCESS_HALFOP)
1096     {
1097     if (!(*errors & SM_ERR_NOOPS))
1098     sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
1099     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
1100     me.name, source_p->name, chname);
1101     *errors |= SM_ERR_NOOPS;
1102     return;
1103     }
1104    
1105     if ((dir == MODE_QUERY) || parc <= *parn)
1106     return;
1107    
1108     opnick = parv[(*parn)++];
1109    
1110     if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL)
1111     return;
1112     if (!IsClient(targ_p))
1113     return;
1114    
1115     if ((member = find_channel_link(targ_p, chptr)) == NULL)
1116     {
1117     if (!(*errors & SM_ERR_NOTONCHANNEL))
1118     sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
1119     me.name, source_p->name, opnick, chname);
1120     *errors |= SM_ERR_NOTONCHANNEL;
1121     return;
1122     }
1123    
1124     if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
1125     return;
1126    
1127     /* no redundant mode changes */
1128     if (dir == MODE_ADD && has_member_flags(member, CHFL_VOICE))
1129     return;
1130     if (dir == MODE_DEL && !has_member_flags(member, CHFL_VOICE))
1131     return;
1132    
1133     mode_changes[mode_count].letter = 'v';
1134     mode_changes[mode_count].dir = dir;
1135     mode_changes[mode_count].caps = 0;
1136     mode_changes[mode_count].nocaps = 0;
1137     mode_changes[mode_count].mems = ALL_MEMBERS;
1138     mode_changes[mode_count].id = targ_p->id;
1139     mode_changes[mode_count].arg = targ_p->name;
1140     mode_changes[mode_count++].client = targ_p;
1141    
1142     if (dir == MODE_ADD)
1143     AddMemberFlag(member, CHFL_VOICE);
1144     else
1145     DelMemberFlag(member, CHFL_VOICE);
1146     }
1147    
1148     static void
1149     chm_limit(struct Client *client_p, struct Client *source_p,
1150     struct Channel *chptr, int parc, int *parn,
1151     char **parv, int *errors, int alev, int dir, char c, void *d,
1152     const char *chname)
1153     {
1154     int i, limit;
1155     char *lstr;
1156    
1157     if (alev < CHACCESS_HALFOP)
1158     {
1159     if (!(*errors & SM_ERR_NOOPS))
1160     sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
1161     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
1162     me.name, source_p->name, chname);
1163     *errors |= SM_ERR_NOOPS;
1164     return;
1165     }
1166    
1167     if (dir == MODE_QUERY)
1168     return;
1169    
1170     if ((dir == MODE_ADD) && parc > *parn)
1171     {
1172     lstr = parv[(*parn)++];
1173    
1174     if ((limit = atoi(lstr)) <= 0)
1175     return;
1176    
1177     ircsprintf(lstr, "%d", limit);
1178    
1179     /* if somebody sets MODE #channel +ll 1 2, accept latter --fl */
1180     for (i = 0; i < mode_count; i++)
1181     {
1182     if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
1183     mode_changes[i].letter = 0;
1184     }
1185    
1186     mode_changes[mode_count].letter = c;
1187     mode_changes[mode_count].dir = MODE_ADD;
1188     mode_changes[mode_count].caps = 0;
1189     mode_changes[mode_count].nocaps = 0;
1190     mode_changes[mode_count].mems = ALL_MEMBERS;
1191     mode_changes[mode_count].id = NULL;
1192     mode_changes[mode_count++].arg = lstr;
1193    
1194     chptr->mode.limit = limit;
1195     }
1196     else if (dir == MODE_DEL)
1197     {
1198     if (!chptr->mode.limit)
1199     return;
1200    
1201     chptr->mode.limit = 0;
1202    
1203     mode_changes[mode_count].letter = c;
1204     mode_changes[mode_count].dir = MODE_DEL;
1205     mode_changes[mode_count].caps = 0;
1206     mode_changes[mode_count].nocaps = 0;
1207     mode_changes[mode_count].mems = ALL_MEMBERS;
1208     mode_changes[mode_count].id = NULL;
1209     mode_changes[mode_count++].arg = NULL;
1210     }
1211     }
1212    
1213     static void
1214     chm_key(struct Client *client_p, struct Client *source_p,
1215     struct Channel *chptr, int parc, int *parn,
1216     char **parv, int *errors, int alev, int dir, char c, void *d,
1217     const char *chname)
1218     {
1219     int i;
1220     char *key;
1221    
1222     if (alev < CHACCESS_HALFOP)
1223     {
1224     if (!(*errors & SM_ERR_NOOPS))
1225     sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
1226     ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
1227     me.name, source_p->name, chname);
1228     *errors |= SM_ERR_NOOPS;
1229     return;
1230     }
1231    
1232     if (dir == MODE_QUERY)
1233     return;
1234    
1235     if ((dir == MODE_ADD) && parc > *parn)
1236     {
1237     key = parv[(*parn)++];
1238    
1239     if (MyClient(source_p))
1240     fix_key(key);
1241     else
1242     fix_key_old(key);
1243    
1244     if (*key == '\0')
1245     return;
1246    
1247     assert(key[0] != ' ');
1248     strlcpy(chptr->mode.key, key, sizeof(chptr->mode.key));
1249    
1250     /* if somebody does MODE #channel +kk a b, accept latter --fl */
1251     for (i = 0; i < mode_count; i++)
1252     {
1253     if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
1254     mode_changes[i].letter = 0;
1255     }
1256    
1257     mode_changes[mode_count].letter = c;
1258     mode_changes[mode_count].dir = MODE_ADD;
1259     mode_changes[mode_count].caps = 0;
1260     mode_changes[mode_count].nocaps = 0;
1261     mode_changes[mode_count].mems = ALL_MEMBERS;
1262     mode_changes[mode_count].id = NULL;
1263     mode_changes[mode_count++].arg = chptr->mode.key;
1264     }
1265     else if (dir == MODE_DEL)
1266     {
1267     if (parc > *parn)
1268     (*parn)++;
1269    
1270     if (chptr->mode.key[0] == '\0')
1271     return;
1272    
1273     chptr->mode.key[0] = '\0';
1274    
1275     mode_changes[mode_count].letter = c;
1276     mode_changes[mode_count].dir = MODE_DEL;
1277     mode_changes[mode_count].caps = 0;
1278     mode_changes[mode_count].nocaps = 0;
1279     mode_changes[mode_count].mems = ALL_MEMBERS;
1280     mode_changes[mode_count].id = NULL;
1281     mode_changes[mode_count++].arg = "*";
1282     }
1283     }
1284    
1285     struct ChannelMode
1286     {
1287     void (*func) (struct Client *client_p, struct Client *source_p,
1288     struct Channel *chptr, int parc, int *parn, char **parv,
1289     int *errors, int alev, int dir, char c, void *d,
1290     const char *chname);
1291     void *d;
1292     };
1293    
1294     /* *INDENT-OFF* */
1295     static struct ChannelMode ModeTable[255] =
1296     {
1297     {chm_nosuch, NULL},
1298     {chm_nosuch, NULL}, /* A */
1299     {chm_nosuch, NULL}, /* B */
1300     {chm_nosuch, NULL}, /* C */
1301     {chm_nosuch, NULL}, /* D */
1302     {chm_nosuch, NULL}, /* E */
1303     {chm_nosuch, NULL}, /* F */
1304     {chm_nosuch, NULL}, /* G */
1305     {chm_nosuch, NULL}, /* H */
1306     {chm_invex, NULL}, /* I */
1307     {chm_nosuch, NULL}, /* J */
1308     {chm_nosuch, NULL}, /* K */
1309     {chm_nosuch, NULL}, /* L */
1310     {chm_nosuch, NULL}, /* M */
1311     {chm_nosuch, NULL}, /* N */
1312     {chm_nosuch, NULL}, /* O */
1313     {chm_nosuch, NULL}, /* P */
1314     {chm_nosuch, NULL}, /* Q */
1315     {chm_nosuch, NULL}, /* R */
1316     {chm_nosuch, NULL}, /* S */
1317     {chm_nosuch, NULL}, /* T */
1318     {chm_nosuch, NULL}, /* U */
1319     {chm_nosuch, NULL}, /* V */
1320     {chm_nosuch, NULL}, /* W */
1321     {chm_nosuch, NULL}, /* X */
1322     {chm_nosuch, NULL}, /* Y */
1323     {chm_nosuch, NULL}, /* Z */
1324     {chm_nosuch, NULL},
1325     {chm_nosuch, NULL},
1326     {chm_nosuch, NULL},
1327     {chm_nosuch, NULL},
1328     {chm_nosuch, NULL},
1329     {chm_nosuch, NULL},
1330     {chm_nosuch, NULL}, /* a */
1331     {chm_ban, NULL}, /* b */
1332     {chm_nosuch, NULL}, /* c */
1333     {chm_nosuch, NULL}, /* d */
1334     {chm_except, NULL}, /* e */
1335     {chm_nosuch, NULL}, /* f */
1336     {chm_nosuch, NULL}, /* g */
1337     #ifdef HALFOPS
1338     {chm_hop, NULL}, /* h */
1339     #else
1340     {chm_nosuch, NULL}, /* h */
1341     #endif
1342     {chm_simple, (void *) MODE_INVITEONLY}, /* i */
1343     {chm_nosuch, NULL}, /* j */
1344     {chm_key, NULL}, /* k */
1345     {chm_limit, NULL}, /* l */
1346     {chm_simple, (void *) MODE_MODERATED}, /* m */
1347     {chm_simple, (void *) MODE_NOPRIVMSGS}, /* n */
1348     {chm_op, NULL}, /* o */
1349     {chm_simple, (void *) MODE_PRIVATE}, /* p */
1350     {chm_nosuch, NULL}, /* q */
1351     {chm_nosuch, NULL}, /* r */
1352     {chm_simple, (void *) MODE_SECRET}, /* s */
1353     {chm_simple, (void *) MODE_TOPICLIMIT}, /* t */
1354     {chm_nosuch, NULL}, /* u */
1355     {chm_voice, NULL}, /* v */
1356     {chm_nosuch, NULL}, /* w */
1357     {chm_nosuch, NULL}, /* x */
1358     {chm_nosuch, NULL}, /* y */
1359     {chm_nosuch, NULL}, /* z */
1360     };
1361     /* *INDENT-ON* */
1362    
1363     /* get_channel_access()
1364     *
1365     * inputs - pointer to Client struct
1366     * - pointer to Membership struct
1367     * output - CHACCESS_CHANOP if we should let them have
1368     * chanop level access, 0 for peon level access.
1369     * side effects - NONE
1370     */
1371     static int
1372     get_channel_access(struct Client *source_p, struct Membership *member)
1373     {
1374     /* Let hacked servers in for now... */
1375     if (!MyClient(source_p))
1376     return CHACCESS_CHANOP;
1377    
1378     if (member == NULL)
1379     return CHACCESS_NOTONCHAN;
1380    
1381     /* just to be sure.. */
1382     assert(source_p == member->client_p);
1383    
1384     if (has_member_flags(member, CHFL_CHANOP))
1385     return CHACCESS_CHANOP;
1386    
1387     #ifdef HALFOPS
1388     if (has_member_flags(member, CHFL_HALFOP))
1389     return CHACCESS_HALFOP;
1390     #endif
1391    
1392     return CHACCESS_PEON;
1393     }
1394    
1395     /* void send_cap_mode_changes(struct Client *client_p,
1396     * struct Client *source_p,
1397     * struct Channel *chptr, int cap, int nocap)
1398     * Input: The client sending(client_p), the source client(source_p),
1399     * the channel to send mode changes for(chptr)
1400     * Output: None.
1401     * Side-effects: Sends the appropriate mode changes to capable servers.
1402     *
1403     * send_cap_mode_changes() will loop the server list itself, because
1404     * at this point in time we have 4 capabs for channels, CAP_IE, CAP_EX,
1405     * and a server could support any number of these..
1406     * so we make the modebufs per server, tailoring them to each servers
1407     * specific demand. Its not very pretty, but its one of the few realistic
1408     * ways to handle having this many capabs for channel modes.. --fl_
1409     *
1410     * Reverted back to my original design, except that we now keep a count
1411     * of the number of servers which each combination as an optimisation, so
1412     * the capabs combinations which are not needed are not worked out. -A1kmm
1413     */
1414     /* rewritten to ensure parabuf < MODEBUFLEN -db */
1415    
1416     static void
1417     send_cap_mode_changes(struct Client *client_p, struct Client *source_p,
1418     struct Channel *chptr, int cap, int nocap)
1419     {
1420     int i, mbl, pbl, arglen, nc, mc;
1421     int len;
1422     const char *arg = NULL;
1423     char *parptr;
1424     int dir = MODE_QUERY;
1425    
1426     mc = 0;
1427     nc = 0;
1428     pbl = 0;
1429    
1430     parabuf[0] = '\0';
1431     parptr = parabuf;
1432    
1433     if ((cap & CAP_TS6) && source_p->id[0] != '\0')
1434     mbl = ircsprintf(modebuf, ":%s TMODE %lu %s ", source_p->id,
1435     (unsigned long)chptr->channelts, chptr->chname);
1436     else
1437     mbl = ircsprintf(modebuf, ":%s MODE %s ", source_p->name,
1438     chptr->chname);
1439    
1440     /* loop the list of - modes we have */
1441     for (i = 0; i < mode_count; i++)
1442     {
1443     /* if they dont support the cap we need, or they do support a cap they
1444     * cant have, then dont add it to the modebuf.. that way they wont see
1445     * the mode
1446     */
1447     if ((mode_changes[i].letter == 0) ||
1448     ((cap & mode_changes[i].caps) != mode_changes[i].caps)
1449     || ((nocap & mode_changes[i].nocaps) != mode_changes[i].nocaps))
1450     continue;
1451    
1452     arg = "";
1453    
1454     if ((cap & CAP_TS6) && mode_changes[i].id)
1455     arg = mode_changes[i].id;
1456     if (*arg == '\0')
1457     arg = mode_changes[i].arg;
1458    
1459     /* if we're creeping past the buf size, we need to send it and make
1460     * another line for the other modes
1461     * XXX - this could give away server topology with uids being
1462     * different lengths, but not much we can do, except possibly break
1463     * them as if they were the longest of the nick or uid at all times,
1464     * which even then won't work as we don't always know the uid -A1kmm.
1465     */
1466     if (arg != NULL)
1467     arglen = strlen(arg);
1468     else
1469     arglen = 0;
1470    
1471     if ((mc == MAXMODEPARAMS) ||
1472     ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) ||
1473     (pbl + arglen + BAN_FUDGE) >= MODEBUFLEN)
1474     {
1475     if (nc != 0)
1476     sendto_server(client_p, source_p, chptr, cap, nocap,
1477     LL_ICHAN | LL_ICLIENT, "%s %s",
1478     modebuf, parabuf);
1479     nc = 0;
1480     mc = 0;
1481    
1482     if ((cap & CAP_TS6) && source_p->id[0] != '\0')
1483     mbl = ircsprintf(modebuf, ":%s MODE %s ", source_p->id,
1484     chptr->chname);
1485     else
1486     mbl = ircsprintf(modebuf, ":%s MODE %s ", source_p->name,
1487     chptr->chname);
1488    
1489     pbl = 0;
1490     parabuf[0] = '\0';
1491     parptr = parabuf;
1492     dir = MODE_QUERY;
1493     }
1494    
1495     if (dir != mode_changes[i].dir)
1496     {
1497     modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1498     dir = mode_changes[i].dir;
1499     }
1500    
1501     modebuf[mbl++] = mode_changes[i].letter;
1502     modebuf[mbl] = '\0';
1503     nc++;
1504    
1505     if (arg != NULL)
1506     {
1507     len = ircsprintf(parptr, "%s ", arg);
1508     pbl += len;
1509     parptr += len;
1510     mc++;
1511     }
1512     }
1513    
1514     if (pbl && parabuf[pbl - 1] == ' ')
1515     parabuf[pbl - 1] = 0;
1516    
1517     if (nc != 0)
1518     sendto_server(client_p, source_p, chptr, cap, nocap,
1519     LL_ICLIENT, "%s %s", modebuf, parabuf);
1520     }
1521    
1522     /* void send_mode_changes(struct Client *client_p,
1523     * struct Client *source_p,
1524     * struct Channel *chptr)
1525     * Input: The client sending(client_p), the source client(source_p),
1526     * the channel to send mode changes for(chptr),
1527     * mode change globals.
1528     * Output: None.
1529     * Side-effects: Sends the appropriate mode changes to other clients
1530     * and propagates to servers.
1531     */
1532     /* ensure parabuf < MODEBUFLEN -db */
1533     static void
1534     send_mode_changes(struct Client *client_p, struct Client *source_p,
1535     struct Channel *chptr, char *chname)
1536     {
1537     int i, mbl, pbl, arglen, nc, mc;
1538     int len;
1539     const char *arg = NULL;
1540     char *parptr;
1541     int dir = MODE_QUERY;
1542    
1543     /* bail out if we have nothing to do... */
1544     if (!mode_count)
1545     return;
1546    
1547     if (IsServer(source_p))
1548     mbl = ircsprintf(modebuf, ":%s MODE %s ", (IsHidden(source_p) ||
1549     ConfigServerHide.hide_servers) ?
1550     me.name : source_p->name, chname);
1551     else
1552     mbl = ircsprintf(modebuf, ":%s!%s@%s MODE %s ", source_p->name,
1553     source_p->username, source_p->host, chname);
1554    
1555     mc = 0;
1556     nc = 0;
1557     pbl = 0;
1558    
1559     parabuf[0] = '\0';
1560     parptr = parabuf;
1561    
1562     for (i = 0; i < mode_count; i++)
1563     {
1564     if (mode_changes[i].letter == 0 ||
1565     mode_changes[i].mems == NON_CHANOPS ||
1566     mode_changes[i].mems == ONLY_SERVERS)
1567     continue;
1568    
1569     arg = mode_changes[i].arg;
1570     if (arg != NULL)
1571     arglen = strlen(arg);
1572     else
1573     arglen = 0;
1574    
1575     if ((mc == MAXMODEPARAMS) ||
1576     ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) ||
1577     ((arglen + pbl + BAN_FUDGE) >= MODEBUFLEN))
1578     {
1579     if (mbl && modebuf[mbl - 1] == '-')
1580     modebuf[mbl - 1] = '\0';
1581    
1582     if (nc != 0)
1583     sendto_channel_local(ALL_MEMBERS, NO, chptr, "%s %s", modebuf, parabuf);
1584    
1585     nc = 0;
1586     mc = 0;
1587    
1588     if (IsServer(source_p))
1589     mbl = ircsprintf(modebuf, ":%s MODE %s ", me.name, chname);
1590     else
1591     mbl = ircsprintf(modebuf, ":%s!%s@%s MODE %s ", source_p->name,
1592     source_p->username, source_p->host, chname);
1593    
1594     pbl = 0;
1595     parabuf[0] = '\0';
1596     parptr = parabuf;
1597     dir = MODE_QUERY;
1598     }
1599    
1600     if (dir != mode_changes[i].dir)
1601     {
1602     modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1603     dir = mode_changes[i].dir;
1604     }
1605    
1606     modebuf[mbl++] = mode_changes[i].letter;
1607     modebuf[mbl] = '\0';
1608     nc++;
1609    
1610     if (arg != NULL)
1611     {
1612     len = ircsprintf(parptr, "%s ", arg);
1613     pbl += len;
1614     parptr += len;
1615     mc++;
1616     }
1617     }
1618    
1619     if (pbl && parabuf[pbl - 1] == ' ')
1620     parabuf[pbl - 1] = 0;
1621    
1622     if (nc != 0)
1623     sendto_channel_local(ALL_MEMBERS, NO, chptr, "%s %s", modebuf, parabuf);
1624    
1625     nc = 0;
1626     mc = 0;
1627    
1628     /* Now send to servers... */
1629     for (i = 0; i < NCHCAP_COMBOS; i++)
1630     if (chcap_combos[i].count != 0)
1631     send_cap_mode_changes(client_p, source_p, chptr,
1632     chcap_combos[i].cap_yes,
1633     chcap_combos[i].cap_no);
1634     }
1635    
1636     /* void set_channel_mode(struct Client *client_p, struct Client *source_p,
1637     * struct Channel *chptr, int parc, char **parv,
1638     * char *chname)
1639     * Input: The client we received this from, the client this originated
1640     * from, the channel, the parameter count starting at the modes,
1641     * the parameters, the channel name.
1642     * Output: None.
1643     * Side-effects: Changes the channel membership and modes appropriately,
1644     * sends the appropriate MODE messages to the appropriate
1645     * clients.
1646     */
1647     void
1648     set_channel_mode(struct Client *client_p, struct Client *source_p, struct Channel *chptr,
1649     struct Membership *member, int parc, char *parv[], char *chname)
1650     {
1651     int dir = MODE_ADD;
1652     int parn = 1;
1653     int alevel, errors = 0;
1654     char *ml = parv[0], c;
1655     int table_position;
1656    
1657     mode_count = 0;
1658     mode_limit = 0;
1659     simple_modes_mask = 0;
1660    
1661     alevel = get_channel_access(source_p, member);
1662    
1663     for (; (c = *ml) != '\0'; ml++)
1664     {
1665     #if 0
1666     if(mode_count > 20)
1667     break;
1668     #endif
1669     switch (c)
1670     {
1671     case '+':
1672     dir = MODE_ADD;
1673     break;
1674     case '-':
1675     dir = MODE_DEL;
1676     break;
1677     case '=':
1678     dir = MODE_QUERY;
1679     break;
1680     default:
1681     if (c < 'A' || c > 'z')
1682     table_position = 0;
1683     else
1684     table_position = c - 'A' + 1;
1685     ModeTable[table_position].func(client_p, source_p, chptr,
1686     parc, &parn,
1687     parv, &errors, alevel, dir, c,
1688     ModeTable[table_position].d,
1689     chname);
1690     break;
1691     }
1692     }
1693    
1694     send_mode_changes(client_p, source_p, chptr, chname);
1695     }

Properties

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