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