]> jfr.im git - irc/rqf/shadowircd.git/blob - modules/core/m_sjoin.c
Argh, wrong replace caused by MS VS 2005 interface.
[irc/rqf/shadowircd.git] / modules / core / m_sjoin.c
1 /*
2 * ircd-ratbox: A slightly useful ircd.
3 * m_sjoin.c: Joins a user to a channel.
4 *
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * USA
23 *
24 * $Id: m_sjoin.c 3434 2007-04-28 23:47:25Z jilles $
25 */
26
27 #include "stdinc.h"
28 #include "channel.h"
29 #include "client.h"
30 #include "hash.h"
31 #include "irc_string.h"
32 #include "sprintf_irc.h"
33 #include "ircd.h"
34 #include "numeric.h"
35 #include "send.h"
36 #include "common.h"
37 #include "msg.h"
38 #include "parse.h"
39 #include "modules.h"
40 #include "s_serv.h"
41 #include "s_conf.h"
42
43 static int ms_sjoin(struct Client *, struct Client *, int, const char **);
44
45 struct Message sjoin_msgtab = {
46 "SJOIN", 0, 0, 0, MFLG_SLOW,
47 {mg_unreg, mg_ignore, mg_ignore, {ms_sjoin, 0}, mg_ignore, mg_ignore}
48 };
49
50 mapi_clist_av1 sjoin_clist[] = { &sjoin_msgtab, NULL };
51
52 DECLARE_MODULE_AV1(sjoin, NULL, NULL, sjoin_clist, NULL, NULL, "$Revision: 3434 $");
53
54 /*
55 * ms_sjoin
56 * parv[0] - sender
57 * parv[1] - TS
58 * parv[2] - channel
59 * parv[3] - modes + n arguments (key and/or limit)
60 * parv[4+n] - flags+nick list (all in one parameter)
61 *
62 * process a SJOIN, taking the TS's into account to either ignore the
63 * incoming modes or undo the existing ones or merge them, and JOIN
64 * all the specified users while sending JOIN/MODEs to local clients
65 */
66
67
68 static char modebuf[MODEBUFLEN];
69 static char parabuf[MODEBUFLEN];
70 static const char *para[MAXMODEPARAMS];
71 static char *mbuf;
72 static int pargs;
73
74 static void set_final_mode(struct Mode *mode, struct Mode *oldmode);
75 static void remove_our_modes(struct Channel *chptr, struct Client *source_p);
76 static void remove_ban_list(struct Channel *chptr, struct Client *source_p,
77 rb_dlink_list * list, char c, int cap, int mems);
78
79 static int
80 ms_sjoin(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
81 {
82 static char buf_nick[BUFSIZE];
83 static char buf_uid[BUFSIZE];
84 static const char empty_modes[] = "0";
85 struct Channel *chptr;
86 struct Client *target_p, *fakesource_p;
87 time_t newts;
88 time_t oldts;
89 static struct Mode mode, *oldmode;
90 const char *modes;
91 int args = 0;
92 int keep_our_modes = 1;
93 int keep_new_modes = 1;
94 int fl;
95 int isnew;
96 int mlen_nick, mlen_uid;
97 int len_nick;
98 int len_uid;
99 int len;
100 int joins = 0;
101 const char *s;
102 char *ptr_nick;
103 char *ptr_uid;
104 char *p;
105 int i, joinc = 0, timeslice = 0;
106 static char empty[] = "";
107 rb_dlink_node *ptr, *next_ptr;
108
109 if(!IsChannelName(parv[2]) || !check_channel_name(parv[2]))
110 return 0;
111
112 /* SJOIN's for local channels can't happen. */
113 if(*parv[2] == '&')
114 return 0;
115
116 modebuf[0] = parabuf[0] = mode.key[0] = mode.forward[0] = '\0';
117 pargs = mode.mode = mode.limit = mode.join_num = mode.join_time = 0;
118
119 /* Hide connecting server on netburst -- jilles */
120 if (ConfigServerHide.flatten_links && !HasSentEob(source_p))
121 fakesource_p = &me;
122 else
123 fakesource_p = source_p;
124
125 mbuf = modebuf;
126 newts = atol(parv[1]);
127
128 s = parv[3];
129 while (*s)
130 {
131 switch (*(s++))
132 {
133 case 'i':
134 mode.mode |= MODE_INVITEONLY;
135 break;
136 case 'n':
137 mode.mode |= MODE_NOPRIVMSGS;
138 break;
139 case 'p':
140 mode.mode |= MODE_PRIVATE;
141 break;
142 case 's':
143 mode.mode |= MODE_SECRET;
144 break;
145 case 'm':
146 mode.mode |= MODE_MODERATED;
147 break;
148 case 't':
149 mode.mode |= MODE_TOPICLIMIT;
150 break;
151 case 'r':
152 mode.mode |= MODE_REGONLY;
153 break;
154 case 'L':
155 mode.mode |= MODE_EXLIMIT;
156 break;
157 case 'P':
158 mode.mode |= MODE_PERMANENT;
159 break;
160 case 'c':
161 mode.mode |= MODE_NOCOLOR;
162 break;
163 case 'g':
164 mode.mode |= MODE_FREEINVITE;
165 break;
166 case 'z':
167 mode.mode |= MODE_OPMODERATE;
168 break;
169 case 'F':
170 mode.mode |= MODE_FREETARGET;
171 break;
172 case 'Q':
173 mode.mode |= MODE_DISFORWARD;
174 break;
175 case 'f':
176 strlcpy(mode.forward, parv[4 + args], sizeof(mode.forward));
177 args++;
178 if(parc < 5 + args)
179 return 0;
180 break;
181 case 'j':
182 sscanf(parv[4 + args], "%d:%d", &joinc, &timeslice);
183 args++;
184 mode.join_num = joinc;
185 mode.join_time = timeslice;
186 if(parc < 5 + args)
187 return 0;
188 break;
189 case 'k':
190 strlcpy(mode.key, parv[4 + args], sizeof(mode.key));
191 args++;
192 if(parc < 5 + args)
193 return 0;
194 break;
195 case 'l':
196 mode.limit = atoi(parv[4 + args]);
197 args++;
198 if(parc < 5 + args)
199 return 0;
200 break;
201 }
202 }
203
204 if(parv[args + 4])
205 {
206 s = parv[args + 4];
207
208 /* remove any leading spaces */
209 while (*s == ' ')
210 s++;
211 }
212 else
213 s = "";
214
215 if((chptr = get_or_create_channel(source_p, parv[2], &isnew)) == NULL)
216 return 0; /* channel name too long? */
217
218
219 oldts = chptr->channelts;
220 oldmode = &chptr->mode;
221
222 #ifdef IGNORE_BOGUS_TS
223 if(newts < 800000000)
224 {
225 sendto_realops_snomask(SNO_DEBUG, L_ALL,
226 "*** Bogus TS %ld on %s ignored from %s",
227 (long) newts, chptr->chname, client_p->name);
228
229 newts = (oldts == 0) ? oldts : 800000000;
230 }
231 #else
232 if(!isnew && !newts && oldts)
233 {
234 sendto_channel_local(ALL_MEMBERS, chptr,
235 ":%s NOTICE %s :*** Notice -- TS for %s "
236 "changed from %ld to 0",
237 me.name, chptr->chname, chptr->chname, (long) oldts);
238 sendto_realops_snomask(SNO_GENERAL, L_ALL,
239 "Server %s changing TS on %s from %ld to 0",
240 source_p->name, chptr->chname, (long) oldts);
241 }
242 #endif
243
244 if(isnew)
245 chptr->channelts = newts;
246
247 else if(newts == 0 || oldts == 0)
248 chptr->channelts = 0;
249 else if(newts == oldts)
250 ;
251 else if(newts < oldts)
252 {
253 /* If configured, kick people trying to join +i/+k
254 * channels by recreating them on split servers.
255 * Don't kick if the source has sent EOB (services
256 * deopping everyone by TS-1 SJOIN).
257 * -- jilles */
258 if (ConfigChannel.kick_on_split_riding &&
259 !HasSentEob(source_p) &&
260 ((mode.mode & MODE_INVITEONLY) ||
261 (mode.key[0] != 0 && irccmp(mode.key, oldmode->key) != 0)))
262 {
263 struct membership *msptr;
264 struct Client *who;
265 int l = rb_dlink_list_length(&chptr->members);
266 int b = rb_dlink_list_length(&chptr->banlist) +
267 rb_dlink_list_length(&chptr->exceptlist) +
268 rb_dlink_list_length(&chptr->invexlist) +
269 rb_dlink_list_length(&chptr->quietlist);
270
271 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->locmembers.head)
272 {
273 msptr = ptr->data;
274 who = msptr->client_p;
275 sendto_one(who, ":%s KICK %s %s :Net Rider",
276 me.name, chptr->chname, who->name);
277
278 sendto_server(NULL, chptr, CAP_TS6, NOCAPS,
279 ":%s KICK %s %s :Net Rider",
280 me.id, chptr->chname,
281 who->id);
282 sendto_server(NULL, chptr, NOCAPS, CAP_TS6,
283 ":%s KICK %s %s :Net Rider",
284 me.name, chptr->chname, who->name);
285 remove_user_from_channel(msptr);
286 if (--l == 0)
287 break;
288 }
289 if (l == 0)
290 {
291 /* Channel was emptied, create a new one */
292 if((chptr = get_or_create_channel(source_p, parv[2], &isnew)) == NULL)
293 return 0; /* oops! */
294
295 /* If the source does not do TS6,
296 * nontimestamped bans have been sent to it,
297 * but we have just lost those here. Let's
298 * warn the channel about this. Because
299 * of the kicks, any users on the channel
300 * will be at client_p. -- jilles */
301 if (!has_id(source_p) && b > 0)
302 sendto_one(client_p, ":%s NOTICE %s :*** Notice -- possible ban desync on %s, please remove any bans just added by servers", get_id(&me, client_p), parv[2], parv[2]);
303 oldmode = &chptr->mode;
304 }
305 }
306 keep_our_modes = NO;
307 chptr->channelts = newts;
308 }
309 else
310 keep_new_modes = NO;
311
312 if(!keep_new_modes)
313 mode = *oldmode;
314 else if(keep_our_modes)
315 {
316 mode.mode |= oldmode->mode;
317 if(oldmode->limit > mode.limit)
318 mode.limit = oldmode->limit;
319 if(strcmp(mode.key, oldmode->key) < 0)
320 strcpy(mode.key, oldmode->key);
321 if(oldmode->join_num > mode.join_num ||
322 (oldmode->join_num == mode.join_num &&
323 oldmode->join_time > mode.join_time))
324 {
325 mode.join_num = oldmode->join_num;
326 mode.join_time = oldmode->join_time;
327 }
328 if(irccmp(mode.forward, oldmode->forward) < 0)
329 strcpy(mode.forward, oldmode->forward);
330 }
331 else
332 {
333 /* If setting -j, clear join throttle state -- jilles */
334 if (!mode.join_num)
335 chptr->join_count = chptr->join_delta = 0;
336 }
337
338 set_final_mode(&mode, oldmode);
339 chptr->mode = mode;
340
341 /* Lost the TS, other side wins, so remove modes on this side */
342 if(!keep_our_modes)
343 {
344 remove_our_modes(chptr, fakesource_p);
345 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->invites.head)
346 {
347 del_invite(chptr, ptr->data);
348 }
349 sendto_channel_local(ALL_MEMBERS, chptr,
350 ":%s NOTICE %s :*** Notice -- TS for %s changed from %ld to %ld",
351 me.name, chptr->chname, chptr->chname,
352 (long) oldts, (long) newts);
353 /* Update capitalization in channel name, this makes the
354 * capitalization timestamped like modes are -- jilles */
355 strcpy(chptr->chname, parv[2]);
356 }
357
358 if(*modebuf != '\0')
359 sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s %s %s",
360 fakesource_p->name, chptr->chname, modebuf, parabuf);
361
362 *modebuf = *parabuf = '\0';
363
364 if(parv[3][0] != '0' && keep_new_modes)
365 modes = channel_modes(chptr, source_p);
366 else
367 modes = empty_modes;
368
369 mlen_nick = rb_sprintf(buf_nick, ":%s SJOIN %ld %s %s :",
370 source_p->name, (long) chptr->channelts, parv[2], modes);
371 ptr_nick = buf_nick + mlen_nick;
372
373 /* working on the presumption eventually itll be more efficient to
374 * build a TS6 buffer without checking its needed..
375 */
376 mlen_uid = rb_sprintf(buf_uid, ":%s SJOIN %ld %s %s :",
377 use_id(source_p), (long) chptr->channelts, parv[2], modes);
378 ptr_uid = buf_uid + mlen_uid;
379
380 mbuf = modebuf;
381 para[0] = para[1] = para[2] = para[3] = empty;
382 pargs = 0;
383 len_nick = len_uid = 0;
384
385 /* if theres a space, theres going to be more than one nick, change the
386 * first space to \0, so s is just the first nick, and point p to the
387 * second nick
388 */
389 if((p = strchr(s, ' ')) != NULL)
390 {
391 *p++ = '\0';
392 }
393
394 *mbuf++ = '+';
395
396 while (s)
397 {
398 fl = 0;
399
400 for (i = 0; i < 2; i++)
401 {
402 if(*s == '@')
403 {
404 fl |= CHFL_CHANOP;
405 s++;
406 }
407 else if(*s == '+')
408 {
409 fl |= CHFL_VOICE;
410 s++;
411 }
412 }
413
414 /* if the client doesnt exist or is fake direction, skip. */
415 if(!(target_p = find_client(s)) ||
416 (target_p->from != client_p) || !IsPerson(target_p))
417 goto nextnick;
418
419 /* we assume for these we can fit at least one nick/uid in.. */
420
421 /* check we can fit another status+nick+space into a buffer */
422 if((mlen_nick + len_nick + NICKLEN + 3) > (BUFSIZE - 3))
423 {
424 *(ptr_nick - 1) = '\0';
425 sendto_server(client_p->from, NULL, NOCAPS, CAP_TS6, "%s", buf_nick);
426 ptr_nick = buf_nick + mlen_nick;
427 len_nick = 0;
428 }
429
430 if((mlen_uid + len_uid + IDLEN + 3) > (BUFSIZE - 3))
431 {
432 *(ptr_uid - 1) = '\0';
433 sendto_server(client_p->from, NULL, CAP_TS6, NOCAPS, "%s", buf_uid);
434 ptr_uid = buf_uid + mlen_uid;
435 len_uid = 0;
436 }
437
438 if(keep_new_modes)
439 {
440 if(fl & CHFL_CHANOP)
441 {
442 *ptr_nick++ = '@';
443 *ptr_uid++ = '@';
444 len_nick++;
445 len_uid++;
446 }
447 if(fl & CHFL_VOICE)
448 {
449 *ptr_nick++ = '+';
450 *ptr_uid++ = '+';
451 len_nick++;
452 len_uid++;
453 }
454 }
455
456 /* copy the nick to the two buffers */
457 len = rb_sprintf(ptr_nick, "%s ", target_p->name);
458 ptr_nick += len;
459 len_nick += len;
460 len = rb_sprintf(ptr_uid, "%s ", use_id(target_p));
461 ptr_uid += len;
462 len_uid += len;
463
464 if(!keep_new_modes)
465 fl = 0;
466
467 if(!IsMember(target_p, chptr))
468 {
469 add_user_to_channel(chptr, target_p, fl);
470 sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s",
471 target_p->name,
472 target_p->username, target_p->host, parv[2]);
473 joins++;
474 }
475
476 if(fl & CHFL_CHANOP)
477 {
478 *mbuf++ = 'o';
479 para[pargs++] = target_p->name;
480
481 /* a +ov user.. bleh */
482 if(fl & CHFL_VOICE)
483 {
484 /* its possible the +o has filled up MAXMODEPARAMS, if so, start
485 * a new buffer
486 */
487 if(pargs >= MAXMODEPARAMS)
488 {
489 *mbuf = '\0';
490 sendto_channel_local(ALL_MEMBERS, chptr,
491 ":%s MODE %s %s %s %s %s %s",
492 fakesource_p->name, chptr->chname,
493 modebuf,
494 para[0], para[1], para[2], para[3]);
495 mbuf = modebuf;
496 *mbuf++ = '+';
497 para[0] = para[1] = para[2] = para[3] = NULL;
498 pargs = 0;
499 }
500
501 *mbuf++ = 'v';
502 para[pargs++] = target_p->name;
503 }
504 }
505 else if(fl & CHFL_VOICE)
506 {
507 *mbuf++ = 'v';
508 para[pargs++] = target_p->name;
509 }
510
511 if(pargs >= MAXMODEPARAMS)
512 {
513 *mbuf = '\0';
514 sendto_channel_local(ALL_MEMBERS, chptr,
515 ":%s MODE %s %s %s %s %s %s",
516 fakesource_p->name,
517 chptr->chname,
518 modebuf, para[0], para[1], para[2], para[3]);
519 mbuf = modebuf;
520 *mbuf++ = '+';
521 para[0] = para[1] = para[2] = para[3] = NULL;
522 pargs = 0;
523 }
524
525 nextnick:
526 /* p points to the next nick */
527 s = p;
528
529 /* if there was a trailing space and p was pointing to it, then we
530 * need to exit.. this has the side effect of breaking double spaces
531 * in an sjoin.. but that shouldnt happen anyway
532 */
533 if(s && (*s == '\0'))
534 s = p = NULL;
535
536 /* if p was NULL due to no spaces, s wont exist due to the above, so
537 * we cant check it for spaces.. if there are no spaces, then when
538 * we next get here, s will be NULL
539 */
540 if(s && ((p = strchr(s, ' ')) != NULL))
541 {
542 *p++ = '\0';
543 }
544 }
545
546 *mbuf = '\0';
547 if(pargs)
548 {
549 sendto_channel_local(ALL_MEMBERS, chptr,
550 ":%s MODE %s %s %s %s %s %s",
551 fakesource_p->name, chptr->chname, modebuf,
552 para[0], CheckEmpty(para[1]),
553 CheckEmpty(para[2]), CheckEmpty(para[3]));
554 }
555
556 if(!joins && !(chptr->mode.mode & MODE_PERMANENT) && isnew)
557 {
558 destroy_channel(chptr);
559
560 return 0;
561 }
562
563 /* Keep the colon if we're sending an SJOIN without nicks -- jilles */
564 if (joins)
565 {
566 *(ptr_nick - 1) = '\0';
567 *(ptr_uid - 1) = '\0';
568 }
569
570 sendto_server(client_p->from, NULL, CAP_TS6, NOCAPS, "%s", buf_uid);
571 sendto_server(client_p->from, NULL, NOCAPS, CAP_TS6, "%s", buf_nick);
572
573 /* if the source does TS6 we have to remove our bans. Its now safe
574 * to issue -b's to the non-ts6 servers, as the sjoin we've just
575 * sent will kill any ops they have.
576 */
577 if(!keep_our_modes && source_p->id[0] != '\0')
578 {
579 if(rb_dlink_list_length(&chptr->banlist) > 0)
580 remove_ban_list(chptr, fakesource_p, &chptr->banlist, 'b', NOCAPS, ALL_MEMBERS);
581
582 if(rb_dlink_list_length(&chptr->exceptlist) > 0)
583 remove_ban_list(chptr, fakesource_p, &chptr->exceptlist,
584 'e', CAP_EX, ONLY_CHANOPS);
585
586 if(rb_dlink_list_length(&chptr->invexlist) > 0)
587 remove_ban_list(chptr, fakesource_p, &chptr->invexlist,
588 'I', CAP_IE, ONLY_CHANOPS);
589
590 if(rb_dlink_list_length(&chptr->quietlist) > 0)
591 remove_ban_list(chptr, fakesource_p, &chptr->quietlist,
592 'q', NOCAPS, ALL_MEMBERS);
593
594 chptr->bants++;
595 }
596
597 return 0;
598 }
599
600 static void
601 set_final_mode(struct Mode *mode, struct Mode *oldmode)
602 {
603 int dir = MODE_QUERY;
604 char *pbuf = parabuf;
605 int len;
606 int i;
607
608 /* ok, first get a list of modes we need to add */
609 for (i = 0; chmode_flags[i].letter; i++)
610 {
611 if((mode->mode & chmode_flags[i].mode) && !(oldmode->mode & chmode_flags[i].mode))
612 {
613 if(dir != MODE_ADD)
614 {
615 *mbuf++ = '+';
616 dir = MODE_ADD;
617 }
618 *mbuf++ = chmode_flags[i].letter;
619 }
620 }
621
622 /* now the ones we need to remove. */
623 for (i = 0; chmode_flags[i].letter; i++)
624 {
625 if((oldmode->mode & chmode_flags[i].mode) && !(mode->mode & chmode_flags[i].mode))
626 {
627 if(dir != MODE_DEL)
628 {
629 *mbuf++ = '-';
630 dir = MODE_DEL;
631 }
632 *mbuf++ = chmode_flags[i].letter;
633 }
634 }
635
636 if(oldmode->limit && !mode->limit)
637 {
638 if(dir != MODE_DEL)
639 {
640 *mbuf++ = '-';
641 dir = MODE_DEL;
642 }
643 *mbuf++ = 'l';
644 }
645 if(oldmode->key[0] && !mode->key[0])
646 {
647 if(dir != MODE_DEL)
648 {
649 *mbuf++ = '-';
650 dir = MODE_DEL;
651 }
652 *mbuf++ = 'k';
653 len = rb_sprintf(pbuf, "%s ", oldmode->key);
654 pbuf += len;
655 pargs++;
656 }
657 if(oldmode->join_num && !mode->join_num)
658 {
659 if(dir != MODE_DEL)
660 {
661 *mbuf++ = '-';
662 dir = MODE_DEL;
663 }
664 *mbuf++ = 'j';
665 }
666 if(oldmode->forward[0] && !mode->forward[0])
667 {
668 if(dir != MODE_DEL)
669 {
670 *mbuf++ = '-';
671 dir = MODE_DEL;
672 }
673 *mbuf++ = 'f';
674 }
675 if(mode->limit && oldmode->limit != mode->limit)
676 {
677 if(dir != MODE_ADD)
678 {
679 *mbuf++ = '+';
680 dir = MODE_ADD;
681 }
682 *mbuf++ = 'l';
683 len = rb_sprintf(pbuf, "%d ", mode->limit);
684 pbuf += len;
685 pargs++;
686 }
687 if(mode->key[0] && strcmp(oldmode->key, mode->key))
688 {
689 if(dir != MODE_ADD)
690 {
691 *mbuf++ = '+';
692 dir = MODE_ADD;
693 }
694 *mbuf++ = 'k';
695 len = rb_sprintf(pbuf, "%s ", mode->key);
696 pbuf += len;
697 pargs++;
698 }
699 if(mode->join_num && (oldmode->join_num != mode->join_num || oldmode->join_time != mode->join_time))
700 {
701 if(dir != MODE_ADD)
702 {
703 *mbuf++ = '+';
704 dir = MODE_ADD;
705 }
706 *mbuf++ = 'j';
707 len = rb_sprintf(pbuf, "%d:%d ", mode->join_num, mode->join_time);
708 pbuf += len;
709 pargs++;
710 }
711 if(mode->forward[0] && strcmp(oldmode->forward, mode->forward) && ConfigChannel.use_forward)
712 {
713 if(dir != MODE_ADD)
714 {
715 *mbuf++ = '+';
716 dir = MODE_ADD;
717 }
718 *mbuf++ = 'f';
719 len = rb_sprintf(pbuf, "%s ", mode->forward);
720 pbuf += len;
721 pargs++;
722 }
723 *mbuf = '\0';
724 }
725
726 /*
727 * remove_our_modes
728 *
729 * inputs -
730 * output -
731 * side effects -
732 */
733 static void
734 remove_our_modes(struct Channel *chptr, struct Client *source_p)
735 {
736 struct membership *msptr;
737 rb_dlink_node *ptr;
738 char lmodebuf[MODEBUFLEN];
739 char *lpara[MAXMODEPARAMS];
740 int count = 0;
741 int i;
742
743 mbuf = lmodebuf;
744 *mbuf++ = '-';
745
746 for (i = 0; i < MAXMODEPARAMS; i++)
747 lpara[i] = NULL;
748
749 RB_DLINK_FOREACH(ptr, chptr->members.head)
750 {
751 msptr = ptr->data;
752
753 if(is_chanop(msptr))
754 {
755 msptr->flags &= ~CHFL_CHANOP;
756 lpara[count++] = msptr->client_p->name;
757 *mbuf++ = 'o';
758
759 /* +ov, might not fit so check. */
760 if(is_voiced(msptr))
761 {
762 if(count >= MAXMODEPARAMS)
763 {
764 *mbuf = '\0';
765 sendto_channel_local(ALL_MEMBERS, chptr,
766 ":%s MODE %s %s %s %s %s %s",
767 me.name, chptr->chname,
768 lmodebuf, lpara[0], lpara[1],
769 lpara[2], lpara[3]);
770
771 /* preserve the initial '-' */
772 mbuf = lmodebuf;
773 *mbuf++ = '-';
774 count = 0;
775
776 for (i = 0; i < MAXMODEPARAMS; i++)
777 lpara[i] = NULL;
778 }
779
780 msptr->flags &= ~CHFL_VOICE;
781 lpara[count++] = msptr->client_p->name;
782 *mbuf++ = 'v';
783 }
784 }
785 else if(is_voiced(msptr))
786 {
787 msptr->flags &= ~CHFL_VOICE;
788 lpara[count++] = msptr->client_p->name;
789 *mbuf++ = 'v';
790 }
791 else
792 continue;
793
794 if(count >= MAXMODEPARAMS)
795 {
796 *mbuf = '\0';
797 sendto_channel_local(ALL_MEMBERS, chptr,
798 ":%s MODE %s %s %s %s %s %s",
799 me.name, chptr->chname, lmodebuf,
800 lpara[0], lpara[1], lpara[2], lpara[3]);
801 mbuf = lmodebuf;
802 *mbuf++ = '-';
803 count = 0;
804
805 for (i = 0; i < MAXMODEPARAMS; i++)
806 lpara[i] = NULL;
807 }
808 }
809
810 if(count != 0)
811 {
812 *mbuf = '\0';
813 sendto_channel_local(ALL_MEMBERS, chptr,
814 ":%s MODE %s %s %s %s %s %s",
815 me.name, chptr->chname, lmodebuf,
816 EmptyString(lpara[0]) ? "" : lpara[0],
817 EmptyString(lpara[1]) ? "" : lpara[1],
818 EmptyString(lpara[2]) ? "" : lpara[2],
819 EmptyString(lpara[3]) ? "" : lpara[3]);
820
821 }
822 }
823
824 /* remove_ban_list()
825 *
826 * inputs - channel, source, list to remove, char of mode, caps needed
827 * outputs -
828 * side effects - given list is removed, with modes issued to local clients
829 * and non-TS6 servers.
830 */
831 static void
832 remove_ban_list(struct Channel *chptr, struct Client *source_p,
833 rb_dlink_list * list, char c, int cap, int mems)
834 {
835 static char lmodebuf[BUFSIZE];
836 static char lparabuf[BUFSIZE];
837 struct Ban *banptr;
838 rb_dlink_node *ptr;
839 rb_dlink_node *next_ptr;
840 char *pbuf;
841 int count = 0;
842 int cur_len, mlen, plen;
843
844 pbuf = lparabuf;
845
846 cur_len = mlen = rb_sprintf(lmodebuf, ":%s MODE %s -", source_p->name, chptr->chname);
847 mbuf = lmodebuf + mlen;
848
849 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
850 {
851 banptr = ptr->data;
852
853 /* trailing space, and the mode letter itself */
854 plen = strlen(banptr->banstr) + 2;
855
856 if(count >= MAXMODEPARAMS || (cur_len + plen) > BUFSIZE - 4)
857 {
858 /* remove trailing space */
859 *mbuf = '\0';
860 *(pbuf - 1) = '\0';
861
862 sendto_channel_local(mems, chptr, "%s %s", lmodebuf, lparabuf);
863 /* Tricky tricky. If we changed source_p to &me
864 * in ms_sjoin(), this still won't send stuff
865 * where it should not be sent, because the
866 * real source_p does TS6 -- jilles */
867 sendto_server(source_p, chptr, cap, CAP_TS6, "%s %s", lmodebuf, lparabuf);
868
869 cur_len = mlen;
870 mbuf = lmodebuf + mlen;
871 pbuf = lparabuf;
872 count = 0;
873 }
874
875 *mbuf++ = c;
876 cur_len += plen;
877 pbuf += rb_sprintf(pbuf, "%s ", banptr->banstr);
878 count++;
879
880 free_ban(banptr);
881 }
882
883 *mbuf = '\0';
884 *(pbuf - 1) = '\0';
885 sendto_channel_local(mems, chptr, "%s %s", lmodebuf, lparabuf);
886 sendto_server(source_p, chptr, cap, CAP_TS6, "%s %s", lmodebuf, lparabuf);
887
888 list->head = list->tail = NULL;
889 list->length = 0;
890 }