]> jfr.im git - solanum.git/blame - modules/core/m_join.c
Remove another silly outdated comment [ci skip]
[solanum.git] / modules / core / m_join.c
CommitLineData
212380e3
AC
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
212380e3
AC
23 */
24
25#include "stdinc.h"
212380e3
AC
26#include "channel.h"
27#include "client.h"
28#include "common.h"
29#include "hash.h"
4562c604 30#include "match.h"
212380e3
AC
31#include "ircd.h"
32#include "numeric.h"
33#include "send.h"
34#include "s_serv.h"
35#include "s_conf.h"
36#include "s_newconf.h"
37#include "msg.h"
38#include "parse.h"
39#include "modules.h"
212380e3 40#include "packet.h"
acdf71d9 41#include "chmode.h"
7e132ff0 42#include "ratelimit.h"
77d3d2db 43#include "s_assert.h"
212380e3 44
428ca87b
AC
45static int m_join(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
46static int ms_join(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
47static int ms_sjoin(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
823ab528 48static const char join_desc[] = "Provides the JOIN and TS6 SJOIN commands to facilitate joining and creating channels";
212380e3
AC
49
50static int h_can_create_channel;
51static int h_channel_join;
52
53struct Message join_msgtab = {
7baa37a9 54 "JOIN", 0, 0, 0, 0,
212380e3
AC
55 {mg_unreg, {m_join, 2}, {ms_join, 2}, mg_ignore, mg_ignore, {m_join, 2}}
56};
57
8cc12805 58struct Message sjoin_msgtab = {
7baa37a9 59 "SJOIN", 0, 0, 0, 0,
1766edef 60 {mg_unreg, mg_ignore, mg_ignore, {ms_sjoin, 4}, mg_ignore, mg_ignore}
8cc12805
VY
61};
62
63mapi_clist_av1 join_clist[] = { &join_msgtab, &sjoin_msgtab, NULL };
212380e3
AC
64
65mapi_hlist_av1 join_hlist[] = {
66 { "can_create_channel", &h_can_create_channel },
67 { "channel_join", &h_channel_join },
68 { NULL, NULL },
69};
70
823ab528 71DECLARE_MODULE_AV2(join, NULL, NULL, join_clist, join_hlist, NULL, NULL, NULL, join_desc);
212380e3 72
f4a80ce6 73static void do_join_0(struct Client *client_p, struct Client *source_p);
212380e3 74static int check_channel_name_loc(struct Client *source_p, const char *name);
35bfe0e6 75static void send_join_error(struct Client *source_p, int numeric, const char *name);
212380e3
AC
76
77static void set_final_mode(struct Mode *mode, struct Mode *oldmode);
78static void remove_our_modes(struct Channel *chptr, struct Client *source_p);
79
8cc12805 80static void remove_ban_list(struct Channel *chptr, struct Client *source_p,
8afeb720 81 rb_dlink_list * list, char c, int mems);
8cc12805 82
212380e3
AC
83static char modebuf[MODEBUFLEN];
84static char parabuf[MODEBUFLEN];
8cc12805 85static const char *para[MAXMODEPARAMS];
212380e3 86static char *mbuf;
8cc12805 87static int pargs;
212380e3
AC
88
89/* Check what we will forward to, without sending any notices to the user
90 * -- jilles
91 */
92static struct Channel *
93check_forward(struct Client *source_p, struct Channel *chptr,
765d839d 94 char *key, int *err)
212380e3
AC
95{
96 int depth = 0, i;
d9af501a 97 const char *next = NULL;
765d839d
EM
98
99 /* The caller (m_join) is only interested in the reason
100 * for the original channel.
101 */
102 if ((*err = can_join(source_p, chptr, key, &next)) == 0)
103 return chptr;
212380e3 104
6a85e665
JT
105 /* User is +Q, or forwarding disabled */
106 if (IsNoForward(source_p) || !ConfigChannel.use_forward)
212380e3
AC
107 return NULL;
108
109 while (depth < 16)
110 {
97532cfa
JT
111 if (next == NULL)
112 return NULL;
765d839d 113 chptr = find_channel(next);
212380e3
AC
114 /* Can only forward to existing channels */
115 if (chptr == NULL)
116 return NULL;
117 /* Already on there, show original error message */
118 if (IsMember(source_p, chptr))
119 return NULL;
120 /* Juped. Sending a warning notice would be unfair */
121 if (hash_find_resv(chptr->chname))
122 return NULL;
123 /* Don't forward to +Q channel */
124 if (chptr->mode.mode & MODE_DISFORWARD)
125 return NULL;
765d839d 126 i = can_join(source_p, chptr, key, &next);
212380e3
AC
127 if (i == 0)
128 return chptr;
212380e3
AC
129 depth++;
130 }
131
132 return NULL;
133}
134
135/*
136 * m_join
212380e3
AC
137 * parv[1] = channel
138 * parv[2] = channel password (key)
139 */
140static int
428ca87b 141m_join(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
212380e3
AC
142{
143 static char jbuf[BUFSIZE];
765d839d 144 struct Channel *chptr = NULL, *chptr2 = NULL;
212380e3
AC
145 struct ConfItem *aconf;
146 char *name;
147 char *key = NULL;
095efcf0 148 const char *modes;
212380e3
AC
149 int i, flags = 0;
150 char *p = NULL, *p2 = NULL;
151 char *chanlist;
152 char *mykey;
212380e3
AC
153
154 jbuf[0] = '\0';
155
156 /* rebuild the list of channels theyre supposed to be joining.
157 * this code has a side effect of losing keys, but..
158 */
159 chanlist = LOCAL_COPY(parv[1]);
4a2651e5 160 for(name = rb_strtok_r(chanlist, ",", &p); name; name = rb_strtok_r(NULL, ",", &p))
212380e3
AC
161 {
162 /* check the length and name of channel is ok */
163 if(!check_channel_name_loc(source_p, name) || (strlen(name) > LOC_CHANNELLEN))
164 {
165 sendto_one_numeric(source_p, ERR_BADCHANNAME,
166 form_str(ERR_BADCHANNAME), (unsigned char *) name);
167 continue;
168 }
169
f4a80ce6
JT
170 /* join 0 parts all channels */
171 if(*name == '0' && (name[1] == ',' || name[1] == '\0') && name == chanlist)
172 {
173 (void) strcpy(jbuf, "0");
174 continue;
175 }
176
212380e3 177 /* check it begins with # or &, and local chans are disabled */
341f971e
SB
178 else if(!IsChannelName(name) ||
179 ( ConfigChannel.disable_local_channels && name[0] == '&'))
212380e3
AC
180 {
181 sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
182 form_str(ERR_NOSUCHCHANNEL), name);
183 continue;
184 }
185
186 /* see if its resv'd */
187 if(!IsExemptResv(source_p) && (aconf = hash_find_resv(name)))
188 {
189 sendto_one_numeric(source_p, ERR_BADCHANNAME,
190 form_str(ERR_BADCHANNAME), name);
191
192 /* dont warn for opers */
193 if(!IsExemptJupe(source_p) && !IsOper(source_p))
194 sendto_realops_snomask(SNO_SPY, L_NETWIDE,
195 "User %s (%s@%s) is attempting to join locally juped channel %s (%s)",
196 source_p->name, source_p->username,
63aecfb9 197 source_p->orighost, name, aconf->passwd);
212380e3
AC
198 /* dont update tracking for jupe exempt users, these
199 * are likely to be spamtrap leaves
200 */
201 else if(IsExemptJupe(source_p))
202 aconf->port--;
203
204 continue;
205 }
206
207 if(splitmode && !IsOper(source_p) && (*name != '&') &&
208 ConfigChannel.no_join_on_split)
209 {
210 sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
211 me.name, source_p->name, name);
212 continue;
213 }
214
215 if(*jbuf)
216 (void) strcat(jbuf, ",");
1f9de103 217 (void) rb_strlcat(jbuf, name, sizeof(jbuf));
212380e3
AC
218 }
219
220 if(parc > 2)
221 {
222 mykey = LOCAL_COPY(parv[2]);
4a2651e5 223 key = rb_strtok_r(mykey, ",", &p2);
212380e3
AC
224 }
225
4a2651e5
VY
226 for(name = rb_strtok_r(jbuf, ",", &p); name;
227 key = (key) ? rb_strtok_r(NULL, ",", &p2) : NULL, name = rb_strtok_r(NULL, ",", &p))
212380e3
AC
228 {
229 hook_data_channel_activity hook_info;
230
f4a80ce6
JT
231 /* JOIN 0 simply parts all channels the user is in */
232 if(*name == '0' && !atoi(name))
233 {
234 if(source_p->user->channel.head == NULL)
235 continue;
236
237 do_join_0(&me, source_p);
238 continue;
239 }
240
212380e3
AC
241 /* look for the channel */
242 if((chptr = find_channel(name)) != NULL)
243 {
244 if(IsMember(source_p, chptr))
245 continue;
246
247 flags = 0;
248 }
249 else
250 {
251 hook_data_client_approval moduledata;
252
253 moduledata.client = source_p;
254 moduledata.approved = 0;
255
256 call_hook(h_can_create_channel, &moduledata);
257
544cde90 258 if(moduledata.approved != 0)
212380e3 259 {
35bfe0e6
JT
260 if(moduledata.approved != ERR_CUSTOM)
261 send_join_error(source_p,
262 moduledata.approved,
263 name);
212380e3
AC
264 continue;
265 }
266
267 if(splitmode && !IsOper(source_p) && (*name != '&') &&
268 ConfigChannel.no_create_on_split)
269 {
270 sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
271 me.name, source_p->name, name);
272 continue;
273 }
274
275 flags = CHFL_CHANOP;
276 }
277
5b96d9a6 278 if((rb_dlink_list_length(&source_p->user->channel) >=
212380e3 279 (unsigned long) ConfigChannel.max_chans_per_user) &&
a4721f5e 280 (!IsExtendChans(source_p) ||
5b96d9a6 281 (rb_dlink_list_length(&source_p->user->channel) >=
a4721f5e 282 (unsigned long) ConfigChannel.max_chans_per_user_large)))
212380e3
AC
283 {
284 sendto_one(source_p, form_str(ERR_TOOMANYCHANNELS),
285 me.name, source_p->name, name);
cddbab51 286 continue;
212380e3
AC
287 }
288
212380e3
AC
289 if(chptr == NULL) /* If I already have a chptr, no point doing this */
290 {
291 chptr = get_or_create_channel(source_p, name, NULL);
292
293 if(chptr == NULL)
294 {
295 sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
296 me.name, source_p->name, name);
212380e3
AC
297 continue;
298 }
299 }
300
765d839d
EM
301 /* If check_forward returns NULL, they couldn't join and there wasn't a usable forward channel. */
302 if(!(chptr2 = check_forward(source_p, chptr, key, &i)))
212380e3 303 {
765d839d
EM
304 /* might be wrong, but is there any other better location for such?
305 * see extensions/chm_operonly.c for other comments on this
306 * -- dwr
307 */
308 if(i != ERR_CUSTOM)
35bfe0e6 309 send_join_error(source_p, i, name);
765d839d 310 continue;
212380e3 311 }
765d839d
EM
312 else if(chptr != chptr2)
313 sendto_one_numeric(source_p, ERR_LINKCHANNEL, form_str(ERR_LINKCHANNEL), name, chptr2->chname);
314
315 chptr = chptr2;
212380e3 316
ff91faaf
JT
317 if(flags == 0 &&
318 !IsOper(source_p) && !IsExemptSpambot(source_p))
cf3564d6
JT
319 check_spambot_warning(source_p, name);
320
212380e3
AC
321 /* add the user to the channel */
322 add_user_to_channel(chptr, source_p, flags);
323 if (chptr->mode.join_num &&
e3354945 324 rb_current_time() - chptr->join_delta >= chptr->mode.join_time)
212380e3
AC
325 {
326 chptr->join_count = 0;
e3354945 327 chptr->join_delta = rb_current_time();
212380e3
AC
328 }
329 chptr->join_count++;
330
7e132ff0
KB
331 /* credit user for join */
332 credit_client_join(source_p);
333
212380e3
AC
334 /* we send the user their join here, because we could have to
335 * send a mode out next.
336 */
805cfa5a 337 send_channel_join(chptr, source_p);
212380e3
AC
338
339 /* its a new channel, set +nt and burst. */
340 if(flags & CHFL_CHANOP)
341 {
e3354945 342 chptr->channelts = rb_current_time();
63eb8567 343 chptr->mode.mode |= ConfigChannel.autochanmodes;
095efcf0 344 modes = channel_modes(chptr, &me);
212380e3 345
095efcf0
JT
346 sendto_channel_local(ONLY_CHANOPS, chptr, ":%s MODE %s %s",
347 me.name, chptr->chname, modes);
212380e3 348
db2545b1
JT
349 sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
350 ":%s SJOIN %ld %s %s :@%s",
351 me.id, (long) chptr->channelts,
352 chptr->chname, modes, source_p->id);
212380e3
AC
353 }
354 else
355 {
212380e3 356 sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
bee3b671 357 ":%s JOIN %ld %s +",
212380e3 358 use_id(source_p), (long) chptr->channelts,
bee3b671 359 chptr->chname);
212380e3
AC
360 }
361
362 del_invite(chptr, source_p);
363
364 if(chptr->topic != NULL)
365 {
366 sendto_one(source_p, form_str(RPL_TOPIC), me.name,
367 source_p->name, chptr->chname, chptr->topic);
368
369 sendto_one(source_p, form_str(RPL_TOPICWHOTIME),
370 me.name, source_p->name, chptr->chname,
0cce01d3
JT
371 chptr->topic_info,
372 (unsigned long)chptr->topic_time);
212380e3
AC
373 }
374
375 channel_member_names(chptr, source_p, 1);
376
212380e3
AC
377 hook_info.client = source_p;
378 hook_info.chptr = chptr;
379 hook_info.key = key;
380 call_hook(h_channel_join, &hook_info);
381 }
382
383 return 0;
384}
385
386/*
387 * ms_join
35835646
JT
388 * parv[1] = channel TS
389 * parv[2] = channel
390 * parv[3] = "+", formerly channel modes but now unused
391 * alternatively, a single "0" parameter parts all channels
212380e3
AC
392 */
393static int
428ca87b 394ms_join(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
212380e3
AC
395{
396 struct Channel *chptr;
bee3b671 397 static struct Mode mode;
212380e3
AC
398 time_t oldts;
399 time_t newts;
400 int isnew;
212380e3 401 int keep_our_modes = YES;
637c4932 402 rb_dlink_node *ptr, *next_ptr;
212380e3 403
f4a80ce6
JT
404 /* special case for join 0 */
405 if((parv[1][0] == '0') && (parv[1][1] == '\0') && parc == 2)
406 {
407 do_join_0(client_p, source_p);
408 return 0;
409 }
410
212380e3
AC
411 if(parc < 4)
412 return 0;
413
414 if(!IsChannelName(parv[2]) || !check_channel_name(parv[2]))
415 return 0;
416
417 /* joins for local channels cant happen. */
418 if(parv[2][0] == '&')
419 return 0;
420
421 mbuf = modebuf;
422 mode.key[0] = mode.forward[0] = '\0';
423 mode.mode = mode.limit = mode.join_num = mode.join_time = 0;
424
212380e3
AC
425 if((chptr = get_or_create_channel(source_p, parv[2], &isnew)) == NULL)
426 return 0;
427
428 newts = atol(parv[1]);
429 oldts = chptr->channelts;
212380e3
AC
430
431#ifdef IGNORE_BOGUS_TS
432 if(newts < 800000000)
433 {
434 sendto_realops_snomask(SNO_DEBUG, L_ALL,
435 "*** Bogus TS %ld on %s ignored from %s",
436 (long) newts, chptr->chname, client_p->name);
437 newts = (oldts == 0) ? oldts : 800000000;
438 }
439#else
440 /* making a channel TS0 */
441 if(!isnew && !newts && oldts)
442 {
443 sendto_channel_local(ALL_MEMBERS, chptr,
444 ":%s NOTICE %s :*** Notice -- TS for %s changed from %ld to 0",
445 me.name, chptr->chname, chptr->chname, (long) oldts);
446 sendto_realops_snomask(SNO_GENERAL, L_ALL,
447 "Server %s changing TS on %s from %ld to 0",
448 source_p->name, chptr->chname, (long) oldts);
449 }
450#endif
451
452 if(isnew)
453 chptr->channelts = newts;
454 else if(newts == 0 || oldts == 0)
455 chptr->channelts = 0;
456 else if(newts == oldts)
457 ;
458 else if(newts < oldts)
459 {
460 keep_our_modes = NO;
461 chptr->channelts = newts;
462 }
212380e3 463
212380e3
AC
464 /* Lost the TS, other side wins, so remove modes on this side */
465 if(!keep_our_modes)
466 {
bee3b671
JT
467 set_final_mode(&mode, &chptr->mode);
468 chptr->mode = mode;
212380e3 469 remove_our_modes(chptr, source_p);
637c4932 470 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->invites.head)
212380e3
AC
471 {
472 del_invite(chptr, ptr->data);
473 }
bee3b671
JT
474 /* If setting -j, clear join throttle state -- jilles */
475 chptr->join_count = chptr->join_delta = 0;
212380e3
AC
476 sendto_channel_local(ALL_MEMBERS, chptr,
477 ":%s NOTICE %s :*** Notice -- TS for %s changed from %ld to %ld",
478 me.name, chptr->chname, chptr->chname,
479 (long) oldts, (long) newts);
1117fbd3
JT
480 /* Update capitalization in channel name, this makes the
481 * capitalization timestamped like modes are -- jilles */
482 strcpy(chptr->chname, parv[2]);
bee3b671
JT
483 if(*modebuf != '\0')
484 sendto_channel_local(ALL_MEMBERS, chptr,
485 ":%s MODE %s %s %s",
486 source_p->servptr->name,
487 chptr->chname, modebuf, parabuf);
488 *modebuf = *parabuf = '\0';
6fb6bd15
AC
489
490 /* since we're dropping our modes, we want to clear the mlock as well. --nenolod */
491 set_channel_mlock(client_p, source_p, chptr, NULL, FALSE);
212380e3
AC
492 }
493
212380e3
AC
494 if(!IsMember(source_p, chptr))
495 {
496 add_user_to_channel(chptr, source_p, CHFL_PEON);
497 if (chptr->mode.join_num &&
e3354945 498 rb_current_time() - chptr->join_delta >= chptr->mode.join_time)
212380e3
AC
499 {
500 chptr->join_count = 0;
e3354945 501 chptr->join_delta = rb_current_time();
212380e3
AC
502 }
503 chptr->join_count++;
805cfa5a 504 send_channel_join(chptr, source_p);
212380e3
AC
505 }
506
212380e3 507 sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
bee3b671
JT
508 ":%s JOIN %ld %s +",
509 source_p->id, (long) chptr->channelts, chptr->chname);
212380e3
AC
510 return 0;
511}
512
8cc12805 513static int
428ca87b 514ms_sjoin(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
8cc12805 515{
8cc12805
VY
516 static char buf_uid[BUFSIZE];
517 static const char empty_modes[] = "0";
518 struct Channel *chptr;
519 struct Client *target_p, *fakesource_p;
520 time_t newts;
521 time_t oldts;
522 static struct Mode mode, *oldmode;
523 const char *modes;
524 int args = 0;
525 int keep_our_modes = 1;
526 int keep_new_modes = 1;
527 int fl;
528 int isnew;
890423fb 529 int mlen_uid;
8cc12805
VY
530 int len_uid;
531 int len;
532 int joins = 0;
533 const char *s;
8cc12805
VY
534 char *ptr_uid;
535 char *p;
536 int i, joinc = 0, timeslice = 0;
537 static char empty[] = "";
538 rb_dlink_node *ptr, *next_ptr;
539
b733b9fa
JT
540 if(parc < 5)
541 return 0;
542
8cc12805
VY
543 if(!IsChannelName(parv[2]) || !check_channel_name(parv[2]))
544 return 0;
545
546 /* SJOIN's for local channels can't happen. */
547 if(*parv[2] == '&')
548 return 0;
549
550 modebuf[0] = parabuf[0] = mode.key[0] = mode.forward[0] = '\0';
551 pargs = mode.mode = mode.limit = mode.join_num = mode.join_time = 0;
552
553 /* Hide connecting server on netburst -- jilles */
554 if (ConfigServerHide.flatten_links && !HasSentEob(source_p))
555 fakesource_p = &me;
556 else
557 fakesource_p = source_p;
558
559 mbuf = modebuf;
560 newts = atol(parv[1]);
561
562 s = parv[3];
563 while (*s)
564 {
565 switch (*(s++))
566 {
8cc12805 567 case 'f':
f427c8b0 568 rb_strlcpy(mode.forward, parv[4 + args], sizeof(mode.forward));
8cc12805
VY
569 args++;
570 if(parc < 5 + args)
571 return 0;
572 break;
573 case 'j':
574 sscanf(parv[4 + args], "%d:%d", &joinc, &timeslice);
575 args++;
576 mode.join_num = joinc;
577 mode.join_time = timeslice;
578 if(parc < 5 + args)
579 return 0;
580 break;
581 case 'k':
f427c8b0 582 rb_strlcpy(mode.key, parv[4 + args], sizeof(mode.key));
8cc12805
VY
583 args++;
584 if(parc < 5 + args)
585 return 0;
586 break;
587 case 'l':
588 mode.limit = atoi(parv[4 + args]);
589 args++;
590 if(parc < 5 + args)
591 return 0;
592 break;
efccc22c
VY
593 default:
594 if(chmode_flags[(int) *s] != 0)
595 {
596 mode.mode |= chmode_flags[(int) *s];
597 }
8cc12805
VY
598 }
599 }
600
601 if(parv[args + 4])
602 {
603 s = parv[args + 4];
604
605 /* remove any leading spaces */
606 while (*s == ' ')
607 s++;
608 }
609 else
610 s = "";
611
612 if((chptr = get_or_create_channel(source_p, parv[2], &isnew)) == NULL)
613 return 0; /* channel name too long? */
614
615
616 oldts = chptr->channelts;
617 oldmode = &chptr->mode;
618
619#ifdef IGNORE_BOGUS_TS
620 if(newts < 800000000)
621 {
622 sendto_realops_snomask(SNO_DEBUG, L_ALL,
623 "*** Bogus TS %ld on %s ignored from %s",
624 (long) newts, chptr->chname, client_p->name);
625
626 newts = (oldts == 0) ? oldts : 800000000;
627 }
628#else
629 if(!isnew && !newts && oldts)
630 {
631 sendto_channel_local(ALL_MEMBERS, chptr,
632 ":%s NOTICE %s :*** Notice -- TS for %s "
633 "changed from %ld to 0",
634 me.name, chptr->chname, chptr->chname, (long) oldts);
635 sendto_realops_snomask(SNO_GENERAL, L_ALL,
636 "Server %s changing TS on %s from %ld to 0",
637 source_p->name, chptr->chname, (long) oldts);
638 }
639#endif
640
641 if(isnew)
642 chptr->channelts = newts;
55abcbb2 643
8cc12805
VY
644 else if(newts == 0 || oldts == 0)
645 chptr->channelts = 0;
646 else if(newts == oldts)
647 ;
648 else if(newts < oldts)
649 {
650 /* If configured, kick people trying to join +i/+k
651 * channels by recreating them on split servers.
a1574df4
JT
652 * If the source has sent EOB, assume this is some
653 * sort of hack by services. If cmode +i is set,
654 * services can send kicks if needed; if the key
655 * differs, services cannot kick in a race-free
656 * manner so do so here.
8cc12805
VY
657 * -- jilles */
658 if (ConfigChannel.kick_on_split_riding &&
a1574df4
JT
659 ((!HasSentEob(source_p) &&
660 mode.mode & MODE_INVITEONLY) ||
8cc12805
VY
661 (mode.key[0] != 0 && irccmp(mode.key, oldmode->key) != 0)))
662 {
663 struct membership *msptr;
664 struct Client *who;
665 int l = rb_dlink_list_length(&chptr->members);
8cc12805
VY
666
667 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->locmembers.head)
668 {
669 msptr = ptr->data;
670 who = msptr->client_p;
671 sendto_one(who, ":%s KICK %s %s :Net Rider",
672 me.name, chptr->chname, who->name);
673
674 sendto_server(NULL, chptr, CAP_TS6, NOCAPS,
675 ":%s KICK %s %s :Net Rider",
676 me.id, chptr->chname,
677 who->id);
8cc12805
VY
678 remove_user_from_channel(msptr);
679 if (--l == 0)
680 break;
681 }
682 if (l == 0)
683 {
684 /* Channel was emptied, create a new one */
685 if((chptr = get_or_create_channel(source_p, parv[2], &isnew)) == NULL)
686 return 0; /* oops! */
687
8cc12805
VY
688 oldmode = &chptr->mode;
689 }
690 }
691 keep_our_modes = NO;
692 chptr->channelts = newts;
693 }
694 else
695 keep_new_modes = NO;
696
697 if(!keep_new_modes)
698 mode = *oldmode;
699 else if(keep_our_modes)
700 {
701 mode.mode |= oldmode->mode;
702 if(oldmode->limit > mode.limit)
703 mode.limit = oldmode->limit;
704 if(strcmp(mode.key, oldmode->key) < 0)
705 strcpy(mode.key, oldmode->key);
706 if(oldmode->join_num > mode.join_num ||
707 (oldmode->join_num == mode.join_num &&
708 oldmode->join_time > mode.join_time))
709 {
710 mode.join_num = oldmode->join_num;
711 mode.join_time = oldmode->join_time;
712 }
713 if(irccmp(mode.forward, oldmode->forward) < 0)
714 strcpy(mode.forward, oldmode->forward);
715 }
716 else
717 {
718 /* If setting -j, clear join throttle state -- jilles */
719 if (!mode.join_num)
720 chptr->join_count = chptr->join_delta = 0;
721 }
722
723 set_final_mode(&mode, oldmode);
724 chptr->mode = mode;
725
726 /* Lost the TS, other side wins, so remove modes on this side */
727 if(!keep_our_modes)
728 {
729 remove_our_modes(chptr, fakesource_p);
730 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->invites.head)
731 {
732 del_invite(chptr, ptr->data);
733 }
7b22c84f
JT
734
735 if(rb_dlink_list_length(&chptr->banlist) > 0)
736 remove_ban_list(chptr, fakesource_p, &chptr->banlist, 'b', ALL_MEMBERS);
737 if(rb_dlink_list_length(&chptr->exceptlist) > 0)
738 remove_ban_list(chptr, fakesource_p, &chptr->exceptlist,
739 'e', ONLY_CHANOPS);
740 if(rb_dlink_list_length(&chptr->invexlist) > 0)
741 remove_ban_list(chptr, fakesource_p, &chptr->invexlist,
742 'I', ONLY_CHANOPS);
743 if(rb_dlink_list_length(&chptr->quietlist) > 0)
744 remove_ban_list(chptr, fakesource_p, &chptr->quietlist,
745 'q', ALL_MEMBERS);
746 chptr->bants++;
747
8cc12805
VY
748 sendto_channel_local(ALL_MEMBERS, chptr,
749 ":%s NOTICE %s :*** Notice -- TS for %s changed from %ld to %ld",
750 me.name, chptr->chname, chptr->chname,
751 (long) oldts, (long) newts);
752 /* Update capitalization in channel name, this makes the
753 * capitalization timestamped like modes are -- jilles */
754 strcpy(chptr->chname, parv[2]);
6fb6bd15
AC
755
756 /* since we're dropping our modes, we want to clear the mlock as well. --nenolod */
757 set_channel_mlock(client_p, source_p, chptr, NULL, FALSE);
8cc12805
VY
758 }
759
760 if(*modebuf != '\0')
761 sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s %s %s",
762 fakesource_p->name, chptr->chname, modebuf, parabuf);
763
764 *modebuf = *parabuf = '\0';
765
766 if(parv[3][0] != '0' && keep_new_modes)
767 modes = channel_modes(chptr, source_p);
768 else
769 modes = empty_modes;
770
5203cba5 771 mlen_uid = sprintf(buf_uid, ":%s SJOIN %ld %s %s :",
8cc12805
VY
772 use_id(source_p), (long) chptr->channelts, parv[2], modes);
773 ptr_uid = buf_uid + mlen_uid;
774
775 mbuf = modebuf;
776 para[0] = para[1] = para[2] = para[3] = empty;
777 pargs = 0;
40709472 778 len_uid = 0;
8cc12805
VY
779
780 /* if theres a space, theres going to be more than one nick, change the
781 * first space to \0, so s is just the first nick, and point p to the
782 * second nick
783 */
784 if((p = strchr(s, ' ')) != NULL)
785 {
786 *p++ = '\0';
787 }
788
789 *mbuf++ = '+';
790
791 while (s)
792 {
793 fl = 0;
794
795 for (i = 0; i < 2; i++)
796 {
797 if(*s == '@')
798 {
799 fl |= CHFL_CHANOP;
800 s++;
801 }
802 else if(*s == '+')
803 {
804 fl |= CHFL_VOICE;
805 s++;
806 }
807 }
808
809 /* if the client doesnt exist or is fake direction, skip. */
810 if(!(target_p = find_client(s)) ||
811 (target_p->from != client_p) || !IsPerson(target_p))
812 goto nextnick;
813
814 /* we assume for these we can fit at least one nick/uid in.. */
815
816 /* check we can fit another status+nick+space into a buffer */
8cc12805
VY
817 if((mlen_uid + len_uid + IDLEN + 3) > (BUFSIZE - 3))
818 {
819 *(ptr_uid - 1) = '\0';
820 sendto_server(client_p->from, NULL, CAP_TS6, NOCAPS, "%s", buf_uid);
821 ptr_uid = buf_uid + mlen_uid;
822 len_uid = 0;
823 }
824
825 if(keep_new_modes)
826 {
827 if(fl & CHFL_CHANOP)
828 {
8cc12805 829 *ptr_uid++ = '@';
8cc12805
VY
830 len_uid++;
831 }
832 if(fl & CHFL_VOICE)
833 {
8cc12805 834 *ptr_uid++ = '+';
8cc12805
VY
835 len_uid++;
836 }
837 }
838
839 /* copy the nick to the two buffers */
5203cba5 840 len = sprintf(ptr_uid, "%s ", use_id(target_p));
8cc12805
VY
841 ptr_uid += len;
842 len_uid += len;
843
844 if(!keep_new_modes)
845 fl = 0;
846
847 if(!IsMember(target_p, chptr))
848 {
849 add_user_to_channel(chptr, target_p, fl);
805cfa5a 850 send_channel_join(chptr, target_p);
8cc12805
VY
851 joins++;
852 }
853
854 if(fl & CHFL_CHANOP)
855 {
856 *mbuf++ = 'o';
857 para[pargs++] = target_p->name;
858
859 /* a +ov user.. bleh */
860 if(fl & CHFL_VOICE)
861 {
862 /* its possible the +o has filled up MAXMODEPARAMS, if so, start
863 * a new buffer
864 */
865 if(pargs >= MAXMODEPARAMS)
866 {
867 *mbuf = '\0';
868 sendto_channel_local(ALL_MEMBERS, chptr,
869 ":%s MODE %s %s %s %s %s %s",
870 fakesource_p->name, chptr->chname,
871 modebuf,
872 para[0], para[1], para[2], para[3]);
873 mbuf = modebuf;
874 *mbuf++ = '+';
875 para[0] = para[1] = para[2] = para[3] = NULL;
876 pargs = 0;
877 }
878
879 *mbuf++ = 'v';
880 para[pargs++] = target_p->name;
881 }
882 }
883 else if(fl & CHFL_VOICE)
884 {
885 *mbuf++ = 'v';
886 para[pargs++] = target_p->name;
887 }
888
889 if(pargs >= MAXMODEPARAMS)
890 {
891 *mbuf = '\0';
892 sendto_channel_local(ALL_MEMBERS, chptr,
893 ":%s MODE %s %s %s %s %s %s",
894 fakesource_p->name,
895 chptr->chname,
896 modebuf, para[0], para[1], para[2], para[3]);
897 mbuf = modebuf;
898 *mbuf++ = '+';
899 para[0] = para[1] = para[2] = para[3] = NULL;
900 pargs = 0;
901 }
902
903 nextnick:
904 /* p points to the next nick */
905 s = p;
906
907 /* if there was a trailing space and p was pointing to it, then we
908 * need to exit.. this has the side effect of breaking double spaces
909 * in an sjoin.. but that shouldnt happen anyway
910 */
911 if(s && (*s == '\0'))
912 s = p = NULL;
913
914 /* if p was NULL due to no spaces, s wont exist due to the above, so
915 * we cant check it for spaces.. if there are no spaces, then when
916 * we next get here, s will be NULL
917 */
918 if(s && ((p = strchr(s, ' ')) != NULL))
919 {
920 *p++ = '\0';
921 }
922 }
923
924 *mbuf = '\0';
925 if(pargs)
926 {
927 sendto_channel_local(ALL_MEMBERS, chptr,
928 ":%s MODE %s %s %s %s %s %s",
929 fakesource_p->name, chptr->chname, modebuf,
930 para[0], CheckEmpty(para[1]),
931 CheckEmpty(para[2]), CheckEmpty(para[3]));
932 }
933
934 if(!joins && !(chptr->mode.mode & MODE_PERMANENT) && isnew)
935 {
936 destroy_channel(chptr);
937
938 return 0;
939 }
940
941 /* Keep the colon if we're sending an SJOIN without nicks -- jilles */
942 if (joins)
943 {
8cc12805
VY
944 *(ptr_uid - 1) = '\0';
945 }
946
947 sendto_server(client_p->from, NULL, CAP_TS6, NOCAPS, "%s", buf_uid);
8cc12805 948
8cc12805
VY
949 return 0;
950}
951
f4a80ce6
JT
952/*
953 * do_join_0
954 *
955 * inputs - pointer to client doing join 0
956 * output - NONE
957 * side effects - Use has decided to join 0. This is legacy
958 * from the days when channels were numbers not names. *sigh*
f4a80ce6
JT
959 */
960static void
961do_join_0(struct Client *client_p, struct Client *source_p)
962{
963 struct membership *msptr;
964 struct Channel *chptr = NULL;
5b96d9a6 965 rb_dlink_node *ptr;
f4a80ce6
JT
966
967 /* Finish the flood grace period... */
968 if(MyClient(source_p) && !IsFloodDone(source_p))
969 flood_endgrace(source_p);
970
f4a80ce6 971 sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s JOIN 0", use_id(source_p));
f4a80ce6 972
f4a80ce6
JT
973 while((ptr = source_p->user->channel.head))
974 {
4eb9a3ca
JT
975 if(MyConnect(source_p) &&
976 !IsOper(source_p) && !IsExemptSpambot(source_p))
977 check_spambot_warning(source_p, NULL);
978
f4a80ce6
JT
979 msptr = ptr->data;
980 chptr = msptr->chptr;
981 sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s PART %s",
982 source_p->name,
983 source_p->username, source_p->host, chptr->chname);
984 remove_user_from_channel(msptr);
985 }
986}
987
212380e3
AC
988static int
989check_channel_name_loc(struct Client *source_p, const char *name)
990{
6865c0b0
JT
991 const char *p;
992
212380e3
AC
993 s_assert(name != NULL);
994 if(EmptyString(name))
995 return 0;
996
997 if(ConfigFileEntry.disable_fake_channels && !IsOper(source_p))
998 {
6865c0b0 999 for(p = name; *p; ++p)
212380e3 1000 {
6865c0b0 1001 if(!IsChanChar(*p) || IsFakeChanChar(*p))
212380e3
AC
1002 return 0;
1003 }
1004 }
1005 else
1006 {
6865c0b0 1007 for(p = name; *p; ++p)
212380e3 1008 {
6865c0b0 1009 if(!IsChanChar(*p))
212380e3
AC
1010 return 0;
1011 }
1012 }
1013
6865c0b0
JT
1014 if(ConfigChannel.only_ascii_channels)
1015 {
1016 for(p = name; *p; ++p)
1017 if(*p < 33 || *p > 126)
1018 return 0;
1019 }
1020
212380e3
AC
1021 return 1;
1022}
1023
35bfe0e6
JT
1024/* send_join_error()
1025 *
1026 * input - client to send to, reason, channel name
1027 * output - none
1028 * side effects - error message sent to client
1029 */
1030static void
1031send_join_error(struct Client *source_p, int numeric, const char *name)
1032{
1033 /* This stuff is necessary because the form_str macro only
1034 * accepts constants.
1035 */
1036 switch (numeric)
1037 {
1038#define NORMAL_NUMERIC(i) \
1039 case i: \
1040 sendto_one(source_p, form_str(i), \
1041 me.name, source_p->name, name); \
1042 break
1043
1044 NORMAL_NUMERIC(ERR_BANNEDFROMCHAN);
1045 NORMAL_NUMERIC(ERR_INVITEONLYCHAN);
1046 NORMAL_NUMERIC(ERR_BADCHANNELKEY);
1047 NORMAL_NUMERIC(ERR_CHANNELISFULL);
1048 NORMAL_NUMERIC(ERR_NEEDREGGEDNICK);
1049 NORMAL_NUMERIC(ERR_THROTTLE);
1050
1051 default:
1052 sendto_one_numeric(source_p, numeric,
1053 "%s :Cannot join channel", name);
1054 break;
1055 }
1056}
1057
212380e3
AC
1058static void
1059set_final_mode(struct Mode *mode, struct Mode *oldmode)
1060{
1061 int dir = MODE_QUERY;
1062 char *pbuf = parabuf;
1063 int len;
1064 int i;
1065
1066 /* ok, first get a list of modes we need to add */
efccc22c 1067 for (i = 0; i < 256; i++)
212380e3 1068 {
efccc22c 1069 if((mode->mode & chmode_flags[i]) && !(oldmode->mode & chmode_flags[i]))
212380e3
AC
1070 {
1071 if(dir != MODE_ADD)
1072 {
1073 *mbuf++ = '+';
1074 dir = MODE_ADD;
1075 }
efccc22c 1076 *mbuf++ = i;
212380e3
AC
1077 }
1078 }
1079
1080 /* now the ones we need to remove. */
efccc22c 1081 for (i = 0; i < 256; i++)
212380e3 1082 {
efccc22c 1083 if((oldmode->mode & chmode_flags[i]) && !(mode->mode & chmode_flags[i]))
212380e3
AC
1084 {
1085 if(dir != MODE_DEL)
1086 {
1087 *mbuf++ = '-';
1088 dir = MODE_DEL;
1089 }
efccc22c 1090 *mbuf++ = i;
212380e3
AC
1091 }
1092 }
1093
1094 if(oldmode->limit && !mode->limit)
1095 {
1096 if(dir != MODE_DEL)
1097 {
1098 *mbuf++ = '-';
1099 dir = MODE_DEL;
1100 }
1101 *mbuf++ = 'l';
1102 }
1103 if(oldmode->key[0] && !mode->key[0])
1104 {
1105 if(dir != MODE_DEL)
1106 {
1107 *mbuf++ = '-';
1108 dir = MODE_DEL;
1109 }
1110 *mbuf++ = 'k';
5203cba5 1111 len = sprintf(pbuf, "%s ", oldmode->key);
212380e3
AC
1112 pbuf += len;
1113 }
1114 if(oldmode->join_num && !mode->join_num)
1115 {
1116 if(dir != MODE_DEL)
1117 {
1118 *mbuf++ = '-';
1119 dir = MODE_DEL;
1120 }
1121 *mbuf++ = 'j';
1122 }
1123 if(oldmode->forward[0] && !mode->forward[0])
1124 {
1125 if(dir != MODE_DEL)
1126 {
1127 *mbuf++ = '-';
1128 dir = MODE_DEL;
1129 }
1130 *mbuf++ = 'f';
1131 }
1132 if(mode->limit && oldmode->limit != mode->limit)
1133 {
1134 if(dir != MODE_ADD)
1135 {
1136 *mbuf++ = '+';
1137 dir = MODE_ADD;
1138 }
1139 *mbuf++ = 'l';
5203cba5 1140 len = sprintf(pbuf, "%d ", mode->limit);
212380e3
AC
1141 pbuf += len;
1142 }
1143 if(mode->key[0] && strcmp(oldmode->key, mode->key))
1144 {
1145 if(dir != MODE_ADD)
1146 {
1147 *mbuf++ = '+';
1148 dir = MODE_ADD;
1149 }
1150 *mbuf++ = 'k';
5203cba5 1151 len = sprintf(pbuf, "%s ", mode->key);
212380e3
AC
1152 pbuf += len;
1153 }
1154 if(mode->join_num && (oldmode->join_num != mode->join_num || oldmode->join_time != mode->join_time))
1155 {
1156 if(dir != MODE_ADD)
1157 {
1158 *mbuf++ = '+';
1159 dir = MODE_ADD;
1160 }
1161 *mbuf++ = 'j';
5203cba5 1162 len = sprintf(pbuf, "%d:%d ", mode->join_num, mode->join_time);
212380e3
AC
1163 pbuf += len;
1164 }
2da6f6eb
JT
1165 if(mode->forward[0] && strcmp(oldmode->forward, mode->forward) &&
1166 ConfigChannel.use_forward)
212380e3
AC
1167 {
1168 if(dir != MODE_ADD)
1169 {
1170 *mbuf++ = '+';
1171 dir = MODE_ADD;
1172 }
1173 *mbuf++ = 'f';
5203cba5 1174 len = sprintf(pbuf, "%s ", mode->forward);
212380e3
AC
1175 pbuf += len;
1176 }
1177 *mbuf = '\0';
1178}
1179
1180/*
1181 * remove_our_modes
1182 *
1183 * inputs -
55abcbb2
KB
1184 * output -
1185 * side effects -
212380e3
AC
1186 */
1187static void
1188remove_our_modes(struct Channel *chptr, struct Client *source_p)
1189{
1190 struct membership *msptr;
5b96d9a6 1191 rb_dlink_node *ptr;
212380e3
AC
1192 char lmodebuf[MODEBUFLEN];
1193 char *lpara[MAXMODEPARAMS];
1194 int count = 0;
1195 int i;
1196
1197 mbuf = lmodebuf;
1198 *mbuf++ = '-';
1199
1200 for(i = 0; i < MAXMODEPARAMS; i++)
1201 lpara[i] = NULL;
1202
5b96d9a6 1203 RB_DLINK_FOREACH(ptr, chptr->members.head)
212380e3
AC
1204 {
1205 msptr = ptr->data;
1206
1207 if(is_chanop(msptr))
1208 {
1209 msptr->flags &= ~CHFL_CHANOP;
1210 lpara[count++] = msptr->client_p->name;
1211 *mbuf++ = 'o';
1212
1213 /* +ov, might not fit so check. */
1214 if(is_voiced(msptr))
1215 {
1216 if(count >= MAXMODEPARAMS)
1217 {
1218 *mbuf = '\0';
1219 sendto_channel_local(ALL_MEMBERS, chptr,
1220 ":%s MODE %s %s %s %s %s %s",
7bf78de0 1221 source_p->name, chptr->chname,
212380e3
AC
1222 lmodebuf, lpara[0], lpara[1],
1223 lpara[2], lpara[3]);
1224
1225 /* preserve the initial '-' */
1226 mbuf = lmodebuf;
1227 *mbuf++ = '-';
1228 count = 0;
1229
1230 for(i = 0; i < MAXMODEPARAMS; i++)
1231 lpara[i] = NULL;
1232 }
1233
1234 msptr->flags &= ~CHFL_VOICE;
1235 lpara[count++] = msptr->client_p->name;
1236 *mbuf++ = 'v';
1237 }
1238 }
1239 else if(is_voiced(msptr))
1240 {
1241 msptr->flags &= ~CHFL_VOICE;
1242 lpara[count++] = msptr->client_p->name;
1243 *mbuf++ = 'v';
1244 }
1245 else
1246 continue;
1247
1248 if(count >= MAXMODEPARAMS)
1249 {
1250 *mbuf = '\0';
1251 sendto_channel_local(ALL_MEMBERS, chptr,
1252 ":%s MODE %s %s %s %s %s %s",
7bf78de0 1253 source_p->name, chptr->chname, lmodebuf,
212380e3
AC
1254 lpara[0], lpara[1], lpara[2], lpara[3]);
1255 mbuf = lmodebuf;
1256 *mbuf++ = '-';
1257 count = 0;
1258
1259 for(i = 0; i < MAXMODEPARAMS; i++)
1260 lpara[i] = NULL;
1261 }
1262 }
1263
1264 if(count != 0)
1265 {
1266 *mbuf = '\0';
1267 sendto_channel_local(ALL_MEMBERS, chptr,
1268 ":%s MODE %s %s %s %s %s %s",
7bf78de0 1269 source_p->name, chptr->chname, lmodebuf,
212380e3
AC
1270 EmptyString(lpara[0]) ? "" : lpara[0],
1271 EmptyString(lpara[1]) ? "" : lpara[1],
1272 EmptyString(lpara[2]) ? "" : lpara[2],
1273 EmptyString(lpara[3]) ? "" : lpara[3]);
1274
1275 }
1276}
8cc12805
VY
1277
1278/* remove_ban_list()
1279 *
1280 * inputs - channel, source, list to remove, char of mode, caps needed
1281 * outputs -
1282 * side effects - given list is removed, with modes issued to local clients
8cc12805
VY
1283 */
1284static void
1285remove_ban_list(struct Channel *chptr, struct Client *source_p,
8afeb720 1286 rb_dlink_list * list, char c, int mems)
8cc12805
VY
1287{
1288 static char lmodebuf[BUFSIZE];
1289 static char lparabuf[BUFSIZE];
1290 struct Ban *banptr;
1291 rb_dlink_node *ptr;
1292 rb_dlink_node *next_ptr;
1293 char *pbuf;
1294 int count = 0;
1295 int cur_len, mlen, plen;
1296
1297 pbuf = lparabuf;
1298
5203cba5 1299 cur_len = mlen = sprintf(lmodebuf, ":%s MODE %s -", source_p->name, chptr->chname);
8cc12805
VY
1300 mbuf = lmodebuf + mlen;
1301
1302 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
1303 {
1304 banptr = ptr->data;
1305
1306 /* trailing space, and the mode letter itself */
23f6b63a
JT
1307 plen = strlen(banptr->banstr) +
1308 (banptr->forward ? strlen(banptr->forward) + 1 : 0) + 2;
8cc12805
VY
1309
1310 if(count >= MAXMODEPARAMS || (cur_len + plen) > BUFSIZE - 4)
1311 {
1312 /* remove trailing space */
1313 *mbuf = '\0';
1314 *(pbuf - 1) = '\0';
1315
1316 sendto_channel_local(mems, chptr, "%s %s", lmodebuf, lparabuf);
8cc12805
VY
1317
1318 cur_len = mlen;
1319 mbuf = lmodebuf + mlen;
1320 pbuf = lparabuf;
1321 count = 0;
1322 }
1323
1324 *mbuf++ = c;
1325 cur_len += plen;
23f6b63a 1326 if (banptr->forward)
5203cba5 1327 pbuf += sprintf(pbuf, "%s$%s ", banptr->banstr, banptr->forward);
23f6b63a 1328 else
5203cba5 1329 pbuf += sprintf(pbuf, "%s ", banptr->banstr);
8cc12805
VY
1330 count++;
1331
1332 free_ban(banptr);
1333 }
1334
1335 *mbuf = '\0';
1336 *(pbuf - 1) = '\0';
1337 sendto_channel_local(mems, chptr, "%s %s", lmodebuf, lparabuf);
8cc12805
VY
1338
1339 list->head = list->tail = NULL;
1340 list->length = 0;
1341}