ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/cmode.C
Revision: 1.7
Committed: Sun Sep 9 20:05:52 2007 UTC (16 years, 8 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.6: +2 -1 lines
Log Message:
- changed configurations to the c++ stdlib
- more #defines to enum
- removed getopt.h and link.h from the system as they were unused
- reworked logstreams
- added an itoa with old syntax
- made klines objects
- moved some global variables into appropriate classes
- fixed boost.foreach's compiler workaround #if's
- allow other files to add exceptions with ADD_EXCEPTION
- changed mynick_t to c++ object
- moved servers.h out of atheme.h
- corrected PING from inspircd 1.2

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