ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/channel_mode.c
Revision: 1175
Committed: Sun Aug 14 10:47:48 2011 UTC (14 years ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/src/channel_mode.c
File size: 52492 byte(s)
Log Message:
- several fixes to services compatibility mode

File Contents

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

Properties

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