]> jfr.im git - irc/rqf/shadowircd.git/blob - modules/core/m_sjoin.c
[svn] - the new plan:
[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 3131 2007-01-21 15:36:31Z 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: 3131 $");
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 }
355
356 if(*modebuf != '\0')
357 sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s %s %s",
358 fakesource_p->name, chptr->chname, modebuf, parabuf);
359
360 *modebuf = *parabuf = '\0';
361
362 if(parv[3][0] != '0' && keep_new_modes)
363 modes = channel_modes(chptr, source_p);
364 else
365 modes = empty_modes;
366
367 mlen_nick = ircsprintf(buf_nick, ":%s SJOIN %ld %s %s :",
368 source_p->name, (long) chptr->channelts, parv[2], modes);
369 ptr_nick = buf_nick + mlen_nick;
370
371 /* working on the presumption eventually itll be more efficient to
372 * build a TS6 buffer without checking its needed..
373 */
374 mlen_uid = ircsprintf(buf_uid, ":%s SJOIN %ld %s %s :",
375 use_id(source_p), (long) chptr->channelts, parv[2], modes);
376 ptr_uid = buf_uid + mlen_uid;
377
378 mbuf = modebuf;
379 para[0] = para[1] = para[2] = para[3] = empty;
380 pargs = 0;
381 len_nick = len_uid = 0;
382
383 /* if theres a space, theres going to be more than one nick, change the
384 * first space to \0, so s is just the first nick, and point p to the
385 * second nick
386 */
387 if((p = strchr(s, ' ')) != NULL)
388 {
389 *p++ = '\0';
390 }
391
392 *mbuf++ = '+';
393
394 while (s)
395 {
396 fl = 0;
397
398 for (i = 0; i < 2; i++)
399 {
400 if(*s == '@')
401 {
402 fl |= CHFL_CHANOP;
403 s++;
404 }
405 else if(*s == '+')
406 {
407 fl |= CHFL_VOICE;
408 s++;
409 }
410 }
411
412 /* if the client doesnt exist or is fake direction, skip. */
413 if(!(target_p = find_client(s)) ||
414 (target_p->from != client_p) || !IsPerson(target_p))
415 goto nextnick;
416
417 /* we assume for these we can fit at least one nick/uid in.. */
418
419 /* check we can fit another status+nick+space into a buffer */
420 if((mlen_nick + len_nick + NICKLEN + 3) > (BUFSIZE - 3))
421 {
422 *(ptr_nick - 1) = '\0';
423 sendto_server(client_p->from, NULL, NOCAPS, CAP_TS6, "%s", buf_nick);
424 ptr_nick = buf_nick + mlen_nick;
425 len_nick = 0;
426 }
427
428 if((mlen_uid + len_uid + IDLEN + 3) > (BUFSIZE - 3))
429 {
430 *(ptr_uid - 1) = '\0';
431 sendto_server(client_p->from, NULL, CAP_TS6, NOCAPS, "%s", buf_uid);
432 ptr_uid = buf_uid + mlen_uid;
433 len_uid = 0;
434 }
435
436 if(keep_new_modes)
437 {
438 if(fl & CHFL_CHANOP)
439 {
440 *ptr_nick++ = '@';
441 *ptr_uid++ = '@';
442 len_nick++;
443 len_uid++;
444 }
445 if(fl & CHFL_VOICE)
446 {
447 *ptr_nick++ = '+';
448 *ptr_uid++ = '+';
449 len_nick++;
450 len_uid++;
451 }
452 }
453
454 /* copy the nick to the two buffers */
455 len = ircsprintf(ptr_nick, "%s ", target_p->name);
456 ptr_nick += len;
457 len_nick += len;
458 len = ircsprintf(ptr_uid, "%s ", use_id(target_p));
459 ptr_uid += len;
460 len_uid += len;
461
462 if(!keep_new_modes)
463 {
464 if(fl & CHFL_CHANOP)
465 fl = CHFL_DEOPPED;
466 else
467 fl = 0;
468 }
469
470 if(!IsMember(target_p, chptr))
471 {
472 add_user_to_channel(chptr, target_p, fl);
473 sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s JOIN :%s",
474 target_p->name,
475 target_p->username, target_p->host, parv[2]);
476 joins++;
477 }
478
479 if(fl & CHFL_CHANOP)
480 {
481 *mbuf++ = 'o';
482 para[pargs++] = target_p->name;
483
484 /* a +ov user.. bleh */
485 if(fl & CHFL_VOICE)
486 {
487 /* its possible the +o has filled up MAXMODEPARAMS, if so, start
488 * a new buffer
489 */
490 if(pargs >= MAXMODEPARAMS)
491 {
492 *mbuf = '\0';
493 sendto_channel_local(ALL_MEMBERS, chptr,
494 ":%s MODE %s %s %s %s %s %s",
495 fakesource_p->name, chptr->chname,
496 modebuf,
497 para[0], para[1], para[2], para[3]);
498 mbuf = modebuf;
499 *mbuf++ = '+';
500 para[0] = para[1] = para[2] = para[3] = NULL;
501 pargs = 0;
502 }
503
504 *mbuf++ = 'v';
505 para[pargs++] = target_p->name;
506 }
507 }
508 else if(fl & CHFL_VOICE)
509 {
510 *mbuf++ = 'v';
511 para[pargs++] = target_p->name;
512 }
513
514 if(pargs >= MAXMODEPARAMS)
515 {
516 *mbuf = '\0';
517 sendto_channel_local(ALL_MEMBERS, chptr,
518 ":%s MODE %s %s %s %s %s %s",
519 fakesource_p->name,
520 chptr->chname,
521 modebuf, para[0], para[1], para[2], para[3]);
522 mbuf = modebuf;
523 *mbuf++ = '+';
524 para[0] = para[1] = para[2] = para[3] = NULL;
525 pargs = 0;
526 }
527
528 nextnick:
529 /* p points to the next nick */
530 s = p;
531
532 /* if there was a trailing space and p was pointing to it, then we
533 * need to exit.. this has the side effect of breaking double spaces
534 * in an sjoin.. but that shouldnt happen anyway
535 */
536 if(s && (*s == '\0'))
537 s = p = NULL;
538
539 /* if p was NULL due to no spaces, s wont exist due to the above, so
540 * we cant check it for spaces.. if there are no spaces, then when
541 * we next get here, s will be NULL
542 */
543 if(s && ((p = strchr(s, ' ')) != NULL))
544 {
545 *p++ = '\0';
546 }
547 }
548
549 *mbuf = '\0';
550 if(pargs)
551 {
552 sendto_channel_local(ALL_MEMBERS, chptr,
553 ":%s MODE %s %s %s %s %s %s",
554 fakesource_p->name, chptr->chname, modebuf,
555 para[0], CheckEmpty(para[1]),
556 CheckEmpty(para[2]), CheckEmpty(para[3]));
557 }
558
559 if(!joins && !(chptr->mode.mode & MODE_PERMANENT))
560 {
561 if(isnew)
562 destroy_channel(chptr);
563
564 return 0;
565 }
566
567 /* Keep the colon if we're sending an SJOIN without nicks -- jilles */
568 if (joins)
569 {
570 *(ptr_nick - 1) = '\0';
571 *(ptr_uid - 1) = '\0';
572 }
573
574 sendto_server(client_p->from, NULL, CAP_TS6, NOCAPS, "%s", buf_uid);
575 sendto_server(client_p->from, NULL, NOCAPS, CAP_TS6, "%s", buf_nick);
576
577 /* if the source does TS6 we have to remove our bans. Its now safe
578 * to issue -b's to the non-ts6 servers, as the sjoin we've just
579 * sent will kill any ops they have.
580 */
581 if(!keep_our_modes && source_p->id[0] != '\0')
582 {
583 if(dlink_list_length(&chptr->banlist) > 0)
584 remove_ban_list(chptr, fakesource_p, &chptr->banlist, 'b', NOCAPS, ALL_MEMBERS);
585
586 if(dlink_list_length(&chptr->exceptlist) > 0)
587 remove_ban_list(chptr, fakesource_p, &chptr->exceptlist,
588 'e', CAP_EX, ONLY_CHANOPS);
589
590 if(dlink_list_length(&chptr->invexlist) > 0)
591 remove_ban_list(chptr, fakesource_p, &chptr->invexlist,
592 'I', CAP_IE, ONLY_CHANOPS);
593
594 if(dlink_list_length(&chptr->quietlist) > 0)
595 remove_ban_list(chptr, fakesource_p, &chptr->quietlist,
596 'q', NOCAPS, ALL_MEMBERS);
597
598 chptr->bants++;
599 }
600
601 return 0;
602 }
603
604 struct mode_letter
605 {
606 int mode;
607 char letter;
608 };
609
610 static struct mode_letter flags[] = {
611 {MODE_NOPRIVMSGS, 'n'},
612 {MODE_TOPICLIMIT, 't'},
613 {MODE_SECRET, 's'},
614 {MODE_MODERATED, 'm'},
615 {MODE_INVITEONLY, 'i'},
616 {MODE_PRIVATE, 'p'},
617 {MODE_REGONLY, 'r'},
618 {MODE_EXLIMIT, 'L'},
619 {MODE_PERMANENT, 'P'},
620 {MODE_NOCOLOR, 'c'},
621 {MODE_FREEINVITE, 'g'},
622 {MODE_OPMODERATE, 'z'},
623 {MODE_FREETARGET, 'F'},
624 {MODE_DISFORWARD, 'Q'},
625 {0, 0}
626 };
627
628 static void
629 set_final_mode(struct Mode *mode, struct Mode *oldmode)
630 {
631 int dir = MODE_QUERY;
632 char *pbuf = parabuf;
633 int len;
634 int i;
635
636 /* ok, first get a list of modes we need to add */
637 for (i = 0; flags[i].letter; i++)
638 {
639 if((mode->mode & flags[i].mode) && !(oldmode->mode & flags[i].mode))
640 {
641 if(dir != MODE_ADD)
642 {
643 *mbuf++ = '+';
644 dir = MODE_ADD;
645 }
646 *mbuf++ = flags[i].letter;
647 }
648 }
649
650 /* now the ones we need to remove. */
651 for (i = 0; flags[i].letter; i++)
652 {
653 if((oldmode->mode & flags[i].mode) && !(mode->mode & flags[i].mode))
654 {
655 if(dir != MODE_DEL)
656 {
657 *mbuf++ = '-';
658 dir = MODE_DEL;
659 }
660 *mbuf++ = flags[i].letter;
661 }
662 }
663
664 if(oldmode->limit && !mode->limit)
665 {
666 if(dir != MODE_DEL)
667 {
668 *mbuf++ = '-';
669 dir = MODE_DEL;
670 }
671 *mbuf++ = 'l';
672 }
673 if(oldmode->key[0] && !mode->key[0])
674 {
675 if(dir != MODE_DEL)
676 {
677 *mbuf++ = '-';
678 dir = MODE_DEL;
679 }
680 *mbuf++ = 'k';
681 len = ircsprintf(pbuf, "%s ", oldmode->key);
682 pbuf += len;
683 pargs++;
684 }
685 if(oldmode->join_num && !mode->join_num)
686 {
687 if(dir != MODE_DEL)
688 {
689 *mbuf++ = '-';
690 dir = MODE_DEL;
691 }
692 *mbuf++ = 'j';
693 }
694 if(oldmode->forward[0] && !mode->forward[0])
695 {
696 if(dir != MODE_DEL)
697 {
698 *mbuf++ = '-';
699 dir = MODE_DEL;
700 }
701 *mbuf++ = 'f';
702 }
703 if(mode->limit && oldmode->limit != mode->limit)
704 {
705 if(dir != MODE_ADD)
706 {
707 *mbuf++ = '+';
708 dir = MODE_ADD;
709 }
710 *mbuf++ = 'l';
711 len = ircsprintf(pbuf, "%d ", mode->limit);
712 pbuf += len;
713 pargs++;
714 }
715 if(mode->key[0] && strcmp(oldmode->key, mode->key))
716 {
717 if(dir != MODE_ADD)
718 {
719 *mbuf++ = '+';
720 dir = MODE_ADD;
721 }
722 *mbuf++ = 'k';
723 len = ircsprintf(pbuf, "%s ", mode->key);
724 pbuf += len;
725 pargs++;
726 }
727 if(mode->join_num && (oldmode->join_num != mode->join_num || oldmode->join_time != mode->join_time))
728 {
729 if(dir != MODE_ADD)
730 {
731 *mbuf++ = '+';
732 dir = MODE_ADD;
733 }
734 *mbuf++ = 'j';
735 len = ircsprintf(pbuf, "%d:%d ", mode->join_num, mode->join_time);
736 pbuf += len;
737 pargs++;
738 }
739 if(mode->forward[0] && strcmp(oldmode->forward, mode->forward) && ConfigChannel.use_forward)
740 {
741 if(dir != MODE_ADD)
742 {
743 *mbuf++ = '+';
744 dir = MODE_ADD;
745 }
746 *mbuf++ = 'f';
747 len = ircsprintf(pbuf, "%s ", mode->forward);
748 pbuf += len;
749 pargs++;
750 }
751 *mbuf = '\0';
752 }
753
754 /*
755 * remove_our_modes
756 *
757 * inputs -
758 * output -
759 * side effects -
760 */
761 static void
762 remove_our_modes(struct Channel *chptr, struct Client *source_p)
763 {
764 struct membership *msptr;
765 dlink_node *ptr;
766 char lmodebuf[MODEBUFLEN];
767 char *lpara[MAXMODEPARAMS];
768 int count = 0;
769 int i;
770
771 mbuf = lmodebuf;
772 *mbuf++ = '-';
773
774 for (i = 0; i < MAXMODEPARAMS; i++)
775 lpara[i] = NULL;
776
777 DLINK_FOREACH(ptr, chptr->members.head)
778 {
779 msptr = ptr->data;
780
781 if(is_chanop(msptr))
782 {
783 msptr->flags &= ~CHFL_CHANOP;
784 lpara[count++] = msptr->client_p->name;
785 *mbuf++ = 'o';
786
787 /* +ov, might not fit so check. */
788 if(is_voiced(msptr))
789 {
790 if(count >= MAXMODEPARAMS)
791 {
792 *mbuf = '\0';
793 sendto_channel_local(ALL_MEMBERS, chptr,
794 ":%s MODE %s %s %s %s %s %s",
795 me.name, chptr->chname,
796 lmodebuf, lpara[0], lpara[1],
797 lpara[2], lpara[3]);
798
799 /* preserve the initial '-' */
800 mbuf = lmodebuf;
801 *mbuf++ = '-';
802 count = 0;
803
804 for (i = 0; i < MAXMODEPARAMS; i++)
805 lpara[i] = NULL;
806 }
807
808 msptr->flags &= ~CHFL_VOICE;
809 lpara[count++] = msptr->client_p->name;
810 *mbuf++ = 'v';
811 }
812 }
813 else if(is_voiced(msptr))
814 {
815 msptr->flags &= ~CHFL_VOICE;
816 lpara[count++] = msptr->client_p->name;
817 *mbuf++ = 'v';
818 }
819 else
820 continue;
821
822 if(count >= MAXMODEPARAMS)
823 {
824 *mbuf = '\0';
825 sendto_channel_local(ALL_MEMBERS, chptr,
826 ":%s MODE %s %s %s %s %s %s",
827 me.name, chptr->chname, lmodebuf,
828 lpara[0], lpara[1], lpara[2], lpara[3]);
829 mbuf = lmodebuf;
830 *mbuf++ = '-';
831 count = 0;
832
833 for (i = 0; i < MAXMODEPARAMS; i++)
834 lpara[i] = NULL;
835 }
836 }
837
838 if(count != 0)
839 {
840 *mbuf = '\0';
841 sendto_channel_local(ALL_MEMBERS, chptr,
842 ":%s MODE %s %s %s %s %s %s",
843 me.name, chptr->chname, lmodebuf,
844 EmptyString(lpara[0]) ? "" : lpara[0],
845 EmptyString(lpara[1]) ? "" : lpara[1],
846 EmptyString(lpara[2]) ? "" : lpara[2],
847 EmptyString(lpara[3]) ? "" : lpara[3]);
848
849 }
850 }
851
852 /* remove_ban_list()
853 *
854 * inputs - channel, source, list to remove, char of mode, caps needed
855 * outputs -
856 * side effects - given list is removed, with modes issued to local clients
857 * and non-TS6 servers.
858 */
859 static void
860 remove_ban_list(struct Channel *chptr, struct Client *source_p,
861 dlink_list * list, char c, int cap, int mems)
862 {
863 static char lmodebuf[BUFSIZE];
864 static char lparabuf[BUFSIZE];
865 struct Ban *banptr;
866 dlink_node *ptr;
867 dlink_node *next_ptr;
868 char *pbuf;
869 int count = 0;
870 int cur_len, mlen, plen;
871
872 pbuf = lparabuf;
873
874 cur_len = mlen = ircsprintf(lmodebuf, ":%s MODE %s -", source_p->name, chptr->chname);
875 mbuf = lmodebuf + mlen;
876
877 DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
878 {
879 banptr = ptr->data;
880
881 /* trailing space, and the mode letter itself */
882 plen = strlen(banptr->banstr) + 2;
883
884 if(count >= MAXMODEPARAMS || (cur_len + plen) > BUFSIZE - 4)
885 {
886 /* remove trailing space */
887 *mbuf = '\0';
888 *(pbuf - 1) = '\0';
889
890 sendto_channel_local(mems, chptr, "%s %s", lmodebuf, lparabuf);
891 /* Tricky tricky. If we changed source_p to &me
892 * in ms_sjoin(), this still won't send stuff
893 * where it should not be sent, because the
894 * real source_p does TS6 -- jilles */
895 sendto_server(source_p, chptr, cap, CAP_TS6, "%s %s", lmodebuf, lparabuf);
896
897 cur_len = mlen;
898 mbuf = lmodebuf + mlen;
899 pbuf = lparabuf;
900 count = 0;
901 }
902
903 *mbuf++ = c;
904 cur_len += plen;
905 pbuf += ircsprintf(pbuf, "%s ", banptr->banstr);
906 count++;
907
908 free_ban(banptr);
909 }
910
911 *mbuf = '\0';
912 *(pbuf - 1) = '\0';
913 sendto_channel_local(mems, chptr, "%s %s", lmodebuf, lparabuf);
914 sendto_server(source_p, chptr, cap, CAP_TS6, "%s %s", lmodebuf, lparabuf);
915
916 list->head = list->tail = NULL;
917 list->length = 0;
918 }