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