1 /*
2  * names.c: This here is used to maintain a list of all the people currently
3  * on your channel.  Seems to work
4  *
5  * Written By Michael Sandrof
6  *
7  * Copyright (c) 1990 Michael Sandrof.
8  * Copyright (c) 1991, 1992 Troy Rollo.
9  * Copyright (c) 1992-2000 Matthew R. Green.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. The name of the author may not be used to endorse or promote products
21  *    derived from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  * renamed to channels.c and extensively modified by
36  * Joshua J. Drake
37  */
38 
39 #include "irc.h"
40 IRCII_RCSID("@(#)$Id: names.c,v 1.81 2000/08/31 12:10:52 mrg Exp $");
41 
42 #include "dma.h"
43 #include "ircaux.h"
44 #include "channels.h"
45 #include "window.h"
46 #include "screen.h"
47 #include "server.h"
48 #include "lastlog.h"
49 #include "list.h"
50 #include "output.h"
51 #include "notify.h"
52 #include "vars.h"
53 
54 #include "nicks.h"
55 #include "bans.h"
56 #include "ckey.h"
57 #include "friends.h"
58 #include "ninjacmd.h"
59 
60 /* channel identifiers */
61 #define STRING_CHANNEL '+'
62 #define MULTI_CHANNEL '#'
63 #define LOCAL_CHANNEL '&'
64 #define SAFE_CHANNEL '!'
65 
66 /* from channels.h */
67 static	u_char	mode_str[] = MODE_STRING;
68 
69 static	void	free_channel _((Channel **));
70 static	void	show_channel _((Channel *));
71 static	void	clear_channel _((Channel *));
72 static	u_char	*recreate_mode _((Channel *));
73 static	int	decifer_mode _((u_char *, Channel *, u_char *));
74 
75 /* ninja extensions */
76 static	void	clear_channel_nicks _((Channel *));
77 static	void	clear_channel_bans _((Channel *));
78 static	void	clear_channel_excepts _((Channel *));
79 static	void	clear_channel_denys _((Channel *));
80 
81 /* clear_channel: erases all entries in a nick list for the given channel */
82 /* in ninja this also removes other channel information */
83 static	void
clear_channel(chan)84 clear_channel(chan)
85 	Channel *chan;
86 {
87    clear_channel_nicks(chan);
88    clear_channel_bans(chan);
89    clear_channel_excepts(chan);
90    clear_channel_denys(chan);
91 }
92 
93 /* clear channel nicks */
94 static	void
clear_channel_nicks(chan)95 clear_channel_nicks(chan)
96     	Channel *chan;
97 {
98    Nick *tmp, *next;
99 
100    for (tmp = chan->nicks; tmp; tmp = next)
101      {
102 	next = tmp->next;
103 	free_nick(&tmp);
104      }
105    chan->nicks = (Nick *) 0;
106 }
107 
108 /* clear channel bans */
109 static	void
clear_channel_bans(chan)110 clear_channel_bans(chan)
111     	Channel *chan;
112 {
113    Ban *tmp, *next;
114 
115    for (tmp = chan->bans; tmp; tmp = next)
116      {
117 	next = tmp->next;
118 	new_free(&(tmp->ban));
119 	new_free(&(tmp->owner));
120 	new_free(&tmp);
121      }
122    chan->bans = (Ban *) 0;
123 }
124 
125 /* clear channel exceptions */
126 static	void
clear_channel_excepts(chan)127 clear_channel_excepts(chan)
128     	Channel *chan;
129 {
130    Except *tmp, *next;
131 
132    for (tmp = chan->excepts; tmp; tmp = next)
133      {
134 	next = tmp->next;
135 	new_free(&(tmp->exception));
136 	new_free(&(tmp->owner));
137 	new_free(&tmp);
138      }
139    chan->excepts = (Except *) 0;
140 }
141 
142 /* clear channel deny lines */
143 static	void
clear_channel_denys(chan)144 clear_channel_denys(chan)
145     	Channel *chan;
146 {
147    Deny *tmp, *next;
148 
149    for (tmp = chan->denys; tmp; tmp = next)
150      {
151 	next = tmp->next;
152 	new_free(&(tmp->regexp));
153 	new_free(&(tmp->owner));
154 	new_free(&tmp);
155      }
156    chan->denys = (Deny *) 0;
157 }
158 
159 /*
160  * we need this to deal with !channels.
161  */
162 int
same_channel(channel,chan2)163 same_channel(channel, chan2)
164 	Channel *channel;
165 	u_char	*chan2;
166 {
167 	size_t	len, len2;
168 
169 	/* take the easy way out */
170 	if (*channel->channel != '!' && *chan2 != '!')
171 		return (!my_stricmp(channel->channel, chan2));
172 
173 	/*
174 	 * OK, so what we have is channel = "!fooo" and chan2 = "!JUNKfoo".
175 	 */
176 	len = my_strlen(channel->channel);
177 	len2 = my_strlen(chan2);
178 
179 	/* bail out on known stuff */
180 	if (len > len2)
181 		return (0);
182 	if (len == len2)
183 		return (!my_stricmp(channel->channel, chan2));
184 
185 	/*
186 	 * replace the channel name if we are the same!
187 	 */
188 	if (!my_stricmp(channel->channel + 1, chan2 + 1 + (len2 - len)))
189 	{
190 		malloc_strcpy(&channel->channel, chan2);
191 		return (1);
192 	}
193 	return (0);
194 }
195 
196 extern	Channel *
197 lookup_channel(channel, server, do_unlink)
198 	u_char	*channel;
199 	int	server;
200 	int	do_unlink;
201 {
202    Channel	*chan, *last = (Channel *) 0;
203 
204    if (server == -1)
205      server = primary_server;
206    if (server < 0 || server >= number_of_servers)
207        return (Channel *) 0;
208    chan = server_list[server].chan_list;
209    while (chan)
210      {
211 	if (chan->server == server && same_channel(chan, channel))
212 	  {
213 	     if (do_unlink == CHAN_UNLINK)
214 	       {
215 		  if (last)
216 		    last->next = chan->next;
217 		  else
218 		    server_list[server].chan_list = chan->next;
219 	       }
220 	     break;
221 	  }
222 	last = chan;
223 	chan = chan->next;
224      }
225    return chan;
226 }
227 
228 /*
229  * add_channel: adds the named channel to the channel list.  If the channel
230  * is already in the list, its attributes are modified accordingly with the
231  * connected and copy parameters.
232  */
233 void
add_channel(channel,server,connected,copy)234 add_channel(channel, server, connected, copy)
235 	u_char	*channel;
236 	int	server;
237 	int	connected;
238 	Channel *copy;
239 {
240    Channel *new;
241    int	do_add = 0;
242    /* u_char *tkey; */
243 
244    /*
245     * avoid adding channel "0"
246     */
247    if (channel[0] == '0'&& channel[1] == '\0')
248      return;
249    /* also avoid adding non-channels,
250     * if this is triggered, whatever is calling this is buggy
251     */
252    if (!is_channel(channel))
253      {
254 	put_error("add_channel() trying to add channel \"%s\".. notify ninjairc@qoop.org",
255 		  channel);
256 	return;
257      }
258 
259    if ((new = lookup_channel(channel, server, CHAN_NOUNLINK)) == (Channel *) 0)
260      {
261 	new = (Channel *) new_malloc(sizeof(Channel));
262 	/* setting stuff to 0 is pointless because..
263 	 * dma_Malloc does memset(mem, 0, sizeof(mem))
264 	 *
265 	new->channel = (u_char *) 0;
266 	new->status = 0;
267 	new->key = (u_char *) 0;
268 	new->nicks = (Nick *) 0;
269 	new->mode = 0;
270 	new->limit = 0;
271 	 */
272 	new->s_mode = empty_string;
273 
274 	/*
275 	 * not sure if this is needed..
276 	 *
277 	tkey = get_ckey(channel);
278 	if (tkey)
279 	  {
280 	     dma_strcpy(&new->key, tkey);
281 	 // dont do this, let the server do it!
282 	     // new->mode |= MODE_KEY;
283 	  }
284 	 */
285 	malloc_strcpy(&new->channel, channel);
286 	if ((new->window = is_bound(channel, server)) == (Window *) 0)
287 	  new->window = curr_scr_win;
288 	do_add = 1;
289 	add_to_list((List **) &server_list[server].chan_list, (List *) new);
290      }
291    else
292      {
293 	if (new->connected != CHAN_LIMBO && new->connected != CHAN_JOINING)
294 	  yell("--- add_channel: add_channel found channel not CHAN_LIMBO/JOINING: %s", new->channel);
295      }
296 
297    if (do_add || (connected == CHAN_JOINED))
298      {
299 #ifdef SHOW_JOIN_TIME
300 	gettimeofday(&new->join_time, NULL);
301 #endif
302 	new->server = server;
303 	clear_channel(new);
304      }
305    if (copy)
306      {
307 	new->mode = copy->mode;
308 	new->limit = copy->limit;
309 	new->window = copy->window;
310 	malloc_strcpy(&new->key, copy->key);
311      }
312    new->connected = connected;
313    if ((connected == CHAN_JOINED) && !is_current_channel(channel, server, 0))
314      {
315 	int	flag = 1;
316 	Window	*tmp, *expected, *possible = (Window *) 0;
317 
318 	expected = new->window;
319 
320 	while ((tmp = traverse_all_windows(&flag)))
321 	  {
322 	     if (tmp->server == server)
323 	       {
324 		  if (tmp == expected)
325 		    {
326 		       set_channel_by_refnum(tmp->refnum, channel);
327 		       new->window = tmp;
328 		       update_all_status();
329 		       return;
330 		    }
331 		  else if (!possible)
332 		    possible = tmp;
333 	       }
334 	  }
335 	if (possible)
336 	  {
337 	     set_channel_by_refnum(possible->refnum, channel);
338 	     new->window = possible;
339 	     update_all_status();
340 	     return;
341 	  }
342 	set_channel_by_refnum(0, channel);
343 	new->window = curr_scr_win;
344      }
345    update_all_windows();
346 }
347 
348 /*
349  * add_to_channel: adds the given nickname to the given channel.  If the
350  * nickname is already on the channel, nothing happens.  If the channel is
351  * not on the channel list, nothing happens (although perhaps the channel
352  * should be addded to the list?  but this should never happen)
353  *
354  * this will return the channel pointer, if you don't need it cast the call
355  * to void.
356  */
357 Channel *
add_to_channel(channel,nick,server,oper,chop,voice,user,host,real,hops,here,serv_str)358 add_to_channel(channel, nick, server,
359 	       oper, chop, voice,
360 	       user, host, real,
361 	       hops, here, serv_str)
362 	u_char	*channel;
363 	u_char	*nick;
364 	int	server;
365 	int	oper;
366 	int	chop;
367 	int	voice;
368 /* ninja extensions! */
369 	u_char	*user;
370 	u_char	*host;
371 	u_char	*real;
372 	int	hops;
373 	int	here;
374 	u_char	*serv_str;
375 {
376    Nick *new;
377    Channel *chan;
378    int ischop = chop;
379    int hasvoice = voice;
380    int isoper = oper;
381 
382    if (!nick)
383      return NULL;
384    if ((chan = lookup_channel(channel, server, CHAN_NOUNLINK)))
385      {
386 	/* these two if statements should never
387 	 * be true with ninja using the WHO command
388 	 * to cache users instead of names
389 	 */
390 	if (*nick == '+')
391 	  {
392 	     hasvoice = 1;
393 	     nick++;
394 	  }
395 	if (*nick == '@')
396 	  {
397 	     nick++;
398 	     if (!my_stricmp(nick, get_server_nickname(server))
399 		 && !(chan->status & CHAN_MODE))
400 	       {
401 		  u_char	*mode = recreate_mode(chan);
402 
403 		  if (*mode)
404 		    {
405 		       int	old_server = from_server;
406 
407 		       from_server = server;
408 		       send_to_server("MODE %s %s", chan->channel, mode);
409 		       from_server = old_server;
410 		    }
411 		  chan->status |= CHAN_CHOP;
412 	       }
413 	     ischop = 1;
414 	  }
415 
416 	if ((new = (Nick *) remove_from_list((List **) &(chan->nicks), nick)))
417 	  free_nick(&new);
418 	new = (Nick *) new_malloc(sizeof(Nick));
419 	/* dma_Malloc already bzero's data
420 	new->nick = (u_char *) 0;
421 	 */
422 	if (ischop == 1)
423 	  new->status |= NICK_CHOP;
424 	if (hasvoice == 1)
425 	  new->status |= NICK_VOICE;
426 	if (isoper == 1)
427 	  new->status |= NICK_OPER;
428 	if (here == 1)
429 	  new->status |= NICK_HERE;
430 	else if (here == 0)
431 	  new->status |= NICK_AWAY;
432 	new->hops = hops;
433 	malloc_strcpy(&(new->nick), nick);
434 	malloc_strcpy(&(new->user), user);
435 	malloc_strcpy(&(new->host), host);
436 	malloc_strcpy(&(new->realname), real);
437 	malloc_strcpy(&(new->server), serv_str);
438 	add_to_list((List **) &(chan->nicks), (List *) new);
439      }
440    if (here != -1) /* don't do this on names output, wait for who output */
441      notify_mark(nick, NFY_ONLINE, !NFY_FROM_QRY, user, host, (new->status & NICK_AWAY));
442    return chan;
443 }
444 
445 
446 /*
447  * recreate_mode: converts the bitmap representation of a channels mode into
448  * a string
449  *
450  * there were some possible overflows in here.. fixed by jjd 9/25/01
451  */
452 static	u_char	*
recreate_mode(chan)453 recreate_mode(chan)
454 	Channel *chan;
455 {
456    int	mode_pos = 0, mode;
457    static	u_char	*s;
458    u_char	buffer[BIG_BUFFER_SIZE];
459    int len, left;
460 
461    memset(buffer, 0, sizeof(buffer));	 /* ultra-paranoia */
462    s = buffer;
463    mode = chan->mode;
464    while (mode && (s-buffer) < (sizeof(buffer)-1))
465      {
466 	if (mode % 2)
467 	  *s++ = mode_str[mode_pos];
468 	mode /= 2;
469 	mode_pos++;
470      }
471    left = sizeof(buffer) - (s - buffer) - 1;
472    if (chan->key
473        && (chan->mode & MODE_KEY)
474        && !get_int_var(HIDE_CHANNEL_KEYS_VAR)
475        && left > 2)
476      {
477 	*s++ = ' ';
478 	len = my_strlen(chan->key);
479 	my_strncpy(s, chan->key, MIN(left, len));
480 	s += len;
481 	left -= len;
482      }
483    if (chan->limit && left > 1)
484      snprintf(CP(s), left, " %d", chan->limit);
485 
486    if (chan->s_mode == empty_string)
487      chan->s_mode = NULL;
488    malloc_strcpy(&chan->s_mode, buffer);
489    return chan->s_mode;
490 }
491 
492 /*
493  * decifer_mode: This will figure out the mode string as returned by mode
494  * commands and convert that mode string into a one byte bit map of modes
495  */
496 static	int
decifer_mode(mode_string,chan,from)497 decifer_mode(mode_string, chan, from)
498 	u_char	*mode_string;
499 	Channel *chan;
500 	u_char	*from;
501 {
502    u_char	*limit = 0;
503    u_char	*person;
504    int	add = 0;
505    int	limit_set = 0;
506    int	limit_reset = 0;
507    u_char	*rest, *the_key;
508    Nick *ThisNick;
509    u_long	value = 0;
510    u_char	*copy, *free_copy = (u_char *) 0;
511    int old_status = 0;
512 
513    dma_strcpy(&free_copy, mode_string);
514    copy = free_copy;
515    if (!(copy = next_arg(copy, &rest)))
516      {
517 	dma_Free(&free_copy);
518 	return -1;
519      }
520    for (; *copy; copy++)
521      {
522 	switch (*copy)
523 	  {
524 	   case '+':
525 	     add = 1;
526 	     value = 0;
527 	     break;
528 	   case '-':
529 	     add = 0;
530 	     value = 0;
531 	     break;
532 /*
533  * Ninja supports 2.8-hybird modes for now
534  *
535 	   case 'a':
536 	     value = MODE_ANONYMOUS;
537 	     break;
538 	   case 'c':
539 	     value = MODE_COLOURLESS;
540 	     break;
541  */
542 	   case 'i':
543 	     value = MODE_INVITE;
544 	     break;
545 	   case 'k':
546 	     value = MODE_KEY;
547 	     the_key = next_arg(rest, &rest);
548 	     if (add)
549 	       malloc_strcpy(&(chan->key), the_key);
550 	     else
551 	       new_free(&(chan->key));
552 	     add_ckey(chan->channel, chan->key);
553 	     break;
554 	   case 'l':
555 	     value = MODE_LIMIT;
556 	     if (add)
557 	       {
558 		  limit_set = 1;
559 		  if (!(limit = next_arg(rest, &rest)))
560 		    limit = empty_string;
561 		  else if (0 == my_strcmp(limit, zero))
562 		    limit_reset = 1, limit_set = 0, add = 0;
563 	       }
564 	     else
565 	       limit_reset = 1;
566 	     break;
567 	   case 'm':
568 	     value = MODE_MODERATED;
569 	     break;
570 	   case 'o':
571 	     /* if its me, update my channel status */
572 	     if ((person = next_arg(rest, &rest)) && !my_stricmp(person, get_server_nickname(from_server))) {
573 		old_status = chan->status;
574 		if (add)
575 		  chan->status |= CHAN_CHOP;
576 		else
577 		  chan->status &= ~CHAN_CHOP;
578 	     }
579 	     /* the nick */
580 	     ThisNick = (Nick *) list_lookup((List **) &(chan->nicks), person, !USE_WILDCARDS, !REMOVE_FROM_LIST);
581 	     if (ThisNick)
582 	       {
583 		  if (add)
584 		    ThisNick->status |= NICK_CHOP;
585 		  else
586 		    ThisNick->status &= ~NICK_CHOP;
587 	       }
588 	     /* if im getting opped and the channel is sync'd, check friends */
589 	     if (add
590 		 && my_stricmp(person, get_server_nickname(from_server)) == 0
591 		 && old_status != chan->status
592 		 && ((chan->status & CHAN_MODE)
593 		     && (chan->status & CHAN_WHO)))
594 	       friends_channel_sync(chan);
595 	     break;
596 	   case 'n':
597 	     value = MODE_MSGS;
598 	     break;
599 	   case 'p':
600 	     value = MODE_PRIVATE;
601 	     break;
602 /*
603 	   case 'q':
604 	     value = MODE_QUIET;
605 	     break;
606 	   case 'r':
607 	     value = MODE_REOP;
608 	     break;
609  */
610 	   case 's':
611 	     value = MODE_SECRET;
612 	     break;
613 	   case 't':
614 	     value = MODE_TOPIC;
615 	     break;
616 	   case 'v':
617 	     person = next_arg(rest, &rest);
618 	     ThisNick = (Nick *) list_lookup((List **) &(chan->nicks), person, !USE_WILDCARDS, !REMOVE_FROM_LIST);
619 	     if (ThisNick)
620 	       {
621 		  if (add)
622 		    ThisNick->status |= NICK_VOICE;
623 		  else
624 		    ThisNick->status &= ~NICK_VOICE;
625 	       }
626 	     break;
627 	     /* ban cache */
628 	   case 'b':
629 	     person = next_arg(rest, &rest);
630 	     if (!person || !*person)
631 	       break;
632 	     if (add)
633 	       {
634 		  u_char tmpstr[32];
635 
636 		  snprintf(tmpstr, sizeof(tmpstr)-1, "%lu", (unsigned long)time(NULL));
637 		  tmpstr[sizeof(tmpstr)-1] = '\0';
638 		  add_ban(chan, person, from, tmpstr);
639 	       }
640 	     else
641 	       {
642 		  Ban *new;
643 		  if ((new = (Ban *) remove_from_list((List **) &(chan->bans), person)))
644 		    {
645 		       dma_Free(&(new->ban));
646 		       dma_Free(&(new->owner));
647 		       dma_Free(&new);
648 		    }
649 	       }
650 	     break;
651 	     /* exception cache */
652 	   case 'e':
653 	     person = next_arg(rest, &rest);
654 	     if (!person || !*person)
655 	       break;
656 	     if (add)
657 	       {
658 		  u_char tmpstr[32];
659 
660 		  snprintf(tmpstr, sizeof(tmpstr)-1, "%lu", (unsigned long)time(NULL));
661 		  tmpstr[sizeof(tmpstr)-1] = '\0';
662 		  /* add_exception(chan, person, from, tmpstr);
663 		   */
664 	       }
665 	     else
666 	       {
667 		  Except *new;
668 		  if ((new = (Except *) remove_from_list((List **) &(chan->excepts), person)))
669 		    {
670 		       dma_Free(&(new->exception));
671 		       dma_Free(&(new->owner));
672 		       dma_Free(&new);
673 		    }
674 	       }
675 	     break;
676 	     /* deny cache */
677 	   case 'd':
678 	     person = next_arg(rest, &rest);
679 	     if (!person || !*person)
680 	       break;
681 	     if (add)
682 	       {
683 		  u_char tmpstr[32];
684 
685 		  snprintf(tmpstr, sizeof(tmpstr)-1, "%lu", (unsigned long)time(NULL));
686 		  tmpstr[sizeof(tmpstr)-1] = '\0';
687 		  /* add_deny(chan, person, from, tmpstr);
688 		   */
689 	       }
690 	     else
691 	       {
692 		  Deny *new;
693 		  if ((new = (Deny *) remove_from_list((List **) &(chan->denys), person)))
694 		    {
695 		       dma_Free(&(new->regexp));
696 		       dma_Free(&(new->owner));
697 		       dma_Free(&new);
698 		    }
699 	       }
700 	     break;
701 	     /* misc unsupported modes w/arguments */
702 	   case 'I':
703 	   case 'O': /* this is a weird special case */
704 	     (void) next_arg(rest, &rest);
705 	     break;
706 /*
707 	   case 'R':
708 	     value = MODE_REGONLY;
709 	     break;
710  */
711 	  }
712 	if (add)
713 	  chan->mode |= value;
714 	else
715 	  chan->mode &= ~value;
716      }
717    if (limit_set)
718      limit_set = my_atoi(limit);
719    else if (limit_reset)
720      limit_set = 0;
721    else
722      limit_set = -1;
723    dma_Free(&free_copy);
724    return limit_set;
725 }
726 
727 /*
728  * get_channel_mode: returns the current mode string for the given channel
729  */
730 u_char	*
get_channel_mode(channel,server)731 get_channel_mode(channel, server)
732 	u_char	*channel;
733 	int	server;
734 {
735    Channel *tmp;
736 
737    if ((tmp = lookup_channel(channel, server, CHAN_NOUNLINK)) && (tmp->status & CHAN_MODE))
738      return recreate_mode(tmp);
739    return empty_string;
740 }
741 
742 /*
743  * update_channel_mode: This will modify the mode for the given channel
744  * according the the new mode given.
745  */
746 void
update_channel_mode(channel,server,mode,from,chan)747 update_channel_mode(channel, server, mode, from, chan)
748 	u_char	*channel;
749 	int	server;
750 	u_char	*mode;
751 	u_char	*from;
752 	Channel *chan;
753 {
754    Channel *tmp;
755    int	limit;
756 
757    if (!chan && !channel)
758      return;
759    if (chan && chan->server == server)
760      tmp = chan;
761    else
762      tmp = lookup_channel(channel, server, CHAN_NOUNLINK);
763    if (!tmp)
764      return;
765    limit = decifer_mode(mode, tmp, from);
766    if (limit != -1)
767      tmp->limit = limit;
768    update_all_status();
769 
770    /* check friend protection... */
771    check_friend_protection(from, tmp, mode);
772 }
773 
774 /*
775  * is_channel_mode: returns the logical AND of the given mode with the
776  * channels mode.  Useful for testing a channels mode
777  *
778  */
779 int
is_channel_mode(channel,mode,server_index)780 is_channel_mode(channel, mode, server_index)
781 	u_char	*channel;
782 	int	mode;
783 	int	server_index;
784 {
785    Channel *tmp;
786 
787    if ((tmp = lookup_channel(channel, server_index, CHAN_NOUNLINK)))
788      return (tmp->mode & mode);
789    return 0;
790 }
791 
792 static	void
free_channel(channel)793 free_channel(channel)
794 	Channel **channel;
795 {
796    clear_channel(*channel);
797    new_free(&(*channel)->channel);
798    new_free(&(*channel)->key);
799    if ((*channel)->s_mode != empty_string)
800      new_free(&(*channel)->s_mode);
801    new_free(&(*channel));
802 }
803 
804 /*
805  * remove_channel: removes the named channel from the
806  * server_list[server].chan_list.  If the channel is not on the
807  * server_list[server].chan_list, nothing happens.  If the channel was
808  * the current channel, this will select the top of the
809  * server_list[server].chan_list to be the current_channel, or 0 if the
810  * list is empty.
811  */
812 void
remove_channel(channel,server)813 remove_channel(channel, server)
814 	u_char	*channel;
815 	int	server;
816 {
817    Channel *tmp;
818 
819    if (channel)
820      {
821 	int refnum = -1;
822 
823 	if ((tmp = lookup_channel(channel, server, CHAN_UNLINK)))
824 	  {
825 	     if (tmp->window)
826 	       refnum = tmp->window->refnum;
827 	     free_channel(&tmp);
828 	  }
829 
830 	(void)is_current_channel(channel, server, refnum);
831      }
832    else
833      {
834 	Channel *next;
835 
836 	for (tmp = server_list[server].chan_list; tmp; tmp = next)
837 	  {
838 	     next = tmp->next;
839 	     free_channel(&tmp);
840 	  }
841 	server_list[server].chan_list = (Channel *) 0;
842      }
843    update_all_windows();
844 }
845 
846 /*
847  * remove_from_channel: removes the given nickname from the given channel. If
848  * the nickname is not on the channel or the channel doesn't exist, nothing
849  * happens.
850  */
851 void
remove_from_channel(channel,nick,server)852 remove_from_channel(channel, nick, server)
853 	u_char	*channel;
854 	u_char	*nick;
855 	int	server;
856 {
857    Channel *chan;
858    Nick *tmp;
859 
860    if (channel)
861      {
862 	if ((chan = lookup_channel(channel, server, CHAN_NOUNLINK)))
863 	  {
864 	     if ((tmp = (Nick *) list_lookup((List **) &(chan->nicks), nick, !USE_WILDCARDS, REMOVE_FROM_LIST)))
865 	       free_nick(&tmp);
866 	  }
867      }
868    else
869      {
870 	for (chan = server_list[server].chan_list; chan; chan = chan->next)
871 	  {
872 	     if ((tmp = (Nick *) list_lookup((List **) &(chan->nicks), nick, !USE_WILDCARDS, REMOVE_FROM_LIST)))
873 	       free_nick(&tmp);
874 	  }
875      }
876 }
877 
878 /*
879  * rename_nick: in response to a changed nickname, this looks up the given
880  * nickname on all you channels and changes it the new_nick
881  */
882 void
rename_nick(old_nick,new_nick,server)883 rename_nick(old_nick, new_nick, server)
884 	u_char	*old_nick,
885 		*new_nick;
886 	int	server;
887 {
888    Channel *chan;
889    Nick *tmp;
890 
891    for (chan = server_list[server].chan_list; chan; chan = chan->next)
892      {
893 	if ((chan->server == server))
894 	  {
895 	     if ((tmp = (Nick *) list_lookup((List **) &chan->nicks, old_nick, !USE_WILDCARDS, !REMOVE_FROM_LIST)))
896 	       {
897 		  /* malloc_strcpy calls free if the pointer is non-null
898 		  new_free(&tmp->nick);
899 		   */
900 		  malloc_strcpy(&tmp->nick, new_nick);
901 	       }
902 	  }
903      }
904 }
905 
906 /*
907  * is_on_channel: returns true if the given nickname is in the given channel,
908  * false otherwise.  Also returns false if the given channel is not on the
909  * channel list.
910  */
911 int
is_on_channel(channel,server,nick)912 is_on_channel(channel, server, nick)
913 	u_char	*channel;
914 	int	server;
915 	u_char	*nick;
916 {
917    Channel *chan;
918 
919    chan = lookup_channel(channel, server, CHAN_NOUNLINK);
920    if (chan && (chan->connected == CHAN_JOINED)
921        /* channel may be "surviving" from a server disconnect/reconnect,
922 	make sure it's connected -Sol */
923        && list_lookup((List **) &(chan->nicks), nick, !USE_WILDCARDS, !REMOVE_FROM_LIST))
924      return 1;
925    return 0;
926 }
927 
928 int
is_chanop(channel,nick)929 is_chanop(channel, nick)
930 	u_char	*channel;
931 	u_char	*nick;
932 {
933    Channel *chan;
934    Nick *tnick;
935 
936    if ((chan = lookup_channel(channel, from_server, CHAN_NOUNLINK)) &&
937        (chan->connected == CHAN_JOINED) &&
938        /* channel may be "surviving" from a disconnect/connect
939 	check here too -Sol */
940        (tnick = (Nick *) list_lookup((List **) &(chan->nicks), nick, !USE_WILDCARDS, !REMOVE_FROM_LIST)) &&
941        (tnick->status & NICK_CHOP))
942      return 1;
943    return 0;
944 }
945 
946 int
has_voice(channel,nick)947 has_voice(channel, nick)
948 	u_char	*channel;
949 	u_char	*nick;
950 {
951    Channel *chan;
952    Nick *tnick;
953 
954    if ((chan = lookup_channel(channel, from_server, CHAN_NOUNLINK)) &&
955        (chan->connected == CHAN_JOINED) &&
956        /* channel may be "surviving" from a disconnect/connect
957 	check here too -Sol */
958        (tnick = (Nick *) list_lookup((List **) &(chan->nicks), nick, !USE_WILDCARDS, !REMOVE_FROM_LIST)) &&
959        (/* come on, this is for voice, not chanops
960 	 * (tnick->status & NICK_CHOP) ||
961 	 */
962 	(tnick->status & NICK_VOICE)))
963      return 1;
964    return 0;
965 }
966 
967 static	void
show_channel(chan)968 show_channel(chan)
969 	Channel *chan;
970 {
971    /*
972    Nick *tmp;
973    int	buffer_len, len;
974    u_char	*nicks = (u_char *) 0;
975    u_char	*s;
976    u_char	buffer[BIG_BUFFER_SIZE];
977 
978    s = recreate_mode(chan);
979    *buffer = (u_char) 0;
980    buffer_len = 0;
981    for (tmp = chan->nicks; tmp; tmp = tmp->next)
982      {
983 	len = my_strlen(tmp->nick);
984 	if (buffer_len + len >= (BIG_BUFFER_SIZE / 2))
985 	  {
986 	     malloc_strcpy(&nicks, buffer);
987 	     say("\t%s +%s (%s): %s", chan->channel, s, get_server_name(chan->server), nicks);
988 	     *buffer = (u_char) 0;
989 	     buffer_len = 0;
990 	  }
991 	my_strmcat(buffer, tmp->nick, BIG_BUFFER_SIZE);
992 	my_strmcat(buffer, " ", BIG_BUFFER_SIZE);
993 	buffer_len += len + 1;
994      }
995    malloc_strcpy(&nicks, buffer);
996    say("\t%s +%s (%s): %s", chan->channel, s, get_server_name(chan->server), nicks);
997    new_free(&nicks);
998     */
999    ninja_scan("SCAN", chan->channel, NULL);
1000 }
1001 
1002 /* list_channels: displays your current channel and your channel list */
1003 void
list_channels()1004 list_channels()
1005 {
1006    Channel *tmp;
1007    int	server, no = 1;
1008    int	first;
1009 
1010    if (connected_to_server < 1)
1011      {
1012 	say("You are not connected to a server, use /SERVER to connect.");
1013 	return;
1014      }
1015    if (get_channel_by_refnum(0))
1016      say("Current channel %s", get_channel_by_refnum(0));
1017    else
1018      say("No current channel for this window");
1019    first = 1;
1020    for (tmp = server_list[get_window_server(0)].chan_list; tmp; tmp = tmp->next)
1021      {
1022 	if (tmp->connected != CHAN_JOINED)
1023 	  continue;
1024 	if (first)
1025 	  say("You are on the following channels:");
1026 	show_channel(tmp);
1027 	first = 0;
1028 	no = 0;
1029      }
1030 
1031    if (connected_to_server > 1)
1032      {
1033 	for (server = 0; server < number_of_servers; server++)
1034 	  {
1035 	     if (server == get_window_server(0))
1036 	       continue;
1037 	     first = 1;
1038 	     for (tmp = server_list[server].chan_list; tmp; tmp = tmp->next)
1039 	       {
1040 		  if (tmp->connected != CHAN_JOINED)
1041 		    continue;
1042 		  if (first)
1043 		    say("Other servers:");
1044 		  show_channel(tmp);
1045 		  first = 0;
1046 		  no = 0;
1047 	       }
1048 	  }
1049      }
1050    if (no)
1051      say("You are not on any channels");
1052 }
1053 
1054 void
switch_channels(key,ptr)1055 switch_channels(key, ptr)
1056 	u_int	key;
1057 	u_char	*ptr;
1058 {
1059    Channel *	tmp;
1060    u_char *	s;
1061 
1062    if (server_list[from_server].chan_list)
1063      {
1064 	if (get_channel_by_refnum(0))
1065 	  {
1066 	     if ((tmp = lookup_channel(get_channel_by_refnum(0), from_server, CHAN_NOUNLINK)))
1067 	       {
1068 		  for (tmp = tmp->next; tmp; tmp = tmp->next)
1069 		    {
1070 		       s = tmp->channel;
1071 		       if (!is_current_channel(s, from_server, 0) && !(is_bound(s, from_server) && curr_scr_win != tmp->window))
1072 			 {
1073 			    set_channel_by_refnum(0, s);
1074 			    update_all_windows();
1075 			    return;
1076 			 }
1077 		    }
1078 	       }
1079 	  }
1080 	for (tmp = server_list[from_server].chan_list; tmp; tmp = tmp->next)
1081 	  {
1082 	     s = tmp->channel;
1083 	     if (!is_current_channel(s, from_server, 0) && !(is_bound(s, from_server) && curr_scr_win != tmp->window))
1084 	       {
1085 		  set_channel_by_refnum(0, s);
1086 		  update_all_windows();
1087 		  return;
1088 	       }
1089 	  }
1090      }
1091 }
1092 
1093 void
change_server_channels(old,new)1094 change_server_channels(old, new)
1095 	int	old,
1096 		new;
1097 {
1098    Channel *tmp;
1099 
1100    if (new == old)
1101      return;
1102    if (old > -1)
1103      {
1104 	for (tmp = server_list[old].chan_list; tmp ;tmp = tmp->next)
1105 	  tmp->server = new;
1106 	server_list[new].chan_list = server_list[old].chan_list;
1107      }
1108    else
1109      server_list[new].chan_list = (Channel *) 0;
1110 }
1111 
1112 void
clear_channel_list(server)1113 clear_channel_list(server)
1114 	int	server;
1115 {
1116    Channel *tmp, *next;
1117    Window		*ptr;
1118    int		flag = 1;
1119 
1120    while ((ptr = traverse_all_windows(&flag)))
1121      if (ptr->server == server && ptr->current_channel)
1122        new_free(&ptr->current_channel);
1123 
1124    for (tmp = server_list[server].chan_list; tmp; tmp = next)
1125      {
1126 	next = tmp->next;
1127 	free_channel(&tmp);
1128      }
1129    server_list[server].chan_list = (Channel *) 0;
1130    return;
1131 }
1132 
1133 /*
1134  * reconnect_all_channels: used after you get disconnected from a server,
1135  * clear each channel nickname list and re-JOINs each channel in the
1136  * channel_list ..
1137  */
1138 void
reconnect_all_channels(server)1139 reconnect_all_channels(server)
1140 	int	server;
1141 {
1142    Channel *tmp = (Channel *) 0;
1143    u_char	*mode, *chan, *key;
1144 
1145    for (tmp = server_list[server].chan_list; tmp; tmp = tmp->next)
1146      {
1147 	chan = tmp->channel;
1148 	if (tmp->key)
1149 	  key = tmp->key;
1150 	else
1151 	  key = get_ckey(chan);
1152 
1153 	if (get_server_version(server) >= Server2_8)
1154 	  send_to_server("JOIN %s%s%s", tmp->channel, key ? " " : "", key ? key : (u_char *) "");
1155 	else
1156 	  {
1157 	     mode = recreate_mode(tmp);
1158 	     send_to_server("JOIN %s%s%s", tmp->channel, mode ? " " : "", mode ? mode : (u_char *) "");
1159 	  }
1160 	tmp->connected = CHAN_JOINING;
1161 	/* mask off the some of the channel cache flags */
1162 	tmp->status = 0;
1163      }
1164 }
1165 
1166 u_char	*
what_channel(nick,server)1167 what_channel(nick, server)
1168 	u_char	*nick;
1169 	int	server;
1170 {
1171    Channel *tmp;
1172 
1173    if (curr_scr_win->current_channel && is_on_channel(curr_scr_win->current_channel, curr_scr_win->server, nick))
1174      return curr_scr_win->current_channel;
1175 
1176    /* XXX: why are we passing "server" when we just use "from_server" */
1177    for (tmp = server_list[from_server].chan_list; tmp; tmp = tmp->next)
1178      if (list_lookup((List **) &(tmp->nicks), nick, !USE_WILDCARDS, !REMOVE_FROM_LIST))
1179        return tmp->channel;
1180 
1181    return (u_char *) 0;
1182 }
1183 
1184 u_char	*
walk_channels(nick,init,server)1185 walk_channels(nick, init, server)
1186 	int	init;
1187 	u_char	*nick;
1188 	int	server;
1189 {
1190    static	Channel *tmp = (Channel *) 0;
1191 
1192    if (init)
1193      tmp = server_list[server].chan_list;
1194    else if (tmp)
1195      tmp = tmp->next;
1196    /* once again?  why from_server ? */
1197    for (;tmp ; tmp = tmp->next)
1198      if ((tmp->server == from_server) && (list_lookup((List **) &(tmp->nicks), nick, !USE_WILDCARDS, !REMOVE_FROM_LIST)))
1199        return (tmp->channel);
1200    return (u_char *) 0;
1201 }
1202 
1203 int
get_channel_oper(channel,server)1204 get_channel_oper(channel, server)
1205 	u_char	*channel;
1206 	int	server;
1207 {
1208    Channel *chan;
1209 
1210    if ((chan = lookup_channel(channel, server, CHAN_NOUNLINK)))
1211      return (chan->status & CHAN_CHOP);
1212    else
1213      return 1;
1214 }
1215 
1216 extern	void
1217 set_channel_window(window, channel, server)
1218 	Window	*window;
1219 	u_char	*channel;
1220 	int	server;
1221 {
1222    Channel	*tmp;
1223 
1224    if (!channel)
1225      return;
1226    for (tmp = server_list[server].chan_list; tmp; tmp = tmp->next)
1227      if (!my_stricmp(channel, tmp->channel))
1228        {
1229 	  tmp->window = window;
1230 	  return;
1231        }
1232 }
1233 
1234 extern	u_char	*
1235 create_channel_list(window)
1236 	Window	*window;
1237 {
1238    Channel	*tmp;
1239    u_char	*value = (u_char *) 0;
1240    u_char	buffer[BIG_BUFFER_SIZE];
1241 
1242    *buffer = '\0';
1243    for (tmp = server_list[window->server].chan_list; tmp; tmp = tmp->next)
1244      {
1245 	if (*buffer != '\0')
1246 	  my_strmcat(buffer, " ", sizeof(buffer)-1);
1247 	my_strmcat(buffer, tmp->channel, sizeof(buffer)-1);
1248      }
1249    malloc_strcpy(&value, buffer);
1250 
1251    return value;
1252 }
1253 
1254 extern void
1255 channel_server_delete(server)
1256 	int     server;
1257 {
1258    Channel     *tmp;
1259    int	i;
1260 
1261    for (i = server + 1; i < number_of_servers; i++)
1262      for (tmp = server_list[i].chan_list ; tmp; tmp = tmp->next)
1263        if (tmp->server >= server)
1264 	 tmp->server--;
1265 }
1266 
1267 extern	int
1268 chan_is_connected(channel, server)
1269 	u_char *	channel;
1270 	int	server;
1271 {
1272    Channel *	cp = lookup_channel(channel, server, CHAN_NOUNLINK);
1273 
1274    if (!cp)
1275      return 0;
1276 
1277    return (cp->connected == CHAN_JOINED);
1278 }
1279 
1280 void
mark_not_connected(server)1281 mark_not_connected(server)
1282 	int	server;
1283 {
1284    Channel	*tmp;
1285 
1286    for (tmp = server_list[server].chan_list; tmp; tmp = tmp->next)
1287      tmp->connected = CHAN_LIMBO;
1288 }
1289 
1290 /*
1291  * take the string specified in "chan" and make it into a channel name.
1292  *
1293  * basically, if there's a & or # at the beginning, get out.
1294  * otherwise we prepend a #
1295  *
1296  * uses a static buffer, so multiple calls on the same line won't work properly.
1297  * ie: printf("%s %s\n", make_chan("hi"), make_chan("yo"));
1298  * would print:
1299  * #yo #yo
1300  */
1301 u_char *
make_chan(u_char * chan)1302 make_chan(u_char *chan)
1303 {
1304    static u_char channel[256];
1305 
1306    /* this should never happen. */
1307    if (!chan || !*chan)
1308      return channel;
1309 
1310    /* this code used to do more, but now it just does this: */
1311      else if (!is_channel(chan))
1312      {
1313 	channel[0] = '\0';
1314 	my_strmcat(channel, "#", sizeof(channel)-1);
1315 	my_strmcat(channel, chan, sizeof(channel)-1);
1316 	return channel;
1317      }
1318    return chan;
1319 }
1320 
1321 /*
1322  * is the channel cached?
1323  *
1324  * this is only called in one place, then end of nincache.c
1325  *
1326  * it is reponsible for printing the join sync time if needed
1327  */
1328 int
chk_channel_cached(chan)1329 chk_channel_cached(chan)
1330    u_char *chan;
1331 {
1332    Channel *c;
1333 
1334    if (!chan)
1335      return 0;
1336    c = lookup_channel(chan, parsing_server_index, CHAN_NOUNLINK);
1337    if (!c)
1338      return 0;
1339    /* if mode, who, or bans isn't cached then neither is the channel..
1340     * there's also CHAN_TIME but i'm not sure what all server support it..
1341     */
1342    if (!(c->status & CHAN_MODE)
1343        || !(c->status & CHAN_WHO)
1344        || !(c->status & CHAN_BANS))
1345      return 0;
1346 
1347    /* if the extra channel mode stuff isn't cached, still not!
1348     *
1349     * these aren't implemented yet
1350     *
1351    if ((server_list[chan->server].cmodes
1352 	&& my_index(server_list[chan->server].cmodes, 'e')
1353 	&& !(chan->status & CHAN_EXCEPT))
1354        || (server_list[chan->server].cmodes
1355 	   && my_index(server_list[chan->server].cmodes, 'd')
1356 	   && !(chan->status & CHAN_DENY)))
1357      return 0;
1358     */
1359 #ifdef SHOW_JOIN_TIME
1360    if (!(c->status & CHAN_SHOWED_TIME))
1361      {
1362 	struct timeval tv, td;
1363 	gettimeofday(&tv, NULL);
1364 	td.tv_sec = tv.tv_sec - c->join_time.tv_sec;
1365 	td.tv_usec = tv.tv_usec - c->join_time.tv_usec;
1366 	save_message_from();
1367 	message_from(c->channel, LOG_CRAP);
1368 	put_info("Channel %s cached in %0.3f seconds.",
1369 		 c->channel,
1370 		 (double)td.tv_sec + ((double)td.tv_usec / 1000000.0));
1371 	restore_message_from();
1372 	c->status |= CHAN_SHOWED_TIME;
1373      }
1374 #endif
1375 
1376    return 1;
1377 }
1378 
1379 /*
1380  * is_channel: determines if the argument is a channel.  If it's a number,
1381  * begins with MULTI_CHANNEL and has no '*', or STRING_CHANNEL, then its a
1382  * channel
1383  */
1384 int
is_channel(to)1385 is_channel(to)
1386    u_char *to;
1387 {
1388    int version;
1389 
1390    if (to == 0)
1391      return 0;
1392    version = get_server_version(from_server);
1393    return ((version < Server2_7 && (isdigit(*to) || (*to == STRING_CHANNEL)
1394 				    || *to == '-'))
1395 	   || (version > Server2_5 && *to == MULTI_CHANNEL)
1396 	   || (version > Server2_7 && *to == LOCAL_CHANNEL)
1397 	   || (version > Server2_8 && *to == STRING_CHANNEL)
1398 	   || (version > Server2_9 && *to == SAFE_CHANNEL)
1399 #ifdef SUPPORT_ICB
1400 	   || (version == ServerICB && my_stricmp(to, get_server_icbgroup(from_server)) == 0)
1401 #endif
1402 	    );
1403 }
1404 
1405