ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/cmode.C
Revision: 1.5
Committed: Thu Aug 30 19:56:24 2007 UTC (16 years, 9 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.4: +5 -5 lines
Log Message:
- put faultcodes into their own namespace
- removed old files
- limited header garbage in atheme.h
- macros to inline bools for connection_t::is_*
- put some connection_t functions into the connection_t class

File Contents

# Content
1 /*
2 * cmode.C: Channel mode change tracking.
3 * Rights to this code are documented in doc/pod/license.pod.
4 *
5 * Copyright © 2005-2007 Atheme Project (http://www.atheme.org)
6 */
7
8 static char const rcsid[] = "$Id: cmode.C,v 1.4 2007-08-28 17:08:12 pippijn Exp $";
9
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 channel_mode (user_t *source, channel_t *chan, int parc, char const * const parv[])
48 {
49 bool matched = false;
50 bool simple_modes_changed = false;
51 int i, parpos = 0, whatt = MTYPE_NUL;
52 unsigned int newlimit;
53 char const *pos = parv[0];
54 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 sfree (chan->extmodes[i]);
128 }
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 sfree (chan->extmodes[i]);
141 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 sfree (chan->key);
190 }
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 sfree (chan->key);
205 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_t::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 phandler->part_sts (chan, cu->user);
288 phandler->join_sts (chan, cu->user, false, channel_modes (chan, true));
289 }
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_t::find (chan->name);
333 if (mc != NULL && (simple_modes_changed || (mc->flags & MC_MLOCK_CHECK)))
334 check_modes (mc, true);
335 }
336 }
337
338 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 /* like channel_mode() but parv array passed as varargs */
346 void
347 channel_mode_va (user_t *source, channel_t *chan, int parc, char const * const parv0, ...)
348 {
349 char const *parv[255];
350 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 char const *p;
413
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 phandler->mode_sts (md->source, md->channel, buf);
547 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 modestack_add_ext (struct modestackdata *md, int dir, int i, char const * const value)
596 {
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 modestack_add_param (struct modestackdata *md, int dir, char type, char const * const value)
616 {
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 phandler->join_sts (channel, u, false, channel_modes (channel, true));
696 modestack_flush (&modestackdata);
697 if (u != NULL)
698 phandler->part_sts (channel, u);
699 }
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 modestack_mode_ext (char *source, channel_t *channel, int dir, int i, char const * const value)
734 {
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 modestack_mode_param (char *source, channel_t *channel, int dir, char type, char const * const value)
751 {
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 sfree (c->key);
772 c->key = NULL;
773 for (i = 0; i < MAXEXTMODES; i++)
774 if (c->extmodes[i] != NULL)
775 {
776 sfree (c->extmodes[i]);
777 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::item *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 sfree (mychan->chan->key);
873 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 sfree (mychan->chan->key);
903 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 sfree (mychan->chan->extmodes[i]);
920 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 sfree (mychan->chan->extmodes[i]);
934 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 */