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