]> jfr.im git - solanum.git/blame - modules/core/m_join.c
Announce changed capabilities on module load
[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"
212380e3 28#include "hash.h"
4562c604 29#include "match.h"
212380e3
AC
30#include "ircd.h"
31#include "numeric.h"
32#include "send.h"
33#include "s_serv.h"
34#include "s_conf.h"
35#include "s_newconf.h"
36#include "msg.h"
37#include "parse.h"
38#include "modules.h"
212380e3 39#include "packet.h"
acdf71d9 40#include "chmode.h"
7e132ff0 41#include "ratelimit.h"
77d3d2db 42#include "s_assert.h"
212380e3 43
eeabf33a
EM
44static const char join_desc[] = "Provides the JOIN and TS6 SJOIN commands to facilitate joining and creating channels";
45
3c7d6fcc
EM
46static void m_join(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
47static void ms_join(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
48static void ms_sjoin(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
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);
3c7d6fcc 74static bool 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 */
3c7d6fcc 140static void
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 }
212380e3
AC
382}
383
384/*
385 * ms_join
35835646
JT
386 * parv[1] = channel TS
387 * parv[2] = channel
388 * parv[3] = "+", formerly channel modes but now unused
389 * alternatively, a single "0" parameter parts all channels
212380e3 390 */
3c7d6fcc 391static void
428ca87b 392ms_join(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
212380e3
AC
393{
394 struct Channel *chptr;
bee3b671 395 static struct Mode mode;
212380e3
AC
396 time_t oldts;
397 time_t newts;
aa7eff28 398 bool isnew;
3c7d6fcc 399 bool keep_our_modes = true;
637c4932 400 rb_dlink_node *ptr, *next_ptr;
212380e3 401
f4a80ce6
JT
402 /* special case for join 0 */
403 if((parv[1][0] == '0') && (parv[1][1] == '\0') && parc == 2)
404 {
405 do_join_0(client_p, source_p);
3c7d6fcc 406 return;
f4a80ce6
JT
407 }
408
212380e3 409 if(parc < 4)
3c7d6fcc 410 return;
212380e3
AC
411
412 if(!IsChannelName(parv[2]) || !check_channel_name(parv[2]))
3c7d6fcc 413 return;
212380e3
AC
414
415 /* joins for local channels cant happen. */
416 if(parv[2][0] == '&')
3c7d6fcc 417 return;
212380e3
AC
418
419 mbuf = modebuf;
420 mode.key[0] = mode.forward[0] = '\0';
421 mode.mode = mode.limit = mode.join_num = mode.join_time = 0;
422
212380e3 423 if((chptr = get_or_create_channel(source_p, parv[2], &isnew)) == NULL)
3c7d6fcc 424 return;
212380e3
AC
425
426 newts = atol(parv[1]);
427 oldts = chptr->channelts;
212380e3 428
212380e3
AC
429 /* making a channel TS0 */
430 if(!isnew && !newts && oldts)
431 {
432 sendto_channel_local(ALL_MEMBERS, chptr,
433 ":%s NOTICE %s :*** Notice -- TS for %s changed from %ld to 0",
434 me.name, chptr->chname, chptr->chname, (long) oldts);
435 sendto_realops_snomask(SNO_GENERAL, L_ALL,
436 "Server %s changing TS on %s from %ld to 0",
437 source_p->name, chptr->chname, (long) oldts);
438 }
212380e3
AC
439
440 if(isnew)
441 chptr->channelts = newts;
442 else if(newts == 0 || oldts == 0)
443 chptr->channelts = 0;
444 else if(newts == oldts)
445 ;
446 else if(newts < oldts)
447 {
3c7d6fcc 448 keep_our_modes = false;
212380e3
AC
449 chptr->channelts = newts;
450 }
212380e3 451
212380e3
AC
452 /* Lost the TS, other side wins, so remove modes on this side */
453 if(!keep_our_modes)
454 {
bee3b671
JT
455 set_final_mode(&mode, &chptr->mode);
456 chptr->mode = mode;
212380e3 457 remove_our_modes(chptr, source_p);
637c4932 458 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->invites.head)
212380e3
AC
459 {
460 del_invite(chptr, ptr->data);
461 }
bee3b671
JT
462 /* If setting -j, clear join throttle state -- jilles */
463 chptr->join_count = chptr->join_delta = 0;
212380e3
AC
464 sendto_channel_local(ALL_MEMBERS, chptr,
465 ":%s NOTICE %s :*** Notice -- TS for %s changed from %ld to %ld",
466 me.name, chptr->chname, chptr->chname,
467 (long) oldts, (long) newts);
1117fbd3
JT
468 /* Update capitalization in channel name, this makes the
469 * capitalization timestamped like modes are -- jilles */
470 strcpy(chptr->chname, parv[2]);
bee3b671
JT
471 if(*modebuf != '\0')
472 sendto_channel_local(ALL_MEMBERS, chptr,
473 ":%s MODE %s %s %s",
474 source_p->servptr->name,
475 chptr->chname, modebuf, parabuf);
476 *modebuf = *parabuf = '\0';
6fb6bd15
AC
477
478 /* since we're dropping our modes, we want to clear the mlock as well. --nenolod */
07554369 479 set_channel_mlock(client_p, source_p, chptr, NULL, false);
212380e3
AC
480 }
481
212380e3
AC
482 if(!IsMember(source_p, chptr))
483 {
484 add_user_to_channel(chptr, source_p, CHFL_PEON);
485 if (chptr->mode.join_num &&
e3354945 486 rb_current_time() - chptr->join_delta >= chptr->mode.join_time)
212380e3
AC
487 {
488 chptr->join_count = 0;
e3354945 489 chptr->join_delta = rb_current_time();
212380e3
AC
490 }
491 chptr->join_count++;
805cfa5a 492 send_channel_join(chptr, source_p);
212380e3
AC
493 }
494
212380e3 495 sendto_server(client_p, chptr, CAP_TS6, NOCAPS,
bee3b671
JT
496 ":%s JOIN %ld %s +",
497 source_p->id, (long) chptr->channelts, chptr->chname);
212380e3
AC
498}
499
3c7d6fcc 500static void
428ca87b 501ms_sjoin(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
8cc12805 502{
8cc12805
VY
503 static char buf_uid[BUFSIZE];
504 static const char empty_modes[] = "0";
505 struct Channel *chptr;
506 struct Client *target_p, *fakesource_p;
507 time_t newts;
508 time_t oldts;
509 static struct Mode mode, *oldmode;
510 const char *modes;
511 int args = 0;
3c7d6fcc
EM
512 bool keep_our_modes = true;
513 bool keep_new_modes = true;
8cc12805 514 int fl;
aa7eff28 515 bool isnew;
890423fb 516 int mlen_uid;
8cc12805
VY
517 int len_uid;
518 int len;
519 int joins = 0;
520 const char *s;
8cc12805
VY
521 char *ptr_uid;
522 char *p;
523 int i, joinc = 0, timeslice = 0;
524 static char empty[] = "";
525 rb_dlink_node *ptr, *next_ptr;
526
b733b9fa 527 if(parc < 5)
3c7d6fcc 528 return;
b733b9fa 529
8cc12805 530 if(!IsChannelName(parv[2]) || !check_channel_name(parv[2]))
3c7d6fcc 531 return;
8cc12805
VY
532
533 /* SJOIN's for local channels can't happen. */
534 if(*parv[2] == '&')
3c7d6fcc 535 return;
8cc12805
VY
536
537 modebuf[0] = parabuf[0] = mode.key[0] = mode.forward[0] = '\0';
538 pargs = mode.mode = mode.limit = mode.join_num = mode.join_time = 0;
539
540 /* Hide connecting server on netburst -- jilles */
541 if (ConfigServerHide.flatten_links && !HasSentEob(source_p))
542 fakesource_p = &me;
543 else
544 fakesource_p = source_p;
545
546 mbuf = modebuf;
547 newts = atol(parv[1]);
548
549 s = parv[3];
550 while (*s)
551 {
552 switch (*(s++))
553 {
8cc12805 554 case 'f':
f427c8b0 555 rb_strlcpy(mode.forward, parv[4 + args], sizeof(mode.forward));
8cc12805
VY
556 args++;
557 if(parc < 5 + args)
3c7d6fcc 558 return;
8cc12805
VY
559 break;
560 case 'j':
561 sscanf(parv[4 + args], "%d:%d", &joinc, &timeslice);
562 args++;
563 mode.join_num = joinc;
564 mode.join_time = timeslice;
565 if(parc < 5 + args)
3c7d6fcc 566 return;
8cc12805
VY
567 break;
568 case 'k':
f427c8b0 569 rb_strlcpy(mode.key, parv[4 + args], sizeof(mode.key));
8cc12805
VY
570 args++;
571 if(parc < 5 + args)
3c7d6fcc 572 return;
8cc12805
VY
573 break;
574 case 'l':
575 mode.limit = atoi(parv[4 + args]);
576 args++;
577 if(parc < 5 + args)
3c7d6fcc 578 return;
8cc12805 579 break;
efccc22c
VY
580 default:
581 if(chmode_flags[(int) *s] != 0)
582 {
583 mode.mode |= chmode_flags[(int) *s];
584 }
8cc12805
VY
585 }
586 }
587
588 if(parv[args + 4])
589 {
590 s = parv[args + 4];
591
592 /* remove any leading spaces */
593 while (*s == ' ')
594 s++;
595 }
596 else
597 s = "";
598
599 if((chptr = get_or_create_channel(source_p, parv[2], &isnew)) == NULL)
3c7d6fcc 600 return; /* channel name too long? */
8cc12805
VY
601
602
603 oldts = chptr->channelts;
604 oldmode = &chptr->mode;
605
8cc12805
VY
606 if(!isnew && !newts && oldts)
607 {
608 sendto_channel_local(ALL_MEMBERS, chptr,
609 ":%s NOTICE %s :*** Notice -- TS for %s "
610 "changed from %ld to 0",
611 me.name, chptr->chname, chptr->chname, (long) oldts);
612 sendto_realops_snomask(SNO_GENERAL, L_ALL,
613 "Server %s changing TS on %s from %ld to 0",
614 source_p->name, chptr->chname, (long) oldts);
615 }
8cc12805
VY
616
617 if(isnew)
618 chptr->channelts = newts;
55abcbb2 619
8cc12805
VY
620 else if(newts == 0 || oldts == 0)
621 chptr->channelts = 0;
622 else if(newts == oldts)
623 ;
624 else if(newts < oldts)
625 {
626 /* If configured, kick people trying to join +i/+k
627 * channels by recreating them on split servers.
a1574df4
JT
628 * If the source has sent EOB, assume this is some
629 * sort of hack by services. If cmode +i is set,
630 * services can send kicks if needed; if the key
631 * differs, services cannot kick in a race-free
632 * manner so do so here.
8cc12805
VY
633 * -- jilles */
634 if (ConfigChannel.kick_on_split_riding &&
a1574df4
JT
635 ((!HasSentEob(source_p) &&
636 mode.mode & MODE_INVITEONLY) ||
8cc12805
VY
637 (mode.key[0] != 0 && irccmp(mode.key, oldmode->key) != 0)))
638 {
639 struct membership *msptr;
640 struct Client *who;
641 int l = rb_dlink_list_length(&chptr->members);
8cc12805
VY
642
643 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->locmembers.head)
644 {
645 msptr = ptr->data;
646 who = msptr->client_p;
647 sendto_one(who, ":%s KICK %s %s :Net Rider",
648 me.name, chptr->chname, who->name);
649
650 sendto_server(NULL, chptr, CAP_TS6, NOCAPS,
651 ":%s KICK %s %s :Net Rider",
652 me.id, chptr->chname,
653 who->id);
8cc12805
VY
654 remove_user_from_channel(msptr);
655 if (--l == 0)
656 break;
657 }
658 if (l == 0)
659 {
660 /* Channel was emptied, create a new one */
661 if((chptr = get_or_create_channel(source_p, parv[2], &isnew)) == NULL)
3c7d6fcc 662 return; /* oops! */
8cc12805 663
8cc12805
VY
664 oldmode = &chptr->mode;
665 }
666 }
3c7d6fcc 667 keep_our_modes = false;
8cc12805
VY
668 chptr->channelts = newts;
669 }
670 else
3c7d6fcc 671 keep_new_modes = false;
8cc12805
VY
672
673 if(!keep_new_modes)
674 mode = *oldmode;
675 else if(keep_our_modes)
676 {
677 mode.mode |= oldmode->mode;
678 if(oldmode->limit > mode.limit)
679 mode.limit = oldmode->limit;
680 if(strcmp(mode.key, oldmode->key) < 0)
681 strcpy(mode.key, oldmode->key);
682 if(oldmode->join_num > mode.join_num ||
683 (oldmode->join_num == mode.join_num &&
684 oldmode->join_time > mode.join_time))
685 {
686 mode.join_num = oldmode->join_num;
687 mode.join_time = oldmode->join_time;
688 }
689 if(irccmp(mode.forward, oldmode->forward) < 0)
690 strcpy(mode.forward, oldmode->forward);
691 }
692 else
693 {
694 /* If setting -j, clear join throttle state -- jilles */
695 if (!mode.join_num)
696 chptr->join_count = chptr->join_delta = 0;
697 }
698
699 set_final_mode(&mode, oldmode);
700 chptr->mode = mode;
701
702 /* Lost the TS, other side wins, so remove modes on this side */
703 if(!keep_our_modes)
704 {
705 remove_our_modes(chptr, fakesource_p);
706 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->invites.head)
707 {
708 del_invite(chptr, ptr->data);
709 }
7b22c84f
JT
710
711 if(rb_dlink_list_length(&chptr->banlist) > 0)
712 remove_ban_list(chptr, fakesource_p, &chptr->banlist, 'b', ALL_MEMBERS);
713 if(rb_dlink_list_length(&chptr->exceptlist) > 0)
714 remove_ban_list(chptr, fakesource_p, &chptr->exceptlist,
715 'e', ONLY_CHANOPS);
716 if(rb_dlink_list_length(&chptr->invexlist) > 0)
717 remove_ban_list(chptr, fakesource_p, &chptr->invexlist,
718 'I', ONLY_CHANOPS);
719 if(rb_dlink_list_length(&chptr->quietlist) > 0)
720 remove_ban_list(chptr, fakesource_p, &chptr->quietlist,
721 'q', ALL_MEMBERS);
722 chptr->bants++;
723
8cc12805
VY
724 sendto_channel_local(ALL_MEMBERS, chptr,
725 ":%s NOTICE %s :*** Notice -- TS for %s changed from %ld to %ld",
726 me.name, chptr->chname, chptr->chname,
727 (long) oldts, (long) newts);
728 /* Update capitalization in channel name, this makes the
729 * capitalization timestamped like modes are -- jilles */
730 strcpy(chptr->chname, parv[2]);
6fb6bd15
AC
731
732 /* since we're dropping our modes, we want to clear the mlock as well. --nenolod */
07554369 733 set_channel_mlock(client_p, source_p, chptr, NULL, false);
8cc12805
VY
734 }
735
736 if(*modebuf != '\0')
737 sendto_channel_local(ALL_MEMBERS, chptr, ":%s MODE %s %s %s",
738 fakesource_p->name, chptr->chname, modebuf, parabuf);
739
740 *modebuf = *parabuf = '\0';
741
742 if(parv[3][0] != '0' && keep_new_modes)
743 modes = channel_modes(chptr, source_p);
744 else
745 modes = empty_modes;
746
5203cba5 747 mlen_uid = sprintf(buf_uid, ":%s SJOIN %ld %s %s :",
8cc12805
VY
748 use_id(source_p), (long) chptr->channelts, parv[2], modes);
749 ptr_uid = buf_uid + mlen_uid;
750
751 mbuf = modebuf;
752 para[0] = para[1] = para[2] = para[3] = empty;
753 pargs = 0;
40709472 754 len_uid = 0;
8cc12805
VY
755
756 /* if theres a space, theres going to be more than one nick, change the
757 * first space to \0, so s is just the first nick, and point p to the
758 * second nick
759 */
760 if((p = strchr(s, ' ')) != NULL)
761 {
762 *p++ = '\0';
763 }
764
765 *mbuf++ = '+';
766
767 while (s)
768 {
769 fl = 0;
770
771 for (i = 0; i < 2; i++)
772 {
773 if(*s == '@')
774 {
775 fl |= CHFL_CHANOP;
776 s++;
777 }
778 else if(*s == '+')
779 {
780 fl |= CHFL_VOICE;
781 s++;
782 }
783 }
784
785 /* if the client doesnt exist or is fake direction, skip. */
786 if(!(target_p = find_client(s)) ||
787 (target_p->from != client_p) || !IsPerson(target_p))
788 goto nextnick;
789
790 /* we assume for these we can fit at least one nick/uid in.. */
791
792 /* check we can fit another status+nick+space into a buffer */
8cc12805
VY
793 if((mlen_uid + len_uid + IDLEN + 3) > (BUFSIZE - 3))
794 {
795 *(ptr_uid - 1) = '\0';
796 sendto_server(client_p->from, NULL, CAP_TS6, NOCAPS, "%s", buf_uid);
797 ptr_uid = buf_uid + mlen_uid;
798 len_uid = 0;
799 }
800
801 if(keep_new_modes)
802 {
803 if(fl & CHFL_CHANOP)
804 {
8cc12805 805 *ptr_uid++ = '@';
8cc12805
VY
806 len_uid++;
807 }
808 if(fl & CHFL_VOICE)
809 {
8cc12805 810 *ptr_uid++ = '+';
8cc12805
VY
811 len_uid++;
812 }
813 }
814
815 /* copy the nick to the two buffers */
5203cba5 816 len = sprintf(ptr_uid, "%s ", use_id(target_p));
8cc12805
VY
817 ptr_uid += len;
818 len_uid += len;
819
820 if(!keep_new_modes)
821 fl = 0;
822
823 if(!IsMember(target_p, chptr))
824 {
825 add_user_to_channel(chptr, target_p, fl);
805cfa5a 826 send_channel_join(chptr, target_p);
8cc12805
VY
827 joins++;
828 }
829
830 if(fl & CHFL_CHANOP)
831 {
832 *mbuf++ = 'o';
833 para[pargs++] = target_p->name;
834
835 /* a +ov user.. bleh */
836 if(fl & CHFL_VOICE)
837 {
838 /* its possible the +o has filled up MAXMODEPARAMS, if so, start
839 * a new buffer
840 */
841 if(pargs >= MAXMODEPARAMS)
842 {
843 *mbuf = '\0';
844 sendto_channel_local(ALL_MEMBERS, chptr,
845 ":%s MODE %s %s %s %s %s %s",
846 fakesource_p->name, chptr->chname,
847 modebuf,
848 para[0], para[1], para[2], para[3]);
849 mbuf = modebuf;
850 *mbuf++ = '+';
851 para[0] = para[1] = para[2] = para[3] = NULL;
852 pargs = 0;
853 }
854
855 *mbuf++ = 'v';
856 para[pargs++] = target_p->name;
857 }
858 }
859 else if(fl & CHFL_VOICE)
860 {
861 *mbuf++ = 'v';
862 para[pargs++] = target_p->name;
863 }
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,
871 chptr->chname,
872 modebuf, 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 nextnick:
880 /* p points to the next nick */
881 s = p;
882
883 /* if there was a trailing space and p was pointing to it, then we
884 * need to exit.. this has the side effect of breaking double spaces
885 * in an sjoin.. but that shouldnt happen anyway
886 */
887 if(s && (*s == '\0'))
888 s = p = NULL;
889
890 /* if p was NULL due to no spaces, s wont exist due to the above, so
891 * we cant check it for spaces.. if there are no spaces, then when
892 * we next get here, s will be NULL
893 */
894 if(s && ((p = strchr(s, ' ')) != NULL))
895 {
896 *p++ = '\0';
897 }
898 }
899
900 *mbuf = '\0';
901 if(pargs)
902 {
903 sendto_channel_local(ALL_MEMBERS, chptr,
904 ":%s MODE %s %s %s %s %s %s",
905 fakesource_p->name, chptr->chname, modebuf,
906 para[0], CheckEmpty(para[1]),
907 CheckEmpty(para[2]), CheckEmpty(para[3]));
908 }
909
910 if(!joins && !(chptr->mode.mode & MODE_PERMANENT) && isnew)
911 {
912 destroy_channel(chptr);
913
3c7d6fcc 914 return;
8cc12805
VY
915 }
916
917 /* Keep the colon if we're sending an SJOIN without nicks -- jilles */
918 if (joins)
919 {
8cc12805
VY
920 *(ptr_uid - 1) = '\0';
921 }
922
923 sendto_server(client_p->from, NULL, CAP_TS6, NOCAPS, "%s", buf_uid);
8cc12805
VY
924}
925
f4a80ce6
JT
926/*
927 * do_join_0
928 *
929 * inputs - pointer to client doing join 0
930 * output - NONE
931 * side effects - Use has decided to join 0. This is legacy
932 * from the days when channels were numbers not names. *sigh*
f4a80ce6
JT
933 */
934static void
935do_join_0(struct Client *client_p, struct Client *source_p)
936{
937 struct membership *msptr;
938 struct Channel *chptr = NULL;
5b96d9a6 939 rb_dlink_node *ptr;
f4a80ce6
JT
940
941 /* Finish the flood grace period... */
942 if(MyClient(source_p) && !IsFloodDone(source_p))
943 flood_endgrace(source_p);
944
f4a80ce6 945 sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s JOIN 0", use_id(source_p));
f4a80ce6 946
f4a80ce6
JT
947 while((ptr = source_p->user->channel.head))
948 {
4eb9a3ca
JT
949 if(MyConnect(source_p) &&
950 !IsOper(source_p) && !IsExemptSpambot(source_p))
951 check_spambot_warning(source_p, NULL);
952
f4a80ce6
JT
953 msptr = ptr->data;
954 chptr = msptr->chptr;
955 sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s PART %s",
956 source_p->name,
957 source_p->username, source_p->host, chptr->chname);
958 remove_user_from_channel(msptr);
959 }
960}
961
3c7d6fcc 962static bool
212380e3
AC
963check_channel_name_loc(struct Client *source_p, const char *name)
964{
6865c0b0
JT
965 const char *p;
966
212380e3
AC
967 s_assert(name != NULL);
968 if(EmptyString(name))
3c7d6fcc 969 return false;
212380e3
AC
970
971 if(ConfigFileEntry.disable_fake_channels && !IsOper(source_p))
972 {
6865c0b0 973 for(p = name; *p; ++p)
212380e3 974 {
6865c0b0 975 if(!IsChanChar(*p) || IsFakeChanChar(*p))
3c7d6fcc 976 return false;
212380e3
AC
977 }
978 }
979 else
980 {
6865c0b0 981 for(p = name; *p; ++p)
212380e3 982 {
6865c0b0 983 if(!IsChanChar(*p))
3c7d6fcc 984 return false;
212380e3
AC
985 }
986 }
987
6865c0b0
JT
988 if(ConfigChannel.only_ascii_channels)
989 {
990 for(p = name; *p; ++p)
991 if(*p < 33 || *p > 126)
3c7d6fcc 992 return false;
6865c0b0
JT
993 }
994
3c7d6fcc 995 return true;
212380e3
AC
996}
997
35bfe0e6
JT
998/* send_join_error()
999 *
1000 * input - client to send to, reason, channel name
1001 * output - none
1002 * side effects - error message sent to client
1003 */
1004static void
1005send_join_error(struct Client *source_p, int numeric, const char *name)
1006{
1007 /* This stuff is necessary because the form_str macro only
1008 * accepts constants.
1009 */
1010 switch (numeric)
1011 {
1012#define NORMAL_NUMERIC(i) \
1013 case i: \
1014 sendto_one(source_p, form_str(i), \
1015 me.name, source_p->name, name); \
1016 break
1017
1018 NORMAL_NUMERIC(ERR_BANNEDFROMCHAN);
1019 NORMAL_NUMERIC(ERR_INVITEONLYCHAN);
1020 NORMAL_NUMERIC(ERR_BADCHANNELKEY);
1021 NORMAL_NUMERIC(ERR_CHANNELISFULL);
1022 NORMAL_NUMERIC(ERR_NEEDREGGEDNICK);
1023 NORMAL_NUMERIC(ERR_THROTTLE);
1024
1025 default:
1026 sendto_one_numeric(source_p, numeric,
1027 "%s :Cannot join channel", name);
1028 break;
1029 }
1030}
1031
212380e3
AC
1032static void
1033set_final_mode(struct Mode *mode, struct Mode *oldmode)
1034{
1035 int dir = MODE_QUERY;
1036 char *pbuf = parabuf;
1037 int len;
1038 int i;
1039
1040 /* ok, first get a list of modes we need to add */
efccc22c 1041 for (i = 0; i < 256; i++)
212380e3 1042 {
efccc22c 1043 if((mode->mode & chmode_flags[i]) && !(oldmode->mode & chmode_flags[i]))
212380e3
AC
1044 {
1045 if(dir != MODE_ADD)
1046 {
1047 *mbuf++ = '+';
1048 dir = MODE_ADD;
1049 }
efccc22c 1050 *mbuf++ = i;
212380e3
AC
1051 }
1052 }
1053
1054 /* now the ones we need to remove. */
efccc22c 1055 for (i = 0; i < 256; i++)
212380e3 1056 {
efccc22c 1057 if((oldmode->mode & chmode_flags[i]) && !(mode->mode & chmode_flags[i]))
212380e3
AC
1058 {
1059 if(dir != MODE_DEL)
1060 {
1061 *mbuf++ = '-';
1062 dir = MODE_DEL;
1063 }
efccc22c 1064 *mbuf++ = i;
212380e3
AC
1065 }
1066 }
1067
1068 if(oldmode->limit && !mode->limit)
1069 {
1070 if(dir != MODE_DEL)
1071 {
1072 *mbuf++ = '-';
1073 dir = MODE_DEL;
1074 }
1075 *mbuf++ = 'l';
1076 }
1077 if(oldmode->key[0] && !mode->key[0])
1078 {
1079 if(dir != MODE_DEL)
1080 {
1081 *mbuf++ = '-';
1082 dir = MODE_DEL;
1083 }
1084 *mbuf++ = 'k';
5203cba5 1085 len = sprintf(pbuf, "%s ", oldmode->key);
212380e3
AC
1086 pbuf += len;
1087 }
1088 if(oldmode->join_num && !mode->join_num)
1089 {
1090 if(dir != MODE_DEL)
1091 {
1092 *mbuf++ = '-';
1093 dir = MODE_DEL;
1094 }
1095 *mbuf++ = 'j';
1096 }
1097 if(oldmode->forward[0] && !mode->forward[0])
1098 {
1099 if(dir != MODE_DEL)
1100 {
1101 *mbuf++ = '-';
1102 dir = MODE_DEL;
1103 }
1104 *mbuf++ = 'f';
1105 }
1106 if(mode->limit && oldmode->limit != mode->limit)
1107 {
1108 if(dir != MODE_ADD)
1109 {
1110 *mbuf++ = '+';
1111 dir = MODE_ADD;
1112 }
1113 *mbuf++ = 'l';
5203cba5 1114 len = sprintf(pbuf, "%d ", mode->limit);
212380e3
AC
1115 pbuf += len;
1116 }
1117 if(mode->key[0] && strcmp(oldmode->key, mode->key))
1118 {
1119 if(dir != MODE_ADD)
1120 {
1121 *mbuf++ = '+';
1122 dir = MODE_ADD;
1123 }
1124 *mbuf++ = 'k';
5203cba5 1125 len = sprintf(pbuf, "%s ", mode->key);
212380e3
AC
1126 pbuf += len;
1127 }
1128 if(mode->join_num && (oldmode->join_num != mode->join_num || oldmode->join_time != mode->join_time))
1129 {
1130 if(dir != MODE_ADD)
1131 {
1132 *mbuf++ = '+';
1133 dir = MODE_ADD;
1134 }
1135 *mbuf++ = 'j';
5203cba5 1136 len = sprintf(pbuf, "%d:%d ", mode->join_num, mode->join_time);
212380e3
AC
1137 pbuf += len;
1138 }
2da6f6eb
JT
1139 if(mode->forward[0] && strcmp(oldmode->forward, mode->forward) &&
1140 ConfigChannel.use_forward)
212380e3
AC
1141 {
1142 if(dir != MODE_ADD)
1143 {
1144 *mbuf++ = '+';
1145 dir = MODE_ADD;
1146 }
1147 *mbuf++ = 'f';
5203cba5 1148 len = sprintf(pbuf, "%s ", mode->forward);
212380e3
AC
1149 pbuf += len;
1150 }
1151 *mbuf = '\0';
1152}
1153
1154/*
1155 * remove_our_modes
1156 *
1157 * inputs -
55abcbb2
KB
1158 * output -
1159 * side effects -
212380e3
AC
1160 */
1161static void
1162remove_our_modes(struct Channel *chptr, struct Client *source_p)
1163{
1164 struct membership *msptr;
5b96d9a6 1165 rb_dlink_node *ptr;
212380e3
AC
1166 char lmodebuf[MODEBUFLEN];
1167 char *lpara[MAXMODEPARAMS];
1168 int count = 0;
1169 int i;
1170
1171 mbuf = lmodebuf;
1172 *mbuf++ = '-';
1173
1174 for(i = 0; i < MAXMODEPARAMS; i++)
1175 lpara[i] = NULL;
1176
5b96d9a6 1177 RB_DLINK_FOREACH(ptr, chptr->members.head)
212380e3
AC
1178 {
1179 msptr = ptr->data;
1180
1181 if(is_chanop(msptr))
1182 {
1183 msptr->flags &= ~CHFL_CHANOP;
1184 lpara[count++] = msptr->client_p->name;
1185 *mbuf++ = 'o';
1186
1187 /* +ov, might not fit so check. */
1188 if(is_voiced(msptr))
1189 {
1190 if(count >= MAXMODEPARAMS)
1191 {
1192 *mbuf = '\0';
1193 sendto_channel_local(ALL_MEMBERS, chptr,
1194 ":%s MODE %s %s %s %s %s %s",
7bf78de0 1195 source_p->name, chptr->chname,
212380e3
AC
1196 lmodebuf, lpara[0], lpara[1],
1197 lpara[2], lpara[3]);
1198
1199 /* preserve the initial '-' */
1200 mbuf = lmodebuf;
1201 *mbuf++ = '-';
1202 count = 0;
1203
1204 for(i = 0; i < MAXMODEPARAMS; i++)
1205 lpara[i] = NULL;
1206 }
1207
1208 msptr->flags &= ~CHFL_VOICE;
1209 lpara[count++] = msptr->client_p->name;
1210 *mbuf++ = 'v';
1211 }
1212 }
1213 else if(is_voiced(msptr))
1214 {
1215 msptr->flags &= ~CHFL_VOICE;
1216 lpara[count++] = msptr->client_p->name;
1217 *mbuf++ = 'v';
1218 }
1219 else
1220 continue;
1221
1222 if(count >= MAXMODEPARAMS)
1223 {
1224 *mbuf = '\0';
1225 sendto_channel_local(ALL_MEMBERS, chptr,
1226 ":%s MODE %s %s %s %s %s %s",
7bf78de0 1227 source_p->name, chptr->chname, lmodebuf,
212380e3
AC
1228 lpara[0], lpara[1], lpara[2], lpara[3]);
1229 mbuf = lmodebuf;
1230 *mbuf++ = '-';
1231 count = 0;
1232
1233 for(i = 0; i < MAXMODEPARAMS; i++)
1234 lpara[i] = NULL;
1235 }
1236 }
1237
1238 if(count != 0)
1239 {
1240 *mbuf = '\0';
1241 sendto_channel_local(ALL_MEMBERS, chptr,
1242 ":%s MODE %s %s %s %s %s %s",
7bf78de0 1243 source_p->name, chptr->chname, lmodebuf,
212380e3
AC
1244 EmptyString(lpara[0]) ? "" : lpara[0],
1245 EmptyString(lpara[1]) ? "" : lpara[1],
1246 EmptyString(lpara[2]) ? "" : lpara[2],
1247 EmptyString(lpara[3]) ? "" : lpara[3]);
1248
1249 }
1250}
8cc12805
VY
1251
1252/* remove_ban_list()
1253 *
1254 * inputs - channel, source, list to remove, char of mode, caps needed
1255 * outputs -
1256 * side effects - given list is removed, with modes issued to local clients
8cc12805
VY
1257 */
1258static void
1259remove_ban_list(struct Channel *chptr, struct Client *source_p,
8afeb720 1260 rb_dlink_list * list, char c, int mems)
8cc12805
VY
1261{
1262 static char lmodebuf[BUFSIZE];
1263 static char lparabuf[BUFSIZE];
1264 struct Ban *banptr;
1265 rb_dlink_node *ptr;
1266 rb_dlink_node *next_ptr;
1267 char *pbuf;
1268 int count = 0;
1269 int cur_len, mlen, plen;
1270
1271 pbuf = lparabuf;
1272
5203cba5 1273 cur_len = mlen = sprintf(lmodebuf, ":%s MODE %s -", source_p->name, chptr->chname);
8cc12805
VY
1274 mbuf = lmodebuf + mlen;
1275
1276 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
1277 {
1278 banptr = ptr->data;
1279
1280 /* trailing space, and the mode letter itself */
23f6b63a
JT
1281 plen = strlen(banptr->banstr) +
1282 (banptr->forward ? strlen(banptr->forward) + 1 : 0) + 2;
8cc12805
VY
1283
1284 if(count >= MAXMODEPARAMS || (cur_len + plen) > BUFSIZE - 4)
1285 {
1286 /* remove trailing space */
1287 *mbuf = '\0';
1288 *(pbuf - 1) = '\0';
1289
1290 sendto_channel_local(mems, chptr, "%s %s", lmodebuf, lparabuf);
8cc12805
VY
1291
1292 cur_len = mlen;
1293 mbuf = lmodebuf + mlen;
1294 pbuf = lparabuf;
1295 count = 0;
1296 }
1297
1298 *mbuf++ = c;
1299 cur_len += plen;
23f6b63a 1300 if (banptr->forward)
5203cba5 1301 pbuf += sprintf(pbuf, "%s$%s ", banptr->banstr, banptr->forward);
23f6b63a 1302 else
5203cba5 1303 pbuf += sprintf(pbuf, "%s ", banptr->banstr);
8cc12805
VY
1304 count++;
1305
1306 free_ban(banptr);
1307 }
1308
1309 *mbuf = '\0';
1310 *(pbuf - 1) = '\0';
1311 sendto_channel_local(mems, chptr, "%s %s", lmodebuf, lparabuf);
8cc12805
VY
1312
1313 list->head = list->tail = NULL;
1314 list->length = 0;
1315}