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-2017 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 
36 #include "irc.h"
37 IRCII_RCSID("@(#)$eterna: names.c,v 1.145 2018/06/10 00:21:02 mrg Exp $");
38 
39 #include "ircaux.h"
40 #include "names.h"
41 #include "window.h"
42 #include "screen.h"
43 #include "server.h"
44 #include "lastlog.h"
45 #include "list.h"
46 #include "output.h"
47 #include "notify.h"
48 #include "vars.h"
49 #include "sl_irc.h"
50 
51 /* NickList: structure for the list of nicknames of people on a channel */
52 struct nick_stru
53 {
54 	NickList *next;		/* pointer to next nickname entry */
55 	u_char	*nick;		/* nickname of person on channel */
56 	int	chanop;		/* True if the given nick has chanop */
57 	int	hasvoice;	/* Has voice? (Notice this is a bit
58 				 * unreliable if chanop) */
59 };
60 
61 /* ChannelList: structure for the list of channels you are current on */
62 struct	channel_stru
63 {
64 	ChannelList *next;	/* pointer to next channel entry */
65 	u_char	*channel;	/* channel name */
66 	int	server;		/* server index for this channel */
67 	u_int	mode;		/* current mode settings for channel */
68 	u_char	*s_mode;	/* string representation of the above */
69 	int	limit;		/* max users for the channel */
70 	u_char	*key;		/* key for this channel */
71 	ChanListConnected connected;	/* connection status */
72 	Window	*window;	/* the window that the channel is "on" */
73 	NickList *nicks;	/* pointer to list of nicks on channel */
74 	ChanListStatus status;	/* different flags */
75 };
76 
77 /* from names.h */
78 static	u_char	mode_str[] = MODE_STRING;
79 
80 static	int	same_channel(ChannelList *, u_char *);
81 static	void	free_channel(ChannelList **);
82 static	void	show_channel(ChannelList *);
83 static	void	clear_channel(ChannelList *);
84 static	u_char	*recreate_mode(ChannelList *);
85 static	int	decifer_mode(u_char *, u_int *, ChanListStatus *,
86 			     NickList **, u_char **);
87 static	int	switch_channels_backend(ChannelList *);
88 
89 /* clear_channel: erases all entries in a nick list for the given channel */
90 static	void
clear_channel(ChannelList * chan)91 clear_channel(ChannelList *chan)
92 {
93 	NickList *tmp,
94 		*next;
95 
96 	for (tmp = chan->nicks; tmp; tmp = next)
97 	{
98 		next = tmp->next;
99 		new_free(&tmp->nick);
100 		new_free(&tmp);
101 	}
102 	chan->nicks = NULL;
103 	chan->status &= ~CHAN_NAMES;
104 }
105 
106 /*
107  * we need this to deal with !channels.
108  */
109 static	int
same_channel(ChannelList * chan,u_char * channel)110 same_channel(ChannelList *chan, u_char	*channel)
111 {
112 	size_t	len, len2;
113 
114 	/* take the easy way out */
115 	if (*chan->channel != '!' && *channel != '!')
116 		return (!my_stricmp(chan->channel, channel));
117 
118 	/*
119 	 * OK, so what we have is chan->channel = "!!foo" and
120 	 * channel = "!JUNKfoo".
121 	 */
122 	len = my_strlen(chan->channel);
123 	len2 = my_strlen(channel);
124 
125 	/* bail out on known stuff */
126 	if (len > len2)
127 		return (0);
128 	if (len == len2)
129 		return (!my_stricmp(chan->channel, channel));
130 
131 	/*
132 	 * replace the channel name if we are the same!
133 	 */
134 	if (!my_stricmp(chan->channel + 2, channel + 2 + (len2 - len)))
135 	{
136 		malloc_strcpy(&chan->channel, channel);
137 		return 1;
138 	}
139 	return 0;
140 }
141 
142 ChannelList *
lookup_channel(u_char * channel,int server,int do_unlink)143 lookup_channel(u_char *channel, int server, int do_unlink)
144 {
145 	ChannelList	*chan, *last = NULL;
146 
147 	if (!channel || !*channel ||
148 	    (server == -1 && (server = get_primary_server()) == -1))
149 		return NULL;
150 	chan = server_get_chan_list(server);
151 	while (chan)
152 	{
153 		if (chan->server == server && same_channel(chan, channel))
154 		{
155 			if (do_unlink == CHAN_UNLINK)
156 			{
157 				if (last)
158 					last->next = chan->next;
159 				else
160 					server_set_chan_list(server, chan->next);
161 			}
162 			break;
163 		}
164 		last = chan;
165 		chan = chan->next;
166 	}
167 	return chan;
168 }
169 
170 /*
171  * add_channel: adds the named channel to the channel list.  If the channel
172  * is already in the list, its attributes are modified accordingly with the
173  * connected and copy parameters.
174  */
175 void
add_channel(u_char * channel,u_char * key,int server,int connected,ChannelList * copy)176 add_channel(u_char *channel, u_char *key, int server, int connected,
177 	    ChannelList *copy)
178 {
179 	ChannelList *new;
180 	int	do_add = 0;
181 
182 	/*
183 	 * avoid adding channel "0"
184 	 */
185 	if (channel[0] == '0' && channel[1] == '\0')
186 		return;
187 
188 	if ((new = lookup_channel(channel, server, CHAN_NOUNLINK)) == NULL)
189 	{
190 		ChannelList *full_list;
191 
192 		new = new_malloc(sizeof *new);
193 		new->channel = NULL;
194 		new->status = 0;
195 		new->key = 0;
196 		if (key)
197 			malloc_strcpy(&new->key, key);
198 		new->nicks = NULL;
199 		new->s_mode = empty_string();
200 		malloc_strcpy(&new->channel, channel);
201 		new->mode = 0;
202 		new->limit = 0;
203 		do_add = 1;
204 		full_list = server_get_chan_list(server);
205 		if ((new->window = is_bound(channel, server)) == NULL)
206 			new->window = curr_scr_win;
207 		add_to_list((List **)(void *)&full_list, (List *) new);
208 		server_set_chan_list(server, full_list);
209 	}
210 	else
211 	{
212 		if (new->connected != CHAN_LIMBO &&
213 		    new->connected != CHAN_JOINING)
214 			yell("--- add_channel: add_channel found channel "
215 			     "not CHAN_LIMBO/JOINING: %s", new->channel);
216 	}
217 	if (do_add || (connected == CHAN_JOINED))
218 	{
219 		new->server = server;
220 		clear_channel(new);
221 	}
222 	if (copy)
223 	{
224 		new->mode = copy->mode;
225 		new->limit = copy->limit;
226 		new->window = copy->window;
227 		malloc_strcpy(&new->key, copy->key);
228 	}
229 	new->connected = connected;
230 	if (connected == CHAN_JOINED && !is_current_channel(channel, server, 0))
231 	{
232 		Win_Trav wt;
233 		Window	*tmp, *expected,
234 			*possible = NULL;
235 
236 		expected = is_bound(channel, server);
237 		if (expected == NULL)
238 			expected = new->window;
239 
240 		wt.init = 1;
241 		while ((tmp = window_traverse(&wt)))
242 		{
243 			if (window_get_server(tmp) == server)
244 			{
245 				if (tmp == expected)
246 				{
247 					set_channel_by_refnum(window_get_refnum(tmp),
248 							      channel);
249 					new->window = tmp;
250 					update_all_status();
251 					return;
252 				}
253 				else if (!possible)
254 					possible = tmp;
255 			}
256 		}
257 		if (possible)
258 		{
259 			set_channel_by_refnum(window_get_refnum(possible), channel);
260 			new->window = possible;
261 			update_all_status();
262 			return;
263 		}
264 		set_channel_by_refnum(0, channel);
265 		new->window = curr_scr_win;
266 	}
267 	update_all_windows();
268 }
269 
270 void
rename_channel(u_char * oldchan,u_char * newchan,int server)271 rename_channel(u_char *oldchan, u_char *newchan, int server)
272 {
273 	ChannelList *new;
274 
275 	if (!oldchan || !*oldchan || !newchan || !*newchan)
276 		return;
277 	new = lookup_channel(oldchan, server, CHAN_NOUNLINK);
278 	if (!new)
279 		return;
280 
281 	malloc_strcpy(&new->channel, newchan);
282 	if (new->window)
283 		set_channel_by_refnum(window_get_refnum(new->window), newchan);
284 
285 	/* are these necessary? */
286 	update_all_status();
287 	update_all_windows();
288 }
289 
290 /*
291  * add_to_channel: adds the given nickname to the given channel.  If the
292  * nickname is already on the channel, nothing happens.  If the channel is
293  * not on the channel list, nothing happens (although perhaps the channel
294  * should be addded to the list?  but this should never happen)
295  */
296 void
add_to_channel(u_char * channel,u_char * nick,int server,int oper,int voice)297 add_to_channel(u_char *channel, u_char *nick, int server, int oper, int voice)
298 {
299 	NickList *new;
300 	ChannelList *chan;
301 	int	ischop = oper;
302 	int	hasvoice = voice;
303 
304 	if ((chan = lookup_channel(channel, server, CHAN_NOUNLINK)))
305 	{
306 		if (*nick == '+')
307 		{
308 			hasvoice = 1;
309 			nick++;
310 		}
311 		if (*nick == '@')
312 		{
313 			nick++;
314 			if (!my_stricmp(nick, server_get_nickname(server))
315 			    && !((chan->status & CHAN_NAMES)
316 				 && (chan->status & CHAN_MODE)))
317 			{
318 				u_char	*mode = recreate_mode(chan);
319 
320 				if (*mode)
321 				{
322 					int	old_server;
323 
324 					old_server = set_from_server(server);
325 					send_to_server("MODE %s %s",
326 					    chan->channel, mode);
327 					set_from_server(old_server);
328 				}
329 				chan->status |= CHAN_CHOP;
330 			}
331 			ischop = 1;
332 		}
333 
334 		if ((new = (NickList *)
335 		     remove_from_list((List **)(void *)&(chan->nicks), nick)))
336 		{
337 			new_free(&new->nick);
338 			new_free(&new);
339 		}
340 		new = new_malloc(sizeof *new);
341 		new->nick = NULL;
342 		new->chanop = ischop;
343 		new->hasvoice = hasvoice;
344 		malloc_strcpy(&(new->nick), nick);
345 		add_to_list((List **)(void *)&(chan->nicks), (List *) new);
346 	}
347 	notify_mark(nick, 1, 0);
348 }
349 
350 
351 /*
352  * recreate_mode: converts the bitmap representation of a channels mode into
353  * a string
354  */
355 static	u_char	*
recreate_mode(ChannelList * chan)356 recreate_mode(ChannelList *chan)
357 {
358 	u_int	mode;
359 	int	mode_pos = 0,
360 		showkey;
361 	static	u_char	*s;
362 	u_char	modes[33],	/* XXX: 32 bit u_int, also limited by mode_str[] */
363 		limit[33];
364 
365 	limit[0] = '\0';
366 	s = modes;
367 	mode = chan->mode;
368 	while (mode)
369 	{
370 		if (mode % 2)
371 			*s++ = mode_str[mode_pos];
372 		mode /= 2;
373 		mode_pos++;
374 	}
375 	*s = '\0';
376 	showkey = chan->key && *chan->key && !get_int_var(HIDE_CHANNEL_KEYS_VAR);
377 	if (chan->limit)
378 		snprintf(CP(limit), sizeof limit, " %d", chan->limit);
379 
380 	malloc_snprintf(&chan->s_mode, "%s%s%s%s",
381 		modes,
382 		showkey ? UP(" ") : empty_string(),
383 		showkey ? chan->key : empty_string(),
384 		limit);
385 
386 	return chan->s_mode;
387 }
388 
389 /*
390  * decifer_mode: This will figure out the mode string as returned by mode
391  * commands and convert that mode string into a one byte bit map of modes
392  */
393 static	int
decifer_mode(u_char * mode_string,u_int * mode,ChanListStatus * chop,NickList ** nicks,u_char ** key)394 decifer_mode(u_char *mode_string, u_int *mode, ChanListStatus *chop,
395 	     NickList **nicks, u_char **key)
396 {
397 	u_char	*limit = 0;
398 	u_char	*person;
399 	int	add = 0;
400 	int	limit_set = 0;
401 	int	limit_reset = 0;
402 	u_char	*rest,
403 		*the_key;
404 	NickList *ThisNick;
405 	u_int	value = 0;
406 
407 	if (!(mode_string = next_arg(mode_string, &rest)))
408 		return -1;
409 	for (; *mode_string; mode_string++)
410 	{
411 		switch (*mode_string)
412 		{
413 		case '+':
414 			add = 1;
415 			value = 0;
416 			break;
417 		case '-':
418 			add = 0;
419 			value = 0;
420 			break;
421 		case 'a':
422 			value = MODE_ANONYMOUS;
423 			break;
424 		case 'c':
425 			value = MODE_COLOURLESS;
426 			break;
427 		case 'i':
428 			value = MODE_INVITE;
429 			break;
430 		case 'k':
431 			value = MODE_KEY;
432 			the_key = next_arg(rest, &rest);
433 			if (add)
434 				malloc_strcpy(key, the_key);
435 			else
436 				new_free(key);
437 			break;
438 		case 'l':
439 			value = MODE_LIMIT;
440 			if (add)
441 			{
442 				limit_set = 1;
443 				if (!(limit = next_arg(rest, &rest)))
444 					limit = empty_string();
445 				else if (0 == my_strncmp(limit, zero(), 1))
446 					limit_reset = 1, limit_set = 0, add = 0;
447 			}
448 			else
449 				limit_reset = 1;
450 			break;
451 		case 'm':
452 			value = MODE_MODERATED;
453 			break;
454 		case 'o':
455 			if ((person = next_arg(rest, &rest)) &&
456 			    !my_stricmp(person,
457 					server_get_nickname(get_from_server()))) {
458 				if (add)
459 					*chop |= CHAN_CHOP;
460 				else
461 					*chop &= ~CHAN_CHOP;
462 			}
463 			ThisNick = (NickList *)
464 				list_lookup((List **)(void *)nicks, person,
465 					    0, 0);
466 			if (ThisNick)
467 				ThisNick->chanop = add;
468 			break;
469 		case 'n':
470 			value = MODE_MSGS;
471 			break;
472 		case 'p':
473 			value = MODE_PRIVATE;
474 			break;
475 		case 'q':
476 			value = MODE_QUIET;
477 			break;
478 		case 'r':
479 			value = MODE_REOP;
480 			break;
481 		case 's':
482 			value = MODE_SECRET;
483 			break;
484 		case 't':
485 			value = MODE_TOPIC;
486 			break;
487 		case 'v':
488 			person = next_arg(rest, &rest);
489 			ThisNick = (NickList *)
490 				list_lookup((List **) nicks, person,
491 					    0, 0);
492 			if (ThisNick)
493 				ThisNick->hasvoice = add;
494 			break;
495 		case 'b':
496 		case 'e':
497 		case 'I':
498 		case 'O': /* this is a weird special case */
499 			(void) next_arg(rest, &rest);
500 			break;
501 		case 'R':
502 			value = MODE_REGONLY;
503 			break;
504 		}
505 		if (add)
506 			*mode |= value;
507 		else
508 			*mode &= ~value;
509 	}
510 	if (limit_set)
511 		return (my_atoi(limit));
512 	else if (limit_reset)
513 		return(0);
514 	else
515 		return(-1);
516 }
517 
518 /*
519  * get_channel_mode: returns the current mode string for the given channel
520  */
521 u_char	*
get_channel_mode(u_char * channel,int server)522 get_channel_mode(u_char *channel, int server)
523 {
524 	ChannelList *tmp;
525 
526 	if ((tmp = lookup_channel(channel, server, CHAN_NOUNLINK)) &&
527 	    (tmp->status & CHAN_MODE))
528 		return recreate_mode(tmp);
529 	return empty_string();
530 }
531 
532 /*
533  * update_channel_mode: This will modify the mode for the given channel
534  * according the the new mode given.
535  */
536 void
update_channel_mode(u_char * channel,int server,u_char * mode)537 update_channel_mode(u_char *channel, int server, u_char *mode)
538 {
539 	ChannelList *tmp;
540 	int	limit;
541 
542 	if ((tmp = lookup_channel(channel, server, CHAN_NOUNLINK)) &&
543 	    (limit = decifer_mode(mode, &tmp->mode, &tmp->status,
544 				  &tmp->nicks, &tmp->key)) != -1)
545 		tmp->limit = limit;
546 }
547 
548 /*
549  * is_channel_mode: returns the logical AND of the given mode with the
550  * channels mode.  Useful for testing a channels mode
551  */
552 int
is_channel_mode(u_char * channel,u_int mode,int server_index)553 is_channel_mode(u_char *channel, u_int mode, int server_index)
554 {
555 	ChannelList *tmp;
556 
557 	if ((tmp = lookup_channel(channel, server_index, CHAN_NOUNLINK)))
558 		return (tmp->mode & mode);
559 	return 0;
560 }
561 
562 static	void
free_channel(ChannelList ** channel)563 free_channel(ChannelList **channel)
564 {
565 	clear_channel(*channel);
566 	new_free(&(*channel)->channel);
567 	new_free(&(*channel)->key);
568 	new_free(&(*channel)->s_mode);
569 	new_free(&(*channel));
570 }
571 
572 /*
573  * remove_channel: removes the named channel from the specified
574  * server's channel list.
575  * If the channel is not on the this list, nothing happens.
576  * If the channel was the current channel, this will select the top of
577  * the channel list to be the current_channel, or 0 if the list is empty.
578  */
579 void
remove_channel(u_char * channel,int server)580 remove_channel(u_char *channel, int server)
581 {
582 	ChannelList *tmp;
583 
584 	if (channel)
585 	{
586 		int refnum = -1;
587 
588 		tmp = lookup_channel(channel, server, CHAN_UNLINK);
589 		if (tmp)
590 		{
591 			if (tmp->window)
592 				refnum = window_get_refnum(tmp->window);
593 			free_channel(&tmp);
594 		}
595 
596 		(void)is_current_channel(channel, server, refnum);
597 	}
598 	else
599 	{
600 		ChannelList *next;
601 
602 		for (tmp = server_get_chan_list(server); tmp; tmp = next)
603 		{
604 			next = tmp->next;
605 			free_channel(&tmp);
606 		}
607 		server_set_chan_list(server, NULL);
608 	}
609 	update_all_windows();
610 }
611 
612 /*
613  * remove_from_channel: removes the given nickname from the given channel. If
614  * the nickname is not on the channel or the channel doesn't exist, nothing
615  * happens.
616  */
617 void
remove_from_channel(u_char * channel,u_char * nick,int server)618 remove_from_channel(u_char *channel, u_char *nick, int server)
619 {
620 	ChannelList *chan;
621 	NickList *tmp;
622 
623 	if (channel)
624 	{
625 		if ((chan = lookup_channel(channel, server, CHAN_NOUNLINK)))
626 		{
627 			if ((tmp = (NickList *)
628 				list_lookup((List **)(void *)&chan->nicks, nick,
629 					    0, REMOVE_FROM_LIST)))
630 			{
631 				new_free(&tmp->nick);
632 				new_free(&tmp);
633 			}
634 		}
635 	}
636 	else
637 	{
638 		for (chan = server_get_chan_list(server); chan; chan = chan->next)
639 		{
640 			if ((tmp = (NickList *)
641 				list_lookup((List **)(void *)&chan->nicks, nick,
642 					    0, REMOVE_FROM_LIST)))
643 			{
644 				new_free(&tmp->nick);
645 				new_free(&tmp);
646 			}
647 		}
648 	}
649 }
650 
651 /*
652  * rename_nick: in response to a changed nickname, this looks up the given
653  * nickname on all you channels and changes it the new_nick
654  */
655 void
rename_nick(u_char * old_nick,u_char * new_nick,int server)656 rename_nick(u_char *old_nick, u_char *new_nick, int server)
657 {
658 	ChannelList *chan;
659 	NickList *tmp;
660 
661 	for (chan = server_get_chan_list(server); chan; chan = chan->next)
662 	{
663 		if ((chan->server == server) != 0)
664 		{
665 			if ((tmp = (NickList *)
666 				list_lookup((List **)(void *)&chan->nicks,
667 					    old_nick, 0, 0)))
668 			{
669 				new_free(&tmp->nick);
670 				malloc_strcpy(&tmp->nick, new_nick);
671 			}
672 		}
673 	}
674 }
675 
676 /*
677  * is_on_channel: returns true if the given nickname is in the given channel,
678  * false otherwise.  Also returns false if the given channel is not on the
679  * channel list.
680  */
681 int
is_on_channel(u_char * channel,int server,u_char * nick)682 is_on_channel(u_char *channel, int server, u_char *nick)
683 {
684 	ChannelList *chan;
685 
686 	chan = lookup_channel(channel, server, CHAN_NOUNLINK);
687 	if (chan && (chan->connected == CHAN_JOINED)
688 	    && list_lookup((List **)(void *)&(chan->nicks), nick, 0, 0))
689 		return 1;
690 	return 0;
691 }
692 
693 int
is_chanop(u_char * channel,u_char * nick)694 is_chanop(u_char *channel, u_char *nick)
695 {
696 	ChannelList *chan;
697 	NickList *Nick;
698 
699 	if ((chan = lookup_channel(channel, get_from_server(), CHAN_NOUNLINK)) &&
700 	    chan->connected == CHAN_JOINED &&
701 	    /* channel may be "surviving" from a disconnect/connect
702 						check here too -Sol */
703 	    (Nick = (NickList *) list_lookup((List **)(void *)&(chan->nicks),
704 					     nick, 0, 0)) &&
705 	    Nick->chanop)
706 		return 1;
707 	return 0;
708 }
709 
710 int
has_voice(u_char * channel,u_char * nick,int server)711 has_voice(u_char *channel, u_char *nick, int server)
712 {
713 	ChannelList *chan;
714 	NickList *Nick;
715 
716 	if (channel && *channel &&
717 	    (chan = lookup_channel(channel, server, CHAN_NOUNLINK)) &&
718 	    chan->connected == CHAN_JOINED &&
719 		/* channel may be "surviving" from a disconnect/connect
720 						   check here too -Sol */
721 	    (Nick = (NickList *) list_lookup((List **)(void *)&(chan->nicks), nick,
722 					     0, 0)) &&
723 	    (Nick->chanop || Nick->hasvoice))
724 		return 1;
725 	return 0;
726 }
727 
728 static	void
show_channel(ChannelList * chan)729 show_channel(ChannelList *chan)
730 {
731 	NickList *tmp;
732 	size_t	buffer_len,
733 		len;
734 	u_char	*mode;
735 	StringList *sl;
736 
737 	mode = recreate_mode(chan);
738 	sl = sl_init();
739 	buffer_len = 0;
740 	for (tmp = chan->nicks; tmp; tmp = tmp->next)
741 	{
742 		len = my_strlen(tmp->nick);
743 		if (buffer_len + len >= get_co() - 5)
744 		{
745 			u_char	*buffer = sl_concat(sl, UP(" "));
746 			say("\t%s +%s (%s): %s", chan->channel, mode,
747 			    server_get_name(chan->server), buffer);
748 			new_free(&buffer);
749 			sl_free(sl, 0);
750 			sl = sl_init();
751 			buffer_len = 0;
752 		}
753 		sl_add(sl, CP(tmp->nick));
754 		buffer_len += len + 1;
755 	}
756 	if (sl_size(sl))
757 	{
758 		u_char	*buffer = sl_concat(sl, UP(" "));
759 		say("\t%s +%s (%s): %s", chan->channel, mode,
760 		    server_get_name(chan->server), buffer);
761 		new_free(&buffer);
762 	}
763 	sl_free(sl, 0);
764 }
765 
766 /* list_channels: displays your current channel and your channel list */
767 void
list_channels(void)768 list_channels(void)
769 {
770 	ChannelList *tmp;
771 	int	server,
772 		no = 1;
773 	int	first;
774 
775 	if (connected_to_server() < 1)
776 	{
777 		say("You are not connected to a server, use /SERVER to connect.");
778 		return;
779 	}
780 	if (get_channel_by_refnum(0))
781 		say("Current channel %s", get_channel_by_refnum(0));
782 	else
783 		say("No current channel for this window");
784 	first = 1;
785 	for (tmp = server_get_chan_list(get_window_server(0));
786 	     tmp; tmp = tmp->next)
787 	{
788 		if (tmp->connected != CHAN_JOINED)
789 			continue;
790 		if (first)
791 			say("You are on the following channels:");
792 		show_channel(tmp);
793 		first = 0;
794 		no = 0;
795 	}
796 
797 	if (connected_to_server() > 1)
798 	{
799 		for (server = 0; server < number_of_servers(); server++)
800 		{
801 			if (server == get_window_server(0))
802 				continue;
803 			first = 1;
804 			for (tmp = server_get_chan_list(server);
805 			     tmp; tmp = tmp->next)
806 			{
807 				if (tmp->connected != CHAN_JOINED)
808 					continue;
809 				if (first)
810 					say("Other servers:");
811 				show_channel(tmp);
812 				first = 0;
813 				no = 0;
814 			}
815 		}
816 	}
817 	if (no)
818 		say("You are not on any channels");
819 }
820 
821 /*
822  * backend of switch_channels().
823  */
824 static int
switch_channels_backend(ChannelList * chan)825 switch_channels_backend(ChannelList * chan)
826 {
827 	u_char *newchan;
828 	const	int	from_server = get_from_server();
829 
830 	for (; chan; chan = chan->next)
831 	{
832 		newchan = chan->channel;
833 		if (!is_current_channel(newchan, from_server, 0)
834 		    && !(is_bound(newchan, from_server)
835 			 && curr_scr_win != chan->window)
836 		    && (get_int_var(SWITCH_TO_QUIET_CHANNELS)
837 		        || !(chan->mode & MODE_QUIET)))
838 		{
839 			set_channel_by_refnum(0, newchan);
840 			update_all_windows();
841 			return 0;
842 		}
843 	}
844 	return 1;
845 }
846 
847 void
switch_channels(u_int key,u_char * ptr)848 switch_channels(u_int key, u_char *ptr)
849 {
850 	ChannelList *	tmp;
851 	const	int	from_server = get_from_server();
852 
853 	if (server_get_chan_list(from_server) &&
854 	    get_channel_by_refnum(0) &&
855 	    (tmp = lookup_channel(get_channel_by_refnum(0), from_server,
856 				  CHAN_NOUNLINK)) &&
857 	    switch_channels_backend(tmp->next))
858 		switch_channels_backend(server_get_chan_list(from_server));
859 }
860 
861 void
change_server_channels(int old,int new)862 change_server_channels(int old, int new)
863 {
864 	ChannelList *tmp;
865 
866 	if (new == old)
867 		return;
868 	if (old > -1)
869 	{
870 		for (tmp = server_get_chan_list(old); tmp ;tmp = tmp->next)
871 			tmp->server = new;
872 		server_set_chan_list(new, server_get_chan_list(old));
873 	}
874 	else
875 		server_set_chan_list(new, NULL);
876 }
877 
878 void
clear_channel_list(int server)879 clear_channel_list(int server)
880 {
881 	ChannelList *tmp, *next;
882 	Window	*ptr;
883 	Win_Trav wt;
884 
885 	wt.init = 1;
886 	while ((ptr = window_traverse(&wt)))
887 		if (window_get_server(ptr) == server && window_get_current_channel(ptr))
888 			window_set_current_channel(ptr, NULL);
889 
890 	for (tmp = server_get_chan_list(server); tmp; tmp = next)
891 	{
892 		next = tmp->next;
893 		free_channel(&tmp);
894 	}
895 	server_set_chan_list(server, NULL);
896 	return;
897 }
898 
899 /*
900  * reconnect_all_channels: used after you get disconnected from a server,
901  * clear each channel nickname list and re-JOINs each channel in the
902  * channel_list ..
903  */
904 void
reconnect_all_channels(int server)905 reconnect_all_channels(int server)
906 {
907 	ChannelList *tmp = NULL;
908 	u_char	*mode, *chan;
909 
910 	for (tmp = server_get_chan_list(server); tmp; tmp = tmp->next)
911 	{
912 		mode = recreate_mode(tmp);
913 		chan = tmp->channel;
914 		if (server_get_version(server) >= Server2_8)
915 			send_to_server("JOIN %s%s%s", chan, tmp->key ? " " : "",
916 				       tmp->key ? tmp->key : (u_char *) "");
917 		else
918 			send_to_server("JOIN %s%s%s", chan, mode ? " " : "",
919 				       mode ? mode : (u_char *) "");
920 		tmp->connected = CHAN_JOINING;
921 	}
922 }
923 
924 u_char	*
what_channel(u_char * nick,int server)925 what_channel(u_char *nick, int server)
926 {
927 	ChannelList *tmp;
928 	u_char *channel = window_get_current_channel(curr_scr_win);
929 
930 	if (channel && is_on_channel(channel, window_get_server(curr_scr_win),
931 				     nick))
932 		return channel;
933 
934 	for (tmp = server_get_chan_list(get_from_server()); tmp; tmp = tmp->next)
935 		if (list_lookup((List **)(void *)&(tmp->nicks), nick,
936 				0, 0))
937 			return tmp->channel;
938 
939 	return NULL;
940 }
941 
942 u_char	*
walk_channels(u_char * nick,int init,int server)943 walk_channels(u_char *nick, int init, int server)
944 {
945 	static	ChannelList *tmp = NULL;
946 
947 	if (server < 0)
948 		server = get_from_server();
949 	if (init)
950 		tmp = server_get_chan_list(server);
951 	else if (tmp)
952 		tmp = tmp->next;
953 	for (;tmp ; tmp = tmp->next)
954 		if (tmp->server == server &&
955 		    list_lookup((List **)(void *)&(tmp->nicks), nick,
956 				0, 0))
957 			return (tmp->channel);
958 	return NULL;
959 }
960 
961 int
get_channel_oper(u_char * channel,int server)962 get_channel_oper(u_char *channel, int server)
963 {
964 	ChannelList *chan;
965 
966 	if ((chan = lookup_channel(channel, server, CHAN_NOUNLINK)))
967 		return (chan->status & CHAN_CHOP);
968 	else
969 		return 1;
970 }
971 
972 void
set_channel_window(Window * window,u_char * channel,int server)973 set_channel_window(Window *window, u_char *channel, int server)
974 {
975 	ChannelList	*tmp;
976 
977 	if (!channel || server < 0)
978 		return;
979 	for (tmp = server_get_chan_list(server); tmp; tmp = tmp->next)
980 		if (!my_stricmp(channel, tmp->channel))
981 		{
982 			tmp->window = window;
983 			return;
984 		}
985 }
986 
987 u_char	*
create_channel_list(Window * window)988 create_channel_list(Window *window)
989 {
990 	ChannelList	*tmp;
991 	u_char	*value = NULL;
992 	StringList *sl;
993 
994 	if (window_get_server(window) < 0)
995 		malloc_strcpy(&value, empty_string());
996 	else
997 	{
998 		sl = sl_init();
999 		for (tmp = server_get_chan_list(window_get_server(window));
1000 		     tmp; tmp = tmp->next)
1001 		{
1002 			sl_add(sl, CP(tmp->channel));
1003 		}
1004 		value = sl_concat(sl, UP(" "));
1005 		sl_free(sl, 0);
1006 	}
1007 
1008 	return value;
1009 }
1010 
1011 void
channel_server_delete(int server)1012 channel_server_delete(int server)
1013 {
1014 	ChannelList *tmp;
1015 	int	i;
1016 
1017 	for (i = server + 1; i < number_of_servers(); i++)
1018 		for (tmp = server_get_chan_list(i); tmp; tmp = tmp->next)
1019 			if (tmp->server >= server)
1020 				tmp->server--;
1021 }
1022 
1023 int
chan_is_connected(u_char * channel,int server)1024 chan_is_connected(u_char *channel, int server)
1025 {
1026 	ChannelList *	cp = lookup_channel(channel, server, CHAN_NOUNLINK);
1027 
1028 	if (!cp)
1029 		return 0;
1030 
1031 	return (cp->connected == CHAN_JOINED);
1032 }
1033 
1034 void
mark_not_connected(int server)1035 mark_not_connected(int server)
1036 {
1037 	ChannelList	*tmp;
1038 
1039 	if (server >= 0)
1040 		for (tmp = server_get_chan_list(server); tmp; tmp = tmp->next)
1041 		{
1042 			tmp->status = 0;
1043 			tmp->connected = CHAN_LIMBO;
1044 		}
1045 }
1046 
1047 void
free_nicks(Window * window)1048 free_nicks(Window *window)
1049 {
1050 	NickList *nicks = *window_get_nicks(window);
1051 	NickList *tmp, *next;
1052 
1053 	for (tmp = nicks; tmp; tmp = next)
1054 	{
1055 		next = tmp->next;
1056 		new_free(&tmp->nick);
1057 		new_free(&tmp);
1058 	}
1059 }
1060 
1061 void
display_nicks_info(Window * window)1062 display_nicks_info(Window *window)
1063 {
1064 	NickList *nicks = *window_get_nicks(window);
1065 
1066 	if (nicks)
1067 	{
1068 		say("\tName list:");
1069 		for (; nicks; nicks = nicks->next)
1070 			say("\t  %s", nicks->nick);
1071 	}
1072 }
1073 
1074 int
nicks_add_to_window(Window * window,u_char * nick)1075 nicks_add_to_window(Window *window, u_char *nick)
1076 {
1077 	NickList **nicks = window_get_nicks(window);
1078 
1079 	if (!find_in_list((List **)(void *)nicks, nick, 0))
1080 	{
1081 		NickList *new = new_malloc(sizeof *new);
1082 		new->nick = NULL;
1083 		malloc_strcpy(&new->nick, nick);
1084 		add_to_list((List **)(void *)nicks, (List *) new);
1085 		return 1;
1086 	}
1087 	return 0;
1088 }
1089 
1090 int
nicks_remove_from_window(Window * window,u_char * nick)1091 nicks_remove_from_window(Window *window, u_char *nick)
1092 {
1093 	NickList **nicks = window_get_nicks(window);
1094 	NickList *new;
1095 
1096 	if ((new = (NickList *)
1097 		remove_from_list((List **)(void *)nicks, nick)) != NULL)
1098 	{
1099 		new_free(&new->nick);
1100 		new_free(&new);
1101 		return 1;
1102 	}
1103 	return 0;
1104 }
1105 
1106 u_char	*
function_chanusers(u_char * input)1107 function_chanusers(u_char *input)
1108 {
1109 	ChannelList	*chan;
1110 	NickList	*nicks;
1111 	u_char	*result = NULL;
1112 	int	len = 0;
1113 	int	notfirst = 0;
1114 
1115 	chan = lookup_channel(input, get_from_server(), CHAN_NOUNLINK);
1116 	if (NULL == chan)
1117 		return NULL;
1118 
1119 	for (nicks = chan->nicks; nicks; nicks = nicks->next)
1120 		len += (my_strlen(nicks->nick) + 1);
1121 	result = new_malloc(len + 1);
1122 	*result = '\0';
1123 
1124 	for (nicks = chan->nicks; nicks; nicks = nicks->next)
1125 	{
1126 		if (notfirst)
1127 			my_strmcat(result, " ", len);
1128 		else
1129 			notfirst = 1;
1130 		my_strmcat(result, nicks->nick, len);
1131 	}
1132 
1133 	return (result);
1134 }
1135 
1136 int
channel_mode_lookup(u_char * channel,int check_modes,int set_modes)1137 channel_mode_lookup(u_char *channel, int check_modes, int set_modes)
1138 {
1139 	ChannelList *tmp;
1140 
1141 	tmp = lookup_channel(channel, parsing_server(), CHAN_NOUNLINK);
1142 	if (tmp && (tmp->status & check_modes) != check_modes) {
1143 		tmp->status |= set_modes;
1144 		return 1;
1145 	}
1146 	return 0;
1147 }
1148 
1149 /*
1150  * given a server and a channel, look up a window it belongs to.
1151  * NULL means the channel was not found.
1152  */
1153 Window *
channel_window(u_char * channel,int server)1154 channel_window(u_char *channel, int server)
1155 {
1156 	ChannelList *chan;
1157 
1158 	chan = lookup_channel(channel, server, CHAN_NOUNLINK);
1159 	if (!chan)
1160 		return NULL;
1161 	return chan->window ? chan->window : curr_scr_win;
1162 }
1163 
1164 int
channel_is_current_window(u_char * channel,int server)1165 channel_is_current_window(u_char *channel, int server)
1166 {
1167 	ChannelList *chan;
1168 
1169 	chan = lookup_channel(channel, server, CHAN_NOUNLINK);
1170 
1171 	return chan && chan->window != curr_scr_win;
1172 }
1173 
1174 /*
1175  * backend for is_current_channel() that interrogates the channel
1176  * list for each server.
1177  */
1178 int
channel_is_on_window(u_char * channel,int server,Window * found_window,int refnum)1179 channel_is_on_window(u_char *channel, int server, Window *found_window,
1180 		     int refnum)
1181 {
1182 	Window		*tmp;
1183 	ChannelList	*chan;
1184 	ChannelList	*possible = NULL;
1185 	int		found = 0;
1186 
1187 	for (chan = server_get_chan_list(server); chan; chan = chan->next)
1188 	{
1189 		if (!my_stricmp(chan->channel, channel))
1190 			continue;
1191 		if (chan->window == found_window)
1192 		{
1193 			set_channel_by_refnum(window_get_refnum(found_window),
1194 					      chan->channel);
1195 			return 1;
1196 		}
1197 		if (!get_int_var(SAME_WINDOW_ONLY_VAR) &&
1198 		    !is_bound(chan->channel, server) &&
1199 		    chan->window != found_window)
1200 		{
1201 			int	is_current = 0;
1202 			Win_Trav wt;
1203 
1204 			wt.init = 1;
1205 			while ((tmp = window_traverse(&wt)))
1206 			{
1207 				if (window_get_server(tmp) != server)
1208 					continue;
1209 				if (window_get_current_channel(tmp) &&
1210 				    !my_stricmp(chan->channel,
1211 						window_get_current_channel(tmp)))
1212 					is_current = 1;
1213 			}
1214 			if (!is_current)
1215 				possible = chan;
1216 		}
1217 	}
1218 	if (!get_int_var(SAME_WINDOW_ONLY_VAR))
1219 	{
1220 		u_char *delete_channel;
1221 
1222 		if (possible)
1223 		{
1224 			set_channel_by_refnum(window_get_refnum(found_window),
1225 					      possible->channel);
1226 			return 1;
1227 		}
1228 		delete_channel = get_channel_by_refnum((u_int)refnum);
1229 		if (delete_channel &&
1230 		    !(is_bound(delete_channel, server) &&
1231 		    window_get_refnum(found_window) != refnum))
1232 			set_channel_by_refnum(window_get_refnum(found_window),
1233 					      get_channel_by_refnum((u_int)refnum));
1234 	}
1235 	return found;
1236 }
1237 
1238 int
channels_move_server_simple(int old_serv,int server)1239 channels_move_server_simple(int old_serv, int server)
1240 {
1241 	ChannelList *tmp;
1242 	int moved = 0;
1243 
1244 	for (tmp = server_get_chan_list(old_serv); tmp; tmp = tmp->next)
1245 	{
1246 		if (!moved)	/* If we're here, it means
1247 				   we're going to transfer
1248 				   channels to the new server,
1249 				   so we dump old channels
1250 				   first, but only once -Sol */
1251 		{
1252 			moved++;
1253 			clear_channel_list(server);
1254 		}
1255 		add_channel(tmp->channel, 0, server, CHAN_LIMBO, tmp);
1256 	}
1257 	return moved;
1258 }
1259 
1260 void
channels_move_server_complex(Window * window,Window * new_win,int old_serv,int server,int misc,int moved)1261 channels_move_server_complex(Window *window, Window *new_win, int old_serv,
1262 			     int server, int misc, int moved)
1263 {
1264 	ChannelList *tmp;
1265 
1266 	for (tmp = server_get_chan_list(old_serv); tmp; tmp = tmp->next)
1267 	{
1268 		if (tmp->window == NULL ||
1269 		    (tmp->window != window &&
1270 		     (!window_get_server_group(window) ||
1271 		      window_get_server_group(tmp->window) !=
1272 		      window_get_server_group(window))))
1273 			continue;
1274 
1275 		/* Found a channel to be relocated -Sol */
1276 		if (window_get_sticky(tmp->window) || (misc & WIN_FORCE))
1277 		{	/* This channel moves -Sol */
1278 			int	old;
1279 
1280 			if (!moved)
1281 			{
1282 				moved++;
1283 				clear_channel_list(server);
1284 			}
1285 			/* Copy it -Sol */
1286 			add_channel(tmp->channel, 0, server, CHAN_LIMBO, tmp);
1287 			/* On old_serv, leave it -Sol */
1288 			old = set_from_server(old_serv);
1289 			send_to_server("PART %s", tmp->channel);
1290 			set_from_server(old);
1291 			remove_channel(tmp->channel, old_serv);
1292 		}
1293 		else
1294 			tmp->window = new_win;
1295 	}
1296 }
1297 
1298 
1299 void
window_list_channels(Window * window)1300 window_list_channels(Window *window)
1301 {
1302 	ChannelList *tmp;
1303 	int	print_one = 0;
1304 
1305 	if (!window)
1306 		return;
1307 
1308 	for (tmp = server_get_chan_list(window_get_server(window));
1309 	     tmp; tmp = tmp->next)
1310 		if (tmp->window == window)
1311 		{
1312 			if (!print_one)
1313 			{
1314 				say("Channels currently in this window:");
1315 				print_one++;
1316 			}
1317 			say("\t%s", tmp->channel);
1318 		}
1319 	if (!print_one)
1320 		say("There are no channels in this window");
1321 }
1322 
1323 /*
1324  * realloc_channels: Attempts to reallocate a channel to a window of the
1325  * same server
1326  *
1327  * XXX mrg this looks broken to me but i'm not sure.  blah.
1328  */
1329 void
realloc_channels(Window * window)1330 realloc_channels(Window *window)
1331 {
1332 	Window	*tmp;
1333 	Win_Trav wt;
1334 	ChannelList	*chan;
1335 	int	server = window_get_server(window);
1336 
1337 	wt.init = 1;
1338 	while ((tmp = window_traverse(&wt)))
1339 	{
1340 		if (window != tmp && window_get_server(tmp) == server)
1341 		{
1342 			for (chan = server_get_chan_list(server);
1343 			     chan; chan = chan->next)
1344 				if (chan->window == window)
1345 				{
1346 					chan->window = tmp;
1347 					if (!window_get_current_channel(tmp))
1348 						set_channel_by_refnum(window_get_refnum(tmp), chan->channel);
1349 				}
1350 			return;
1351 		}
1352 	}
1353 
1354 	for (chan = server_get_chan_list(server); chan; chan = chan->next)
1355 	{
1356 		chan->window = NULL;
1357 	}
1358 }
1359 
1360 /* swap_channels_win_ptr: must be called because swap_window modifies the
1361  * content of *v_window and *window instead of swapping pointers
1362  */
1363 void
channel_swap_win_ptr(Window * v_window,Window * window)1364 channel_swap_win_ptr(Window *v_window, Window *window)
1365 {
1366 	ChannelList	*chan;
1367 	int	server = window_get_server(window);
1368 	int	v_server = window_get_server(v_window);
1369 
1370 	if (v_server != -1)
1371 	{
1372 		for (chan = server_get_chan_list(v_server);
1373 		     chan; chan = chan->next)
1374 			if (chan->window == v_window)
1375 				chan->window = window;
1376 			else if (chan->window == window)
1377 				chan->window = v_window;
1378 	}
1379 	if (server == v_server)
1380 		return;
1381 	if (server != -1)
1382 		for (chan = server_get_chan_list(server);
1383 		     chan; chan = chan->next)
1384 			if (chan->window == window)
1385 				chan->window = v_window;
1386 }
1387 
1388 int
nicks_has_who_from(NickList ** nicks)1389 nicks_has_who_from(NickList **nicks)
1390 {
1391 	return find_in_list((List **)(void *)nicks, current_who_from(), 0) != NULL;
1392 }
1393