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