ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/cmode.C
Revision: 1.4
Committed: Tue Aug 28 17:08:12 2007 UTC (16 years, 9 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.3: +33 -26 lines
Log Message:
- changed name
- updated the example config to the new system
- added more documentation
- enhanced documentation generators
- added a link to the pdf to the website
- added an RSS feed generator
- transitioned hooks to c++ callbacks
- did various merges with upstream along the way
- added const where appropriate
- removed the old block allocator
- fixed most memory leaks
- transitioned some dictionaries to std::map
- transitioned some lists to std::vector
- made some free functions members where appropriate
- renamed string to dynstr and added a static string ststr
- use NOW instead of time (NULL) if possible
- completely reworked database backends, crypto handlers and protocol handlers
  to use an object factory
- removed the old module system. ermyth does not do any dynamic loading anymore
- fixed most of the build system
- reworked how protocol commands work

File Contents

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