ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-8/src/channel_mode.c
Revision: 356
Committed: Mon Jan 2 22:05:15 2006 UTC (19 years, 7 months ago) by adx
Content type: text/x-csrc
Original Path: ircd-hybrid-7.2/src/channel_mode.c
File size: 47507 byte(s)
Log Message:
+ MFC support for halfop->op rewriting.

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

Properties

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