ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/cmode.C
Revision: 1.8
Committed: Sun Sep 16 18:54:44 2007 UTC (16 years, 8 months ago) by pippijn
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.7: +7 -2 lines
Log Message:
#defines to enum

File Contents

# User Rev Content
1 pippijn 1.1 /*
2     * cmode.C: Channel mode change tracking.
3 pippijn 1.8 *
4     * Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team
5     * Rights to this code are as documented in COPYING.
6     *
7     *
8     * Portions of this file were derived from sources bearing the following license:
9 pippijn 1.2 * Rights to this code are documented in doc/pod/license.pod.
10 pippijn 1.4 * Copyright © 2005-2007 Atheme Project (http://www.atheme.org)
11 pippijn 1.1 */
12    
13 pippijn 1.8 static char const rcsid[] = "$Id: cmode.C,v 1.7 2007-09-09 20:05:52 pippijn Exp $";
14 pippijn 1.1
15     #include "atheme.h"
16 pippijn 1.7 #include "servers.h"
17 pippijn 1.1 #include <account/chanacs.h>
18     #include <account/mychan.h>
19    
20     /* convert mode flags to a text mode string */
21     char *
22     flags_to_string (int flags)
23     {
24     static char buf[32];
25     char *s = buf;
26     int i;
27    
28     for (i = 0; mode_list[i].mode != 0; i++)
29     if (flags & mode_list[i].value)
30     *s++ = mode_list[i].mode;
31    
32     *s = 0;
33    
34     return buf;
35     }
36    
37     /* convert a mode character to a flag. */
38     int
39     mode_to_flag (char c)
40     {
41     int i;
42    
43     for (i = 0; mode_list[i].mode != 0 && mode_list[i].mode != c; i++);
44    
45     return mode_list[i].value;
46     }
47    
48     /* yeah, this should be fun. */
49     /* If source == NULL, apply a mode change from outside to our structures
50     * If source != NULL, apply the mode change and send it out from that user
51     */
52     void
53 pippijn 1.4 channel_mode (user_t *source, channel_t *chan, int parc, char const * const parv[])
54 pippijn 1.1 {
55     bool matched = false;
56     bool simple_modes_changed = false;
57 pippijn 1.6 int i, parpos = 0;
58     mtype whatt = MTYPE_NUL;
59 pippijn 1.1 unsigned int newlimit;
60 pippijn 1.4 char const *pos = parv[0];
61 pippijn 1.1 mychan_t *mc;
62     chanuser_t *cu = NULL;
63     user_t *first_deopped_service = NULL;
64     node_t *n;
65    
66     if ((!pos) || (*pos == '\0'))
67     return;
68    
69     if (!chan)
70     return;
71    
72     /* SJOIN modes of 0 means no change */
73     if (*pos == '0')
74     return;
75    
76     for (; *pos != '\0'; pos++)
77     {
78     matched = false;
79    
80     if (*pos == '+')
81     {
82     whatt = MTYPE_ADD;
83     continue;
84     }
85     if (*pos == '-')
86     {
87     whatt = MTYPE_DEL;
88     continue;
89     }
90    
91     for (i = 0; mode_list[i].mode != '\0'; i++)
92     {
93     if (*pos == mode_list[i].mode)
94     {
95     matched = true;
96    
97     if (whatt == MTYPE_ADD)
98     {
99     if (!(chan->modes & mode_list[i].value))
100     simple_modes_changed = true;
101     chan->modes |= mode_list[i].value;
102     }
103     else
104     {
105     if (chan->modes & mode_list[i].value)
106     simple_modes_changed = true;
107     chan->modes &= ~mode_list[i].value;
108     }
109    
110     if (source)
111     modestack_mode_simple (source->nick, chan, whatt, mode_list[i].value);
112    
113     break;
114     }
115     }
116     if (matched)
117     continue;
118    
119     for (i = 0; ignore_mode_list[i].mode != '\0'; i++)
120     {
121     if (*pos == ignore_mode_list[i].mode)
122     {
123     matched = true;
124     if (whatt == MTYPE_ADD)
125     {
126     if (++parpos >= parc)
127     break;
128     if (source && !ignore_mode_list[i].check (parv[parpos], chan, NULL, NULL, NULL))
129     break;
130     if (chan->extmodes[i])
131     {
132     if (strcmp (chan->extmodes[i], parv[parpos]))
133     simple_modes_changed = true;
134 pippijn 1.4 sfree (chan->extmodes[i]);
135 pippijn 1.1 }
136     else
137     simple_modes_changed = true;
138     chan->extmodes[i] = sstrdup (parv[parpos]);
139     if (source)
140     modestack_mode_ext (source->nick, chan, MTYPE_ADD, i, chan->extmodes[i]);
141     }
142     else
143     {
144     if (chan->extmodes[i])
145     {
146     simple_modes_changed = true;
147 pippijn 1.4 sfree (chan->extmodes[i]);
148 pippijn 1.1 chan->extmodes[i] = NULL;
149     }
150     if (source)
151     modestack_mode_ext (source->nick, chan, MTYPE_DEL, i, NULL);
152     }
153     break;
154     }
155     }
156     if (matched)
157     continue;
158    
159     if (*pos == 'l')
160     {
161     if (whatt == MTYPE_ADD)
162     {
163     if (++parpos >= parc)
164     continue;
165     chan->modes |= CMODE_LIMIT;
166     newlimit = atoi (parv[parpos]);
167     if (chan->limit != newlimit)
168     simple_modes_changed = true;
169     chan->limit = newlimit;
170     if (source)
171     modestack_mode_limit (source->nick, chan, MTYPE_ADD, chan->limit);
172     }
173     else
174     {
175     chan->modes &= ~CMODE_LIMIT;
176     if (chan->limit != 0)
177     simple_modes_changed = true;
178     chan->limit = 0;
179     if (source)
180     modestack_mode_limit (source->nick, chan, MTYPE_DEL, 0);
181     }
182     continue;
183     }
184    
185     if (*pos == 'k')
186     {
187     if (whatt == MTYPE_ADD)
188     {
189     if (++parpos >= parc)
190     continue;
191     chan->modes |= CMODE_KEY;
192     if (chan->key)
193     {
194     if (strcmp (chan->key, parv[parpos]))
195     simple_modes_changed = true;
196 pippijn 1.4 sfree (chan->key);
197 pippijn 1.1 }
198     else
199     simple_modes_changed = true;
200     chan->key = sstrdup (parv[parpos]);
201     if (source)
202     modestack_mode_param (source->nick, chan, MTYPE_ADD, 'k', chan->key);
203     }
204     else
205     {
206     if (chan->key)
207     simple_modes_changed = true;
208     chan->modes &= ~CMODE_KEY;
209     if (source)
210     modestack_mode_param (source->nick, chan, MTYPE_DEL, 'k', chan->key ? chan->key : "*");
211 pippijn 1.4 sfree (chan->key);
212 pippijn 1.1 chan->key = NULL;
213     /* ratbox typically sends either the key or a `*' on -k, so you
214     * should eat a parameter
215     */
216     parpos++;
217     }
218     continue;
219     }
220    
221     if (strchr (ircd->ban_like_modes, *pos))
222     {
223     if (++parpos >= parc)
224     continue;
225     if (whatt == MTYPE_ADD)
226     {
227     chanban_add (chan, parv[parpos], *pos);
228     if (source)
229     modestack_mode_param (source->nick, chan, MTYPE_ADD, *pos, parv[parpos]);
230     }
231     else
232     {
233     chanban_t *c;
234    
235     c = chanban_find (chan, parv[parpos], *pos);
236     chanban_delete (c);
237     if (source)
238     modestack_mode_param (source->nick, chan, MTYPE_DEL, *pos, parv[parpos]);
239     }
240     continue;
241     }
242    
243     for (i = 0; status_mode_list[i].mode != '\0'; i++)
244     {
245     if (*pos == status_mode_list[i].mode)
246     {
247     if (++parpos >= parc)
248     break;
249     cu = chanuser_find (chan, source ? user_find_named (parv[parpos]) : user_find (parv[parpos]));
250    
251     if (cu == NULL)
252     {
253     slog (LG_ERROR, "channel_mode(): MODE %s %c%c %s", chan->name, (whatt == MTYPE_ADD) ? '+' : '-', status_mode_list[i].mode, parv[parpos]);
254     break;
255     }
256    
257     matched = true;
258    
259     if (whatt == MTYPE_ADD)
260     {
261     cu->modes |= status_mode_list[i].value;
262    
263     if (source)
264     modestack_mode_param (source->nick, chan, MTYPE_ADD, *pos, CLIENT_NAME (cu->user));
265    
266     /* see if they did something we have to undo */
267 pippijn 1.5 if (source == NULL && cu->user->server != me.me && chansvs.me != NULL && (mc = mychan_t::find (chan->name)) && mc->flags & MC_SECURE)
268 pippijn 1.1 {
269     if (status_mode_list[i].mode == 'o' && !(chanacs_user_flags (mc, cu->user) & (CA_OP | CA_AUTOOP)))
270     {
271     /* they were opped and aren't on the list, deop them */
272     modestack_mode_param (chansvs.nick, chan, MTYPE_DEL, 'o', CLIENT_NAME (cu->user));
273     cu->modes &= ~status_mode_list[i].value;
274     }
275     else if (ircd->uses_halfops && status_mode_list[i].mode == ircd->halfops_mchar[1] && !(chanacs_user_flags (mc, cu->user) & (CA_HALFOP | CA_AUTOHALFOP)))
276     {
277     /* same for halfops -- jilles */
278     modestack_mode_param (chansvs.nick, chan, MTYPE_DEL, ircd->halfops_mchar[1], CLIENT_NAME (cu->user));
279     cu->modes &= ~status_mode_list[i].value;
280     }
281     }
282     }
283     else
284     {
285     if (cu->user->server == me.me && status_mode_list[i].value == CMODE_OP)
286     {
287     if (source == NULL)
288     {
289     if (first_deopped_service == NULL)
290     {
291     if (chan->nummembers > 1)
292     {
293     slog (LG_DEBUG, "channel_mode(): %s deopped on %s, rejoining", cu->user->nick, chan->name);
294 pippijn 1.4 phandler->part_sts (chan, cu->user);
295     phandler->join_sts (chan, cu->user, false, channel_modes (chan, true));
296 pippijn 1.1 }
297     else
298     {
299     slog (LG_DEBUG, "channel_mode(): %s deopped on %s, opping from other service", cu->user->nick, chan->name);
300     LIST_FOREACH (n, me.me->userlist.head)
301     {
302     if (n->data != cu->user)
303     {
304     modestack_mode_param (((user_t *) n->data)->nick, chan, MTYPE_ADD, *pos, CLIENT_NAME (cu->user));
305     break;
306     }
307     }
308     }
309     first_deopped_service = cu->user;
310     }
311     else if (first_deopped_service != cu->user)
312     {
313     slog (LG_DEBUG, "channel_mode(): %s deopped on %s, opping from %s", cu->user->nick, chan->name, first_deopped_service->nick);
314     modestack_mode_param (first_deopped_service->nick, chan, MTYPE_ADD, *pos, CLIENT_NAME (cu->user));
315     }
316    
317     }
318    
319     continue;
320     }
321    
322     if (source)
323     modestack_mode_param (source->nick, chan, MTYPE_DEL, *pos, CLIENT_NAME (cu->user));
324    
325     cu->modes &= ~status_mode_list[i].value;
326     }
327    
328     break;
329     }
330     }
331     if (matched)
332     continue;
333    
334     slog (LG_DEBUG, "channel_mode(): mode %c not matched", *pos);
335     }
336    
337     if (source == NULL && chansvs.me != NULL)
338     {
339 pippijn 1.5 mc = mychan_t::find (chan->name);
340 pippijn 1.1 if (mc != NULL && (simple_modes_changed || (mc->flags & MC_MLOCK_CHECK)))
341     check_modes (mc, true);
342     }
343     }
344    
345 pippijn 1.4 void
346     channel_mode (user_t *source, channel_t *chan, char const * const arg)
347     {
348     char const * const parv[] = { arg };
349     channel_mode (source, chan, 1, parv);
350     }
351    
352 pippijn 1.1 /* like channel_mode() but parv array passed as varargs */
353     void
354 pippijn 1.4 channel_mode_va (user_t *source, channel_t *chan, int parc, char const * const parv0, ...)
355 pippijn 1.1 {
356 pippijn 1.4 char const *parv[255];
357 pippijn 1.1 int i;
358     va_list va;
359    
360     if (parc == 0)
361     return;
362     #if 0
363     if (parc > sizeof parv / sizeof *parv)
364     {
365     slog (LG_DEBUG, "channel_mode_va(): parc too big (%d), truncating", parc);
366     parc = sizeof parv / sizeof *parv;
367     }
368     #endif
369     parv[0] = parv0;
370     va_start (va, parv0);
371     for (i = 1; i < parc; i++)
372     parv[i] = va_arg (va, char *);
373     va_end (va);
374     channel_mode (source, chan, parc, parv);
375     }
376    
377     static struct modestackdata
378     {
379     char source[HOSTLEN]; /* name */
380     channel_t *channel;
381     int modes_on;
382     int modes_off;
383     unsigned int limit;
384     char extmodes[MAXEXTMODES][512];
385     bool limitused, extmodesused[MAXEXTMODES];
386     char pmodes[2 * MAXMODES + 2];
387     char params[512]; /* includes leading space */
388     int totalparamslen; /* includes leading space */
389     int totallen;
390     int paramcount;
391    
392     unsigned int event;
393     } modestackdata;
394    
395     static void modestack_calclen (struct modestackdata *md);
396    
397     static void
398     modestack_debugprint (struct modestackdata *md)
399     {
400     int i;
401    
402     slog (LG_DEBUG, "modestack_debugprint(): %s MODE %s", md->source, md->channel->name);
403     slog (LG_DEBUG, "simple %x/%x", md->modes_on, md->modes_off);
404     if (md->limitused)
405     slog (LG_DEBUG, "limit %u", (unsigned) md->limit);
406     for (i = 0; i < MAXEXTMODES; i++)
407     if (md->extmodesused[i])
408     slog (LG_DEBUG, "ext %d %s", i, md->extmodes[i]);
409     slog (LG_DEBUG, "pmodes %s%s", md->pmodes, md->params);
410     modestack_calclen (md);
411     slog (LG_DEBUG, "totallen %d/%d", md->totalparamslen, md->totallen);
412     }
413    
414     /* calculates the length fields */
415     static void
416     modestack_calclen (struct modestackdata *md)
417     {
418     int i;
419 pippijn 1.4 char const *p;
420 pippijn 1.1
421     md->totallen = strlen (md->source) + USERLEN + HOSTLEN + 1 + 4 + 1 + 10 + strlen (md->channel->name) + 1;
422     md->totallen += 2 + 32 + strlen (md->pmodes);
423     md->totalparamslen = 0;
424     md->paramcount = (md->limitused != 0);
425     if (md->limitused && md->limit != 0)
426     md->totalparamslen += 11;
427     for (i = 0; i < MAXEXTMODES; i++)
428     if (md->extmodesused[i])
429     {
430     md->paramcount++;
431     if (*md->extmodes[i] != '\0')
432     md->totalparamslen += 1 + strlen (md->extmodes[i]);
433     }
434     md->totalparamslen += strlen (md->params);
435     p = md->params;
436     while (*p != '\0')
437     if (*p++ == ' ')
438     md->paramcount++;
439     md->totallen += md->totalparamslen;
440     }
441    
442     /* clears the data */
443     static void
444     modestack_clear (struct modestackdata *md)
445     {
446     int i;
447    
448     md->modes_on = 0;
449     md->modes_off = 0;
450     md->limitused = 0;
451     for (i = 0; i < MAXEXTMODES; i++)
452     md->extmodesused[i] = 0, *md->extmodes[i] = '\0';
453     md->pmodes[0] = '\0';
454     md->params[0] = '\0';
455     md->totallen = 0;
456     md->totalparamslen = 0;
457     md->paramcount = 0;
458     }
459    
460     /* sends a MODE and clears the data */
461     static void
462     modestack_flush (struct modestackdata *md)
463     {
464     char buf[512];
465     char *end, *p;
466 pippijn 1.6 mtype dir = MTYPE_NUL;
467 pippijn 1.1 int i;
468    
469     p = buf;
470     end = buf + sizeof buf;
471    
472     /* first do the mode letters */
473     if (md->modes_off)
474     {
475     if (dir != MTYPE_DEL)
476     dir = MTYPE_DEL, *p++ = '-';
477     strlcpy (p, flags_to_string (md->modes_off), end - p);
478     p += strlen (p);
479     }
480     if (md->limitused && md->limit == 0)
481     {
482     if (dir != MTYPE_DEL)
483     dir = MTYPE_DEL, *p++ = '-';
484     *p++ = 'l';
485     }
486     for (i = 0; i < MAXEXTMODES; i++)
487     {
488     if (md->extmodesused[i] && *md->extmodes[i] == '\0')
489     {
490     if (dir != MTYPE_DEL)
491     dir = MTYPE_DEL, *p++ = '-';
492     *p++ = ignore_mode_list[i].mode;
493     }
494     }
495     if (md->modes_on)
496     {
497     if (dir != MTYPE_ADD)
498     dir = MTYPE_ADD, *p++ = '+';
499     strlcpy (p, flags_to_string (md->modes_on), end - p);
500     p += strlen (p);
501     }
502     if (md->limitused && md->limit != 0)
503     {
504     if (dir != MTYPE_ADD)
505     dir = MTYPE_ADD, *p++ = '+';
506     *p++ = 'l';
507     }
508     for (i = 0; i < MAXEXTMODES; i++)
509     {
510     if (md->extmodesused[i] && *md->extmodes[i] != '\0')
511     {
512     if (dir != MTYPE_ADD)
513     dir = MTYPE_ADD, *p++ = '+';
514     *p++ = ignore_mode_list[i].mode;
515     }
516     }
517     strlcpy (p, md->pmodes + ((dir == MTYPE_ADD && *md->pmodes == '+') || (dir == MTYPE_DEL && *md->pmodes == '-') ? 1 : 0), end - p);
518     p += strlen (p);
519    
520     /* all mode letters done, now for some checks */
521     if (p == buf)
522     {
523     /*slog(LG_DEBUG, "modestack_flush(): nothing to do"); */
524     return;
525     }
526     if (p + md->totalparamslen >= end)
527     {
528     slog (LG_ERROR, "modestack_flush() overflow: %s", buf);
529     modestack_debugprint (md);
530     modestack_clear (md);
531     return;
532     }
533    
534     /* now the parameters, in the same order */
535     if (md->limitused && md->limit != 0)
536     {
537     snprintf (p, end - p, " %u", (unsigned) md->limit);
538     p += strlen (p);
539     }
540     for (i = 0; i < MAXEXTMODES; i++)
541     {
542     if (md->extmodesused[i] && *md->extmodes[i] != '\0')
543     {
544     snprintf (p, end - p, " %s", md->extmodes[i]);
545     p += strlen (p);
546     }
547     }
548     if (*md->params)
549     {
550     strlcpy (p, md->params, end - p);
551     p += strlen (p);
552     }
553 pippijn 1.4 phandler->mode_sts (md->source, md->channel, buf);
554 pippijn 1.1 modestack_clear (md);
555     }
556    
557     static struct modestackdata *
558     modestack_init (char *source, channel_t *channel)
559     {
560     if (irccasecmp (source, modestackdata.source) || channel != modestackdata.channel)
561     {
562     /*slog(LG_DEBUG, "modestack_init(): new source/channel, flushing"); */
563     modestack_flush (&modestackdata);
564     }
565     strlcpy (modestackdata.source, source, sizeof modestackdata.source);
566     modestackdata.channel = channel;
567     return &modestackdata;
568     }
569    
570     static void
571 pippijn 1.6 modestack_add_simple (struct modestackdata *md, mtype dir, int flags)
572 pippijn 1.1 {
573     if (dir == MTYPE_ADD)
574     md->modes_on |= flags, md->modes_off &= ~flags;
575     else if (dir == MTYPE_DEL)
576     md->modes_off |= flags, md->modes_on &= ~flags;
577     else
578     slog (LG_ERROR, "modestack_add_simple(): invalid direction");
579     }
580    
581     static void
582 pippijn 1.6 modestack_add_limit (struct modestackdata *md, mtype dir, unsigned int limit)
583 pippijn 1.1 {
584     md->limitused = 0;
585     modestack_calclen (md);
586     if (md->paramcount >= MAXMODES)
587     modestack_flush (md);
588     if (dir == MTYPE_ADD)
589     {
590     if (md->totallen + 11 > 512)
591     modestack_flush (md);
592     md->limit = limit;
593     }
594     else if (dir == MTYPE_DEL)
595     md->limit = 0;
596     else
597     slog (LG_ERROR, "modestack_add_limit(): invalid direction");
598     md->limitused = 1;
599     }
600    
601     static void
602 pippijn 1.6 modestack_add_ext (struct modestackdata *md, mtype dir, int i, char const * const value)
603 pippijn 1.1 {
604     md->extmodesused[i] = 0;
605     modestack_calclen (md);
606     if (md->paramcount >= MAXMODES)
607     modestack_flush (md);
608     if (dir == MTYPE_ADD)
609     {
610     if (md->totallen + 1 + strlen (value) > 512)
611     modestack_flush (md);
612     strlcpy (md->extmodes[i], value, sizeof md->extmodes[i]);
613     }
614     else if (dir == MTYPE_DEL)
615     md->extmodes[i][0] = '\0';
616     else
617     slog (LG_ERROR, "modestack_add_ext(): invalid direction");
618     md->extmodesused[i] = 1;
619     }
620    
621     static void
622 pippijn 1.6 modestack_add_param (struct modestackdata *md, mtype dir, char type, char const * const value)
623 pippijn 1.1 {
624     char *p;
625     int n = 0, i;
626     char dir2 = MTYPE_NUL;
627     char str[3];
628    
629     p = md->pmodes;
630     while (*p != '\0')
631     {
632     if (*p == '+')
633     dir2 = MTYPE_ADD;
634     else if (*p == '-')
635     dir2 = MTYPE_DEL;
636     else
637     n++;
638     p++;
639     }
640     n += (md->limitused != 0);
641     for (i = 0; i < MAXEXTMODES; i++)
642     n += (md->extmodesused[i] != 0);
643     modestack_calclen (md);
644     if (n >= MAXMODES || md->totallen + (dir != dir2) + 2 + strlen (value) > 512 || (type == 'k' && strchr (md->pmodes, 'k')))
645     {
646     modestack_flush (md);
647     dir2 = MTYPE_NUL;
648     }
649     if (dir != dir2)
650     {
651     str[0] = dir == MTYPE_ADD ? '+' : '-';
652     str[1] = type;
653     str[2] = '\0';
654     }
655     else
656     {
657     str[0] = type;
658     str[1] = '\0';
659     }
660     strlcat (md->pmodes, str, sizeof md->pmodes);
661     strlcat (md->params, " ", sizeof md->params);
662     strlcat (md->params, value, sizeof md->params);
663     }
664    
665     static void
666     modestack_flush_callback (void *arg)
667     {
668     modestack_flush ((struct modestackdata *) arg);
669     ((struct modestackdata *) arg)->event = 0;
670     }
671    
672     /* flush pending modes for a certain channel */
673     void
674     modestack_flush_channel (channel_t *channel)
675     {
676     if (channel == NULL || channel == modestackdata.channel)
677     modestack_flush (&modestackdata);
678     }
679    
680     /* forget pending modes for a certain channel */
681     void
682     modestack_forget_channel (channel_t *channel)
683     {
684     if (channel == NULL || channel == modestackdata.channel)
685     modestack_clear (&modestackdata);
686     }
687    
688     /* handle a channel that is going to be destroyed */
689     void
690     modestack_finalize_channel (channel_t *channel)
691     {
692     user_t *u;
693    
694     if (channel == modestackdata.channel)
695     {
696     if (modestackdata.modes_off & ircd->perm_mode)
697     {
698     /* A mode change is not a good way to destroy a channel */
699     slog (LG_DEBUG, "modestack_finalize_channel(): flushing modes for %s to clear perm mode", channel->name);
700     u = user_find_named (modestackdata.source);
701     if (u != NULL)
702 pippijn 1.4 phandler->join_sts (channel, u, false, channel_modes (channel, true));
703 pippijn 1.1 modestack_flush (&modestackdata);
704     if (u != NULL)
705 pippijn 1.4 phandler->part_sts (channel, u);
706 pippijn 1.1 }
707     else
708     modestack_clear (&modestackdata);
709     }
710     }
711    
712     /* stack simple modes without parameters */
713     void
714 pippijn 1.6 modestack_mode_simple (char *source, channel_t *channel, mtype dir, int flags)
715 pippijn 1.1 {
716     struct modestackdata *md;
717    
718     if (flags == 0)
719     return;
720     md = modestack_init (source, channel);
721     modestack_add_simple (md, dir, flags);
722     if (!md->event)
723     md->event = event_add_once ("flush_cmode_callback", modestack_flush_callback, md, 0);
724     }
725    
726     /* stack a limit */
727     void
728 pippijn 1.6 modestack_mode_limit (char *source, channel_t *channel, mtype dir, unsigned int limit)
729 pippijn 1.1 {
730     struct modestackdata *md;
731    
732     md = modestack_init (source, channel);
733     modestack_add_limit (md, dir, limit);
734     if (!md->event)
735     md->event = event_add_once ("flush_cmode_callback", modestack_flush_callback, md, 0);
736     }
737    
738     /* stack a non-standard type C mode */
739     void
740 pippijn 1.6 modestack_mode_ext (char *source, channel_t *channel, mtype dir, int i, char const * const value)
741 pippijn 1.1 {
742     struct modestackdata *md;
743    
744     md = modestack_init (source, channel);
745     if (i < 0 || i >= MAXEXTMODES)
746     {
747     slog (LG_ERROR, "modestack_mode_ext(): i=%d out of range (value=\"%s\")", i, value);
748     return;
749     }
750     modestack_add_ext (md, dir, i, value);
751     if (!md->event)
752     md->event = event_add_once ("flush_cmode_callback", modestack_flush_callback, md, 0);
753     }
754    
755     /* stack a type A, B or E mode */
756     void
757 pippijn 1.6 modestack_mode_param (char *source, channel_t *channel, mtype dir, char type, char const * const value)
758 pippijn 1.1 {
759     struct modestackdata *md;
760    
761     md = modestack_init (source, channel);
762     modestack_add_param (md, dir, type, value);
763     if (!md->event)
764     md->event = event_add_once ("flush_cmode_callback", modestack_flush_callback, md, 0);
765     }
766    
767     /* Clear all simple modes (+imnpstkl etc) on a channel */
768     void
769     clear_simple_modes (channel_t *c)
770     {
771     int i;
772    
773     if (c == NULL)
774     return;
775     c->modes = 0;
776     c->limit = 0;
777     if (c->key != NULL)
778 pippijn 1.4 sfree (c->key);
779 pippijn 1.1 c->key = NULL;
780     for (i = 0; i < MAXEXTMODES; i++)
781     if (c->extmodes[i] != NULL)
782     {
783 pippijn 1.4 sfree (c->extmodes[i]);
784 pippijn 1.1 c->extmodes[i] = NULL;
785     }
786     }
787    
788     char *
789     channel_modes (channel_t *c, bool doparams)
790     {
791     static char fullmode[512];
792     char params[512];
793     int i;
794     char *p;
795     char *q;
796    
797     if (c == NULL)
798     return NULL;
799    
800     p = fullmode;
801     q = params;
802     *p++ = '+';
803     *q = '\0';
804     for (i = 0; mode_list[i].mode != '\0'; i++)
805     {
806     if (c->modes & mode_list[i].value)
807     *p++ = mode_list[i].mode;
808     }
809     if (c->limit)
810     {
811     *p++ = 'l';
812     if (doparams)
813     {
814     snprintf (q, params + sizeof params - q, " %d", c->limit);
815     q += strlen (q);
816     }
817     }
818     if (c->key)
819     {
820     *p++ = 'k';
821     if (doparams)
822     {
823     *q++ = ' ';
824     strlcpy (q, c->key, params + sizeof params - q);
825     q += strlen (q);
826     }
827     }
828     for (i = 0; ignore_mode_list[i].mode != '\0'; i++)
829     {
830     if (c->extmodes[i] != NULL)
831     {
832     *p++ = ignore_mode_list[i].mode;
833     if (doparams)
834     {
835     *q++ = ' ';
836     strlcpy (q, c->extmodes[i], params + sizeof params - q);
837     q += strlen (q);
838     }
839     }
840     }
841     strlcpy (p, params, fullmode + sizeof fullmode - p);
842     return fullmode;
843     }
844    
845     void
846     check_modes (mychan_t *mychan, bool sendnow)
847     {
848     int modes;
849     int i;
850 pippijn 1.6 metadata *md;
851 pippijn 1.1 char *p, *q;
852     char str2[512];
853 pippijn 1.5
854 pippijn 1.1 if (!mychan || !mychan->chan)
855     return;
856     mychan->flags &= ~MC_MLOCK_CHECK;
857    
858     /* check what's locked on */
859     modes = ~mychan->chan->modes & mychan->mlock_on;
860     modes &= ~(CMODE_KEY | CMODE_LIMIT);
861     if (sendnow)
862     modestack_mode_simple (chansvs.nick, mychan->chan, MTYPE_ADD, modes);
863     mychan->chan->modes |= modes;
864    
865     if (mychan->mlock_limit && mychan->mlock_limit != mychan->chan->limit)
866     {
867     mychan->chan->limit = mychan->mlock_limit;
868     if (sendnow)
869     modestack_mode_limit (chansvs.nick, mychan->chan, MTYPE_ADD, mychan->mlock_limit);
870     }
871    
872     if (mychan->mlock_key)
873     {
874     if (mychan->chan->key && strcmp (mychan->chan->key, mychan->mlock_key))
875     {
876     /* some ircds still need this... :\ -- jilles */
877     if (sendnow)
878     modestack_mode_param (chansvs.nick, mychan->chan, MTYPE_DEL, 'k', mychan->chan->key);
879 pippijn 1.4 sfree (mychan->chan->key);
880 pippijn 1.1 mychan->chan->key = NULL;
881     }
882    
883     if (mychan->chan->key == NULL)
884     {
885     mychan->chan->key = sstrdup (mychan->mlock_key);
886     if (sendnow)
887     modestack_mode_param (chansvs.nick, mychan->chan, MTYPE_ADD, 'k', mychan->mlock_key);
888     }
889     }
890    
891     /* check what's locked off */
892     modes = mychan->chan->modes & mychan->mlock_off;
893     modes &= ~(CMODE_KEY | CMODE_LIMIT);
894     if (sendnow)
895     modestack_mode_simple (chansvs.nick, mychan->chan, MTYPE_DEL, modes);
896     mychan->chan->modes &= ~modes;
897    
898     if (mychan->chan->limit && (mychan->mlock_off & CMODE_LIMIT))
899     {
900     if (sendnow)
901     modestack_mode_limit (chansvs.nick, mychan->chan, MTYPE_DEL, 0);
902     mychan->chan->limit = 0;
903     }
904    
905     if (mychan->chan->key && (mychan->mlock_off & CMODE_KEY))
906     {
907     if (sendnow)
908     modestack_mode_param (chansvs.nick, mychan->chan, MTYPE_DEL, 'k', mychan->chan->key);
909 pippijn 1.4 sfree (mychan->chan->key);
910 pippijn 1.1 mychan->chan->key = NULL;
911     }
912    
913     /* non-standard type C modes separately */
914     md = mychan->find_metadata ("private:mlockext");
915     if (md != NULL)
916     {
917     p = md->value;
918     while (*p != '\0')
919     {
920     for (i = 0; ignore_mode_list[i].mode != '\0'; i++)
921     {
922     if (ignore_mode_list[i].mode == *p)
923     {
924     if ((p[1] == ' ' || p[1] == '\0') && mychan->chan->extmodes[i] != NULL)
925     {
926 pippijn 1.4 sfree (mychan->chan->extmodes[i]);
927 pippijn 1.1 mychan->chan->extmodes[i] = NULL;
928     if (sendnow)
929     modestack_mode_ext (chansvs.nick, mychan->chan, MTYPE_DEL, i, NULL);
930     }
931     else if (p[1] != ' ' && p[1] != '\0')
932     {
933     strlcpy (str2, p + 1, sizeof str2);
934     q = strchr (str2, ' ');
935     if (q != NULL)
936     *q = '\0';
937     if ((mychan->chan->extmodes[i] == NULL || strcmp (mychan->chan->extmodes[i], str2)) && ignore_mode_list[i].check (str2, mychan->chan, mychan, NULL, NULL))
938     {
939     if (mychan->chan->extmodes[i] != NULL)
940 pippijn 1.4 sfree (mychan->chan->extmodes[i]);
941 pippijn 1.1 mychan->chan->extmodes[i] = sstrdup (str2);
942     if (sendnow)
943     modestack_mode_ext (chansvs.nick, mychan->chan, MTYPE_ADD, i, mychan->chan->extmodes[i]);
944     }
945     }
946     }
947     }
948     while (*p != ' ' && *p != '\0')
949     p++;
950     while (*p == ' ')
951     p++;
952     }
953     }
954    
955     }
956    
957     /* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
958     * vim:ts=8
959     * vim:sw=8
960     * vim:noexpandtab
961     */