]> jfr.im git - irc.git/blame - software/ircd/www.irc.org/ftp/irc/server/irc2.11.2p3/ircd/channel.c
init
[irc.git] / software / ircd / www.irc.org / ftp / irc / server / irc2.11.2p3 / ircd / channel.c
CommitLineData
3bd189cb
JR
1/************************************************************************
2 * IRC - Internet Relay Chat, ircd/channel.c
3 * Copyright (C) 1990 Jarkko Oikarinen and
4 * University of Oulu, Co Center
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 1, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21/* -- Jto -- 09 Jul 1990
22 * Bug fix
23 */
24
25/* -- Jto -- 03 Jun 1990
26 * Moved m_channel() and related functions from s_msg.c to here
27 * Many changes to start changing into string channels...
28 */
29
30/* -- Jto -- 24 May 1990
31 * Moved is_full() from list.c
32 */
33
34#ifndef lint
35static const volatile char rcsid[] = "@(#)$Id: channel.c,v 1.279 2010/08/12 16:23:14 bif Exp $";
36#endif
37
38#include "os.h"
39#include "s_defines.h"
40#define CHANNEL_C
41#include "s_externs.h"
42#undef CHANNEL_C
43
44static char asterix[2]="*";
45
46#define BanLen(x) ((strlen(x->nick)+strlen(x->user)+strlen(x->host)))
47#define BanMatch(x,y) ((!match(x->nick,y->nick)&&!match(x->user,y->user)&&!match(x->host,y->host)))
48#define BanExact(x,y) ((!mycmp(x->nick,y->nick)&&!mycmp(x->user,y->user)&&!mycmp(x->host,y->host)))
49
50aChannel *channel = NullChn;
51
52static void add_invite (aClient *, aClient *, aChannel *);
53static int can_join (aClient *, aChannel *, char *);
54void channel_modes (aClient *, char *, char *, aChannel *);
55static int check_channelmask (aClient *, aClient *, char *);
56
57#ifdef JAPANESE
58static int jp_chname (char *);
59#endif
60
61static aChannel *get_channel (aClient *, char *, int);
62static int set_mode (aClient *, aClient *, aChannel *, int *,
63 int, char **);
64static void free_channel (aChannel *);
65
66static int add_modeid (int, aClient *, aChannel *, aListItem *);
67static int del_modeid (int, aChannel *, aListItem *);
68static Link *match_modeid (int, aClient *, aChannel *);
69static void names_channel (aClient *,aClient *,char *,aChannel *,int);
70static void free_bei (aListItem *bei);
71static aListItem *make_bei (char *nick, char *user, char *host);
72
73
74static char *PartFmt = ":%s PART %s :%s";
75
76/*
77 * some buffers for rebuilding channel/nick lists with ,'s
78 */
79static char buf[BUFSIZE];
80static char modebuf[MODEBUFLEN], parabuf[MODEBUFLEN], uparabuf[MODEBUFLEN];
81
82/*
83 * return the length (>=0) of a chain of links.
84 */
85static int list_length(invLink *lp)
86{
87 Reg int count = 0;
88
89 for (; lp; lp = lp->next)
90 count++;
91 return count;
92}
93
94/*
95** find_chasing
96** Find the client structure for a nick name (user) using history
97** mechanism if necessary. If the client is not found, an error
98** message (NO SUCH NICK) is generated. If the client was found
99** through the history, chasing will be 1 and otherwise 0.
100*/
101static aClient *find_chasing(aClient *sptr, char *user, int *chasing)
102{
103 Reg aClient *who = find_client(user, (aClient *)NULL);
104
105 if (chasing)
106 *chasing = 0;
107 if (who)
108 return who;
109 if (!(who = get_history(user, (long)KILLCHASETIMELIMIT)))
110 {
111 sendto_one(sptr, replies[ERR_NOSUCHNICK], ME, BadTo(sptr->name), user);
112 return NULL;
113 }
114 if (chasing)
115 *chasing = 1;
116 return who;
117}
118
119/*
120 * Fixes a string so that the first white space found becomes an end of
121 * string marker (`\0`). Returns the 'fixed' string or static "*" if the string
122 * was NULL length or a NULL pointer.
123 */
124static char *check_string(char *s)
125{
126 char *str = s;
127
128 if (BadPtr(s))
129 return asterix;
130
131 for ( ;*s; s++)
132 if (isspace(*s))
133 {
134 *s = '\0';
135 break;
136 }
137
138 return (BadPtr(str)) ? asterix : str;
139}
140
141static void free_bei(aListItem *bei)
142{
143 if (bei->nick != asterix)
144 {
145 MyFree(bei->nick);
146 }
147 if (bei->user != asterix)
148 {
149 MyFree(bei->user);
150 }
151 if (bei->host != asterix)
152 {
153 MyFree(bei->host);
154 }
155 MyFree(bei);
156}
157
158/* Prepare and fill ListItem struct. Note: check_string takes care of
159** cleaning parts, including possible use of static asterix. */
160static aListItem *make_bei(char *nick, char *user, char *host)
161{
162 aListItem *tmp;
163 int len;
164
165 tmp = (struct ListItem *)MyMalloc(sizeof(aListItem));
166
167 nick = check_string(nick);
168 if (nick == asterix)
169 {
170 tmp->nick = asterix;
171 }
172 else
173 {
174 len = MIN(strlen(nick), NICKLEN) + 1;
175 tmp->nick = (char *) MyMalloc(len);
176 strncpyzt(tmp->nick, nick, len);
177 }
178 user = check_string(user);
179 if (user == asterix)
180 {
181 tmp->user = asterix;
182 }
183 else
184 {
185 len = MIN(strlen(user), USERLEN) + 1;
186 tmp->user=(char *) MyMalloc(len);
187 strncpyzt(tmp->user, user, len);
188 }
189 host = check_string(host);
190 if (host == asterix)
191 {
192 tmp->host = asterix;
193 }
194 else
195 {
196 len = MIN(strlen(host), HOSTLEN) + 1;
197 tmp->host=(char *) MyMalloc(len);
198 strncpyzt(tmp->host, host, len);
199 }
200
201 return tmp;
202}
203
204/*
205 * Ban functions to work with mode +b/+e/+I
206 */
207/* add_modeid - add an id to the list of modes "type" for chptr
208 * (belongs to cptr)
209 */
210
211static int add_modeid(int type, aClient *cptr, aChannel *chptr,
212 aListItem *modeid)
213{
214 Reg Link *mode;
215 Reg int cnt = 0, len = 0;
216
217 if (MyClient(cptr))
218 {
219 (void) collapse(modeid->nick);
220 (void) collapse(modeid->user);
221 (void) collapse(modeid->host);
222 }
223
224 for (mode = chptr->mlist; mode; mode = mode->next)
225 {
226 len += BanLen(mode->value.alist);
227 if (MyClient(cptr))
228 {
229 if ((len > MAXBANLENGTH) || (++cnt >= MAXBANS))
230 {
231 sendto_one(cptr, replies[ERR_BANLISTFULL],
232 ME, BadTo(cptr->name),
233 chptr->chname, modeid->nick,
234 modeid->user, modeid->host);
235 return -1;
236 }
237 if (type == mode->flags &&
238 BanExact(mode->value.alist, modeid))
239 {
240 int rpl;
241
242 if (type == CHFL_BAN)
243 rpl = RPL_BANLIST;
244 else if (type == CHFL_EXCEPTION)
245 rpl = RPL_EXCEPTLIST;
246 else if (type == CHFL_REOPLIST)
247 rpl = RPL_REOPLIST;
248 else
249 rpl = RPL_INVITELIST;
250
251 sendto_one(cptr, replies[rpl], ME, BadTo(cptr->name),
252 chptr->chname, mode->value.alist->nick,
253 mode->value.alist->user,
254 mode->value.alist->host);
255 return -1;
256 }
257 }
258 else if (type == mode->flags && BanExact(mode->value.alist, modeid))
259 {
260 return -1;
261 }
262
263 }
264 mode = make_link();
265 istat.is_bans++;
266 bzero((char *)mode, sizeof(Link));
267 mode->flags = type;
268 mode->next = chptr->mlist;
269 mode->value.alist = modeid;
270 istat.is_banmem += BanLen(modeid);
271 chptr->mlist = mode;
272 return 0;
273}
274
275/*
276 * del_modeid - delete an id belonging to chptr
277 * if modeid is null, delete all ids belonging to chptr. (seems to be unused)
278 */
279static int del_modeid(int type, aChannel *chptr, aListItem *modeid)
280{
281 Reg Link **mode;
282 Reg Link *tmp;
283
284 /* mode == NULL rewritten inside loop */
285 for (mode = &(chptr->mlist); *mode; mode = &((*mode)->next))
286 {
287 if (type == (*mode)->flags &&
288 (modeid == NULL ? 1 : BanExact(modeid, (*mode)->value.alist)))
289 {
290 tmp = *mode;
291 *mode = tmp->next;
292 istat.is_banmem -= BanLen(tmp->value.alist);
293 istat.is_bans--;
294 free_bei(tmp->value.alist);
295 free_link(tmp);
296 break;
297 }
298 }
299 return 0;
300}
301
302/*
303 * match_modeid - returns a pointer to the mode structure if matching else NULL
304 */
305static Link *match_modeid(int type, aClient *cptr, aChannel *chptr)
306{
307 Reg Link *tmp;
308
309 if (!IsPerson(cptr))
310 return NULL;
311
312 for (tmp = chptr->mlist; tmp; tmp = tmp->next)
313 {
314 if (tmp->flags == type)
315 {
316 if (match(tmp->value.alist->nick, cptr->name) != 0)
317 {
318 /* seems like no match on nick, but... */
319 if (isdigit(tmp->value.alist->nick[0]))
320 {
321 /* ...perhaps it is UID-ban? */
322 if (match(tmp->value.alist->nick,
323 cptr->user->uid) != 0)
324 {
325 /* no match on UID */
326 continue;
327 }
328 /* We have match on UID!
329 * Go now for the user part */
330 }
331 else
332 {
333 /* no match on nick part */
334 continue;
335 }
336 }
337 if (match(tmp->value.alist->user, cptr->user->username) != 0)
338 {
339 /* no match on user part */
340 continue;
341 }
342 /* At this point n!u of a client matches that of a beI.
343 * Proceeding to more intensive checks of hostname,
344 * IP, CIDR
345 */
346 if (match(tmp->value.alist->host, cptr->user->host) == 0)
347 {
348 /* match */
349 break;
350 }
351 /* if our client, let's check IP and CIDR */
352 /* perhaps we could relax it and check remotes too? */
353 if (MyConnect(cptr))
354 {
355 Link *acf = cptr->confs;
356
357 /* scroll acf to I:line */
358 if (IsAnOper(cptr))
359 {
360 acf = acf->next;
361 /* above is faster but will fail if we introduce
362 ** something that will attach another conf for
363 ** client -- the following will have to be used:
364 for (; acf; acf = acf->next)
365 if (acf->value.aconf->status & CONF_CLIENT)
366 break;
367 */
368 }
369
370 if (IsConfNoResolveMatch(acf->value.aconf))
371 {
372 /* user->host contains IP and was just
373 * checked; try sockhost, it may have
374 * hostname.
375 */
376 if (match(tmp->value.alist->host,
377 cptr->sockhost) == 0)
378 {
379 /* match */
380 break;
381 }
382 }
383 else
384 /* Yay, it's 2.11, we have string ip! */
385 if (match(tmp->value.alist->host, cptr->user->sip) == 0)
386 {
387 /* match */
388 break;
389 }
390 /* so now we check CIDR */
391 if (strchr(tmp->value.alist->host, '/') &&
392 match_ipmask(tmp->value.alist->host, cptr, 0) == 0)
393 {
394 break;
395 }
396 }
397 }
398 }
399 return (tmp);
400}
401
402/*
403 * adds a user to a channel by adding another link to the channels member
404 * chain.
405 */
406static void add_user_to_channel(aChannel *chptr, aClient *who, int flags)
407{
408 Reg Link *ptr;
409 Reg int sz = sizeof(aChannel) + strlen(chptr->chname);
410
411 if (who->user)
412 {
413 ptr = make_link();
414 ptr->flags = flags;
415 ptr->value.cptr = who;
416 ptr->next = chptr->members;
417 chptr->members = ptr;
418 istat.is_chanusers++;
419 if (chptr->users++ == 0)
420 {
421 istat.is_chan++;
422 istat.is_chanmem += sz;
423 }
424 if (chptr->users == 1 && chptr->history)
425 {
426 /* Locked channel */
427 istat.is_hchan--;
428 istat.is_hchanmem -= sz;
429 /*
430 ** The modes had been kept, but now someone is joining,
431 ** they should be reset to avoid desynchs
432 ** (you wouldn't want to join a +i channel, either)
433 **
434 ** This can be wrong in some cases such as a netjoin
435 ** which will not complete, or on a mixed net (with
436 ** servers that don't do channel delay) - kalt
437 */
438 if (*chptr->chname != '!')
439 bzero((char *)&chptr->mode, sizeof(Mode));
440 }
441
442#ifdef USE_SERVICES
443 if (chptr->users == 1)
444 check_services_butone(SERVICE_WANT_CHANNEL|
445 SERVICE_WANT_VCHANNEL,
446 NULL, &me, "CHANNEL %s %d",
447 chptr->chname, chptr->users);
448 else
449 check_services_butone(SERVICE_WANT_VCHANNEL,
450 NULL, &me, "CHANNEL %s %d",
451 chptr->chname, chptr->users);
452#endif
453 ptr = make_link();
454 ptr->flags = flags;
455 ptr->value.chptr = chptr;
456 ptr->next = who->user->channel;
457 who->user->channel = ptr;
458 if (!IsQuiet(chptr))
459 {
460 who->user->joined++;
461 istat.is_userc++;
462 }
463
464 if (!(ptr = find_user_link(chptr->clist, who->from)))
465 {
466 ptr = make_link();
467 ptr->value.cptr = who->from;
468 ptr->next = chptr->clist;
469 chptr->clist = ptr;
470 }
471 ptr->flags++;
472 }
473}
474
475void remove_user_from_channel(aClient *sptr, aChannel *chptr)
476{
477 Reg Link **curr;
478 Reg Link *tmp, *tmp2;
479
480 for (curr = &chptr->members; (tmp = *curr); curr = &tmp->next)
481 if (tmp->value.cptr == sptr)
482 {
483 /*
484 * if a chanop leaves (no matter how), record
485 * the time to be able to later massreop if
486 * necessary.
487 */
488 if (tmp->flags & CHFL_CHANOP)
489 {
490 chptr->reop = timeofday + LDELAYCHASETIMELIMIT +
491 myrand() % 300;
492 }
493
494 *curr = tmp->next;
495 free_link(tmp);
496 break;
497 }
498 for (curr = &sptr->user->channel; (tmp = *curr); curr = &tmp->next)
499 if (tmp->value.chptr == chptr)
500 {
501 *curr = tmp->next;
502 free_link(tmp);
503 break;
504 }
505 if (sptr->from)
506 tmp2 = find_user_link(chptr->clist, sptr->from);
507 else
508 tmp2 = find_user_link(chptr->clist, sptr);
509 if (tmp2 && !--tmp2->flags)
510 for (curr = &chptr->clist; (tmp = *curr); curr = &tmp->next)
511 if (tmp2 == tmp)
512 {
513 *curr = tmp->next;
514 free_link(tmp);
515 break;
516 }
517 if (!IsQuiet(chptr))
518 {
519 sptr->user->joined--;
520 istat.is_userc--;
521 }
522#ifdef USE_SERVICES
523 if (chptr->users == 1)
524 check_services_butone(SERVICE_WANT_CHANNEL|
525 SERVICE_WANT_VCHANNEL, NULL, &me,
526 "CHANNEL %s %d", chptr->chname,
527 chptr->users-1);
528 else
529 check_services_butone(SERVICE_WANT_VCHANNEL, NULL, &me,
530 "CHANNEL %s %d", chptr->chname,
531 chptr->users-1);
532#endif
533 if (--chptr->users <= 0)
534 {
535 u_int sz = sizeof(aChannel) + strlen(chptr->chname);
536
537 istat.is_chan--;
538 istat.is_chanmem -= sz;
539 istat.is_hchan++;
540 istat.is_hchanmem += sz;
541 free_channel(chptr);
542 }
543 istat.is_chanusers--;
544}
545
546static void change_chan_flag(Link *lp, aChannel *chptr)
547{
548 Reg Link *tmp;
549 aClient *cptr = lp->value.cptr;
550
551 /*
552 * Set the channel members flags...
553 */
554 tmp = find_user_link(chptr->members, cptr);
555 if (lp->flags & MODE_ADD)
556 tmp->flags |= lp->flags & MODE_FLAGS;
557 else
558 {
559 tmp->flags &= ~lp->flags & MODE_FLAGS;
560 if (lp->flags & CHFL_CHANOP)
561 tmp->flags &= ~CHFL_UNIQOP;
562 }
563 /*
564 * and make sure client membership mirrors channel
565 */
566 tmp = find_user_link(cptr->user->channel, (aClient *)chptr);
567 if (lp->flags & MODE_ADD)
568 tmp->flags |= lp->flags & MODE_FLAGS;
569 else
570 {
571 tmp->flags &= ~lp->flags & MODE_FLAGS;
572 if (lp->flags & CHFL_CHANOP)
573 tmp->flags &= ~CHFL_UNIQOP;
574 }
575}
576
577int is_chan_op(aClient *cptr, aChannel *chptr)
578{
579 Reg Link *lp;
580 int chanop = 0;
581
582 if (MyConnect(cptr) && IsPerson(cptr) && IsRestricted(cptr) &&
583 *chptr->chname != '&')
584 return 0;
585 if (chptr)
586 if ((lp = find_user_link(chptr->members, cptr)))
587 chanop = (lp->flags & (CHFL_CHANOP|CHFL_UNIQOP));
588 if (chanop)
589 chptr->reop = 0;
590 return chanop;
591}
592
593int has_voice(aClient *cptr, aChannel *chptr)
594{
595 Reg Link *lp;
596
597 if (chptr)
598 if ((lp = find_user_link(chptr->members, cptr)))
599 return (lp->flags & CHFL_VOICE);
600
601 return 0;
602}
603
604int can_send(aClient *cptr, aChannel *chptr)
605{
606 Reg Link *lp;
607 Reg int member;
608
609 member = IsMember(cptr, chptr);
610 lp = find_user_link(chptr->members, cptr);
611
612 if (chptr->mode.mode & MODE_MODERATED &&
613 (!lp || !(lp->flags & (CHFL_CHANOP|CHFL_VOICE))))
614 return (MODE_MODERATED);
615
616 if (chptr->mode.mode & MODE_NOPRIVMSGS && !member)
617 return (MODE_NOPRIVMSGS);
618
619 /* checking +be is not reliable for remote clients for case
620 ** when exception is in cidr format. working around that is
621 ** horrible. basically inet_pton for each UNICK and keeping
622 ** it in client struct, plus dealing somehow with non-inet6
623 ** servers getting inet6 clients ips from remote servers...
624 ** in short it seems better to allow remote clients to just
625 ** talk, trusting a bit remote servers, than to reject good
626 ** messages. --B. */
627 if (!MyConnect(cptr))
628 return 0;
629
630 if ((!lp || !(lp->flags & (CHFL_CHANOP | CHFL_VOICE))) &&
631 !match_modeid(CHFL_EXCEPTION, cptr, chptr) &&
632 match_modeid(CHFL_BAN, cptr, chptr))
633 return (MODE_BAN);
634
635 return 0;
636}
637
638#ifdef JAPANESE
639char *get_channelmask(char *chname)
640{
641 char *mask;
642
643 mask = rindex(chname, ':');
644 if (!mask || index(mask, '\033'))
645 {
646 /* If '\033' is in the mask, well, it's not a real mask,
647 ** but a JIS encoded channel name. --Beeth */
648 return NULL;
649 }
650 return mask;
651}
652
653/* This tries to find out if given chname is JIS encoded:
654** a) ":" followed somewhere by '\033'
655** b) comma in chname (impossible if not for JIS)
656** c) one of {, }, ~, \ between JIS marks.
657**
658** Returns 1 if seems JIS encoded, 0 otherwise.
659*/
660int jp_chname(char *chname)
661{
662 char *mask, *cn;
663 int flag = 0;
664
665 if (!chname || !*chname)
666 return 0;
667 mask = rindex(chname, ':');
668 if (mask && index(mask, '\033'))
669 return 1;
670 if (index(chname, ','))
671 return 1;
672
673 cn = chname;
674 while (*cn)
675 {
676 if (cn[0] == '\033'
677 && (cn[1] == '$' || cn[1] == '(')
678 && cn[2] == 'B')
679 {
680 flag = (cn[1] == '$') ? 1 : 0;
681 cn += 2;
682 }
683 else if (flag == 1 &&
684 (*cn == '{' || *cn == '}' || *cn == '~' || *cn == '\\'))
685 {
686 return 1;
687 }
688 cn++;
689 }
690 return 0;
691}
692
693#define IsJPFlag(x) (((x)->flags & FLAGS_JP))
694#define IsJPChan(x, y) ( ((x) && IsJPFlag((x))) || jp_chname((y)) )
695
696/*
697** This checks for valid combination of channel name and server,
698** so Japanese channels are not sent to non-Japanese servers.
699**
700** If cptr is NULL, then function is reduced to checking if channel name
701** is (likely to be) Japanese (if it is not, it can be sent anywhere).
702**
703** Otherwise cptr should be a JP flagged server or not a server at all.
704**
705** Returns 1 if it is safe to use given combination of params or 0 if not.
706**
707** Note: this should be split in two functions for clarity.
708*/
709int jp_valid(aClient *cptr, aChannel *chptr, char *chname)
710{
711 return ( !IsJPChan(chptr, chname) ||
712 (cptr && (!IsServer(cptr) || IsJPFlag(cptr))) );
713}
714#endif
715
716aChannel *find_channel(char *chname, aChannel *chptr)
717{
718 aChannel *achptr = chptr;
719
720 if (chname && *chname)
721 achptr = hash_find_channel(chname, chptr);
722 return achptr;
723}
724
725void setup_server_channels(aClient *mp)
726{
727 aChannel *chptr;
728 int smode;
729
730 smode = MODE_MODERATED|MODE_TOPICLIMIT|MODE_NOPRIVMSGS|MODE_ANONYMOUS|
731 MODE_QUIET;
732
733 chptr = get_channel(mp, "&ERRORS", CREATE);
734 strcpy(chptr->topic, "SERVER MESSAGES: server errors");
735 add_user_to_channel(chptr, mp, CHFL_CHANOP);
736 chptr->mode.mode = smode;
737 chptr = get_channel(mp, "&NOTICES", CREATE);
738 strcpy(chptr->topic, "SERVER MESSAGES: warnings and notices");
739 add_user_to_channel(chptr, mp, CHFL_CHANOP);
740 chptr->mode.mode = smode;
741 chptr = get_channel(mp, "&KILLS", CREATE);
742 strcpy(chptr->topic, "SERVER MESSAGES: operator and server kills");
743 add_user_to_channel(chptr, mp, CHFL_CHANOP);
744 chptr->mode.mode = smode;
745 chptr = get_channel(mp, "&CHANNEL", CREATE);
746 strcpy(chptr->topic, "SERVER MESSAGES: fake modes");
747 add_user_to_channel(chptr, mp, CHFL_CHANOP);
748 chptr->mode.mode = smode;
749 chptr = get_channel(mp, "&NUMERICS", CREATE);
750 strcpy(chptr->topic, "SERVER MESSAGES: numerics received");
751 add_user_to_channel(chptr, mp, CHFL_CHANOP);
752 chptr->mode.mode = smode;
753 chptr = get_channel(mp, "&SERVERS", CREATE);
754 strcpy(chptr->topic, "SERVER MESSAGES: servers joining and leaving");
755 add_user_to_channel(chptr, mp, CHFL_CHANOP);
756 chptr->mode.mode = smode;
757 chptr = get_channel(mp, "&HASH", CREATE);
758 strcpy(chptr->topic, "SERVER MESSAGES: hash tables growth");
759 add_user_to_channel(chptr, mp, CHFL_CHANOP);
760 chptr->mode.mode = smode;
761 chptr = get_channel(mp, "&LOCAL", CREATE);
762 strcpy(chptr->topic, "SERVER MESSAGES: notices about local connections");
763 add_user_to_channel(chptr, mp, CHFL_CHANOP);
764 chptr->mode.mode = smode;
765 chptr = get_channel(mp, "&SERVICES", CREATE);
766 strcpy(chptr->topic, "SERVER MESSAGES: services joining and leaving");
767 add_user_to_channel(chptr, mp, CHFL_CHANOP);
768 chptr->mode.mode = smode;
769#if defined(USE_IAUTH)
770 chptr = get_channel(mp, "&AUTH", CREATE);
771 strcpy(chptr->topic,
772 "SERVER MESSAGES: messages from the authentication slave");
773 add_user_to_channel(chptr, mp, CHFL_CHANOP);
774 chptr->mode.mode = smode;
775#endif
776 chptr = get_channel(mp, "&SAVE", CREATE);
777 strcpy(chptr->topic,
778 "SERVER MESSAGES: save messages");
779 add_user_to_channel(chptr, mp, CHFL_CHANOP);
780 chptr->mode.mode = smode;
781 chptr = get_channel(mp, "&DEBUG", CREATE);
782 strcpy(chptr->topic, "SERVER MESSAGES: debug messages [you shouldn't be here! ;)]");
783 add_user_to_channel(chptr, mp, CHFL_CHANOP);
784 chptr->mode.mode = smode|MODE_SECRET;
785 chptr = get_channel(mp, "&WALLOPS", CREATE);
786 strcpy(chptr->topic, "SERVER MESSAGES: wallops received");
787 add_user_to_channel(chptr, mp, CHFL_CHANOP);
788 chptr->mode.mode = smode;
789#ifdef CLIENTS_CHANNEL
790 chptr = get_channel(mp, "&CLIENTS", CREATE);
791 strcpy(chptr->topic, "SERVER MESSAGES: clients activity");
792 add_user_to_channel(chptr, mp, CHFL_CHANOP);
793 chptr->mode.mode = smode|MODE_SECRET|MODE_INVITEONLY;
794#endif
795 chptr = get_channel(mp, "&OPER", CREATE);
796 strcpy(chptr->topic, "SERVER MESSAGES: for your trusted eyes only");
797 add_user_to_channel(chptr, mp, CHFL_CHANOP);
798 chptr->mode.mode = smode|MODE_SECRET|MODE_INVITEONLY;
799
800 setup_svchans();
801}
802
803/*
804 * write the "simple" list of channel modes for channel chptr onto buffer mbuf
805 * with the parameters in pbuf.
806 */
807void channel_modes(aClient *cptr, char *mbuf, char *pbuf, aChannel *chptr)
808{
809 *mbuf++ = '+';
810 if (chptr->mode.mode & MODE_SECRET)
811 *mbuf++ = 's';
812 else if (chptr->mode.mode & MODE_PRIVATE)
813 *mbuf++ = 'p';
814 if (chptr->mode.mode & MODE_MODERATED)
815 *mbuf++ = 'm';
816 if (chptr->mode.mode & MODE_TOPICLIMIT)
817 *mbuf++ = 't';
818 if (chptr->mode.mode & MODE_INVITEONLY)
819 *mbuf++ = 'i';
820 if (chptr->mode.mode & MODE_NOPRIVMSGS)
821 *mbuf++ = 'n';
822 if (chptr->mode.mode & MODE_ANONYMOUS)
823 *mbuf++ = 'a';
824 if (chptr->mode.mode & MODE_QUIET)
825 *mbuf++ = 'q';
826 if (chptr->mode.mode & MODE_REOP)
827 *mbuf++ = 'r';
828 if (chptr->mode.limit)
829 {
830 *mbuf++ = 'l';
831 if (IsMember(cptr, chptr) || IsServer(cptr))
832 sprintf(pbuf, "%d ", chptr->mode.limit);
833 }
834 if (*chptr->mode.key)
835 {
836 *mbuf++ = 'k';
837 if (IsMember(cptr, chptr) || IsServer(cptr))
838 (void)strcat(pbuf, chptr->mode.key);
839 }
840 *mbuf++ = '\0';
841 return;
842}
843
844static void send_mode_list(aClient *cptr, char *chname, Link *top,
845 int mask, char flag)
846{
847 Reg Link *lp;
848 Reg char *cp, *name;
849 int count = 0, send = 0;
850 char tmpbei[NICKLEN+1+USERLEN+1+HOSTLEN+1];
851
852 cp = modebuf + strlen(modebuf);
853 if (*parabuf)
854 {
855 /*
856 ** we have some modes in parabuf,
857 ** so check how many of them.
858 ** however, don't count initial '+'
859 */
860 count = strlen(modebuf) - 1;
861 }
862 for (lp = top; lp; lp = lp->next)
863 {
864 if (!(lp->flags & mask))
865 continue;
866 if (mask == CHFL_BAN || mask == CHFL_EXCEPTION ||
867 mask == CHFL_INVITE || mask == CHFL_REOPLIST)
868 {
869 /* XXX: rewrite latter to simply use alist, DO NOT copy it --B. */
870 sprintf(tmpbei, "%s!%s@%s", lp->value.alist->nick,
871 lp->value.alist->user, lp->value.alist->host);
872 name = tmpbei;
873 }
874 else
875 name = lp->value.cptr->name;
876 if (strlen(parabuf) + strlen(name) + 10 < (size_t) MODEBUFLEN)
877 {
878 if (*parabuf)
879 {
880 (void)strcat(parabuf, " ");
881 }
882 (void)strcat(parabuf, name);
883 count++;
884 *cp++ = flag;
885 *cp = '\0';
886 }
887 else
888 {
889 if (*parabuf)
890 {
891 send = 1;
892 }
893 }
894 if (count == MAXMODEPARAMS)
895 {
896 send = 1;
897 }
898 if (send)
899 {
900 /*
901 ** send out MODEs, it's either MAXMODEPARAMS of them
902 ** or long enough that they filled up parabuf
903 */
904 sendto_one(cptr, ":%s MODE %s %s %s",
905 IsServer(cptr) ? me.serv->sid : ME,
906 chname, modebuf, parabuf);
907 send = 0;
908 *parabuf = '\0';
909 cp = modebuf;
910 *cp++ = '+';
911 if (count != MAXMODEPARAMS)
912 {
913 /*
914 ** we weren't able to fit another 'name'
915 ** into parabuf, so we have to send it
916 ** in another turn, appending it now to
917 ** empty parabuf and setting count to 1
918 */
919 (void)strcpy(parabuf, name);
920 *cp++ = flag;
921 count = 1;
922 }
923 else
924 {
925 count = 0;
926 }
927 *cp = '\0';
928 }
929 }
930}
931
932/*
933 * send "cptr" a full list of the modes for channel chptr.
934 */
935void send_channel_modes(aClient *cptr, aChannel *chptr)
936{
937 char *me2 = me.serv->sid;
938
939 if (check_channelmask(&me, cptr, chptr->chname))
940 return;
941#ifdef JAPANESE
942 /* We did not send channel members, we don't send channel
943 ** modes to servers that are not prepared to handle JIS encoding. */
944 if (!jp_valid(cptr, chptr, NULL))
945 return;
946#endif
947
948 *modebuf = *parabuf = '\0';
949 channel_modes(cptr, modebuf, parabuf, chptr);
950
951 if (modebuf[1] || *parabuf)
952 {
953 sendto_one(cptr, ":%s MODE %s %s %s",
954 me2, chptr->chname, modebuf, parabuf);
955 }
956
957 *parabuf = '\0';
958 *modebuf = '+';
959 modebuf[1] = '\0';
960 send_mode_list(cptr, chptr->chname, chptr->mlist, CHFL_BAN, 'b');
961 send_mode_list(cptr, chptr->chname, chptr->mlist,
962 CHFL_EXCEPTION, 'e');
963 send_mode_list(cptr, chptr->chname, chptr->mlist,
964 CHFL_INVITE, 'I');
965 send_mode_list(cptr, chptr->chname, chptr->mlist,
966 CHFL_REOPLIST, 'R');
967 if (modebuf[1] || *parabuf)
968 {
969 /* complete sending, if anything left in buffers */
970 sendto_one(cptr, ":%s MODE %s %s %s",
971 me2, chptr->chname, modebuf, parabuf);
972 }
973}
974
975/*
976 * send "cptr" a full list of the channel "chptr" members and their
977 * +ov status, using NJOIN
978 */
979void send_channel_members(aClient *cptr, aChannel *chptr)
980{
981 Reg Link *lp;
982 Reg aClient *c2ptr;
983 Reg int cnt = 0, len = 0, nlen;
984 char *p;
985 char *me2 = me.serv->sid;
986
987 if (check_channelmask(&me, cptr, chptr->chname) == -1)
988 return;
989#ifdef JAPANESE
990 /* We do not send channel members to servers that are not prepared
991 ** to handle JIS encoding. */
992 if (!jp_valid(cptr, chptr, NULL))
993 return;
994#endif
995 sprintf(buf, ":%s NJOIN %s :", me2, chptr->chname);
996 len = strlen(buf);
997
998 for (lp = chptr->members; lp; lp = lp->next)
999 {
1000 c2ptr = lp->value.cptr;
1001 p = c2ptr->user ? c2ptr->user->uid : c2ptr->name;
1002 nlen = strlen(p);
1003 if ((len + nlen) > (size_t) (BUFSIZE - 9)) /* ,@+ \r\n\0 */
1004 {
1005 sendto_one(cptr, "%s", buf);
1006 sprintf(buf, ":%s NJOIN %s :", me2, chptr->chname);
1007 len = strlen(buf);
1008 cnt = 0;
1009 }
1010 if (cnt)
1011 {
1012 buf[len++] = ',';
1013 buf[len] = '\0';
1014 }
1015 if (lp->flags & (CHFL_UNIQOP|CHFL_CHANOP|CHFL_VOICE))
1016 {
1017 if (lp->flags & CHFL_UNIQOP)
1018 {
1019 buf[len++] = '@';
1020 buf[len++] = '@';
1021 }
1022 else
1023 {
1024 if (lp->flags & CHFL_CHANOP)
1025 buf[len++] = '@';
1026 }
1027 if (lp->flags & CHFL_VOICE)
1028 buf[len++] = '+';
1029 buf[len] = '\0';
1030 }
1031 (void)strcpy(buf + len, p);
1032 len += nlen;
1033 cnt++;
1034 }
1035 if (*buf && cnt)
1036 sendto_one(cptr, "%s", buf);
1037
1038 return;
1039}
1040
1041/*
1042 * m_mode
1043 * parv[0] - sender
1044 * parv[1] - target; channels and/or user
1045 * parv[2] - optional modes
1046 * parv[n] - optional parameters
1047 */
1048
1049int m_mode(aClient *cptr, aClient *sptr, int parc, char *parv[])
1050{
1051 int penalty = 0;
1052 aChannel *chptr;
1053 char *name, *p = NULL;
1054
1055 parv[1] = canonize(parv[1]);
1056
1057 for (name = strtoken(&p, parv[1], ","); name;
1058 name = strtoken(&p, NULL, ","))
1059 {
1060 if (clean_channelname(name) == -1)
1061 {
1062 penalty += 1;
1063 continue;
1064 }
1065 chptr = find_channel(name, NullChn);
1066 if (chptr == NullChn)
1067 {
1068 parv[1] = name;
1069 penalty += m_umode(cptr, sptr, parc, parv);
1070 continue;
1071 }
1072 if (check_channelmask(sptr, cptr, name))
1073 {
1074 penalty += 1;
1075 continue;
1076 }
1077 if (!UseModes(name))
1078 {
1079 sendto_one(sptr, replies[ERR_NOCHANMODES], ME, BadTo(parv[0]),
1080 name);
1081 penalty += 1;
1082 continue;
1083 }
1084 if (parc < 3) /* Only a query */
1085 {
1086 *modebuf = *parabuf = '\0';
1087 modebuf[1] = '\0';
1088 channel_modes(sptr, modebuf, parabuf, chptr);
1089 sendto_one(sptr, replies[RPL_CHANNELMODEIS], ME, BadTo(parv[0]),
1090 chptr->chname, modebuf, parabuf);
1091 penalty += 1;
1092 }
1093 else /* Check parameters for the channel */
1094 {
1095 if(0==set_mode(cptr, sptr, chptr,
1096 &penalty, parc - 2, parv + 2))
1097 continue; /* no valid mode change */
1098 } /* else(parc>2) */
1099 } /* for (parv1) */
1100 return penalty;
1101}
1102
1103/*
1104 * Check and try to apply the channel modes passed in the parv array for
1105 * the client cptr to channel chptr.
1106 * Also sends it to everybody that should get it.
1107 */
1108static int set_mode(aClient *cptr, aClient *sptr, aChannel *chptr,
1109 int *penalty, int parc, char *parv[])
1110{
1111 static Link chops[MAXMODEPARAMS+3];
1112 static int flags[] = {
1113 MODE_PRIVATE, 'p', MODE_SECRET, 's',
1114 MODE_MODERATED, 'm', MODE_NOPRIVMSGS, 'n',
1115 MODE_TOPICLIMIT, 't', MODE_INVITEONLY, 'i',
1116 MODE_ANONYMOUS, 'a', MODE_REOP, 'r',
1117 0x0, 0x0 };
1118
1119 Reg Link *lp = NULL;
1120 Reg char *curr = parv[0], *cp = NULL, *ucp = NULL;
1121 Reg int *ip;
1122 u_int whatt = MODE_ADD;
1123 int limitset = 0, count = 0, chasing = 0;
1124 int nusers = 0, ischop, new, len, ulen, keychange = 0, opcnt = 0;
1125 int reopseen = 0;
1126 aClient *who;
1127 Mode *mode, oldm;
1128 Link *plp = NULL;
1129#if 0
1130 int compat = -1; /* to prevent mixing old/new modes */
1131#endif
1132 char *mbuf = modebuf, *pbuf = parabuf, *upbuf = uparabuf;
1133 int tmp_chfl = 0, tmp_rpl = 0, tmp_rpl2 = 0, tmp_mode = 0;
1134
1135 *mbuf = *pbuf = *upbuf = '\0';
1136 if (parc < 1)
1137 return 0;
1138
1139 mode = &(chptr->mode);
1140 bcopy((char *)mode, (char *)&oldm, sizeof(Mode));
1141 ischop = IsServer(sptr) || is_chan_op(sptr, chptr);
1142 new = mode->mode;
1143
1144 while (curr && *curr && count >= 0)
1145 {
1146#if 0
1147 if (compat == -1 && *curr != '-' && *curr != '+')
1148 {
1149 if (*curr == 'R')
1150 {
1151 compat = 1;
1152 }
1153 else
1154 {
1155 compat = 0;
1156 }
1157 }
1158#endif
1159 switch (*curr)
1160 {
1161 case '+':
1162 whatt = MODE_ADD;
1163 break;
1164 case '-':
1165 whatt = MODE_DEL;
1166 break;
1167 case 'O':
1168 if (parc > 0)
1169 {
1170 if (*chptr->chname == '!')
1171 {
1172 if (IsMember(sptr, chptr))
1173 {
1174 *penalty += 1;
1175 parc--;
1176 /* Feature: no other modes after this query */
1177 *(curr+1) = '\0';
1178 for (lp = chptr->members; lp; lp = lp->next)
1179 if (lp->flags & CHFL_UNIQOP)
1180 {
1181 sendto_one(sptr,
1182 replies[RPL_UNIQOPIS],
1183 ME, BadTo(sptr->name),
1184 chptr->chname,
1185 lp->value.cptr->name);
1186 break;
1187 }
1188 if (!lp)
1189 sendto_one(sptr,
1190 replies[ERR_NOSUCHNICK],
1191 ME, BadTo(sptr->name),
1192 chptr->chname);
1193 break;
1194 }
1195 else /* not IsMember() */
1196 {
1197 if (!IsServer(sptr))
1198 {
1199 sendto_one(sptr, replies[ERR_NOTONCHANNEL], ME, BadTo(sptr->name),
1200 chptr->chname);
1201 *(curr+1) = '\0';
1202 break;
1203 }
1204 }
1205 }
1206 else /* *chptr->chname != '!' */
1207 sendto_one(cptr, replies[ERR_UNKNOWNMODE],
1208 ME, BadTo(sptr->name), *curr, chptr->chname);
1209 *(curr+1) = '\0';
1210 break;
1211 }
1212 /*
1213 * is this really ever used ?
1214 * or do ^G & NJOIN do the trick?
1215 */
1216 if (*chptr->chname != '!' || whatt == MODE_DEL ||
1217 !IsServer(sptr))
1218 {
1219 *penalty += 1;
1220 --parc;
1221 parv++;
1222 break;
1223 }
1224 case 'o' :
1225 case 'v' :
1226 *penalty += 1;
1227 if (--parc <= 0)
1228 break;
1229 parv++;
1230 *parv = check_string(*parv);
1231 if (opcnt >= MAXMODEPARAMS)
1232#ifndef V29PlusOnly
1233 if (MyClient(sptr) || opcnt >= MAXMODEPARAMS + 1)
1234#endif
1235 break;
1236 if (!IsServer(sptr) && !IsMember(sptr, chptr))
1237 {
1238 sendto_one(sptr, replies[ERR_NOTONCHANNEL],
1239 ME, BadTo(sptr->name),
1240 chptr->chname);
1241 break;
1242 }
1243 /*
1244 * Check for nickname changes and try to follow these
1245 * to make sure the right client is affected by the
1246 * mode change.
1247 */
1248 if (!(IsServer(cptr) &&
1249 (who = find_uid(parv[0], NULL))) &&
1250 !(who = find_chasing(sptr, parv[0], &chasing)))
1251 break;
1252 if (!IsMember(who, chptr))
1253 {
1254 sendto_one(sptr, replies[ERR_USERNOTINCHANNEL],
1255 ME, BadTo(sptr->name),
1256 who->name, chptr->chname);
1257 break;
1258 }
1259 if (who == cptr && whatt == MODE_ADD && *curr == 'o')
1260 break;
1261
1262 if (whatt == MODE_ADD)
1263 {
1264 lp = &chops[opcnt++];
1265 lp->value.cptr = who;
1266 lp->flags = (*curr == 'O') ? MODE_UNIQOP:
1267 (*curr == 'o') ? MODE_CHANOP:
1268 MODE_VOICE;
1269 lp->flags |= MODE_ADD;
1270 if (chptr->reop && IsServer(sptr) && !IsBursting(sptr))
1271 {
1272 reopseen = 1;
1273 }
1274 }
1275 else if (whatt == MODE_DEL)
1276 {
1277 lp = &chops[opcnt++];
1278 lp->value.cptr = who;
1279 lp->flags = (*curr == 'o') ? MODE_CHANOP:
1280 MODE_VOICE;
1281 lp->flags |= MODE_DEL;
1282 }
1283 if (plp && plp->flags == lp->flags &&
1284 plp->value.cptr == lp->value.cptr)
1285 {
1286 opcnt--;
1287 break;
1288 }
1289 plp = lp;
1290 /*
1291 ** If this server noticed the nick change, the
1292 ** information must be propagated back upstream.
1293 ** This is a bit early, but at most this will generate
1294 ** just some extra messages if nick appeared more than
1295 ** once in the MODE message... --msa
1296 */
1297/* nobody can figure this part of the code anymore.. -kalt
1298 if (chasing && ischop)
1299 sendto_one(cptr, ":%s MODE %s %c%c %s",
1300 ME, chptr->chname,
1301 whatt == MODE_ADD ? '+' : '-',
1302 *curr, who->name);
1303*/
1304 count++;
1305 *penalty += 2;
1306 break;
1307 case 'k':
1308 *penalty += 1;
1309 if (--parc <= 0)
1310 break;
1311 parv++;
1312 /* check now so we eat the parameter if present */
1313 if (keychange)
1314 break;
1315 {
1316 Reg u_char *s;
1317
1318 for (s = (u_char *)*parv; *s; )
1319 {
1320 /* comma cannot be inside key --Beeth */
1321 if (*s == ',')
1322 *s = '.';
1323 if (*s > 0x7f)
1324 if (*s > 0xa0)
1325 *s++ &= 0x7f;
1326 else
1327 *s = '\0';
1328 else
1329 s++;
1330 }
1331 }
1332
1333 if (!**parv)
1334 break;
1335 *parv = check_string(*parv);
1336 if (opcnt >= MAXMODEPARAMS)
1337#ifndef V29PlusOnly
1338 if (MyClient(sptr) || opcnt >= MAXMODEPARAMS + 1)
1339#endif
1340 break;
1341 if (whatt == MODE_ADD)
1342 {
1343 /* stop key swapping during netjoin
1344 ** (prefer "highest" key) */
1345 if (IsServer(sptr) && IsBursting(sptr) &&
1346 *mode->key && strncmp(mode->key, *parv,
1347 (size_t) KEYLEN) >= 0)
1348 break;
1349 if (ischop)
1350 {
1351 if (**parv == ':')
1352 /* this won't propagate right*/
1353 break;
1354 lp = &chops[opcnt++];
1355 lp->value.cp = *parv;
1356 if (strlen(lp->value.cp) >
1357 (size_t) KEYLEN)
1358 lp->value.cp[KEYLEN] = '\0';
1359 lp->flags = MODE_KEY|MODE_ADD;
1360 keychange = 1;
1361 }
1362 }
1363 else if (whatt == MODE_DEL)
1364 {
1365 if (*mode->key && (ischop || IsServer(cptr)))
1366 {
1367 lp = &chops[opcnt++];
1368 lp->value.cp = *parv;
1369 lp->value.cp[0] = '*';
1370 lp->value.cp[1] = '\0';
1371 lp->flags = MODE_KEY|MODE_DEL;
1372 keychange = 1;
1373 }
1374 }
1375 count++;
1376 *penalty += 2;
1377 break;
1378 case 'b':
1379 case 'e':
1380 case 'I':
1381 case 'R':
1382 switch (*curr)
1383 {
1384 case 'b':
1385 tmp_chfl = CHFL_BAN;
1386 tmp_rpl = RPL_BANLIST;
1387 tmp_rpl2 = RPL_ENDOFBANLIST;
1388 tmp_mode = MODE_BAN;
1389 break;
1390 case 'e':
1391 tmp_chfl = CHFL_EXCEPTION;
1392 tmp_rpl = RPL_EXCEPTLIST;
1393 tmp_rpl2 = RPL_ENDOFEXCEPTLIST;
1394 tmp_mode = MODE_EXCEPTION;
1395 break;
1396 case 'I':
1397 tmp_chfl = CHFL_INVITE;
1398 tmp_rpl = RPL_INVITELIST;
1399 tmp_rpl2 = RPL_ENDOFINVITELIST;
1400 tmp_mode = MODE_INVITE;
1401 break;
1402 case 'R':
1403 tmp_chfl = CHFL_REOPLIST;
1404 tmp_rpl = RPL_REOPLIST;
1405 tmp_rpl2 = RPL_ENDOFREOPLIST;
1406 tmp_mode = MODE_REOPLIST;
1407 break;
1408 }
1409 *penalty += 1;
1410 if (--parc <= 0) /* beIR list query */
1411 {
1412 /* Feature: no other modes after query */
1413 *(curr+1) = '\0'; /* Stop MODE # bb.. */
1414 for (lp = chptr->mlist; lp; lp = lp->next)
1415 {
1416 if (lp->flags == tmp_chfl)
1417 {
1418 sendto_one(cptr,
1419 replies[tmp_rpl],
1420 ME, BadTo(cptr->name),
1421 chptr->chname,
1422 lp->value.alist->nick,
1423 lp->value.alist->user,
1424 lp->value.alist->host);
1425 }
1426 }
1427 sendto_one(cptr, replies[tmp_rpl2],
1428 ME, BadTo(cptr->name),
1429 chptr->chname);
1430 break;
1431 }
1432 parv++;
1433 if (BadPtr(*parv))
1434 break;
1435 if (opcnt >= MAXMODEPARAMS)
1436#ifndef V29PlusOnly
1437 if (MyClient(sptr) || opcnt >= MAXMODEPARAMS + 1)
1438#endif
1439 break;
1440 if (whatt == MODE_ADD)
1441 {
1442 if (**parv == ':')
1443 /* this won't propagate right */
1444 break;
1445 lp = &chops[opcnt++];
1446 /* we deal with it later at parseNUH */
1447 lp->value.cp = *parv;
1448 lp->flags = MODE_ADD|tmp_mode;
1449 }
1450 else if (whatt == MODE_DEL)
1451 {
1452 lp = &chops[opcnt++];
1453 lp->value.cp = *parv;
1454 lp->flags = MODE_DEL|tmp_mode;
1455 }
1456 count++;
1457 *penalty += 2;
1458 break;
1459 case 'l':
1460 *penalty += 1;
1461 /*
1462 * limit 'l' to only *1* change per mode command but
1463 * eat up others.
1464 */
1465 if (limitset || !ischop)
1466 {
1467 if (whatt == MODE_ADD && --parc > 0)
1468 parv++;
1469 break;
1470 }
1471 if (whatt == MODE_DEL)
1472 {
1473 limitset = 1;
1474 nusers = 0;
1475 count++;
1476 break;
1477 }
1478 if (--parc > 0)
1479 {
1480 if (BadPtr(*parv))
1481 break;
1482 if (opcnt >= MAXMODEPARAMS)
1483#ifndef V29PlusOnly
1484 if (MyClient(sptr) ||
1485 opcnt >= MAXMODEPARAMS + 1)
1486#endif
1487 break;
1488 if (!(nusers = atoi(*++parv)))
1489 break;
1490 if (IsServer(sptr) && IsBursting(sptr) &&
1491 mode->limit >= nusers)
1492 break;
1493 lp = &chops[opcnt++];
1494 lp->flags = MODE_ADD|MODE_LIMIT;
1495 limitset = 1;
1496 count++;
1497 *penalty += 2;
1498 break;
1499 }
1500 sendto_one(cptr, replies[ERR_NEEDMOREPARAMS],
1501 ME, BadTo(cptr->name), "MODE +l");
1502 break;
1503 case 'i' : /* falls through for default case */
1504 if (whatt == MODE_DEL && ischop)
1505 while ((lp = chptr->invites))
1506 del_invite(lp->value.cptr, chptr);
1507 default:
1508 *penalty += 1;
1509 for (ip = flags; *ip; ip += 2)
1510 if (*(ip+1) == *curr)
1511 break;
1512
1513 if (*ip)
1514 {
1515 if (*ip == MODE_ANONYMOUS &&
1516 whatt == MODE_DEL && *chptr->chname == '!')
1517 sendto_one(sptr,
1518 replies[ERR_UNIQOPRIVSNEEDED],
1519 ME, BadTo(sptr->name), chptr->chname);
1520 else if (((*ip == MODE_ANONYMOUS &&
1521 whatt == MODE_ADD &&
1522 *chptr->chname == '#') ||
1523 (*ip == MODE_REOP && whatt == MODE_ADD &&
1524 *chptr->chname != '!')) &&
1525 !IsServer(sptr))
1526 sendto_one(cptr,
1527 replies[ERR_UNKNOWNMODE],
1528 ME, BadTo(sptr->name), *curr,
1529 chptr->chname);
1530 else if (*ip == MODE_ANONYMOUS && whatt == MODE_ADD &&
1531 !IsServer(sptr) &&
1532 !(is_chan_op(sptr,chptr) &CHFL_UNIQOP)
1533 && *chptr->chname == '!')
1534 /* 2 modes restricted to UNIQOP */
1535 sendto_one(sptr,
1536 replies[ERR_UNIQOPRIVSNEEDED],
1537 ME, BadTo(sptr->name), chptr->chname);
1538 else
1539 {
1540 /*
1541 ** If the channel is +s, ignore +p
1542 ** modes coming from a server.
1543 ** (Otherwise, it's desynch'ed) -kalt
1544 */
1545 if (whatt == MODE_ADD &&
1546 *ip == MODE_PRIVATE &&
1547 IsServer(sptr) &&
1548 (new & MODE_SECRET))
1549 break;
1550 if (whatt == MODE_ADD)
1551 {
1552 if (*ip == MODE_PRIVATE)
1553 new &= ~MODE_SECRET;
1554 else if (*ip == MODE_SECRET)
1555 new &= ~MODE_PRIVATE;
1556 new |= *ip;
1557 }
1558 else
1559 new &= ~*ip;
1560 count++;
1561 *penalty += 2;
1562 }
1563 }
1564 else if (!IsServer(cptr))
1565 sendto_one(cptr, replies[ERR_UNKNOWNMODE],
1566 ME, BadTo(cptr->name), *curr, chptr->chname);
1567 break;
1568 }
1569 curr++;
1570 /*
1571 * Make sure modes strings such as "+m +t +p +i" are parsed
1572 * fully.
1573 */
1574 if (!*curr && parc > 0)
1575 {
1576 curr = *++parv;
1577 parc--;
1578 }
1579#if 0
1580 /*
1581 * Make sure new (+R) mode won't get mixed with old modes
1582 * together on the same line.
1583 */
1584 if (MyClient(sptr) && curr && *curr != '-' && *curr != '+')
1585 {
1586 if (*curr == 'R')
1587 {
1588 if (compat == 0)
1589 {
1590 *curr = '\0';
1591 }
1592 }
1593 else if (compat == 1)
1594 {
1595 *curr = '\0';
1596 }
1597 }
1598#endif
1599 } /* end of while loop for MODE processing */
1600
1601 if (reopseen)
1602 {
1603 ircstp->is_rreop++;
1604 }
1605
1606 whatt = 0;
1607
1608 for (ip = flags; *ip; ip += 2)
1609 if ((*ip & new) && !(*ip & oldm.mode))
1610 {
1611 if (whatt == 0)
1612 {
1613 *mbuf++ = '+';
1614 whatt = 1;
1615 }
1616 if (ischop)
1617 {
1618 mode->mode |= *ip;
1619 if (*ip == MODE_ANONYMOUS && MyPerson(sptr))
1620 {
1621 sendto_channel_butone(NULL, &me, chptr, ":%s NOTICE %s :The anonymous flag is being set on channel %s.", ME, chptr->chname, chptr->chname);
1622 sendto_channel_butone(NULL, &me, chptr, ":%s NOTICE %s :Be aware that anonymity on IRC is NOT securely enforced!", ME, chptr->chname);
1623 }
1624 }
1625 /* +r coming from server must trigger reop. If not
1626 ** needed, it will be reset to 0 elsewhere, --B. */
1627 if (*ip == MODE_REOP && IsServer(sptr))
1628 {
1629 chptr->reop = timeofday + LDELAYCHASETIMELIMIT;
1630 }
1631 *mbuf++ = *(ip+1);
1632 }
1633
1634 for (ip = flags; *ip; ip += 2)
1635 if ((*ip & oldm.mode) && !(*ip & new))
1636 {
1637 if (whatt != -1)
1638 {
1639 *mbuf++ = '-';
1640 whatt = -1;
1641 }
1642 if (ischop)
1643 mode->mode &= ~*ip;
1644 *mbuf++ = *(ip+1);
1645 }
1646
1647 if (limitset && !nusers && mode->limit)
1648 {
1649 if (whatt != -1)
1650 {
1651 *mbuf++ = '-';
1652 whatt = -1;
1653 }
1654 mode->mode &= ~MODE_LIMIT;
1655 mode->limit = 0;
1656 *mbuf++ = 'l';
1657 }
1658
1659 /*
1660 * Reconstruct "+beIRkOov" chain.
1661 */
1662 if (opcnt)
1663 {
1664 Reg int i = 0;
1665 Reg char c = '\0';
1666 char *user, *host, numeric[16];
1667 int tmplen;
1668
1669/* if (opcnt > MAXMODEPARAMS)
1670 opcnt = MAXMODEPARAMS;
1671*/
1672 for (; i < opcnt; i++)
1673 {
1674 lp = &chops[i];
1675 /*
1676 * make sure we have correct mode change sign
1677 */
1678 if (whatt != (lp->flags & (MODE_ADD|MODE_DEL)))
1679 {
1680 if (lp->flags & MODE_ADD)
1681 {
1682 *mbuf++ = '+';
1683 whatt = MODE_ADD;
1684 }
1685 else
1686 {
1687 *mbuf++ = '-';
1688 whatt = MODE_DEL;
1689 }
1690 }
1691 len = strlen(pbuf);
1692 ulen = strlen(upbuf);
1693 /*
1694 * get c as the mode char and tmp as a pointer to
1695 * the paramter for this mode change.
1696 */
1697 switch(lp->flags & MODE_WPARAS)
1698 {
1699 case MODE_CHANOP :
1700 c = 'o';
1701 cp = lp->value.cptr->name;
1702 ucp = lp->value.cptr->user ?
1703 lp->value.cptr->user->uid : cp;
1704 break;
1705 case MODE_UNIQOP :
1706 c = 'O';
1707 cp = lp->value.cptr->name;
1708 ucp = lp->value.cptr->user ?
1709 lp->value.cptr->user->uid : cp;
1710 break;
1711 case MODE_VOICE :
1712 c = 'v';
1713 cp = lp->value.cptr->name;
1714 ucp = lp->value.cptr->user ?
1715 lp->value.cptr->user->uid : cp;
1716 break;
1717 case MODE_BAN :
1718 case MODE_EXCEPTION :
1719 case MODE_INVITE :
1720 case MODE_REOPLIST :
1721 switch(lp->flags & MODE_WPARAS)
1722 {
1723 case MODE_BAN :
1724 c = 'b'; break;
1725 case MODE_EXCEPTION :
1726 c = 'e'; break;
1727 case MODE_INVITE :
1728 c = 'I'; break;
1729 case MODE_REOPLIST :
1730 c = 'R'; break;
1731 }
1732 /* parseNUH: */
1733 cp = lp->value.cp;
1734 if ((user = index(cp, '!')))
1735 *user++ = '\0';
1736 if ((host = rindex(user ? user : cp, '@')))
1737 *host++ = '\0';
1738 lp->value.alist = make_bei(cp, user, host);
1739 if (user)
1740 user[-1] = '!';
1741 if (host)
1742 host[-1] = '@';
1743 break;
1744 case MODE_KEY :
1745 c = 'k';
1746 cp = lp->value.cp;
1747 break;
1748 case MODE_LIMIT :
1749 c = 'l';
1750 (void)sprintf(numeric, "%-15d", nusers);
1751 if ((cp = index(numeric, ' ')))
1752 *cp = '\0';
1753 cp = numeric;
1754 break;
1755 }
1756
1757 switch(lp->flags & MODE_WPARAS)
1758 {
1759 case MODE_BAN :
1760 case MODE_EXCEPTION :
1761 case MODE_INVITE :
1762 case MODE_REOPLIST :
1763 tmplen = BanLen(lp->value.alist) + 2 /* !@ */;
1764 if (len + tmplen + 2 > (size_t) MODEBUFLEN)
1765 {
1766 free_bei(lp->value.alist);
1767 tmplen = -1;
1768 }
1769 break;
1770 default:
1771 tmplen = strlen(cp);
1772 if (len + tmplen + 2 > (size_t) MODEBUFLEN)
1773 {
1774 tmplen = -1;
1775 }
1776 }
1777
1778 if (tmplen == -1)
1779 break;
1780 /*
1781 * pass on +/-o/v regardless of whether they are
1782 * redundant or effective but check +b's to see if
1783 * it existed before we created it.
1784 */
1785 switch(lp->flags & MODE_WPARAS)
1786 {
1787 case MODE_KEY :
1788 if (IsServer(sptr) &&
1789 !strncmp(mode->key, cp, (size_t) KEYLEN))
1790 break;
1791 *mbuf++ = c;
1792 (void)strcat(pbuf, cp);
1793 (void)strcat(upbuf, cp);
1794 len += strlen(cp);
1795 ulen += strlen(cp);
1796 (void)strcat(pbuf, " ");
1797 (void)strcat(upbuf, " ");
1798 len++;
1799 ulen++;
1800 if (!ischop)
1801 break;
1802 if (strlen(cp) > (size_t) KEYLEN)
1803 *(cp+KEYLEN) = '\0';
1804 if (whatt == MODE_ADD)
1805 strncpyzt(mode->key, cp,
1806 sizeof(mode->key));
1807 else
1808 *mode->key = '\0';
1809 break;
1810 case MODE_LIMIT :
1811 if (IsServer(sptr) && mode->limit == nusers)
1812 break;
1813 *mbuf++ = c;
1814 (void)strcat(pbuf, cp);
1815 (void)strcat(upbuf, cp);
1816 len += strlen(cp);
1817 ulen += strlen(cp);
1818 (void)strcat(pbuf, " ");
1819 (void)strcat(upbuf, " ");
1820 len++;
1821 ulen++;
1822 if (!ischop)
1823 break;
1824 mode->limit = nusers;
1825 break;
1826 case MODE_CHANOP : /* fall through case */
1827 if (ischop && lp->value.cptr == sptr &&
1828 lp->flags == (MODE_CHANOP|MODE_DEL))
1829 {
1830 chptr->reop = timeofday +
1831 LDELAYCHASETIMELIMIT +
1832 myrand() % 300;
1833 }
1834 case MODE_UNIQOP :
1835 case MODE_VOICE :
1836 *mbuf++ = c;
1837 (void)strcat(pbuf, cp);
1838 (void)strcat(upbuf, ucp);
1839 len += strlen(cp);
1840 ulen += strlen(ucp);
1841 (void)strcat(pbuf, " ");
1842 (void)strcat(upbuf, " ");
1843 len++;
1844 ulen++;
1845 if (ischop)
1846 change_chan_flag(lp, chptr);
1847 break;
1848 case MODE_BAN :
1849 case MODE_EXCEPTION :
1850 case MODE_INVITE :
1851 case MODE_REOPLIST :
1852 switch(lp->flags & MODE_WPARAS)
1853 {
1854 case MODE_BAN :
1855 tmp_chfl = CHFL_BAN; break;
1856 case MODE_EXCEPTION :
1857 tmp_chfl = CHFL_EXCEPTION; break;
1858 case MODE_INVITE :
1859 tmp_chfl = CHFL_INVITE; break;
1860 case MODE_REOPLIST :
1861 tmp_chfl = CHFL_REOPLIST; break;
1862 }
1863 if (tmp_chfl == CHFL_REOPLIST &&
1864 (whatt & MODE_ADD))
1865 {
1866 /* Just restarted servers will not have
1867 ** chanops leaving, so no other way to
1868 ** set ->reop. As we prefer not to op
1869 ** remote clients, set this here, upon
1870 ** each +R from remote server, so that
1871 ** reop_channel has a chance to work.
1872 ** It's mostly harmless, as chptr->reop
1873 ** will be reset to 0 in is_chan_op()
1874 ** and even if not, reop_channel() will
1875 ** NOT give ops if ops are already on
1876 ** the channel. --B. */
1877 if (IsServer(sptr))
1878 {
1879 chptr->reop = timeofday +
1880 LDELAYCHASETIMELIMIT +
1881 myrand() % 300;
1882 }
1883 }
1884 if (ischop &&
1885 (((whatt & MODE_ADD) &&
1886 !add_modeid(tmp_chfl, sptr, chptr,
1887 lp->value.alist))||
1888 ((whatt & MODE_DEL) &&
1889 !del_modeid(tmp_chfl, chptr,
1890 lp->value.alist))))
1891 {
1892 char nuh[NICKLEN+USERLEN+HOSTLEN+3];
1893
1894 /* I could strcat on u/pbuf directly,
1895 ** but this looks nicer. Note that alist
1896 ** values were already cleaned. --B. */
1897 tmplen = sprintf(nuh, "%s!%s@%s",
1898 lp->value.alist->nick,
1899 lp->value.alist->user,
1900 lp->value.alist->host);
1901 *mbuf++ = c;
1902 (void)strcat(pbuf, nuh);
1903 (void)strcat(upbuf, nuh);
1904 len += tmplen;
1905 ulen += tmplen;
1906 (void)strcat(pbuf, " ");
1907 (void)strcat(upbuf, " ");
1908 len++;
1909 ulen++;
1910 if ((whatt & MODE_DEL))
1911 free_bei(lp->value.alist);
1912 }
1913 else
1914 {
1915 /* We have to free lp->value.alist
1916 ** allocated by make_bei, otherwise
1917 ** it is memleak. del_modeid always
1918 ** succeeds, so it is freed above.
1919 ** If add_modeid succeeds, it uses
1920 ** pointer, if not, we free it here.
1921 ** This also covers all other cases,
1922 ** like !ischop. --B. */
1923 free_bei(lp->value.alist);
1924 }
1925 break;
1926 }
1927 } /* for (; i < opcnt; i++) */
1928 } /* if (opcnt) */
1929
1930 *mbuf = '\0';
1931 mbuf = modebuf;
1932
1933 if ((!ischop) && (count) && MyConnect(sptr) && !IsServer(sptr))
1934 {
1935 /* rejected mode change */
1936 int num = ERR_CHANOPRIVSNEEDED;
1937
1938 if (IsClient(sptr) && IsRestricted(sptr))
1939 {
1940 num = ERR_RESTRICTED;
1941 }
1942 sendto_one(sptr, replies[num], ME, sptr->name, chptr->chname);
1943 return -count;
1944 }
1945
1946 /* Send the mode changes out. */
1947 if (strlen(modebuf) > 1)
1948 {
1949 char *s; /* Sender for messages to 2.11s. */
1950
1951 if (IsServer(sptr))
1952 {
1953 s = sptr->serv->sid;
1954 }
1955 else if (sptr->user)
1956 {
1957 s = sptr->user->uid;
1958 }
1959 else
1960 {
1961 s = sptr->name;
1962 }
1963
1964 sendto_match_servs_v(chptr, cptr, SV_UID,
1965 ":%s MODE %s %s %s", s, chptr->chname, mbuf, upbuf);
1966
1967 if ((IsServer(cptr) && !IsServer(sptr) && !ischop))
1968 {
1969 sendto_flag(SCH_CHAN, "Fake: %s MODE %s %s %s",
1970 sptr->name, chptr->chname, mbuf, pbuf);
1971 ircstp->is_fake++;
1972 }
1973 else
1974 {
1975 sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s %s",
1976 sptr->name, chptr->chname, mbuf, pbuf);
1977#ifdef USE_SERVICES
1978 *modebuf = *parabuf = '\0';
1979 modebuf[1] = '\0';
1980 channel_modes(&me, modebuf, parabuf, chptr);
1981 check_services_butone(SERVICE_WANT_MODE, NULL, sptr,
1982 "MODE %s %s", chptr->chname, modebuf);
1983#endif
1984 }
1985 }
1986
1987 return ischop ? count : -count;
1988}
1989
1990static int can_join(aClient *sptr, aChannel *chptr, char *key)
1991{
1992 invLink *lp = NULL;
1993 Link *banned;
1994 int limit = 0;
1995
1996 if (chptr->users == 0 && (bootopt & BOOT_PROT) &&
1997 chptr->history != 0 && *chptr->chname != '!')
1998 return (timeofday > chptr->history) ? 0 : ERR_UNAVAILRESOURCE;
1999
2000#ifdef CLIENTS_CHANNEL
2001 if (*chptr->chname == '&' && !strcmp(chptr->chname, "&CLIENTS")
2002 && is_allowed(sptr, ACL_CLIENTS))
2003 return 0;
2004#endif
2005 if (*chptr->chname == '&' && !strcmp(chptr->chname, "&OPER")
2006 && IsAnOper(sptr))
2007 return 0;
2008
2009 for (lp = sptr->user->invited; lp; lp = lp->next)
2010 if (lp->chptr == chptr)
2011 break;
2012
2013 if ((banned = match_modeid(CHFL_BAN, sptr, chptr)))
2014 {
2015 if (match_modeid(CHFL_EXCEPTION, sptr, chptr))
2016 {
2017 banned = NULL;
2018 }
2019 else if (lp == NULL) /* not invited */
2020 {
2021 return (ERR_BANNEDFROMCHAN);
2022 }
2023 }
2024
2025 if ((chptr->mode.mode & MODE_INVITEONLY)
2026 && !match_modeid(CHFL_INVITE, sptr, chptr)
2027 && (lp == NULL))
2028 return (ERR_INVITEONLYCHAN);
2029
2030 if (*chptr->mode.key && (BadPtr(key) || mycmp(chptr->mode.key, key)))
2031 return (ERR_BADCHANNELKEY);
2032
2033 if (chptr->mode.limit && (chptr->users >= chptr->mode.limit))
2034 {
2035 /* ->reop is set when there are no chanops on the channel,
2036 ** so we allow people matching +R to join no matter limit,
2037 ** so they can get reopped --B. */
2038 if (chptr->reop > 0 && match_modeid(CHFL_REOPLIST, sptr, chptr))
2039 return 0;
2040 if (lp == NULL)
2041 return (ERR_CHANNELISFULL);
2042 else
2043 limit = 1;
2044 }
2045
2046 if (banned)
2047 {
2048 sendto_channel_butone(&me, &me, chptr,
2049 ":%s NOTICE %s :%s carries an invitation from %s"
2050 " (overriding%s ban on %s!%s@%s).",
2051 ME, chptr->chname, sptr->name, lp->who,
2052 limit ? " channel limit and" : "",
2053 banned->value.alist->nick,
2054 banned->value.alist->user,
2055 banned->value.alist->host);
2056 }
2057 else if (limit)
2058 {
2059 sendto_channel_butone(&me, &me, chptr,
2060 ":%s NOTICE %s :%s carries an invitation from %s"
2061 " (overriding channel limit).", ME, chptr->chname,
2062 sptr->name, lp->who);
2063 }
2064 return 0;
2065}
2066
2067/*
2068** Remove bells and commas from channel name
2069*/
2070
2071int clean_channelname(char *cn)
2072{
2073 int flag = 0;
2074
2075 while (*cn)
2076 {
2077 if (*cn == '\007' || *cn == ' ' || (!flag && *cn == ','))
2078 {
2079 *cn = '\0';
2080 return 0;
2081 }
2082#ifdef JAPANESE
2083 /* Japanese channel names can have comma in their name, but
2084 ** only between "\033$B" (begin) and "\033(B" (end) markers.
2085 ** So we mark it (using flag) for above check. --Beeth */
2086 if (cn[0] == '\033'
2087 && (cn[1] == '$' || cn[1] == '(')
2088 && cn[2] == 'B')
2089 {
2090 flag = (cn[1] == '$') ? 1 : 0;
2091 cn += 2;
2092 }
2093#endif
2094 cn++;
2095 }
2096 /* If flag is 1 here, Japanese channel name is incomplete! */
2097 return flag;
2098}
2099
2100/*
2101** Return -1 if mask is present and doesnt match our server name.
2102*/
2103static int check_channelmask(aClient *sptr, aClient *cptr, char *chname)
2104{
2105 char *s;
2106
2107 if (*chname == '&' && IsServer(cptr))
2108 return -1;
2109 s = get_channelmask(chname);
2110 if (!s)
2111 return 0;
2112 s++;
2113 if (*s == '\0' /* ':' was last char, thus empty mask --B. */
2114 || match(s, ME) || (IsServer(cptr) && match(s, cptr->name)))
2115 {
2116 if (MyClient(sptr))
2117 sendto_one(sptr, replies[ERR_BADCHANMASK], ME,
2118 BadTo(sptr->name), chname);
2119 return -1;
2120 }
2121 return 0;
2122}
2123
2124/*
2125** Get Channel block for i (and allocate a new channel
2126** block, if it didn't exists before).
2127*/
2128static aChannel *get_channel(aClient *cptr, char *chname, int flag)
2129{
2130 Reg aChannel *chptr;
2131 int len;
2132
2133 if (BadPtr(chname))
2134 return NULL;
2135
2136 len = strlen(chname);
2137 if (MyClient(cptr) && len > CHANNELLEN)
2138 {
2139 len = CHANNELLEN;
2140 *(chname+CHANNELLEN) = '\0';
2141#ifdef JAPANESE
2142#if 0
2143 /* XXX-JP: I think I know why it is here, but it
2144 ** seems it is completely unneeded. */
2145 if (check_channelmask(cptr, cptr, chname) == -1)
2146 return NULL;
2147#endif
2148#endif
2149 }
2150 if ((chptr = find_channel(chname, (aChannel *)NULL)))
2151 return (chptr);
2152 if (flag == CREATE)
2153 {
2154 chptr = (aChannel *)MyMalloc(sizeof(aChannel) + len);
2155 bzero((char *)chptr, sizeof(aChannel));
2156 strncpyzt(chptr->chname, chname, len+1);
2157 if (channel)
2158 channel->prevch = chptr;
2159 chptr->prevch = NULL;
2160 chptr->nextch = channel;
2161 chptr->history = 0;
2162#ifdef JAPANESE
2163 chptr->flags = 0;
2164 if (jp_chname(chname))
2165 chptr->flags = FLAGS_JP;
2166#endif
2167 channel = chptr;
2168 (void)add_to_channel_hash_table(chname, chptr);
2169 }
2170 return chptr;
2171}
2172
2173/*
2174 * add_invite():
2175 * sptr: who invites
2176 * cptr who gets invitation
2177 * chptr what channel
2178 */
2179static void add_invite(aClient *sptr, aClient *cptr, aChannel *chptr)
2180{
2181
2182 /*
2183 assert(sptr!=NULL);
2184 assert(cptr!=NULL);
2185 assert(chptr!=NULL);
2186 */
2187
2188 del_invite(cptr, chptr);
2189
2190 /*
2191 * delete last link in chain if the list is max length
2192 */
2193 if (list_length(cptr->user->invited) >= MAXCHANNELSPERUSER)
2194 {
2195 del_invite(cptr, cptr->user->invited->chptr);
2196 }
2197
2198 /*
2199 * add client to channel invite list
2200 */
2201 {
2202 Reg Link *inv;
2203
2204 inv = make_link();
2205 inv->value.cptr = cptr;
2206 inv->next = chptr->invites;
2207 chptr->invites = inv;
2208 istat.is_useri++;
2209 }
2210 /*
2211 * add channel to the end of the client invite list
2212 */
2213 {
2214 Reg invLink *inv, **tmp;
2215 char who[NICKLEN+USERLEN+HOSTLEN+3];
2216 int len;
2217
2218 for (tmp = &(cptr->user->invited); *tmp; tmp = &((*tmp)->next))
2219 ;
2220 inv = make_invlink();
2221 (*tmp) = inv;
2222 inv->chptr = chptr;
2223 inv->next = NULL;
2224 len = sprintf(who, "%s!%s@%s", sptr->name,
2225 sptr->user->username, sptr->user->host);
2226 inv->who = (char *)MyMalloc(len + 1);
2227 istat.is_banmem += len;
2228 strcpy(inv->who, who);
2229 istat.is_invite++;
2230 }
2231}
2232
2233/*
2234 * Delete Invite block from channel invite list and client invite list
2235 */
2236void del_invite(aClient *cptr, aChannel *chptr)
2237{
2238 {
2239 Reg Link **inv, *tmp;
2240
2241 for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
2242 {
2243 if (tmp->value.cptr == cptr)
2244 {
2245 *inv = tmp->next;
2246 free_link(tmp);
2247 istat.is_invite--;
2248 break;
2249 }
2250 }
2251 }
2252 {
2253 Reg invLink **inv, *tmp;
2254
2255 for (inv = &(cptr->user->invited); (tmp = *inv); inv = &tmp->next)
2256 {
2257 if (tmp->chptr == chptr)
2258 {
2259 *inv = tmp->next;
2260 istat.is_banmem -= (strlen(tmp->who)+1);
2261 free(tmp->who);
2262 free_invlink(tmp);
2263 istat.is_useri--;
2264 break;
2265 }
2266 }
2267 }
2268}
2269
2270/*
2271** The last user has left the channel, free data in the channel block,
2272** and eventually the channel block itself.
2273*/
2274static void free_channel(aChannel *chptr)
2275{
2276 Reg Link *tmp;
2277 Link *obtmp;
2278 int len = sizeof(aChannel) + strlen(chptr->chname), now = 0;
2279
2280 if (chptr->history == 0 || timeofday >= chptr->history)
2281 /* no lock, nor expired lock, channel is no more, free it */
2282 now = 1;
2283
2284 if (*chptr->chname != '!' || now)
2285 {
2286 while ((tmp = chptr->invites))
2287 del_invite(tmp->value.cptr, chptr);
2288
2289 tmp = chptr->mlist;
2290 while (tmp)
2291 {
2292 obtmp = tmp;
2293 tmp = tmp->next;
2294 istat.is_banmem -= BanLen(obtmp->value.alist);
2295 istat.is_bans--;
2296 free_bei(obtmp->value.alist);
2297 free_link(obtmp);
2298 }
2299 chptr->mlist = NULL;
2300 }
2301
2302 if (now)
2303 {
2304 istat.is_hchan--;
2305 istat.is_hchanmem -= len;
2306 if (chptr->prevch)
2307 chptr->prevch->nextch = chptr->nextch;
2308 else
2309 channel = chptr->nextch;
2310 if (chptr->nextch)
2311 chptr->nextch->prevch = chptr->prevch;
2312 del_from_channel_hash_table(chptr->chname, chptr);
2313
2314 if (*chptr->chname == '!' && close_chid(chptr->chname+1))
2315 cache_chid(chptr);
2316 else
2317 MyFree(chptr);
2318 }
2319}
2320
2321/*
2322** m_join
2323** parv[0] = sender prefix
2324** parv[1] = channel
2325** parv[2] = channel password (key)
2326*/
2327int m_join(aClient *cptr, aClient *sptr, int parc, char *parv[])
2328{
2329 static char jbuf[BUFSIZE];
2330 Reg Link *lp;
2331 Reg aChannel *chptr;
2332 Reg char *name, *key = NULL;
2333 int i, tmplen, flags = 0;
2334 char *p = NULL, *p2 = NULL;
2335
2336 /* This is the only case we get JOIN over s2s link. --B. */
2337 /* It could even be its own command. */
2338 if (IsServer(cptr))
2339 {
2340 if (parv[1][0] == '0' && parv[1][1] == '\0')
2341 {
2342 if (sptr->user->channel == NULL)
2343 return 0;
2344 while ((lp = sptr->user->channel))
2345 {
2346 chptr = lp->value.chptr;
2347 sendto_channel_butserv(chptr, sptr,
2348 PartFmt,
2349 parv[0], chptr->chname,
2350 key ? key : "");
2351 remove_user_from_channel(sptr, chptr);
2352 }
2353 sendto_match_servs(NULL, cptr, ":%s JOIN 0 :%s",
2354 sptr->user->uid, key ? key : parv[0]);
2355 }
2356 else
2357 {
2358 /* Well, technically this is an error.
2359 ** Let's ignore it for now. --B. */
2360 }
2361 return 0;
2362 }
2363 /* These should really be assert()s. */
2364 if (!sptr || !sptr->user)
2365 return 0;
2366
2367 *jbuf = '\0';
2368 /*
2369 ** Rebuild list of channels joined to be the actual result of the
2370 ** JOIN. Note that "JOIN 0" is the destructive problem.
2371 ** Also note that this can easily trash the correspondance between
2372 ** parv[1] and parv[2] lists.
2373 */
2374 for (i = 0, name = strtoken(&p, parv[1], ","); name;
2375 name = strtoken(&p, NULL, ","))
2376 {
2377 if (check_channelmask(sptr, cptr, name)==-1)
2378 continue;
2379 if (*name == '0' && !atoi(name))
2380 {
2381 (void)strcpy(jbuf, "0");
2382 i = 1;
2383 continue;
2384 }
2385 if (clean_channelname(name) == -1)
2386 {
2387 sendto_one(sptr, replies[ERR_NOSUCHCHANNEL],
2388 ME, BadTo(parv[0]), name);
2389 continue;
2390 }
2391 if (*name == '!')
2392 {
2393 chptr = NULL;
2394 /*
2395 ** !channels are special:
2396 ** !!channel is supposed to be a new channel,
2397 ** and requires a unique name to be built.
2398 ** ( !#channel is obsolete )
2399 ** !channel cannot be created, and must already
2400 ** exist.
2401 */
2402 if (*(name+1) == '\0' ||
2403 (*(name+1) == '#' && *(name+2) == '\0') ||
2404 (*(name+1) == '!' && *(name+2) == '\0'))
2405 {
2406 sendto_one(sptr, replies[ERR_NOSUCHCHANNEL],
2407 ME, BadTo(parv[0]), name);
2408 continue;
2409 }
2410 if (*name == '!' && (*(name+1) == '#' ||
2411 *(name+1) == '!'))
2412 {
2413 chptr = hash_find_channels(name+2, NULL);
2414 if (chptr)
2415 {
2416 sendto_one(sptr,
2417 replies[ERR_TOOMANYTARGETS],
2418 ME, BadTo(parv[0]),
2419 "Duplicate", name,
2420 "Join aborted.");
2421 continue;
2422 }
2423 if (check_chid(name+2))
2424 {
2425 /*
2426 * This is a bit wrong: if a channel
2427 * rightfully ceases to exist, it
2428 * can still be *locked* for up to
2429 * 2*CHIDNB^3 seconds (~24h)
2430 * Is it a reasonnable price to pay to
2431 * ensure shortname uniqueness? -kalt
2432 */
2433 sendto_one(sptr, replies[ERR_UNAVAILRESOURCE],
2434 ME, BadTo(parv[0]), name);
2435 continue;
2436 }
2437 sprintf(buf, "!%.*s%s", CHIDLEN, get_chid(),
2438 name+2);
2439 name = buf;
2440 }
2441 else if (!find_channel(name, NullChn) &&
2442 !(*name == '!' && *name != 0 &&
2443 (chptr = hash_find_channels(name+1, NULL))))
2444 {
2445 sendto_one(sptr, replies[ERR_NOSUCHCHANNEL],
2446 ME, BadTo(parv[0]), name);
2447 continue;
2448 }
2449 else if (chptr)
2450 {
2451 /* joining a !channel using the short name */
2452 if (hash_find_channels(name+1, chptr))
2453 {
2454 sendto_one(sptr,
2455 replies[ERR_TOOMANYTARGETS],
2456 ME, BadTo(parv[0]),
2457 "Duplicate", name,
2458 "Join aborted.");
2459 continue;
2460 }
2461 name = chptr->chname;
2462 }
2463 }
2464 if (!IsChannelName(name) ||
2465 (*name == '+' && (*(name+1) == '#' || *(name+1) == '!')) ||
2466 (*name == '!' && IsChannelName(name+1)))
2467 {
2468 sendto_one(sptr, replies[ERR_NOSUCHCHANNEL],
2469 ME, BadTo(parv[0]), name);
2470 continue;
2471 }
2472 tmplen = strlen(name);
2473 if (i + tmplen + 2 /* comma and \0 */
2474 >= sizeof(jbuf) )
2475 {
2476 break;
2477 }
2478 if (*jbuf)
2479 {
2480 jbuf[i++] = ',';
2481 }
2482 (void)strcpy(jbuf + i, name);
2483 i += tmplen;
2484 }
2485
2486 p = NULL;
2487 if (parv[2])
2488 key = strtoken(&p2, parv[2], ",");
2489 for (name = strtoken(&p, jbuf, ","); name;
2490 key = (key) ? strtoken(&p2, NULL, ",") : NULL,
2491 name = strtoken(&p, NULL, ","))
2492 {
2493 /*
2494 ** JOIN 0 sends out a part for all channels a user
2495 ** has joined.
2496 */
2497 if (*name == '0' && !atoi(name))
2498 {
2499 if (sptr->user->channel == NULL)
2500 continue;
2501 while ((lp = sptr->user->channel))
2502 {
2503 chptr = lp->value.chptr;
2504 sendto_channel_butserv(chptr, sptr,
2505 PartFmt,
2506 parv[0], chptr->chname,
2507 key ? key : "");
2508 remove_user_from_channel(sptr, chptr);
2509 }
2510 sendto_match_servs(NULL, cptr, ":%s JOIN 0 :%s",
2511 sptr->user->uid, key ? key : parv[0]);
2512 continue;
2513 }
2514
2515 /* Weren't those names just cleaned? --B. */
2516 if (clean_channelname(name) == -1)
2517 continue;
2518
2519 /* Get chptr for given name. Do not create channel yet.
2520 ** Can return NULL. */
2521 chptr = get_channel(sptr, name, !CREATE);
2522
2523 if (chptr && IsMember(sptr, chptr))
2524 {
2525 continue;
2526 }
2527
2528 if (MyConnect(sptr) && !(chptr && IsQuiet(chptr)) &&
2529 sptr->user->joined >= MAXCHANNELSPERUSER)
2530 {
2531 sendto_one(sptr, replies[ERR_TOOMANYCHANNELS],
2532 ME, BadTo(parv[0]), name);
2533 /* can't return, need to send the info everywhere */
2534 continue;
2535 }
2536
2537 if (!strncmp(name, "\x23\x1f\x02\xb6\x03\x34\x63\x68\x02\x1f",
2538 10))
2539 {
2540 sptr->exitc = EXITC_VIRUS;
2541 return exit_client(sptr, sptr, &me, "Virus Carrier");
2542 }
2543
2544 if (!chptr)
2545 {
2546 /* Oh well, create the channel. */
2547 chptr = get_channel(sptr, name, CREATE);
2548 }
2549
2550 if (!chptr)
2551 {
2552 /* Should NEVER happen. */
2553 sendto_flag(SCH_ERROR, "Could not create channel!");
2554 sendto_one(sptr, "%s *** %s :Could not create channel!",
2555 ME, BadTo(parv[0]));
2556 continue;
2557 }
2558
2559 if ((i = can_join(sptr, chptr, key)))
2560 {
2561 sendto_one(sptr, replies[i], ME, BadTo(parv[0]), name);
2562 continue;
2563 }
2564
2565 /*
2566 ** local client is first to enter previously nonexistant
2567 ** channel so make them (rightfully) the Channel
2568 ** Operator.
2569 */
2570 flags = 0;
2571 if (UseModes(name) &&
2572 (*name != '#' || !IsSplit()) &&
2573 (!IsRestricted(sptr) || (*name == '&')) && !chptr->users &&
2574 !(chptr->history && *chptr->chname == '!'))
2575 {
2576 if (*name == '!')
2577 flags |= CHFL_UNIQOP|CHFL_CHANOP;
2578 else
2579 flags |= CHFL_CHANOP;
2580 }
2581 /* Complete user entry to the new channel */
2582 add_user_to_channel(chptr, sptr, flags);
2583 /* Notify all users on the channel */
2584 sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s",
2585 parv[0], chptr->chname);
2586
2587 del_invite(sptr, chptr);
2588 if (chptr->topic[0] != '\0')
2589 {
2590 sendto_one(sptr, replies[RPL_TOPIC], ME,
2591 BadTo(parv[0]), chptr->chname, chptr->topic);
2592#ifdef TOPIC_WHO_TIME
2593 if (chptr->topic_t > 0)
2594 {
2595 sendto_one(sptr, replies[RPL_TOPIC_WHO_TIME],
2596 ME, BadTo(parv[0]),
2597 chptr->chname, IsAnonymous(chptr) ?
2598 "anonymous!anonymous@anonymous." :
2599 chptr->topic_nuh,
2600 chptr->topic_t);
2601 }
2602#endif
2603 }
2604
2605 names_channel(cptr, sptr, parv[0], chptr, 1);
2606 if (IsAnonymous(chptr) && !IsQuiet(chptr))
2607 {
2608 sendto_one(sptr, ":%s NOTICE %s :Channel %s has the anonymous flag set.", ME, chptr->chname, chptr->chname);
2609 sendto_one(sptr, ":%s NOTICE %s :Be aware that anonymity on IRC is NOT securely enforced!", ME, chptr->chname);
2610 }
2611 /*
2612 ** notify other servers
2613 */
2614 if (get_channelmask(name) || *chptr->chname == '!' /* compat */
2615#ifdef JAPANESE
2616 /* sendto_match_servs_v() is checking the same
2617 ** and NOT sending things out. --B. */
2618 || !jp_valid(NULL, chptr, NULL)
2619#endif
2620 )
2621 {
2622 sendto_match_servs_v(chptr, cptr, SV_UID,
2623 ":%s NJOIN %s :%s%s", me.serv->sid, name,
2624 flags & CHFL_UNIQOP ? "@@" :
2625 flags & CHFL_CHANOP ? "@" : "",
2626 sptr->user ? sptr->user->uid : parv[0]);
2627 }
2628 else if (*chptr->chname != '&')
2629 {
2630 sendto_serv_v(cptr, SV_UID, ":%s NJOIN %s :%s%s",
2631 me.serv->sid, name,
2632 flags & CHFL_UNIQOP ? "@@" :
2633 flags & CHFL_CHANOP ? "@" : "",
2634 sptr->user ? sptr->user->uid : parv[0]);
2635 }
2636 }
2637 return 2;
2638}
2639
2640/*
2641** m_njoin
2642** parv[0] = sender prefix
2643** parv[1] = channel
2644** parv[2] = channel members and modes
2645*/
2646int m_njoin(aClient *cptr, aClient *sptr, int parc, char *parv[])
2647{
2648 char *name, *target;
2649 char mbuf[3] /* "ov" */;
2650 char uidbuf[BUFSIZE], *u;
2651 char *p = NULL;
2652 int chop, cnt = 0;
2653 aChannel *chptr = NULL;
2654 aClient *acptr;
2655 int maxlen;
2656
2657 /* get channel pointer */
2658 if (!IsChannelName(parv[1]))
2659 {
2660 sendto_one(sptr, replies[ERR_NOSUCHCHANNEL],
2661 ME, BadTo(parv[0]), parv[1]);
2662 return 0;
2663 }
2664 if (check_channelmask(sptr, cptr, parv[1]) == -1)
2665 {
2666 sendto_flag(SCH_DEBUG, "received NJOIN for %s from %s",
2667 parv[1], get_client_name(cptr, TRUE));
2668 return 0;
2669 }
2670 /* Use '&me', because NJOIN is, unlike JOIN, always for
2671 ** remote clients, see get_channel() what's that for. --B. */
2672 chptr = get_channel(&me, parv[1], CREATE);
2673 /* assert(chptr != NULL); */
2674
2675 /* Hack for creating empty channels and locking them.
2676 ** This also allows for getting MODEs for such channels (otherwise
2677 ** they'd get ignored). We need that to prevent desynch, especially
2678 ** after we (re)started.
2679 ** This requires that single dot cannot be used as a name of
2680 ** remote clients that can join channels. --B. */
2681 if (parv[2][0] == '.' && parv[2][1] == '\0')
2682 {
2683 /* If we have clients on a channel, it cannot be
2684 ** locked, can it? --B. */
2685 if (chptr->users == 0 && chptr->history == 0)
2686 {
2687 chptr->history = timeofday + (*chptr->chname == '!' ?
2688 LDELAYCHASETIMELIMIT : DELAYCHASETIMELIMIT);
2689 istat.is_hchan++;
2690 istat.is_hchanmem += sizeof(aChannel) +
2691 strlen(chptr->chname);
2692 }
2693 /* There cannot be anything else in this NJOIN. */
2694 return 0;
2695 }
2696
2697 *uidbuf = '\0'; u = uidbuf;
2698 /* 17 comes from syntax ": NJOIN :,@@+\r\n\0" */
2699 maxlen = BUFSIZE - 17 - strlen(parv[0]) - strlen(parv[1]) - NICKLEN;
2700 for (target = strtoken(&p, parv[2], ","); target;
2701 target = strtoken(&p, NULL, ","))
2702 {
2703 /* check for modes */
2704 chop = 0;
2705 mbuf[0] = '\0';
2706 if (*target == '@')
2707 {
2708 if (*(target+1) == '@')
2709 {
2710 if (*(target+2) == '+')
2711 {
2712 strcpy(mbuf, "ov");
2713 chop = CHFL_UNIQOP| \
2714 CHFL_CHANOP|CHFL_VOICE;
2715 name = target + 3;
2716 }
2717 else
2718 {
2719 strcpy(mbuf, "o");
2720 chop = CHFL_UNIQOP|CHFL_CHANOP;
2721 name = target + 2;
2722 }
2723 }
2724 else
2725 {
2726 if (*(target+1) == '+')
2727 {
2728 strcpy(mbuf, "ov");
2729 chop = CHFL_CHANOP|CHFL_VOICE;
2730 name = target+2;
2731 }
2732 else
2733 {
2734 strcpy(mbuf, "o");
2735 chop = CHFL_CHANOP;
2736 name = target+1;
2737 }
2738 }
2739 }
2740 else if (*target == '+')
2741 {
2742 strcpy(mbuf, "v");
2743 chop = CHFL_VOICE;
2744 name = target+1;
2745 }
2746 else
2747 {
2748 name = target;
2749 }
2750 /* find user */
2751 if (!(acptr = find_person(name, NULL)) &&
2752 !(acptr = find_uid(name, NULL)))
2753 {
2754 /* shouldn't this be an error? --B. */
2755 continue;
2756 }
2757 /* is user who we think? */
2758 if (acptr->from != cptr)
2759 {
2760 /* shouldn't this be a squit-level error? --B. */
2761 continue;
2762 }
2763 /* make sure user isn't already on channel */
2764 if (IsMember(acptr, chptr))
2765 {
2766 if (IsBursting(sptr))
2767 {
2768 sendto_flag(SCH_ERROR, "NJOIN protocol error"
2769 " from %s (%s already on %s)",
2770 get_client_name(cptr, TRUE),
2771 acptr->name, chptr->chname);
2772 sendto_one(cptr, "ERROR :NJOIN protocol error"
2773 " (%s already on %s)",
2774 acptr->name, chptr->chname);
2775 }
2776 else
2777 {
2778 sendto_flag(SCH_CHAN, "Fake: %s JOIN %s",
2779 acptr->name, chptr->chname);
2780 }
2781 /* ignore such join anyway */
2782 continue;
2783 }
2784 /* add user to channel */
2785 add_user_to_channel(chptr, acptr, UseModes(parv[1]) ? chop :0);
2786
2787 /* build buffer for NJOIN and UID capable servers */
2788
2789 /* send it out if too big to fit buffer */
2790 if (u-uidbuf >= maxlen)
2791 {
2792 *u = '\0';
2793 sendto_match_servs_v(chptr, cptr, SV_UID,
2794 ":%s NJOIN %s :%s",
2795 sptr->serv->sid, parv[1], uidbuf);
2796 *uidbuf = '\0'; u = uidbuf;
2797 }
2798
2799 if (u != uidbuf)
2800 {
2801 *u++ = ',';
2802 }
2803
2804 /* Copy the modes. */
2805 for (; target < name; target++)
2806 {
2807 *u++ = *target;
2808 }
2809
2810 target = acptr->user ? acptr->user->uid : acptr->name;
2811 while (*target)
2812 {
2813 *u++ = *target++;
2814 }
2815
2816 /* send join to local users on channel */
2817 /* Little syntax trick. Put ":" before channel name if it is
2818 ** not burst, so clients can use it for discriminating normal
2819 ** join from netjoin. 2.10.x is using NJOIN only during
2820 ** burst, but 2.11 always. Hence we check for EOB from 2.11
2821 ** to know what kind of NJOIN it is. --B. */
2822 sendto_channel_butserv(chptr, acptr, ":%s JOIN %s%s", acptr->name, (
2823#ifdef JAPANESE
2824 /* XXX-JP: explain why jp-patch had that! */
2825 IsServer(sptr) ||
2826#endif
2827 IsBursting(sptr)) ? "" : ":", chptr->chname);
2828 /* build MODE for local users on channel, eventually send it */
2829 if (*mbuf)
2830 {
2831 if (!UseModes(parv[1]))
2832 {
2833 sendto_one(cptr, replies[ERR_NOCHANMODES],
2834 ME, BadTo(parv[0]), parv[1]);
2835 continue;
2836 }
2837 switch (cnt)
2838 {
2839 case 0:
2840 *parabuf = '\0'; *modebuf = '\0';
2841 /* fall through */
2842 case 1:
2843 strcat(modebuf, mbuf);
2844 cnt += strlen(mbuf);
2845 if (*parabuf)
2846 {
2847 strcat(parabuf, " ");
2848 }
2849 strcat(parabuf, acptr->name);
2850 if (mbuf[1])
2851 {
2852 strcat(parabuf, " ");
2853 strcat(parabuf, acptr->name);
2854 }
2855 break;
2856 case 2:
2857 sendto_channel_butserv(chptr, &me,
2858 ":%s MODE %s +%s%c %s %s",
2859 sptr->name, chptr->chname,
2860 modebuf, mbuf[0],
2861 parabuf, acptr->name);
2862 if (mbuf[1])
2863 {
2864 strcpy(modebuf, mbuf+1);
2865 strcpy(parabuf, acptr->name);
2866 cnt = 1;
2867 }
2868 else
2869 cnt = 0;
2870 break;
2871 }
2872 if (cnt == MAXMODEPARAMS)
2873 {
2874 sendto_channel_butserv(chptr, &me,
2875 ":%s MODE %s +%s %s",
2876 sptr->name, chptr->chname,
2877 modebuf, parabuf);
2878 cnt = 0;
2879 }
2880 }
2881 }
2882 /* send eventual MODE leftover */
2883 if (cnt)
2884 sendto_channel_butserv(chptr, &me, ":%s MODE %s +%s %s",
2885 sptr->name, chptr->chname, modebuf, parabuf);
2886
2887 /* send NJOIN */
2888 *u = '\0';
2889 if (uidbuf[0])
2890 {
2891 sendto_match_servs_v(chptr, cptr, SV_UID, ":%s NJOIN %s :%s",
2892 sptr->serv->sid, parv[1], uidbuf);
2893 }
2894
2895 return 0;
2896}
2897
2898/*
2899** m_part
2900** parv[0] = sender prefix
2901** parv[1] = channel
2902*/
2903int m_part(aClient *cptr, aClient *sptr, int parc, char *parv[])
2904{
2905 Reg aChannel *chptr;
2906 char *p = NULL, *name, *comment = "";
2907 int size;
2908
2909 *buf = '\0';
2910
2911 parv[1] = canonize(parv[1]);
2912 comment = (BadPtr(parv[2])) ? "" : parv[2];
2913 if (strlen(comment) > TOPICLEN)
2914 comment[TOPICLEN] = '\0';
2915
2916 /*
2917 ** Broadcasted to other servers is ":nick PART #chan,#chans :comment",
2918 ** so we must make sure buf does not contain too many channels or later
2919 ** they get truncated! "10" comes from all fixed chars: ":", " PART "
2920 ** and ending "\r\n\0". We could subtract strlen(comment)+2 here too,
2921 ** but it's not something we care, is it? :->
2922 ** Btw: if we ever change m_part to have UID as source, fix this! --B.
2923 */
2924 size = BUFSIZE - strlen(parv[0]) - 10;
2925 for (; (name = strtoken(&p, parv[1], ",")); parv[1] = NULL)
2926 {
2927 chptr = get_channel(sptr, name, 0);
2928 if (!chptr)
2929 {
2930 if (MyPerson(sptr))
2931 sendto_one(sptr,
2932 replies[ERR_NOSUCHCHANNEL], ME, BadTo(parv[0]),
2933 name);
2934 continue;
2935 }
2936 if (check_channelmask(sptr, cptr, name))
2937 continue;
2938 if (!IsMember(sptr, chptr))
2939 {
2940 sendto_one(sptr, replies[ERR_NOTONCHANNEL], ME, BadTo(parv[0]),
2941 name);
2942 continue;
2943 }
2944 /*
2945 ** Remove user from the old channel (if any)
2946 */
2947 if (!get_channelmask(name) && (*chptr->chname != '!')
2948#ifdef JAPANESE
2949 /* jp_valid here because in else{} there's
2950 ** sendto_match_servs() which ignores such
2951 ** channels when sending stuff. --B. */
2952 && jp_valid(NULL, chptr, NULL) /* XXX-JP: why not
2953 jp_valid(NULL, chptr, name)?
2954 because user cannot be on
2955 jp-named channel which is not
2956 flagged JP? --B. */
2957#endif
2958 )
2959 { /* channel:*.mask */
2960 if (*name != '&')
2961 {
2962 /* We could've decreased size by 1 when
2963 ** calculating it, but I left it like that
2964 ** for the sake of clarity. --B. */
2965 if (strlen(buf) + strlen(name) + 1
2966 > size)
2967 {
2968 /* Anyway, if it would not fit in the
2969 ** buffer, send it right away. --B */
2970 sendto_serv_butone(cptr, PartFmt,
2971 sptr->user->uid, buf, comment);
2972 *buf = '\0';
2973 }
2974 if (*buf)
2975 (void)strcat(buf, ",");
2976 (void)strcat(buf, name);
2977 }
2978 }
2979 else
2980 sendto_match_servs(chptr, cptr, PartFmt,
2981 sptr->user->uid, name, comment);
2982 sendto_channel_butserv(chptr, sptr, PartFmt,
2983 parv[0], chptr->chname, comment);
2984 remove_user_from_channel(sptr, chptr);
2985 }
2986 if (*buf)
2987 sendto_serv_butone(cptr, PartFmt, sptr->user->uid, buf, comment);
2988 return 4;
2989}
2990
2991/*
2992** m_kick
2993** parv[0] = sender prefix
2994** parv[1] = channel
2995** parv[2] = client to kick
2996** parv[3] = kick comment
2997*/
2998int m_kick(aClient *cptr, aClient *sptr, int parc, char *parv[])
2999{
3000 aClient *who;
3001 aChannel *chptr;
3002 int chasing = 0, penalty = 0;
3003 char *comment, *name, *p = NULL, *user, *p2 = NULL;
3004 char *tmp, *tmp2;
3005 char *sender;
3006 char nbuf[BUFSIZE+1];
3007 int clen, maxlen;
3008
3009 if (IsServer(sptr))
3010 sendto_flag(SCH_NOTICE, "KICK from %s for %s %s",
3011 parv[0], parv[1], parv[2]);
3012 if (BadPtr(parv[3]))
3013 {
3014 comment = "no reason";
3015 }
3016 else
3017 {
3018 comment = parv[3];
3019 if (strlen(comment) > (size_t) TOPICLEN)
3020 comment[TOPICLEN] = '\0';
3021 }
3022
3023 if (IsServer(sptr))
3024 {
3025 sender = sptr->serv->sid;
3026 }
3027 else if (sptr->user)
3028 {
3029 sender = sptr->user->uid;
3030 }
3031 else
3032 {
3033 sender = sptr->name;
3034 }
3035
3036 /* we'll decrease it for each channel later */
3037 maxlen = BUFSIZE - MAX(strlen(sender), strlen(sptr->name))
3038 - strlen(comment) - 10; /* ":", " KICK ", " " and " :" */
3039
3040 for (; (name = strtoken(&p, parv[1], ",")); parv[1] = NULL)
3041 {
3042 if (penalty >= MAXPENALTY && MyPerson(sptr))
3043 break;
3044 chptr = get_channel(sptr, name, !CREATE);
3045 if (!chptr)
3046 {
3047 if (MyPerson(sptr))
3048 sendto_one(sptr,
3049 replies[ERR_NOSUCHCHANNEL], ME, BadTo(parv[0]),
3050 name);
3051 penalty += 2;
3052 continue;
3053 }
3054 if (check_channelmask(sptr, cptr, name))
3055 continue;
3056 if (!UseModes(name))
3057 {
3058 sendto_one(sptr, replies[ERR_NOCHANMODES], ME, BadTo(parv[0]),
3059 name);
3060 penalty += 2;
3061 continue;
3062 }
3063 if (!IsServer(sptr) && !is_chan_op(sptr, chptr))
3064 {
3065 if (!IsMember(sptr, chptr))
3066 sendto_one(sptr, replies[ERR_NOTONCHANNEL],
3067 ME, BadTo(parv[0]), chptr->chname);
3068 else
3069 sendto_one(sptr, replies[ERR_CHANOPRIVSNEEDED],
3070 ME, BadTo(parv[0]), chptr->chname);
3071 penalty += 2;
3072 continue;
3073 }
3074
3075 clen = maxlen - strlen(name) - 1; /* for comma, see down */
3076 nbuf[0] = '\0';
3077 tmp = mystrdup(parv[2]);
3078 for (tmp2 = tmp; (user = strtoken(&p2, tmp2, ",")); tmp2 = NULL)
3079 {
3080 penalty++;
3081 if (!(IsServer(cptr) && (who = find_uid(user, NULL))) &&
3082 !(who = find_chasing(sptr, user, &chasing)))
3083 continue; /* No such user left! */
3084 if (IsMember(who, chptr))
3085 {
3086 /* Local clients. */
3087 sendto_channel_butserv(chptr, sptr,
3088 ":%s KICK %s %s :%s", sptr->name,
3089 chptr->chname, who->name, comment);
3090
3091 /* Nick buffer to kick out. */
3092 /* as we need space for ",nick", we should add
3093 ** 1 on the left side; instead we subtracted 1
3094 ** on the right side, before the loop. */
3095 if (strlen(nbuf) + (who->user ? UIDLEN :
3096 strlen(who->name)) >= clen)
3097 {
3098 sendto_match_servs_v(chptr, cptr,
3099 SV_UID, ":%s KICK %s %s :%s",
3100 sender, name, nbuf, comment);
3101 nbuf[0] = '\0';
3102 }
3103 if (*nbuf)
3104 {
3105 strcat(nbuf, ",");
3106 }
3107 strcat(nbuf, who->user ? who->user->uid :
3108 who->name);
3109
3110 /* kicking last one out may destroy chptr */
3111 if (chptr->users == 1)
3112 {
3113 if (*nbuf)
3114 {
3115 sendto_match_servs_v(chptr,
3116 cptr, SV_UID,
3117 ":%s KICK %s %s :%s",
3118 sender, name,
3119 nbuf, comment);
3120 nbuf[0] = '\0';
3121 }
3122 }
3123 remove_user_from_channel(who, chptr);
3124 penalty += 2;
3125 if (MyPerson(sptr) &&
3126 /* penalties, obvious */
3127 (penalty >= MAXPENALTY
3128 /* Stop if user kicks himself out
3129 ** of channel --B. */
3130 || who == sptr))
3131 {
3132 break;
3133 }
3134 }
3135 else
3136 sendto_one(sptr,
3137 replies[ERR_USERNOTINCHANNEL],
3138 ME, BadTo(parv[0]), user, name);
3139 } /* loop on parv[2] */
3140 MyFree(tmp);
3141 /* finish sending KICK for given channel */
3142 if (*nbuf)
3143 {
3144 sendto_match_servs_v(chptr, cptr, SV_UID,
3145 ":%s KICK %s %s :%s", sender, name,
3146 nbuf, comment);
3147 }
3148 } /* loop on parv[1] */
3149
3150 return penalty;
3151}
3152
3153/*
3154** m_topic
3155** parv[0] = sender prefix
3156** parv[1] = channels list
3157** parv[2] = topic text
3158*/
3159int m_topic(aClient *cptr, aClient *sptr, int parc, char *parv[])
3160{
3161 aChannel *chptr = NullChn;
3162 char *topic = NULL, *name, *p = NULL;
3163 int penalty = 1;
3164
3165 parv[1] = canonize(parv[1]);
3166
3167 for (; (name = strtoken(&p, parv[1], ",")); parv[1] = NULL)
3168 {
3169 if (!IsChannelName(name))
3170 {
3171 sendto_one(sptr, replies[ERR_NOTONCHANNEL], ME,
3172 parv[0], name);
3173 continue;
3174 }
3175 if (!UseModes(name))
3176 {
3177 sendto_one(sptr, replies[ERR_NOCHANMODES], ME,
3178 parv[0], name);
3179 continue;
3180 }
3181 chptr = find_channel(name, NullChn);
3182 if (!chptr)
3183 {
3184 sendto_one(sptr, replies[ERR_NOSUCHCHANNEL], ME,
3185 parv[0], name);
3186 return penalty;
3187 }
3188 if (!IsMember(sptr, chptr))
3189 {
3190 sendto_one(sptr, replies[ERR_NOTONCHANNEL], ME,
3191 parv[0], name);
3192 continue;
3193 }
3194
3195 /* should never be true at this point --B. */
3196 if (check_channelmask(sptr, cptr, name))
3197 continue;
3198
3199 if (parc > 2)
3200 topic = parv[2];
3201
3202 if (!topic) /* only asking for topic */
3203 {
3204 if (chptr->topic[0] == '\0')
3205 {
3206 sendto_one(sptr, replies[RPL_NOTOPIC], ME,
3207 parv[0], chptr->chname);
3208 }
3209 else
3210 {
3211 sendto_one(sptr, replies[RPL_TOPIC], ME,
3212 parv[0], chptr->chname, chptr->topic);
3213#ifdef TOPIC_WHO_TIME
3214 if (chptr->topic_t > 0)
3215 sendto_one(sptr, replies[RPL_TOPIC_WHO_TIME],
3216 ME, BadTo(parv[0]), chptr->chname,
3217 IsAnonymous(chptr) ?
3218 "anonymous!anonymous@anonymous." :
3219 chptr->topic_nuh, chptr->topic_t);
3220#endif
3221 }
3222 }
3223 else if ((chptr->mode.mode & MODE_TOPICLIMIT) == 0 ||
3224 is_chan_op(sptr, chptr))
3225 { /* setting a topic */
3226 strncpyzt(chptr->topic, topic, sizeof(chptr->topic));
3227#ifdef TOPIC_WHO_TIME
3228 sprintf(chptr->topic_nuh, "%s!%s@%s", sptr->name,
3229 sptr->user->username, sptr->user->host);
3230 chptr->topic_t = timeofday;
3231#endif
3232 sendto_match_servs(chptr, cptr,":%s TOPIC %s :%s",
3233 sptr->user->uid, chptr->chname,
3234 chptr->topic);
3235 sendto_channel_butserv(chptr, sptr, ":%s TOPIC %s :%s",
3236 parv[0],
3237 chptr->chname, chptr->topic);
3238#ifdef USE_SERVICES
3239 check_services_butone(SERVICE_WANT_TOPIC,
3240 NULL, sptr, ":%s TOPIC %s :%s",
3241 parv[0], chptr->chname,
3242 chptr->topic);
3243#endif
3244 penalty += 2;
3245 }
3246 else
3247 sendto_one(sptr, replies[ERR_CHANOPRIVSNEEDED], ME, BadTo(parv[0]),
3248 chptr->chname);
3249 }
3250 return penalty;
3251}
3252
3253/*
3254** m_invite
3255** parv[0] - sender prefix
3256** parv[1] - user to invite
3257** parv[2] - channel number
3258*/
3259int m_invite(aClient *cptr, aClient *sptr, int parc, char *parv[])
3260{
3261 aClient *acptr;
3262 aChannel *chptr;
3263
3264 if (!(acptr = find_person(parv[1], (aClient *)NULL)))
3265 {
3266 sendto_one(sptr, replies[ERR_NOSUCHNICK], ME, BadTo(parv[0]), parv[1]);
3267 return 1;
3268 }
3269 if (clean_channelname(parv[2]) == -1)
3270 return 1;
3271 if (check_channelmask(sptr, acptr->user->servp->bcptr, parv[2]))
3272 return 1;
3273 if (*parv[2] == '&' && !MyClient(acptr))
3274 return 1;
3275 chptr = find_channel(parv[2], NullChn);
3276
3277#ifdef JAPANESE
3278 if (!jp_valid(acptr->from, chptr, parv[2]))
3279 {
3280 sendto_one(sptr, replies[ERR_BADCHANMASK], ME,
3281 chptr ? chptr->chname : parv[2]);
3282 return 1;
3283 }
3284#endif
3285 if (!chptr && parv[2][0] == '!')
3286 {
3287 /* Try to find !channel using shortname */
3288 chptr = hash_find_channels(parv[2] + 1, NULL);
3289 }
3290
3291 if (!chptr)
3292 {
3293 sendto_prefix_one(acptr, sptr, ":%s INVITE %s :%s",
3294 parv[0], parv[1], parv[2]);
3295 if (MyConnect(sptr))
3296 {
3297 sendto_one(sptr, replies[RPL_INVITING], ME, BadTo(parv[0]),
3298 acptr->name, parv[2]);
3299 if (acptr->user->flags & FLAGS_AWAY)
3300 send_away(sptr, acptr);
3301 }
3302 return 3;
3303 }
3304
3305 if (!IsMember(sptr, chptr))
3306 {
3307 sendto_one(sptr, replies[ERR_NOTONCHANNEL], ME, BadTo(parv[0]), parv[2]);
3308 return 1;
3309 }
3310
3311 if (IsMember(acptr, chptr))
3312 {
3313 sendto_one(sptr, replies[ERR_USERONCHANNEL], ME, BadTo(parv[0]),
3314 parv[1], parv[2]);
3315 return 1;
3316 }
3317
3318 if ((chptr->mode.mode & MODE_INVITEONLY) && !is_chan_op(sptr, chptr))
3319 {
3320 sendto_one(sptr, replies[ERR_CHANOPRIVSNEEDED],
3321 ME, BadTo(parv[0]), chptr->chname);
3322 return 1;
3323 }
3324
3325 if (MyConnect(sptr))
3326 {
3327 sendto_one(sptr, replies[RPL_INVITING], ME, BadTo(parv[0]),
3328 acptr->name, ((chptr) ? (chptr->chname) : parv[2]));
3329 if (acptr->user->flags & FLAGS_AWAY)
3330 send_away(sptr, acptr);
3331 }
3332
3333 if (MyConnect(acptr))
3334 if (chptr && /* (chptr->mode.mode & MODE_INVITEONLY) && */
3335 sptr->user && is_chan_op(sptr, chptr))
3336 add_invite(sptr, acptr, chptr);
3337
3338 sendto_prefix_one(acptr, sptr, ":%s INVITE %s :%s",parv[0],
3339 acptr->name, ((chptr) ? (chptr->chname) : parv[2]));
3340 return 2;
3341}
3342
3343
3344/*
3345** m_list
3346** parv[0] = sender prefix
3347** parv[1] = channel
3348*/
3349int m_list(aClient *cptr, aClient *sptr, int parc, char *parv[])
3350{
3351 aChannel *chptr;
3352 char *name, *p = NULL;
3353 int rlen = 0;
3354
3355 if (parc > 2 &&
3356 hunt_server(cptr, sptr, ":%s LIST %s %s", 2, parc, parv))
3357 return 10;
3358
3359 if (BadPtr(parv[1]))
3360 {
3361 Link *lp;
3362 int listedchannels = 0;
3363 int maxsendq = 0;
3364
3365 if (!sptr->user)
3366 {
3367 sendto_one(sptr, replies[RPL_LISTEND], ME,
3368 BadTo(parv[0]));
3369 return 2;
3370 }
3371
3372#ifdef LIST_ALIS_NOTE
3373 if (MyConnect(sptr))
3374 {
3375 sendto_one(sptr, ":%s NOTICE %s :%s", ME, parv[0],
3376 LIST_ALIS_NOTE);
3377 }
3378#endif
3379 /* Keep 10% of sendQ free
3380 * Note: Definition of LIST command prevents obtaining
3381 * of complete LIST from remote server, if this
3382 * behaviour is changed, MyConnect() check needs to be added
3383 * here and within following loops as well. - jv
3384 */
3385 maxsendq = (int) ((float) get_sendq(sptr, 0) * (float) 0.9);
3386
3387 /* First, show all +s/+p channels user is on */
3388 for (lp = sptr->user->channel; lp; lp = lp->next)
3389 {
3390 chptr = lp->value.chptr;
3391 if (SecretChannel(chptr) || HiddenChannel(chptr))
3392 {
3393 sendto_one(sptr, replies[RPL_LIST], ME,
3394 BadTo(parv[0]), chptr->chname,
3395 chptr->users, chptr->topic);
3396 listedchannels++;
3397
3398 if (DBufLength(&sptr->sendQ) > maxsendq)
3399 {
3400 sendto_one(sptr,
3401 replies[ERR_TOOMANYMATCHES],
3402 ME, BadTo(parv[0]), "LIST");
3403 goto end_of_list;
3404 }
3405 }
3406 }
3407
3408 /* Second, show all visible channels; +p channels are not
3409 * reported if user is not their member - jv.
3410 */
3411 for (chptr = channel; chptr; chptr = chptr->nextch)
3412 {
3413 if (!chptr->users || /* empty locked channel */
3414 SecretChannel(chptr) || HiddenChannel(chptr))
3415 {
3416 continue;
3417 }
3418 sendto_one(sptr, replies[RPL_LIST], ME, BadTo(parv[0]),
3419 chptr->chname, chptr->users,
3420 chptr->topic);
3421
3422 listedchannels++;
3423
3424 if (DBufLength(&sptr->sendQ) > maxsendq)
3425 {
3426 sendto_one(sptr, replies[ERR_TOOMANYMATCHES],
3427 ME, BadTo(parv[0]), "LIST");
3428
3429 break;
3430 }
3431
3432 }
3433
3434end_of_list:;
3435#ifdef LIST_ALIS_NOTE
3436 /* Send second notice if we listed more than 24 channels
3437 * - usual height of irc client in text mode.
3438 */
3439 if (MyConnect(sptr) && (listedchannels > 24))
3440 {
3441 sendto_one(sptr, ":%s NOTICE %s :%s", ME, parv[0],
3442 LIST_ALIS_NOTE);
3443 }
3444#endif
3445
3446 }
3447 else
3448 {
3449 parv[1] = canonize(parv[1]);
3450 for (; (name = strtoken(&p, parv[1], ",")); parv[1] = NULL)
3451 {
3452 chptr = find_channel(name, NullChn);
3453 if (chptr && ShowChannel(sptr, chptr) && sptr->user)
3454 {
3455 rlen += sendto_one(sptr, replies[RPL_LIST],
3456 ME, BadTo(parv[0]), chptr->chname,
3457 chptr->users, chptr->topic);
3458 if (!MyConnect(sptr) && rlen > CHREPLLEN)
3459 break;
3460 }
3461 if (*name == '!')
3462 {
3463 chptr = NULL;
3464 while ((chptr = hash_find_channels(name + 1,
3465 chptr)))
3466 {
3467 int scr = SecretChannel(chptr) &&
3468 !IsMember(sptr, chptr);
3469 rlen += sendto_one(sptr,
3470 replies[RPL_LIST],
3471 ME, BadTo(parv[0]),
3472 chptr->chname,
3473 (scr) ? -1 :
3474 chptr->users,
3475 (scr) ? "" :
3476 chptr->topic);
3477 if (!MyConnect(sptr) &&
3478 rlen > CHREPLLEN)
3479 break;
3480 }
3481 }
3482 }
3483 }
3484 if (!MyConnect(sptr) && rlen > CHREPLLEN)
3485 sendto_one(sptr, replies[ERR_TOOMANYMATCHES], ME,
3486 BadTo(parv[0]), "LIST");
3487 sendto_one(sptr, replies[RPL_LISTEND], ME, BadTo(parv[0]));
3488 return 2;
3489}
3490/*
3491 * names_channel - send NAMES for one specific channel
3492 * sends RPL_ENDOFNAMES when sendeon > 0
3493 */
3494static void names_channel(aClient *cptr, aClient *sptr, char *to,
3495 aChannel *chptr, int sendeon)
3496{
3497 Reg Link *lp = NULL;
3498 Reg aClient *acptr;
3499 int pxlen, ismember = 0, nlen, maxlen;
3500 char *pbuf = buf;
3501 int showusers = 1;
3502
3503 if (!chptr->users) /* channel in ND */
3504 {
3505 showusers = 0;
3506 }
3507 else
3508 {
3509 ismember = (lp = find_channel_link(sptr->user->channel, chptr))
3510 ? 1 : 0;
3511 }
3512
3513 if (SecretChannel(chptr))
3514 {
3515 if (!ismember)
3516 {
3517 showusers = 0;
3518 }
3519 else
3520 {
3521 *pbuf++ = '@';
3522 }
3523 }
3524 else if (HiddenChannel(chptr))
3525 {
3526 *pbuf++ = '*';
3527 }
3528 else
3529 {
3530 *pbuf++ = '=';
3531 }
3532
3533 if (showusers)
3534 {
3535 *pbuf++ = ' ';
3536 pxlen = strlen(chptr->chname);
3537 memcpy(pbuf, chptr->chname, pxlen);
3538 pbuf += pxlen;
3539 *pbuf++ = ' ';
3540 *pbuf++ = ':';
3541 *pbuf = '\0';
3542 pxlen += 4; /* '[=|*|@]' ' + ' ' + ':' */
3543
3544 if (IsAnonymous(chptr))
3545 {
3546 if (ismember)
3547 {
3548 if (lp->flags & CHFL_CHANOP)
3549 {
3550 *pbuf++ = '@';
3551 }
3552 else if (lp->flags & CHFL_VOICE)
3553 {
3554 *pbuf++ = '+';
3555 }
3556 strcpy(pbuf,to);
3557 }
3558 sendto_one(sptr, replies[RPL_NAMREPLY], ME, BadTo(to),
3559 buf);
3560 }
3561 else
3562 {
3563 /* server names + : : + spaces + "353" + nick length
3564 * +\r\n */
3565 maxlen = BUFSIZE
3566 - 1 /* : */
3567 - strlen(ME)
3568 - 5 /* " 353 " */
3569 - strlen(to)
3570 - 1 /* " " */
3571 - pxlen /* "= #chan :" */
3572 - 2; /* \r\n */
3573
3574 for (lp = chptr->members; lp; lp = lp->next)
3575 {
3576 acptr = lp->value.cptr;
3577
3578 nlen = strlen(acptr->name);
3579 /* This check is needed for server channels
3580 * when someone removes +a mode from them.
3581 * (server is member of such channel).
3582 */
3583 if (strchr(acptr->name, '.'))
3584 {
3585 continue;
3586 }
3587
3588 /* Exceeded allowed length. */
3589 if (((size_t) pbuf - (size_t) buf) + nlen
3590 >= maxlen)
3591 {
3592 *pbuf = '\0';
3593 sendto_one(sptr,
3594 replies[RPL_NAMREPLY],ME ,
3595 BadTo(to) , buf);
3596 pbuf = buf + pxlen; /* save prefix
3597 for another
3598 iteration */
3599 pbuf[0] = '\0';
3600 }
3601
3602 if (!ismember && IsInvisible(acptr))
3603 {
3604 continue;
3605 }
3606 if (lp->flags & CHFL_CHANOP)
3607 {
3608 *pbuf++ = '@';
3609 }
3610 else if (lp->flags & CHFL_VOICE)
3611 {
3612 *pbuf++ = '+';
3613 }
3614
3615 memcpy(pbuf, acptr->name, nlen);
3616 pbuf += nlen;
3617 *pbuf++ = ' ';
3618 }
3619
3620 *pbuf = '\0';
3621 sendto_one(sptr, replies[RPL_NAMREPLY], ME,
3622 BadTo(to), buf);
3623 }
3624 }
3625 if (sendeon)
3626 {
3627 sendto_one(sptr, replies[RPL_ENDOFNAMES],ME ,BadTo(to),
3628 chptr->chname);
3629 }
3630 return;
3631
3632}
3633
3634
3635/************************************************************************
3636 * m_names() - Added by Jto 27 Apr 1989
3637 * Rewritten by jv 27 Apr 2001
3638 ************************************************************************/
3639
3640/*
3641** m_names
3642** parv[0] = sender prefix
3643** parv[1] = channel
3644*/
3645int m_names(aClient *cptr, aClient *sptr, int parc, char *parv[])
3646{
3647 Reg aChannel *chptr;
3648 Reg aClient *acptr;
3649 Reg Link *lp;
3650 int maxlen ,pxlen,nlen,cansend = 0, sent = 1;
3651 char *para = parc > 1 ? parv[1] : NULL,*name, *p = NULL, *pbuf = buf;
3652
3653 if (parc > 2 &&
3654 hunt_server(cptr, sptr, ":%s NAMES %s %s", 2, parc, parv))
3655 {
3656 return MAXPENALTY;
3657 }
3658
3659 if (!BadPtr(para))
3660 {
3661 for (; (name = strtoken(&p, parv[1], ",")); parv[1] = NULL)
3662 {
3663 if (clean_channelname(name) == -1)
3664 continue;
3665 if BadPtr(name)
3666 {
3667 continue;
3668 }
3669 chptr = find_channel(name, NULL);
3670 if (chptr)
3671 {
3672 names_channel(cptr, sptr, parv[0], chptr, 1);
3673 }
3674 else
3675 {
3676 sendto_one(sptr, replies[RPL_ENDOFNAMES],ME ,
3677 parv[0], name);
3678 }
3679 sent++;
3680 if (!MyConnect(sptr) || sent > MAXCHANNELSPERUSER)
3681 {
3682 break;
3683 }
3684 }
3685
3686 sent = sent < 2 ? 2 : (sent * MAXCHANNELSPERUSER) / MAXPENALTY;
3687 return sent < 2 ? 2 : sent;
3688 }
3689 /* Client wants all nicks/channels which is seriously cpu intensive
3690 * Allowed for local clients only.
3691 * First, list all secret channels user is on
3692 */
3693 for (lp = sptr->user->channel; lp; lp = lp->next)
3694 {
3695 chptr = lp->value.chptr;
3696 if (SecretChannel(chptr))
3697 {
3698 names_channel(cptr, sptr, parv[0], chptr, 0);
3699 }
3700 }
3701
3702 /* Second, list all non-secret channels */
3703 for (chptr = channel; chptr; chptr = chptr->nextch)
3704 {
3705 if (!chptr->users || /* channel in CD */
3706 SecretChannel(chptr))
3707 {
3708 continue;
3709 }
3710 names_channel(cptr, sptr, parv[0], chptr, 0);
3711 }
3712 /* Third, list all remaining users
3713 * ie, those which aren't on any channel, or are at Anonymous one
3714 */
3715 strcpy(pbuf, "* * :");
3716 pxlen = 5;
3717 pbuf += pxlen;
3718 maxlen = BUFSIZE
3719 - 1 /* : */
3720 - strlen(ME)
3721 - 5 /* " 353 " */
3722 - strlen(parv[0])
3723 - 1 /* " " */
3724 - pxlen /* "* * :" */
3725 - 2; /* \r\n */
3726
3727
3728 for (acptr = client; acptr ;acptr = acptr->next)
3729 {
3730 if (!IsPerson(acptr) || IsInvisible(acptr))
3731 {
3732 continue;
3733 }
3734
3735 lp = acptr->user->channel;
3736 cansend = 1;
3737 while (lp)
3738 {
3739 chptr = lp->value.chptr;
3740 if (PubChannel(chptr) || SecretChannel(chptr)
3741 || IsMember(sptr, chptr))
3742 { /* already shown */
3743 cansend = 0;
3744 break;
3745 }
3746 lp = lp->next;
3747 }
3748 if (!cansend)
3749 {
3750 continue;
3751 }
3752 nlen = strlen(acptr->name);
3753 if (strchr(acptr->name, '.'))
3754 {
3755 continue;
3756 }
3757
3758 if (((size_t) pbuf - (size_t) buf) + nlen >= maxlen)
3759 {
3760 *pbuf = '\0';
3761 sendto_one(sptr, replies[RPL_NAMREPLY], ME, parv[0],
3762 buf);
3763 sent = 1;
3764 pbuf = buf + pxlen;
3765 pbuf[0] = '\0';
3766 }
3767
3768 memcpy(pbuf, acptr->name, nlen);
3769 pbuf += nlen;
3770 *pbuf++ = ' ';
3771 sent = 0;
3772 }
3773
3774 *pbuf = '\0';
3775 sendto_one(sptr, replies[RPL_NAMREPLY], ME, parv[0], buf);
3776 sendto_one(sptr, replies[RPL_ENDOFNAMES], ME, parv[0], "*");
3777 return MAXPENALTY;
3778}
3779
3780#define CHECKFREQ 300
3781/* consider reoping an opless channel */
3782static int reop_channel(time_t now, aChannel *chptr, int reopmode)
3783{
3784 Link *lp, op;
3785
3786 if (IsSplit() || chptr->reop == 0)
3787 {
3788 /* Should never happen. */
3789 sendto_flag(SCH_DEBUG, "reop_channel should not happen");
3790 return 0;
3791 }
3792
3793 op.value.chptr = NULL;
3794 /* Why do we wait until CD expires? --B. */
3795 if (now - chptr->history > DELAYCHASETIMELIMIT)
3796 {
3797 int idlelimit1 = 0, idlelimit2 = 0;
3798
3799 if (reopmode != CHFL_REOPLIST)
3800 {
3801 /*
3802 ** This selects random idle limits in the range
3803 ** from CHECKFREQ to 4*CHECKFREQ
3804 */
3805 idlelimit1 = CHECKFREQ + myrand() % (2*CHECKFREQ);
3806 idlelimit2 = idlelimit1 + CHECKFREQ +
3807 myrand() % (2*CHECKFREQ);
3808 }
3809
3810 for (lp = chptr->members; lp; lp = lp->next)
3811 {
3812 /* not restricted */
3813 if (IsRestricted(lp->value.cptr))
3814 {
3815 continue;
3816 }
3817 if (lp->flags & CHFL_CHANOP)
3818 {
3819 chptr->reop = 0;
3820 return 0;
3821 }
3822 /* Our client */
3823 if (!MyConnect(lp->value.cptr))
3824 {
3825 continue;
3826 }
3827 /* matching +R list */
3828 if (reopmode == CHFL_REOPLIST &&
3829 NULL == match_modeid(CHFL_REOPLIST,
3830 lp->value.cptr, chptr))
3831 {
3832 continue;
3833 }
3834 /* If +R list or channel reop is heavily overdue,
3835 ** don't care about idle. Find the least idle client.
3836 */
3837 if (reopmode == CHFL_REOPLIST ||
3838 now - chptr->reop > 7*LDELAYCHASETIMELIMIT)
3839 {
3840 if (op.value.cptr == NULL ||
3841 lp->value.cptr->user->last >
3842 op.value.cptr->user->last)
3843 {
3844 op.value.cptr = lp->value.cptr;
3845 continue;
3846 }
3847 continue;
3848 }
3849 /* else hidden in above continue,
3850 ** not to indent too much :> --B. */
3851
3852 /* Channel reop is not heavily overdue. So pick
3853 ** a client, which is a bit idle, but not too much.
3854 ** Find the least idle client possible, though.
3855 */
3856 if (now - lp->value.cptr->user->last >= idlelimit1 &&
3857 now - lp->value.cptr->user->last < idlelimit2 &&
3858 (op.value.cptr == NULL ||
3859 lp->value.cptr->user->last >
3860 op.value.cptr->user->last))
3861 {
3862 op.value.cptr = lp->value.cptr;
3863 }
3864 }
3865 if (op.value.cptr == NULL)
3866 {
3867 return 0;
3868 }
3869 sendto_channel_butone(&me, &me, chptr,
3870 ":%s NOTICE %s :Enforcing channel mode +%c (%d)", ME,
3871 chptr->chname, reopmode == CHFL_REOPLIST ? 'R' : 'r',
3872 now - chptr->reop);
3873 op.flags = MODE_ADD|MODE_CHANOP;
3874 change_chan_flag(&op, chptr);
3875 sendto_match_servs(chptr, NULL, ":%s MODE %s +o %s",
3876 ME, chptr->chname, op.value.cptr->name);
3877 sendto_channel_butserv(chptr, &me, ":%s MODE %s +o %s",
3878 ME, chptr->chname, op.value.cptr->name);
3879 chptr->reop = 0;
3880 ircstp->is_reop++;
3881 return 1;
3882 }
3883 return 0;
3884}
3885
3886/*
3887 * Cleanup locked channels, run frequently.
3888 *
3889 * A channel life is defined by its users and the history stamp.
3890 * It is alive if one of the following is true:
3891 * chptr->users > 0 (normal state)
3892 * chptr->history >= time(NULL) (eventually locked)
3893 * It is locked if empty but alive.
3894 *
3895 * The history stamp is set when a remote user with channel op exits.
3896 */
3897time_t collect_channel_garbage(time_t now)
3898{
3899 static u_int max_nb = 0; /* maximum of live channels */
3900 static u_char split = 0;
3901 Reg aChannel *chptr = channel;
3902 Reg u_int cur_nb = 1, curh_nb = 0, r_cnt = 0;
3903 aChannel *del_ch;
3904#ifdef DEBUGMODE
3905 u_int del = istat.is_hchan;
3906#endif
3907#define SPLITBONUS (CHECKFREQ - 50)
3908
3909 collect_chid();
3910
3911 for (; chptr; chptr = chptr->nextch)
3912 {
3913 if (chptr->users == 0)
3914 {
3915 curh_nb++;
3916 }
3917 else
3918 {
3919 Link *tmp;
3920
3921 cur_nb++;
3922
3923 if (IsSplit())
3924 {
3925 if (chptr->reop > 0)
3926 {
3927 /* Extend reop */
3928 chptr->reop += CHECKFREQ;
3929 }
3930 continue;
3931 }
3932 if (chptr->reop == 0 || chptr->reop > now)
3933 {
3934 continue;
3935 }
3936 for (tmp = chptr->mlist; tmp; tmp = tmp->next)
3937 {
3938 if (tmp->flags == CHFL_REOPLIST)
3939 {
3940 break;
3941 }
3942 }
3943 if (tmp && tmp->flags == CHFL_REOPLIST)
3944 {
3945 r_cnt += reop_channel(now, chptr, CHFL_REOPLIST);
3946 }
3947 else if (chptr->mode.mode & MODE_REOP)
3948 {
3949 r_cnt += reop_channel(now, chptr, !CHFL_REOPLIST);
3950 }
3951 }
3952 }
3953 if (cur_nb > max_nb)
3954 {
3955 max_nb = cur_nb;
3956 }
3957
3958 if (r_cnt > 0)
3959 {
3960 sendto_flag(SCH_CHAN, "Re-opped %u channel(s).", r_cnt);
3961 }
3962
3963 /*
3964 ** check for huge netsplits, if so, garbage collection is not really
3965 ** done but make sure there aren't too many channels kept for
3966 ** history - krys
3967 ** This is dubious, but I'll leave it for now, until better split
3968 ** detection. --B.
3969 */
3970 if ((2*curh_nb > cur_nb) && curh_nb < max_nb)
3971 split = 1;
3972 else
3973 {
3974 split = 0;
3975 /* no empty channel? let's skip the while! */
3976 if (curh_nb == 0)
3977 {
3978#ifdef DEBUGMODE
3979 sendto_flag(SCH_NOTICE,
3980 "Channel garbage: live %u (max %u), hist %u (extended)",
3981 cur_nb - 1, max_nb - 1, curh_nb);
3982#endif
3983 /* Check again after CHECKFREQ seconds */
3984 return (time_t) (now + CHECKFREQ);
3985 }
3986 }
3987
3988 chptr = channel;
3989 while (chptr)
3990 {
3991 /*
3992 ** In case we are likely to be split, extend channel locking.
3993 ** most splits should be short, but reality seems to prove some
3994 ** aren't.
3995 */
3996 if (!chptr->history)
3997 {
3998 chptr = chptr->nextch;
3999 continue;
4000 }
4001 if (split) /* net splitted recently and we have a lock */
4002 chptr->history += SPLITBONUS; /* extend lock */
4003
4004 if ((chptr->users == 0) && (chptr->history <= now))
4005 {
4006 del_ch = chptr;
4007
4008 chptr = del_ch->nextch;
4009 free_channel(del_ch);
4010 }
4011 else
4012 chptr = chptr->nextch;
4013 }
4014
4015#ifdef DEBUGMODE
4016 sendto_flag(SCH_NOTICE,
4017 "Channel garbage: live %u (max %u), hist %u (removed %u)%s",
4018 cur_nb - 1, max_nb - 1, curh_nb, del - istat.is_hchan,
4019 (split) ? " split detected" : "");
4020#endif
4021 /* Check again after CHECKFREQ seconds */
4022 return (time_t) (now + CHECKFREQ);
4023}
4024