1 /*
2  * window.c: Handles the Main Window stuff for irc.  This includes proper
3  * scrolling, saving of screen memory, refreshing, clearing, etc.
4  *
5  * Written By Michael Sandrof
6  *
7  * Copyright (c) 1990 Michael Sandrof.
8  * Copyright (c) 1991, 1992 Troy Rollo.
9  * Copyright (c) 1992-2021 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: window.c,v 1.237 2021/02/27 08:02:14 mrg Exp $");
38 
39 #include "screen.h"
40 #include "menu.h"
41 #include "window.h"
42 #include "vars.h"
43 #include "server.h"
44 #include "list.h"
45 #include "ircterm.h"
46 #include "names.h"
47 #include "ircaux.h"
48 #include "input.h"
49 #include "status.h"
50 #include "output.h"
51 #include "log.h"
52 #include "hook.h"
53 #include "dcc.h"
54 #include "translat.h"
55 #include "icb.h"
56 #include "parse.h"
57 #include "strsep.h"
58 #include "sl_irc.h"
59 
60 /*
61  * WindowStack: The structure for the POP, PUSH, and STACK functions. A
62  * simple linked list with window refnums as the data.
63  *
64  * The code for this probably should move into screen.c.
65  */
66 struct	window_stack_stru
67 {
68 	unsigned int	refnum;
69 	WindowStack *next;
70 };
71 
72 struct	display_stru
73 {
74 	u_char	*line;
75 	int	linetype;
76 	Display	*next;
77 };
78 
79 /*
80  * The main Window structure.
81  */
82 struct window_stru
83 {
84 	unsigned refnum;		/* the unique reference number,
85 					   assigned by IRCII */
86 	u_char	*name;			/* window's logical name */
87 	int	server;			/* server index */
88 	int	prev_server;		/* previous server index */
89 
90 	int	top;			/* The top line of the window, screen
91 					   coordinates */
92 	int	bottom;			/* The botton line of the window, screen
93 					   coordinates */
94 	int	cursor;			/* The cursor position in the window,
95 					   window relative coordinates */
96 	int	line_cnt;		/* counter of number of lines displayed
97 					   in window */
98 	int	scroll;			/* true, window scrolls... false window
99 					   wraps */
100 	int	display_size;		/* number of lines of window - menu
101 					   lines */
102 	int	old_size;		/* if new_size != display_size,
103 					   resize_display is called */
104 	int	visible;		/* true, window is drawn... false window
105 					   is hidden */
106 	int	update;			/* window needs updating flag */
107 	unsigned miscflags;		/* Miscellaneous flags. */
108 
109 	u_char	*prompt;		/* A prompt string, usually set by
110 					   EXEC'd process */
111 	u_char	*status_line[2];	/* The status line strings */
112 
113 	int	double_status;		/* Display the 2nd status line ?*/
114 
115 	Display	*top_of_display,	/* Pointer to first line of display
116 					   structure */
117 		*display_ip;		/* Pointer to insertiong point of
118 					   display structure */
119 
120 	/* hold stuff */
121 	HoldInfo *hold_info;		/* link to our hold info */
122 	int	hold_mode;		/* true, hold mode is on for window */
123 	int	hold_on_next_rite;	/* if true, activate a hold on next call
124 					   to rite() */
125 
126 	int	scrolled_lines;		/* number of lines scrolled back */
127 	int	new_scrolled_lines;	/* number of lines since scroll back
128 					   keys where pressed */
129 
130 	/* stuff that is a property of this window */
131 	u_char	*current_channel;	/* Window's current channel */
132 	u_char	*bound_channel;		/* Channel that belongs in this window */
133 	u_char	*query_nick;		/* User being QUERY'ied in this window */
134 	NickList *nicks;		/* List of nicks that will go to window */
135 	int	window_level;		/* The LEVEL of the window, determines
136 					   what messages go to it */
137 	WindowMenu	*menu;		/* The menu (if any) */
138 
139 	/* lastlog stuff */
140 	LastlogInfo	*lastlog_info;	/* pointer to lastlog info */
141 
142 	int	notify_level;		/* the notify level.. */
143 
144 	/* window log stuff */
145 	u_char	*logfile;		/* window's logfile name */
146 	int	log;			/* file logging for window is on */
147 	FILE	*log_fp;		/* file pointer for the log file */
148 
149 	Screen	*screen;		/* our currently attached screen */
150 	int	server_group;		/* server group number */
151 
152 	Window	*next;			/* pointer to next entry in window list
153 					   (null is end) */
154 	Window	*prev;			/* pointer to previous entry in window
155 					   list (null is end) */
156 	int	sticky;			/* make channels stick to window when
157 					   changing servers ? */
158 };
159 
160 /*
161  * The following should synthesize MAXINT on any machine with an 8 bit
162  * word.
163  */
164 #undef MAXINT
165 #define	MAXINT (-1&~(1<<(sizeof(int)*8-1)))
166 
167 static	Window	*invisible_list = NULL; /* list of hidden windows */
168 static	u_char	*who_from = NULL;	/* nick of person whose message
169 					 * is being displayed */
170 static	int	who_level = LOG_CRAP;	/* Log level of message being
171 					   displayed */
172 
173 /*
174  * status_update_flag: if 1, the status is updated as normal.  If 0, then all
175  * status updating is suppressed
176  */
177 static	int	status_update_flag = 1;
178 
179 #ifdef lines
180 #undef lines
181 #endif /* lines */
182 
183 static	void	remove_from_window_list(Window *);
184 static	void	hide_window(Window *);
185 static	void	hide_other_windows(void);
186 static	void	remove_from_invisible_list(Window *);
187 static	void	revamp_window_levels(Window *);
188 static	void	swap_window(Window *, Window *);
189 static	void	move_window(Window *, int);
190 static	void	grow_window(Window *, int);
191 static	Window	*get_next_window(void);
192 static	Window	*get_previous_window(void);
193 static	void	delete_other_windows(void);
194 static	void	bind_channel(u_char *, Window *);
195 static	void	unbind_channel(u_char *, Window *);
196 static	void	irc_goto_window(int);
197 static	void	list_a_window(Window *, int, int);
198 static	void	list_windows(void);
199 static	void	show_window(Window *);
200 static	void	push_window_by_refnum(u_int);
201 static	void	pop_window(void);
202 static	void	show_stack(void);
203 static	u_int	create_refnum(void);
204 static	int	is_window_name_unique(u_char *);
205 static	void	add_nicks_by_refnum(u_int, u_char *, int);
206 static	Window	*get_window(u_char *, u_char **);
207 static	Window	*get_invisible_window(u_char *, u_char **);
208 static	int	get_number(u_char *, u_char **);
209 static	int	get_boolean(u_char *, u_char **, int *);
210 static	void	display_lastlog_lines(int, int, Window *);
211 static	u_char	**split_up_line(u_char *);
212 static	void	redraw_window(Window *, int, int);
213 static	int	lastlog_lines(Window *);
214 static	void	scrollback_backwards_lines(int);
215 static	void	scrollback_forwards_lines(int);
216 
217 /*
218  * window_traverse: This will do as the name implies, traverse every
219  * window (visible and invisible) and return a pointer to each window on
220  * subsequent calls.  If flag points to a non-zero value, then the traversal
221  * in started from the beginning again, and flag is set to point to 0.  This
222  * returns all visible windows first, then all invisible windows.  It returns
223  * null after all windows have been returned.  It should generally be used as
224  * follows:
225  *
226  * Win_Trav wt;
227  * Window *tmp;
228  *
229  * wt.init = 1;
230  * while ((tmp = window_traverse(&wt)))
231  *	{ code here }
232  *
233  * this version is recursive.
234  */
235 Window	*
window_traverse(Win_Trav * wt)236 window_traverse(Win_Trav *wt)
237 {
238 	int	foo = 1;
239 
240 	/* First call, return the current window basically */
241 	if (wt->init)
242 	{
243 		wt->init = 0;
244 		wt->visible = 1;
245 		if (!screen_first())
246 			return NULL;
247 		wt->screen = screen_first();
248 		wt->which = screen_get_window_list(wt->screen);
249 		if (wt->which)
250 			return (wt->which);
251 		else
252 			foo = 0;
253 	}
254 
255 	/*
256 	 * foo is used to indicate the the current screen has no windows.
257 	 * This happens when we create a new screen..  either way, we want
258 	 * to go on to the next screen, so if foo isn't set, then if which
259 	 * is already null, return it again (this should never happen, if
260 	 * window_traverse()'s is called properly), else move on to
261 	 * the next window
262 	 */
263 	if (foo)
264 	{
265 		if (!wt->which)
266 			return NULL;
267 		else
268 			wt->which = wt->which->next;
269 	}
270 
271 	if (!wt->which)
272 	{
273 		while (wt->screen)
274 		{
275 			wt->screen = screen_get_next(wt->screen);
276 			if (wt->screen && screen_get_alive(wt->screen))
277 				break;
278 		}
279 		if (wt->screen)
280 			wt->which = screen_get_window_list(wt->screen);
281 	}
282 
283 	if (wt->which)
284 		return (wt->which);
285 	/*
286 	 * Got to the end of the visible list..  so we do the invisible list..
287 	 * Should also mean, that we've got to the end of all the visible
288 	 * screen..
289 	 */
290 	if (wt->visible)
291 	{
292 		wt->visible = 0;
293 		wt->which = invisible_list;
294 		return (wt->which);
295 	}
296 	return (NULL);
297 }
298 
299 void
add_window_to_server_group(Window * window,u_char * group)300 add_window_to_server_group(Window *window, u_char *group)
301 {
302 	int	i = find_server_group(group, 1);
303 	Win_Trav wt;
304 	Window	*tmp;
305 
306 	wt.init = 1;
307 	while ((tmp = window_traverse(&wt)) != NULL)
308 		if ((tmp->server_group == i) && (tmp->server != window->server))
309 		{
310 			say("Group %s already contains a different server", group);
311 			return;
312 		}
313 	window->server_group = i;
314 	say("Window's server group is now %s", group);
315 	update_window_status(window, 1);
316 }
317 
318 /*
319  * set_scroll_lines: called by /SET SCROLL_LINES to check the scroll lines
320  * value
321  */
322 void
set_scroll_lines(int size)323 set_scroll_lines(int size)
324 {
325 	if (size == 0)
326 	{
327 		set_var_value(SCROLL_VAR, UP(var_settings(0)));
328 		if (curr_scr_win)
329 			curr_scr_win->scroll = 0;
330 	}
331 	else if (size > curr_scr_win->display_size)
332 	{
333 		say("Maximum lines that may be scrolled is %d",
334 		    curr_scr_win->display_size);
335 		set_int_var(SCROLL_LINES_VAR, (u_int)curr_scr_win->display_size);
336 	}
337 }
338 
339 /*
340  * scroll_window: Given a pointer to a window, this determines if that window
341  * should be scrolled, or the cursor moved to the top of the screen again, or
342  * if it should be left alone.
343  */
344 void
scroll_window(Window * window)345 scroll_window(Window *window)
346 {
347 	if (term_basic())
348 		return;
349 	if (window->cursor == window->display_size)
350 	{
351 		if (window->scroll)
352 		{
353 			int	do_scroll,
354 				i;
355 
356 			if ((do_scroll = get_int_var(SCROLL_LINES_VAR)) <= 0)
357 				do_scroll = 1;
358 
359 			for (i = 0; i < do_scroll; i++)
360 			{
361 				new_free(&window->top_of_display->line);
362 				window->top_of_display =
363 					window->top_of_display->next;
364 			}
365 			if (window->visible)
366 			{
367 				if (term_scroll(window->top + window_menu_lines(window),
368 						window->top + window_menu_lines(window) + window->cursor - 1,
369 						do_scroll))
370 				{
371 					if (number_of_windows() == 1)
372 					{
373 						Window	*tmp;
374 
375 			/*
376 			 * this method of sim-u-scroll seems to work fairly
377 			 * well. The penalty is that you can only have one
378 			 * window, and of course you can't use the scrollback
379 			 * buffer either. Or menus. Actually, this method
380 			 * really doesn't work very well at all anymore.
381 			 */
382 						tmp = get_cursor_window();
383 						term_move_cursor(0, get_li() - 2);
384 						if (term_clear_to_eol())
385 							term_space_erase(0);
386 						term_cr();
387 						term_newline();
388 						for (i = 0; i < do_scroll; i++)
389 						{
390 							term_cr();
391 							term_newline();
392 						}
393 						update_window_status(window, 1);
394 						update_input(UPDATE_ALL);
395 						set_cursor_window(tmp);
396 						Debug(DB_SCROLL, "scroll_window: screen %d cursor_window set to window %d (%d)",
397 							screen_get_screennum(get_current_screen()), window->refnum,
398 							screen_get_screennum(window->screen));
399 					}
400 					else
401 						redraw_window(window, 1, 0);
402 				}
403 				window->cursor -= do_scroll;
404 				term_move_cursor(0, window->cursor + window->top + window_menu_lines(window));
405 			}
406 			else
407 				window->cursor -= do_scroll;
408 		}
409 		else
410 		{
411 			window->cursor = 0;
412 			if (window->visible)
413 				term_move_cursor(0, window->top + window_menu_lines(window));
414 		}
415 	}
416 	else if (window->visible && get_cursor_window() == window)
417 	{
418 		term_cr();
419 		term_newline();
420 	}
421 	if (window->visible && get_cursor_window())
422 	{
423 		if (term_clear_to_eol()) /* && !window->hold_mode && !window->hold_on_next_rite) */
424 		{
425 			term_space_erase(0);
426 			term_cr();
427 		}
428 		term_flush();
429 	}
430 }
431 
432 /*
433  * set_scroll: called by /SET SCROLL to make sure the SCROLL_LINES variable
434  * is set correctly
435  */
436 void
set_scroll(int value)437 set_scroll(int value)
438 {
439 	if (value && (get_int_var(SCROLL_LINES_VAR) == 0))
440 	{
441 		put_it("You must set SCROLL_LINES to a positive value first!");
442 		if (curr_scr_win)
443 			curr_scr_win->scroll = 0;
444 	}
445 	else
446 	{
447 		if (curr_scr_win)
448 		{
449 			int	old_value = curr_scr_win->scroll;
450 
451 			curr_scr_win->scroll = value;
452 			if (old_value != value)
453 				scroll_window(curr_scr_win);
454 		}
455 	}
456 }
457 
458 /*
459  * this is where the real work of scrolling backwards and forwards
460  * through the history is done.
461  *
462  * what happens is some functions are called from other code to
463  * make scroll requests:  forward, back, start, end.  these functions
464  * do some minor house keeping, and then call the function
465  * display_lastlog_lines() to do the real work.
466  *
467  * we keep a split up copy of each line attached to the Display
468  * structure, as well as the original full line, so we can split
469  * it up again when the number of columns changes.  this splitting
470  * can occur either when adding the lines to the lastlog itself,
471  * or, if the line wasn't added to the lastlog, directly below
472  * by calling split_up_line().
473  */
474 
475 /*
476  * how many lastlog lines in this window?
477  */
478 static int
lastlog_lines(Window * window)479 lastlog_lines(Window *window)
480 {
481 	Display	*Disp;
482 	int num_lines = 0, i;
483 	LastlogLineBackInfo *info;
484 
485 	info = lastlog_line_back_alloc(window);
486 
487 	for (i = window->new_scrolled_lines; i--; num_lines++)
488 		(void)lastlog_line_back(info);
489 
490 	for (i = 0, Disp = window->top_of_display; i < window->display_size;
491 			Disp = Disp->next, i++)
492 		if (Disp->linetype)
493 			(void)lastlog_line_back(info);
494 
495 	while (lastlog_line_back(info))
496 		num_lines++;
497 
498 	lastlog_line_back_free(info);
499 
500 	Debug(DB_LASTLOG, "  num_lines ends up as %d", num_lines);
501 	return (num_lines);
502 }
503 
504 /*
505  * in window "window", display the lastlog lines from "start" to "end".
506  */
507 static	void
display_lastlog_lines(int start,int end,Window * window)508 display_lastlog_lines(int start, int end, Window *window)
509 {
510 	Display	*Disp;
511 	u_char	*Line;
512 	int	i;
513 	LastlogLineBackInfo *info;
514 
515 	info = lastlog_line_back_alloc(window);
516 
517 	for (i = window->new_scrolled_lines; i--;)
518 		(void)lastlog_line_back(info);
519 
520 	for (i = 0, Disp = window->top_of_display; i < window->display_size;
521 			Disp = Disp->next, i++)
522 		if (Disp->linetype)
523 			(void)lastlog_line_back(info);
524 
525 	for (i = 0; i < start; i++)
526 		(void)lastlog_line_back(info);
527 
528 	for (; i < end; i++)
529 	{
530 		if (!(Line = lastlog_line_back(info)))
531 			break;
532 		term_move_cursor(0, window->top + window_menu_lines(window) +
533 			window->scrolled_lines - i - 1);
534 		rite(window, Line, 0, 0, 1, 0);
535 	}
536 
537 	lastlog_line_back_free(info);
538 }
539 
540 /*
541  * scrollback_{back,forw}wards_lines: scroll the named distance, called by
542  * internal functions here.
543  */
544 static	void
scrollback_backwards_lines(int ScrollDist)545 scrollback_backwards_lines(int ScrollDist)
546 {
547 	Window	*window;
548 	int totallines;
549 
550 	Debug(DB_SCROLL, "scrollback_backwards_lines(%d)", ScrollDist);
551 	window = curr_scr_win;
552 	if (!window->scrolled_lines && !window->scroll)
553 	{
554 		term_beep();
555 		return;
556 	}
557 	totallines = lastlog_lines(window);
558 	Debug(DB_SCROLL, "totallines = %d, scrolled_lines = %d", totallines, window->scrolled_lines);
559 	if (ScrollDist + window->scrolled_lines > totallines)
560 	{
561 		ScrollDist = totallines - window->scrolled_lines;
562 		Debug(DB_SCROLL, "  adjusting ScrollDist to %d", ScrollDist);
563 	}
564 	if (ScrollDist == 0)
565 	{
566 		term_beep();
567 		return;
568 	}
569 	window->scrolled_lines += ScrollDist;
570 
571 	Debug(DB_SCROLL, "going to term_scroll(%d, %d, %d)",
572 	    window->top + window_menu_lines(window),
573 	    window->top + window_menu_lines(window) + window->display_size - 1,
574 	    -ScrollDist);
575 	term_scroll(window->top + window_menu_lines(window),
576 	    window->top + window_menu_lines(window) + window->display_size - 1,
577 	    -ScrollDist);
578 
579 	Debug(DB_SCROLL, "scrolled_lines=%d, new_scrolled_lines=%d, display_size=%d",
580 	    window->scrolled_lines,
581 	    window->new_scrolled_lines,
582 	    window->display_size);
583 
584 	Debug(DB_SCROLL, "going to display_lastlog_lines(%d, %d, %s)",
585 	    window->scrolled_lines - ScrollDist,
586 	    window->scrolled_lines,
587 	    window->name);
588 	display_lastlog_lines(window->scrolled_lines - ScrollDist,
589 	    window->scrolled_lines,
590 	    window);
591 	cursor_not_in_display();
592 	update_input(UPDATE_JUST_CURSOR);
593 	window->update |= UPDATE_STATUS;
594 	update_window_status(window, 0);
595 }
596 
597 static	void
scrollback_forwards_lines(int ScrollDist)598 scrollback_forwards_lines(int ScrollDist)
599 {
600 	Window	*window;
601 
602 	Debug(DB_SCROLL, "scrollback_forward_lines(%d)", ScrollDist);
603 	window = curr_scr_win;
604 	if (!window->scrolled_lines)
605 	{
606 		term_beep();
607 		return;
608 	}
609 	if (ScrollDist > window->scrolled_lines)
610 		ScrollDist = window->scrolled_lines;
611 
612 	Debug(DB_SCROLL, "scrolled_lines = %d", window->scrolled_lines);
613 	window->scrolled_lines -= ScrollDist;
614 	Debug(DB_SCROLL, "going to term_scroll(%d, %d, %d)",
615 	    window->top + window_menu_lines(window),
616 	    window->top + window_menu_lines(window) + window->display_size - 1,
617 	    ScrollDist);
618 	term_scroll(window->top + window_menu_lines(window),
619 	    window->top + window_menu_lines(window) + window->display_size - 1,
620 	    ScrollDist);
621 
622 	Debug(DB_SCROLL, "scrolled_lines=%d, new_scrolled_lines=%d, display_size=%d",
623 	    window->scrolled_lines,
624 	    window->new_scrolled_lines,
625 	    window->display_size);
626 
627 	if (window->scrolled_lines < window->display_size)
628 		redraw_window(window,
629 		    ScrollDist + window->scrolled_lines - window->display_size, 1);
630 
631 	Debug(DB_SCROLL, "going to display_lastlog_lines(%d, %d, %s)",
632 	    window->scrolled_lines - window->display_size,
633 	    window->scrolled_lines - window->display_size + ScrollDist,
634 	    window->name);
635 	display_lastlog_lines(window->scrolled_lines - window->display_size,
636 	    window->scrolled_lines - window->display_size + ScrollDist,
637 	    window);
638 	cursor_not_in_display();
639 	update_input(UPDATE_JUST_CURSOR);
640 
641 	if (!window->scrolled_lines)
642 	{
643 		window->new_scrolled_lines = 0;
644 		if (window->hold_mode)
645 			window_hold_mode(window, ON, 1);
646 		else
647 			window_hold_mode(window, OFF, 0);
648 	}
649 	window->update |= UPDATE_STATUS;
650 	update_window_status(window, 0);
651 }
652 
653 /*
654  * scrollback_{forw,back}wards: scrolls the window up or down half the screen.
655  * these are called when the respective key are pressed.
656  */
657 void
scrollback_forwards(u_int key,u_char * ptr)658 scrollback_forwards(u_int key, u_char *ptr)
659 {
660 	scrollback_forwards_lines(curr_scr_win->display_size/2);
661 }
662 
663 void
scrollback_backwards(u_int key,u_char * ptr)664 scrollback_backwards(u_int key, u_char *ptr)
665 {
666 	scrollback_backwards_lines(curr_scr_win->display_size/2);
667 }
668 
669 /*
670  * scrollback_end: exits scrollback mode and moves the display back
671  * to the end of the scrollback buffer.
672  */
673 void
scrollback_end(u_int key,u_char * ptr)674 scrollback_end(u_int key, u_char *ptr)
675 {
676 	Window	*window;
677 
678 	window = curr_scr_win;
679 	window->new_scrolled_lines = 0;
680 
681 	if (!window->scrolled_lines)
682 	{
683 		term_beep();
684 		return;
685 	}
686 	if (window->scrolled_lines < window->display_size)
687 		scrollback_forwards_lines(window->scrolled_lines);
688 	else
689 	{
690 		window->scrolled_lines = window->new_scrolled_lines = 0;
691 		redraw_window(window, 1, 1);
692 		cursor_not_in_display();
693 		update_input(UPDATE_JUST_CURSOR);
694 		if (window->hold_mode)
695 			window_hold_mode(window, ON, 1);
696 		else
697 			window_hold_mode(window, OFF, 0);
698 		window->update |= UPDATE_STATUS;
699 		update_window_status(window, 0);
700 	}
701 }
702 
703 /*
704  * scrollback_start: moves the current screen back to the start of
705  * the scrollback buffer.
706  */
707 void
scrollback_start(u_int key,u_char * ptr)708 scrollback_start(u_int key, u_char *ptr)
709 {
710 	Window	*window;
711 	int	num_lines;
712 
713 	window = curr_scr_win;
714 	if (!window_get_lastlog_size(window))
715 	{
716 		term_beep();
717 		return;
718 	}
719 
720 	Debug(DB_SCROLL, "scrollback_start: new_scrolled_lines=%d display_size=%d",
721 		window->new_scrolled_lines, window->display_size);
722 	num_lines = lastlog_lines(window);
723 
724 	if (num_lines < window->display_size)
725 		scrollback_backwards_lines(num_lines);
726 	else
727 	{
728 		window->scrolled_lines = num_lines;
729 		Debug(DB_SCROLL, "going to display_lastlog_lines(%d, %d, %s)",
730 		      num_lines - window->display_size, window->scrolled_lines, window->name);
731 		display_lastlog_lines(num_lines - window->display_size,
732 					window->scrolled_lines, window);
733 		cursor_not_in_display();
734 		update_input(UPDATE_JUST_CURSOR);
735 		window->new_scrolled_lines = 0;
736 		if (window->hold_mode)
737 			window_hold_mode(window, ON, 1);
738 		else
739 			window_hold_mode(window, OFF, 0);
740 		window->update |= UPDATE_STATUS;
741 		update_window_status(window, 0);
742 	}
743 }
744 
745 /*
746  * window_refresh_lastlog: Backend for the REFRESH_WINDOW_LASTLOG
747  * function and more.
748  *
749  * this clears the screen and redisplays the end of the lastlog while
750  * also ensuring scrolling up works properly.  it's kind of like a
751  * reverse ^L.
752  */
753 void
window_refresh_lastlog(Window * window)754 window_refresh_lastlog(Window *window)
755 {
756 	Display *next;
757 	LastlogLineBackInfo *info;
758 	StringList *sl;
759 	u_char	*line;
760 	size_t	iter;
761 	int	cnt;
762 
763 	sl = sl_init();
764 	info = lastlog_line_back_alloc(window);
765 
766 	for (cnt = 0; cnt < window->display_size; cnt++)
767 	{
768 		line = lastlog_line_back(info);
769 		if (!line)
770 			break;
771 		sl_add(sl, CP(line));
772 	}
773 
774 	erase_display(window);
775 
776 	iter = 0;
777 	for (next = window->top_of_display;
778 	     (line = sl_iter_rev(sl, &iter)) != NULL;
779 	     window->cursor++, next = next->next)
780 	{
781 		malloc_strcpy(&next->line, line);
782 		next->linetype = 1;
783 	}
784 	window->display_ip = next;
785 	window->line_cnt = 1;
786 
787 	redraw_window(window, 1, 1);
788 	cursor_not_in_display();
789 	if (window->hold_mode)
790 		window_hold_mode(window, ON, 1);
791 	else
792 		window_hold_mode(window, OFF, 0);
793 	window->update |= UPDATE_STATUS;
794 	update_window_status(window, 0);
795 
796 	sl_free(sl, 0);
797 	lastlog_line_back_free(info);
798 }
799 
800 /*
801  * window_refresh_lastlog_key: REFRESH_WINDOW_LASTLOG frontend
802  */
803 void
window_refresh_lastlog_key(u_int key,u_char * ptr)804 window_refresh_lastlog_key(u_int key, u_char *ptr)
805 {
806 	window_refresh_lastlog(curr_scr_win);
807 }
808 
809 /*
810  * update_all_windows: This goes through each visible window and draws the
811  * necessary portions according the the update field of the window.
812  */
813 void
update_all_windows(void)814 update_all_windows(void)
815 {
816 	Window	*tmp;
817 	int	fast_window,
818 		full_window,
819 		r_status,
820 		u_status;
821 
822 	for (tmp = screen_get_window_list(get_current_screen()); tmp; tmp = window_get_next(tmp))
823 	{
824 		if (tmp->display_size != tmp->old_size)
825 			resize_display(tmp);
826 		if (tmp->update)
827 		{
828 			fast_window = tmp->update & REDRAW_DISPLAY_FAST;
829 			full_window = tmp->update & REDRAW_DISPLAY_FULL;
830 			r_status = tmp->update & REDRAW_STATUS;
831 			u_status = tmp->update & UPDATE_STATUS;
832 			if (full_window)
833 				redraw_window(tmp, 1, 0);
834 			else if (fast_window)
835 				redraw_window(tmp, 0, 0);
836 			if (r_status)
837 				update_window_status(tmp, 1);
838 			else if (u_status)
839 				update_window_status(tmp, 0);
840 		}
841 		tmp->update = 0;
842 	}
843 	for (tmp = invisible_list; tmp; tmp = window_get_next(tmp))
844 	{
845 		if (tmp->display_size != tmp->old_size)
846 			resize_display(tmp);
847 		tmp->update = 0;
848 	}
849 	update_input(UPDATE_JUST_CURSOR);
850 	term_flush();
851 }
852 
853 /*
854  * reset_line_cnt: called by /SET HOLD_MODE to reset the line counter so we
855  * always get a held screen after the proper number of lines
856  */
857 void
reset_line_cnt(int value)858 reset_line_cnt(int value)
859 {
860 	curr_scr_win->hold_mode = value;
861 	curr_scr_win->hold_on_next_rite = 0;
862 	curr_scr_win->line_cnt = 0;
863 }
864 
865 /*
866  * XXX This needs to be rewritten to not use fixed-size arrays
867  * XXX for both output[] and lbuf[].
868  */
869 #define	MAXIMUM_SPLITS	80
870 static	u_char	**
split_up_line(u_char * str)871 split_up_line(u_char *str)
872 {
873 	static	u_char	*output[MAXIMUM_SPLITS] =
874 	{
875 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
876 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
877 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
878 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
879 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
880 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
881 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
882 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
883 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
884 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
885 	};
886 	u_char	lbuf[BIG_BUFFER_SIZE];
887 	u_char	*ptr;
888 	u_char	*cont_ptr,
889 		*cont = NULL,
890 		*temp = NULL,
891 		*mystr = NULL,
892 		c;
893 	int	pos = 0,
894 		col = 0,
895 		nd_cnt = 0,
896 		word_break = 0,
897 		start = 0,
898 		i,
899 		indent = 0,
900 		beep_cnt = 0,
901 		beep_max,
902 		tab_cnt = 0,
903 		tab_max,
904 		line = 0;
905 	int	bold_state = 0,
906 		invert_state = 0,
907 		underline_state = 0,
908 		fg_colour_state = 16,
909 		bg_colour_state = 16;
910 	size_t	len;
911 
912 	struct mb_data mbdata;
913 #ifdef HAVE_ICONV_OPEN
914 	mbdata_init(&mbdata, CP(current_irc_encoding()));
915 #else
916 	mbdata_init(&mbdata, NULL);
917 #endif /* HAVE_ICONV_OPEN */
918 
919 	memset(lbuf, 0, sizeof(lbuf));
920 
921 	for (i = 0; i < MAXIMUM_SPLITS; i++)
922 		new_free(&output[i]);
923 	if (!str || !*str)
924 	{
925 		/* special case to make blank lines show up */
926 		malloc_strcpy(&mystr, UP(" "));
927 		str = mystr;
928 	}
929 
930 	beep_max = get_int_var(BEEP_VAR) ? get_int_var(BEEP_MAX_VAR) : -1;
931 	tab_max = get_int_var(TAB_VAR) ? get_int_var(TAB_MAX_VAR) : -1;
932 	for (ptr = (u_char *) str; *ptr && (pos < sizeof(lbuf) - 8); ptr++)
933 	{
934 		switch (*ptr)
935 		{
936 		case '\007':	/* bell */
937 			if (beep_max == -1)
938 			{
939 				lbuf[pos++] = REV_TOG;
940 				lbuf[pos++] = (*ptr & 127) | 64;
941 				lbuf[pos++] = REV_TOG;
942 				nd_cnt += 2;
943 				col++;
944 			}
945 			else if (!beep_max || (++beep_cnt <= beep_max))
946 			{
947 				lbuf[pos++] = *ptr;
948 				nd_cnt++;
949 				col++;
950 			}
951 			break;
952 		case '\011':	/* tab */
953 			if (tab_max && (++tab_cnt > tab_max))
954 			{
955 				lbuf[pos++] = REV_TOG;
956 				lbuf[pos++] = (*ptr & 127) | 64;
957 				lbuf[pos++] = REV_TOG;
958 				nd_cnt += 2;
959 				col++;
960 			}
961 			else
962 			{
963 				if (indent == 0)
964 					indent = -1;
965 				len = 8 - (col % 8);
966 				word_break = pos;
967 				for (i = 0; i < len; i++)
968 					lbuf[pos++] = ' ';
969 				col += len;
970 			}
971 			break;
972 		case UND_TOG:
973 		case ALL_OFF:
974 		case REV_TOG:
975 		case BOLD_TOG:
976 			switch(*ptr)
977 			{
978 			case UND_TOG:
979 				underline_state = !underline_state;
980 				break;
981 			case REV_TOG:
982 				invert_state = !invert_state;
983 				break;
984 			case BOLD_TOG:
985 				bold_state = !bold_state;
986 				break;
987 			case ALL_OFF:
988 				underline_state = invert_state = bold_state = 0;
989 				fg_colour_state = bg_colour_state = 16;
990 				break;
991 			}
992 			lbuf[pos++] = *ptr;
993 			nd_cnt++;
994 			break;
995 		case COLOUR_TAG:
996 			{
997 				int fg, bg;
998 
999 				lbuf[pos++] = *ptr++;
1000 				decode_colour(&ptr, &fg, &bg);
1001 
1002 				lbuf[pos++] = (u_char)(fg_colour_state = fg) + 1;
1003 				lbuf[pos++] = (u_char)(bg_colour_state = bg) + 1;
1004 				nd_cnt += 3;
1005 				break;
1006 			}
1007 		case ' ':	/* word break */
1008 			if (indent == 0)
1009 				indent = -1;
1010 			word_break = pos;
1011 			lbuf[pos++] = *ptr;
1012 			col++;
1013 			break;
1014 		default:	/* Anything else, make it displayable */
1015 			if (indent == -1)
1016 				indent = pos - nd_cnt;
1017 
1018 			decode_mb(ptr, lbuf + pos, sizeof(lbuf) - pos, &mbdata);
1019 
1020 			/* If the sequence takes multiple columns,
1021 			 * be wrappable now when we can
1022 			 */
1023 			if (mbdata.num_columns > 1)
1024 				word_break = pos;
1025 
1026 			pos += mbdata.output_bytes;
1027 			nd_cnt += mbdata.output_bytes - mbdata.num_columns;
1028 			ptr += mbdata.input_bytes - 1;
1029 			col += mbdata.num_columns;
1030 			break;
1031 		}
1032 		if (pos >= sizeof(lbuf) - 1)
1033 			*ptr = '\0';
1034 
1035 		if (col > get_co())
1036 		{
1037 			char c1;
1038 			int oldpos;
1039 
1040 			/* one big long line, no word breaks */
1041 			if (word_break == 0)
1042 				word_break = pos - (col - get_co());
1043 			c = lbuf[word_break];
1044 			c1 = lbuf[word_break+1];
1045 			lbuf[word_break] = FULL_OFF;
1046 			lbuf[word_break+1] = '\0';
1047 			if (cont)
1048 			{
1049 				malloc_strcpy(&temp, cont);
1050 				malloc_strcat(&temp, &lbuf[start]);
1051 			}
1052 			else
1053 				malloc_strcpy(&temp, &lbuf[start]);
1054 			malloc_strcpy(&output[line++], temp);
1055 			if (line == MAXIMUM_SPLITS)
1056 				break;
1057 			lbuf[word_break] = c;
1058 			lbuf[word_break+1] = c1;
1059 			start = word_break;
1060 			word_break = 0;
1061 			while (lbuf[start] == ' ')
1062 				start++;
1063 			if (start > pos)
1064 				start = pos;
1065 
1066 			if (!(cont_ptr = get_string_var(CONTINUED_LINE_VAR)))
1067 				cont_ptr = empty_string();
1068 
1069 			if (!cont) /* Build it only the first time */
1070 			{
1071 				if (get_int_var(INDENT_VAR) && (indent < get_co() / 3))
1072 				{
1073 					/* Visual length */
1074 					int vlen = my_strlen_c(cont_ptr);
1075 					/* Converted length */
1076 					int clen = my_strlen_ci(cont_ptr);
1077 					int padlen = indent - vlen;
1078 
1079 					if (padlen < 0)
1080 						padlen = 0;
1081 
1082 					cont = new_malloc(clen + padlen + 1);
1083 					my_strcpy_ci(cont, clen + padlen + 1,
1084 						     cont_ptr);
1085 
1086 					for (; padlen > 0; --padlen)
1087 					{
1088 						cont[clen++] = ' ';
1089 						/* Add space */
1090 					}
1091 					cont[clen] = '\0';
1092 				}
1093 				else
1094 				{
1095 					/* Converted length */
1096 					int clen = my_strlen_ci(cont_ptr);
1097 
1098 					/* No indent, just prefix only */
1099 					cont = new_malloc(clen + 1);
1100 					my_strcpy_ci(cont, clen + 1, cont_ptr);
1101 				}
1102 			}
1103 
1104 			/* cont contains internal codes, so use my_strlen_i */
1105 			col = my_strlen_i(cont) + (pos - start);
1106 
1107 			/* rebuild previous state */
1108 			oldpos = pos;
1109 			if (underline_state)
1110 			{
1111 				lbuf[pos++] = UND_TOG;
1112 				nd_cnt++;
1113 			}
1114 			if (invert_state)
1115 			{
1116 				lbuf[pos++] = REV_TOG;
1117 				nd_cnt++;
1118 			}
1119 			if (bold_state)
1120 			{
1121 				lbuf[pos++] = BOLD_TOG;
1122 				nd_cnt++;
1123 			}
1124 			if (fg_colour_state != 16 || bg_colour_state != 16)
1125 			{
1126 				lbuf[pos++] = COLOUR_TAG;
1127 				lbuf[pos++] = fg_colour_state + 1;
1128 				lbuf[pos++] = bg_colour_state + 1;
1129 				nd_cnt++;
1130 			}
1131 			if (pos != oldpos)
1132 				while (start < oldpos)
1133 					lbuf[pos++] = lbuf[start++];
1134 		}
1135 	}
1136 	mbdata_done(&mbdata);
1137 
1138 	if (line < MAXIMUM_SPLITS) {
1139 		lbuf[pos++] = FULL_OFF;
1140 		lbuf[pos] = '\0';
1141 		if (lbuf[start])
1142 		{
1143 			if (cont)
1144 			{
1145 				malloc_strcpy(&temp, cont);
1146 				malloc_strcat(&temp, &lbuf[start]);
1147 			}
1148 			else
1149 				malloc_strcpy(&temp, &lbuf[start]);
1150 			malloc_strcpy(&output[line++], temp);
1151 		}
1152 	}
1153 
1154 	new_free(&mystr);
1155 	new_free(&cont);
1156 	new_free(&temp);
1157 	return output;
1158 }
1159 
1160 /*
1161  * split_up_line_alloc(): like split_up_line() except it doesn't
1162  * return the static arrays, but copies them.  eventually when we
1163  * eliminate split_up_line() usage, we can make this entirely
1164  * dynamic.
1165  */
1166 u_char	**
split_up_line_alloc(u_char * str)1167 split_up_line_alloc(u_char *str)
1168 {
1169 	u_char **lines, **new_lines, **tmp;
1170 	size_t total_lines = 0, count;
1171 
1172 	lines = split_up_line(str);
1173 
1174 	for (tmp = lines; *tmp; tmp++) {
1175 		total_lines++;
1176 	}
1177 
1178 	new_lines = new_malloc(sizeof(*new_lines) * (total_lines + 1));
1179 
1180 	/* Copy the pointers; clear the original from lines[] */
1181 	for (count = 0; count < total_lines; count++) {
1182 		new_lines[count] = lines[count];
1183 		lines[count] = NULL;
1184 	}
1185 	new_lines[count] = NULL;
1186 
1187 	return new_lines;
1188 }
1189 
1190 /*
1191  * add_to_window: adds the given string to the display.  No kidding. This
1192  * routine handles the whole ball of wax.  It keeps track of what's on the
1193  * screen, does the scrolling, everything... well, not quite everything...
1194  * The CONTINUED_LINE idea thanks to Jan L. Peterson (jlp@hamblin.byu.edu)
1195  *
1196  * At least it used to. Now most of this is done by split_up_line, and this
1197  * function just dumps it onto the screen. This is because the scrollback
1198  * functions need to be able to figure out how to split things up too.
1199  */
1200 void
add_to_window(Window * window,u_char * str)1201 add_to_window(Window *window, u_char *str)
1202 {
1203 	int flag;
1204 
1205 	flag = do_hook(WINDOW_LIST, "%u %s", window_get_refnum(window), str);
1206 
1207 	if (flag)
1208 	{
1209 		size_t	len = my_strlen(str);
1210 		u_char	*my_str = new_malloc(len + 2);
1211 		u_char	**lines, **curlinep, **freelines;
1212 		int	logged;
1213 
1214 		add_to_window_log(window, str);
1215 		display_highlight(OFF);
1216 		display_bold(OFF);
1217 		display_colours(get_int_var(FOREGROUND_COLOUR_VAR),
1218 		get_int_var(BACKGROUND_COLOUR_VAR));
1219 		memmove(my_str, str, len);
1220 		my_str[len] = ALL_OFF;
1221 		my_str[len + 1] = '\0';
1222 		lines = add_to_lastlog(window, my_str);
1223 		if (!lines)
1224 			freelines = lines = split_up_line(my_str);
1225 		logged = islogged(window);
1226 		/*
1227 		 * For each of the lines created by split_up_line(),
1228 		 * display the line.
1229 		 * rite() will assume each input line fits on 1 line.
1230 		 */
1231 		for (curlinep = lines; *curlinep; curlinep++)
1232 			rite(window, *curlinep, 0, 0, 0, logged);
1233 		new_free(&my_str);
1234 		if (0)
1235 			new_free(&freelines);
1236 		term_flush();
1237 	}
1238 }
1239 
1240 /*
1241  * set_continued_line: checks the value of CONTINUED_LINE for validity,
1242  * altering it if its no good
1243  */
1244 void
set_continued_line(u_char * value)1245 set_continued_line(u_char *value)
1246 {
1247 	if (value && ((int) my_strlen(value) > (get_co() / 2)))
1248 		value[get_co() / 2] = '\0';
1249 }
1250 
1251 static	void
remove_from_invisible_list(Window * window)1252 remove_from_invisible_list(Window *window)
1253 {
1254 	window->visible = 1;
1255 	window->screen = get_current_screen();
1256 	window->miscflags &= ~WINDOW_NOTIFIED;
1257 	if (window->prev)
1258 		window->prev->next = window->next;
1259 	else
1260 		invisible_list = window->next;
1261 	if (window->next)
1262 		window->next->prev = window->prev;
1263 }
1264 
1265 void
add_to_invisible_list(Window * window)1266 add_to_invisible_list(Window *window)
1267 {
1268 	if ((window->next = invisible_list) != NULL)
1269 		invisible_list->prev = window;
1270 	invisible_list = window;
1271 	window->prev = NULL;
1272 	window->visible = 0;
1273 	window->screen = NULL;
1274 }
1275 
1276 /*
1277  * swap_window: This swaps the given window with the current window.  The
1278  * window passed must be invisible.  Swapping retains the positions of both
1279  * windows in their respective window lists, and retains the dimensions of
1280  * the windows as well, but update them depending on the number of status
1281  * lines displayed
1282  */
1283 static	void
swap_window(Window * v_window,Window * window)1284 swap_window(Window *v_window, Window *window)
1285 {
1286 	Window tmp, *prev, *next;
1287 	int	top, bottom, size;
1288 
1289 	if (window->visible || !v_window->visible)
1290 	{
1291 		say("You can only SWAP a hidden window with a visible window.");
1292 		return;
1293 	}
1294 
1295 	channel_swap_win_ptr(v_window, window);
1296 
1297 	prev = v_window->prev;
1298 	next = v_window->next;
1299 
1300 	set_last_window_refnum(v_window->refnum);
1301 	remove_from_invisible_list(window);
1302 
1303 	tmp = *v_window;
1304 	*v_window = *window;
1305 	v_window->top = tmp.top;
1306 	v_window->bottom = tmp.bottom + tmp.double_status -
1307 		v_window->double_status;
1308 	v_window->display_size = tmp.display_size + menu_lines(tmp.menu) +
1309 		tmp.double_status -
1310 		menu_lines(v_window->menu) - v_window->double_status -
1311 		SCROLL_DISPLAY_OFFSET;
1312 	v_window->prev = prev;
1313 	v_window->next = next;
1314 
1315 	/* I don't understand the use of the following, I'll ignore it
1316 	 * If double status screws window sizes, I should look here
1317 	 * again - krys
1318 	 */
1319 	top = window->top;
1320 	bottom = window->bottom;
1321 	size = window->display_size;
1322 	*window = tmp;
1323 	window->top = top;
1324 	window->bottom = bottom - tmp.double_status;
1325 	window->display_size = size - SCROLL_DISPLAY_OFFSET;
1326 
1327 	add_to_invisible_list(window);
1328 
1329 	v_window->update |= REDRAW_DISPLAY_FULL | REDRAW_STATUS;
1330 	window->update |= REDRAW_DISPLAY_FULL | REDRAW_STATUS;
1331 
1332 	do_hook(WINDOW_SWAP_LIST, "%d %d", v_window->refnum, window->refnum);
1333 }
1334 
1335 /*
1336  * move_window: This moves a window offset positions in the window list. This
1337  * means, of course, that the window will move on the screen as well
1338  */
1339 static	void
move_window(Window * window,int offset)1340 move_window(Window *window, int offset)
1341 {
1342 	Window	*tmp, *last;
1343 	int	win_pos, pos, num;
1344 
1345 	if (offset == 0)
1346 		return;
1347 	last = NULL;
1348 	for (win_pos = 0, tmp = screen_get_window_list(get_current_screen()); tmp;
1349 	    tmp = tmp->next, win_pos++)
1350 	{
1351 		if (window == tmp)
1352 			break;
1353 		last = tmp;
1354 	}
1355 	if (tmp == NULL)
1356 		return;
1357 	if (last == NULL)
1358 		screen_set_window_list(get_current_screen(), tmp->next);
1359 	else
1360 		last->next = tmp->next;
1361 	if (tmp->next)
1362 		tmp->next->prev = last;
1363 	else
1364 		screen_set_window_list_end(get_current_screen(), last);
1365 	num = screen_get_visible_windows(window->screen);
1366 	win_pos = (offset + win_pos) % num;
1367 	if (win_pos < 0)
1368 		win_pos = num + win_pos;
1369 	last = NULL;
1370 	for (pos = 0, tmp = screen_get_window_list(get_current_screen());
1371 	    pos != win_pos; tmp = tmp->next, pos++)
1372 		last = tmp;
1373 	if (last == NULL)
1374 		screen_set_window_list(get_current_screen(), window);
1375 	else
1376 		last->next = window;
1377 	if (tmp)
1378 		tmp->prev = window;
1379 	else
1380 		screen_set_window_list_end(get_current_screen(), window);
1381 	window->prev = last;
1382 	window->next = tmp;
1383 	recalculate_window_positions();
1384 }
1385 
1386 /*
1387  * grow_window: This will increase or descrease the size of the given window
1388  * by offset lines (positive offset increases, negative decreases).
1389  * Obviously, with a fixed terminal size, this means that some other window
1390  * is going to have to change size as well.  Normally, this is the next
1391  * window in the window list (the window below the one being changed) unless
1392  * the window is the last in the window list, then the previous window is
1393  * changed as well
1394  */
1395 static	void
grow_window(Window * window,int offset)1396 grow_window(Window *window, int offset)
1397 {
1398 	Window	*other,
1399 		*tmp;
1400 	int	after,
1401 	window_size,
1402 	other_size;
1403 
1404 	if (window == NULL)
1405 		window = curr_scr_win;
1406 	if (!window->visible)
1407 	{
1408 		say("You cannot change the size of hidden windows!");
1409 		return;
1410 	}
1411 	if (window->next)
1412 	{
1413 		other = window->next;
1414 		after = 1;
1415 	}
1416 	else
1417 	{
1418 		other = NULL;
1419 		for (tmp = screen_get_window_list(get_current_screen()); tmp; tmp = tmp->next)
1420 		{
1421 			if (tmp == window)
1422 				break;
1423 			other = tmp;
1424 		}
1425 		if (other == NULL)
1426 		{
1427 			say("Can't change the size of this window!");
1428 			return;
1429 		}
1430 		after = 0;
1431 	}
1432 	window_size = window->display_size + offset;
1433 	other_size = other->display_size - offset;
1434 	if ((window_size < 4) || (other_size < 4))
1435 	{
1436 		say("Not enough room to resize this window!");
1437 		return;
1438 	}
1439 	if (after)
1440 	{
1441 		window->bottom += offset;
1442 		other->top += offset;
1443 	}
1444 	else
1445 	{
1446 		window->top -= offset;
1447 		other->bottom -= offset;
1448 	}
1449 	window->display_size = window_size - SCROLL_DISPLAY_OFFSET;
1450 	other->display_size = other_size - SCROLL_DISPLAY_OFFSET;
1451 	window->update |= REDRAW_DISPLAY_FULL | REDRAW_STATUS;
1452 	other->update |= REDRAW_DISPLAY_FULL | REDRAW_STATUS;
1453 	term_flush();
1454 }
1455 
1456 /*
1457  * the message_from stack structure.
1458  */
1459 static	struct mfstack
1460 {
1461 	u_char	*who_from;	/* saved from */
1462 	int	who_level;	/* saved level */
1463 	struct mfstack *next;	/* next in the list */
1464 } mfstack_head = { NULL, 0, NULL };
1465 
1466 /*
1467  * save_message_from: this is used to save (for later restoration) the
1468  * who_from variable.  This comes in handy very often when a routine might
1469  * call another routine that might change who_from.   Note that if you
1470  * call this routine, you *must* call restore_message_from().
1471  */
1472 void
save_message_from(void)1473 save_message_from(void)
1474 {
1475 	struct mfstack *mfs;
1476 
1477 	mfs = new_malloc(sizeof *mfs);
1478 
1479 	mfs->who_from = NULL;
1480 	malloc_strcpy(&mfs->who_from, who_from);
1481 	mfs->who_level = who_level;
1482 	mfs->next = mfstack_head.next;
1483 
1484 	mfstack_head.next = mfs;
1485 }
1486 
1487 /* restore_message_from: restores a previously saved who_from variable */
1488 void
restore_message_from(void)1489 restore_message_from(void)
1490 {
1491 	struct mfstack *mfs = mfstack_head.next;
1492 
1493 	if (mfs == NULL)
1494 	{
1495 		/*yell("--- restore_message_from: NULL next pointer, fudging..");*/
1496 		malloc_strcpy(&who_from, NULL);
1497 		who_level = LOG_CRAP;
1498 	}
1499 	else
1500 	{
1501 		malloc_strcpy(&who_from, mfs->who_from);
1502 		who_level = mfs->who_level;
1503 		mfstack_head.next = mfs->next;
1504 		new_free(&mfs->who_from);
1505 		new_free(&mfs);
1506 	}
1507 }
1508 
1509 /*
1510  * message_from: With this you can the who_from variable and the who_level
1511  * variable, used by the display routines to decide which window messages
1512  * should go to.
1513  */
1514 void
message_from(u_char * who,int level)1515 message_from(u_char *who, int level)
1516 {
1517 	malloc_strcpy(&who_from, who);
1518 	who_level = level;
1519 }
1520 
1521 /*
1522  * message_from_level: Like set_lastlog_msg_level, except for message_from.
1523  * this is needed by XECHO, because we could want to output things in more
1524  * than one level.
1525  */
1526 int
message_from_level(int level)1527 message_from_level(int level)
1528 {
1529 	int	temp;
1530 
1531 	temp = who_level;
1532 	who_level = level;
1533 	return temp;
1534 }
1535 
1536 /*
1537  * get_window_by_refnum: Given a reference number to a window, this returns a
1538  * pointer to that window if a window exists with that refnum, null is
1539  * returned otherwise.  The "safe" way to reference a window is throught the
1540  * refnum, since a window might be delete behind your back and and Window
1541  * pointers might become invalid.
1542  */
1543 Window	*
get_window_by_refnum(u_int refnum)1544 get_window_by_refnum(u_int refnum)
1545 {
1546 	Window	*tmp;
1547 
1548 	if (refnum)
1549 	{
1550 		Win_Trav wt;
1551 
1552 		wt.init = 1;
1553 		while ((tmp = window_traverse(&wt)) != NULL)
1554 		{
1555 			if (tmp->refnum == refnum)
1556 				return (tmp);
1557 		}
1558 	}
1559 	else
1560 		return (curr_scr_win);
1561 	return (NULL);
1562 }
1563 
1564 /*
1565  * clear_window_by_refnum: just like clear_window(), but it uses a refnum. If
1566  * the refnum is invalid, the current window is cleared.
1567  */
1568 void
clear_window_by_refnum(u_int refnum)1569 clear_window_by_refnum(u_int refnum)
1570 {
1571 	Window	*tmp;
1572 
1573 	if ((tmp = get_window_by_refnum(refnum)) == NULL)
1574 		tmp = curr_scr_win;
1575 	clear_window(tmp);
1576 }
1577 
1578 /*
1579  * revamp_window_levels: Given a level setting for the current window, this
1580  * makes sure that that level setting is unused by any other window. Thus
1581  * only one window in the system can be set to a given level.  This only
1582  * revamps levels for windows with servers matching the given window
1583  * it also makes sure that only one window has the level `DCC', as this is
1584  * not dependant on a server.
1585  */
1586 static	void
revamp_window_levels(Window * window)1587 revamp_window_levels(Window *window)
1588 {
1589 	Window	*tmp;
1590 	Win_Trav wt;
1591 	int	got_dcc;
1592 
1593 	got_dcc = (LOG_DCC & window->window_level) ? 1 : 0;
1594 	wt.init = 1;
1595 	while ((tmp = window_traverse(&wt)) != NULL)
1596 	{
1597 		if (tmp == window)
1598 			continue;
1599 		if (LOG_DCC & tmp->window_level)
1600 		{
1601 			if (0 != got_dcc)
1602 				tmp->window_level &= ~LOG_DCC;
1603 			got_dcc = 1;
1604 		}
1605 		if (window->server == tmp->server)
1606 			tmp->window_level ^= (tmp->window_level & window->window_level);
1607 	}
1608 }
1609 
1610 /*
1611  * set_level_by_refnum: This sets the window level given a refnum.  It
1612  * revamps the windows levels as well using revamp_window_levels()
1613  */
1614 void
set_level_by_refnum(u_int refnum,int level)1615 set_level_by_refnum(u_int refnum, int level)
1616 {
1617 	Window	*tmp;
1618 
1619 	if ((tmp = get_window_by_refnum(refnum)) == NULL)
1620 		tmp = curr_scr_win;
1621 	tmp->window_level = level;
1622 	revamp_window_levels(tmp);
1623 }
1624 
1625 /*
1626  * set_prompt_by_refnum: changes the prompt for the given window.  A window
1627  * prompt will be used as the target in place of the query user or current
1628  * channel if it is set
1629  */
1630 void
set_prompt_by_refnum(u_int refnum,u_char * prompt)1631 set_prompt_by_refnum(u_int refnum, u_char *prompt)
1632 {
1633 	Window	*tmp;
1634 
1635 	if ((tmp = get_window_by_refnum(refnum)) == NULL)
1636 		tmp = curr_scr_win;
1637 	malloc_strcpy(&tmp->prompt, prompt);
1638 }
1639 
1640 /*
1641  * message_to: This allows you to specify a window (by refnum) as a
1642  * destination for messages.  Used by EXEC routines quite nicely
1643  */
1644 void
message_to(u_int refnum)1645 message_to(u_int refnum)
1646 {
1647 	if (refnum)
1648 		set_to_window(get_window_by_refnum(refnum));
1649 	else
1650 		set_to_window(NULL);
1651 }
1652 
1653 /*
1654  * get_next_window: This returns a pointer to the next *visible* window in
1655  * the window list.  It automatically wraps at the end of the list back to
1656  * the beginning of the list
1657  */
1658 static	Window	*
get_next_window(void)1659 get_next_window(void)
1660 {
1661 	if (curr_scr_win && curr_scr_win->next)
1662 		return window_get_next(curr_scr_win);
1663 	else
1664 		return screen_get_window_list(get_current_screen());
1665 }
1666 
1667 /*
1668  * get_previous_window: this returns the previous *visible* window in the
1669  * window list.  This automatically wraps to the last window in the window
1670  * list
1671  */
1672 static	Window	*
get_previous_window(void)1673 get_previous_window(void)
1674 {
1675 	if (curr_scr_win && curr_scr_win->prev)
1676 		return window_get_prev(curr_scr_win);
1677 	else
1678 		return screen_get_window_list_end(get_current_screen());
1679 }
1680 
1681 /*
1682  * set_current_window: This sets the "current" window to window.  It also
1683  * keeps track of the last_get_current_screen()->current_window by setting it to the
1684  * previous current window.  This assures you that the new current window is
1685  * visible.
1686  * If not, a new current window is chosen from the window list
1687  */
1688 void
set_current_window(Window * window)1689 set_current_window(Window *window)
1690 {
1691 	Window	*tmp;
1692 	unsigned int	refnum;
1693 
1694 	refnum = get_last_window_refnum();
1695 	if (curr_scr_win)
1696 	{
1697 		curr_scr_win->update |= UPDATE_STATUS;
1698 		set_last_window_refnum(curr_scr_win->refnum);
1699 	}
1700 	if ((window == NULL) || (!window->visible))
1701 
1702 	{
1703 		if ((tmp = get_window_by_refnum(refnum)) && (tmp->visible))
1704 			set_curr_scr_win(tmp);
1705 		else
1706 			set_curr_scr_win(get_next_window());
1707 	}
1708 	else
1709 		set_curr_scr_win(window);
1710 	curr_scr_win->update |= UPDATE_STATUS;
1711 }
1712 
1713 /*
1714  * swap_last_window:  This swaps the current window with the last window
1715  * that was hidden.
1716  */
1717 
1718 void
swap_last_window(u_int key,u_char * ptr)1719 swap_last_window(u_int key, u_char *ptr)
1720 {
1721 	if (invisible_list == NULL)
1722 	{
1723 		/* say("There are no hidden windows"); */
1724 		/* Not sure if we need to warn   - phone. */
1725 		return;
1726 	}
1727 	swap_window(curr_scr_win, invisible_list);
1728 	update_all_windows();
1729 	cursor_to_input();
1730 }
1731 
1732 /*
1733  * next_window_key: This switches the current window to the next visible window
1734  */
1735 void
next_window_key(u_int key,u_char * ptr)1736 next_window_key(u_int key, u_char *ptr)
1737 {
1738 	if (number_of_windows() == 1)
1739 		return;
1740 	set_current_window(get_next_window());
1741 	update_all_windows();
1742 }
1743 
1744 /*
1745  * swap_next_window:  This swaps the current window with the next hidden
1746  * window.
1747  */
1748 
1749 void
swap_next_window(u_int key,u_char * ptr)1750 swap_next_window(u_int key, u_char *ptr)
1751 {
1752 	Win_Trav wt;
1753 	Window	*tmp;
1754 	u_int	next = MAXINT;
1755 	int	smallest;
1756 
1757 	if (invisible_list == NULL)
1758 	{
1759 		say("There are no hidden windows");
1760 		return;
1761 	}
1762 	smallest = curr_scr_win->refnum;
1763 	wt.init = 1;
1764 	while ((tmp = window_traverse(&wt)) != NULL)
1765 	{
1766 		if (!tmp->visible)
1767 		{
1768 			if (tmp->refnum < smallest)
1769 				smallest = tmp->refnum;
1770 			if ((tmp->refnum > curr_scr_win->refnum)
1771 			    && (next > tmp->refnum))
1772 				next = tmp->refnum;
1773 		}
1774 	}
1775 	if (next != MAXINT)
1776 		tmp = get_window_by_refnum(next);
1777 	else
1778 		tmp = get_window_by_refnum((u_int)smallest);
1779 	if (tmp)
1780 	{
1781 		swap_window(curr_scr_win, tmp);
1782 		update_all_windows();
1783 		update_all_status();
1784 		cursor_to_input();
1785 	}
1786 }
1787 
1788 /*
1789  * previous_window: This switches the current window to the previous visible
1790  * window
1791  */
1792 void
previous_window(u_int key,u_char * ptr)1793 previous_window(u_int key, u_char *ptr)
1794 {
1795 	if (number_of_windows() == 1)
1796 		return;
1797 	set_current_window(get_previous_window());
1798 	update_all_windows();
1799 }
1800 
1801 /*
1802  * swap_previous_window:  This swaps the current window with the next
1803  * hidden window.
1804  */
1805 
1806 void
swap_previous_window(u_int key,u_char * ptr)1807 swap_previous_window(u_int key, u_char *ptr)
1808 {
1809 	Win_Trav wt;
1810 	Window	*tmp;
1811 	int	previous = 0;
1812 	int	largest;
1813 
1814 	if (invisible_list == NULL)
1815 	{
1816 		say("There are no hidden windows");
1817 		return;
1818 	}
1819 	largest = curr_scr_win->refnum;
1820 	wt.init = 1;
1821 	while ((tmp = window_traverse(&wt)) != NULL)
1822 	{
1823 		if (!tmp->visible)
1824 		{
1825 			if (tmp->refnum > largest)
1826 				largest = tmp->refnum;
1827 			if ((tmp->refnum < curr_scr_win->refnum)
1828 			    && (previous < tmp->refnum))
1829 				previous = tmp->refnum;
1830 		}
1831 	}
1832 	if (previous)
1833 		tmp = get_window_by_refnum((u_int)previous);
1834 	else
1835 		tmp = get_window_by_refnum((u_int)largest);
1836 	if (tmp)
1837 	{
1838 		swap_window(curr_scr_win,tmp);
1839 		update_all_windows();
1840 		update_all_status();
1841 		cursor_to_input();
1842 	}
1843 }
1844 
1845 /*
1846  * back_window:  goes to the last window that was current.  Swapping the
1847  * current window if the last window was hidden.
1848  */
1849 
1850 void
back_window(u_int key,u_char * ptr)1851 back_window(u_int key, u_char *ptr)
1852 {
1853 	Window	*tmp;
1854 
1855 	tmp = get_window_by_refnum(get_last_window_refnum());
1856 	if (tmp)
1857 	{
1858 		if (tmp->visible)
1859 			set_current_window(tmp);
1860 		else
1861 		{
1862 			swap_window(curr_scr_win, tmp);
1863 			update_all_windows();
1864 			update_all_status();
1865 			cursor_to_input();
1866 		}
1867 	}
1868 }
1869 
1870 /*
1871  * The common way to set display_size(), also used externally.
1872  */
1873 void
window_set_display_size_normal(Window * window)1874 window_set_display_size_normal(Window *window)
1875 {
1876 	window->display_size = window->bottom - window->top -
1877 			menu_lines(window->menu) - SCROLL_DISPLAY_OFFSET;
1878 }
1879 
1880 /*
1881  * add_to_window_list: This inserts the given window into the visible window
1882  * list (and thus adds it to the displayed windows on the screen).  The
1883  * window is added by splitting the current window.  If the current window is
1884  * too small, the next largest window is used.  The added window is returned
1885  * as the function value or null is returned if the window couldn't be added
1886  */
1887 Window	*
add_to_window_list(Window * new)1888 add_to_window_list(Window *new)
1889 {
1890 	Window	*biggest = NULL,
1891 		*tmp;
1892 
1893 	incr_visible_windows();
1894 	if (curr_scr_win == NULL)
1895 	{
1896 		screen_set_window_list(get_current_screen(), new);
1897 		screen_set_window_list_end(get_current_screen(), new);
1898 		if (term_basic())
1899 		{
1900 			/* what the hell */
1901 			new->display_size = 24 - SCROLL_DISPLAY_OFFSET;
1902 			set_current_window(new);
1903 			return (new);
1904 		}
1905 		recalculate_windows();
1906 	}
1907 	else
1908 	{
1909 		/* split current window, or find a better window to split */
1910 		if ((curr_scr_win->display_size < 4) ||
1911 				get_int_var(ALWAYS_SPLIT_BIGGEST_VAR))
1912 		{
1913 			int	size = 0;
1914 
1915 			for (tmp = screen_get_window_list(get_current_screen()); tmp;
1916 					tmp = tmp->next)
1917 			{
1918 				if (tmp->display_size > size)
1919 				{
1920 					size = tmp->display_size;
1921 					biggest = tmp;
1922 				}
1923 			}
1924 			if ((biggest == NULL) || (size < 4))
1925 			{
1926 				say("Not enough room for another window!");
1927 				/* Probably a source of memory leaks */
1928 				new_free(&new);
1929 				decr_visible_windows();
1930 				return (NULL);
1931 			}
1932 		}
1933 		else
1934 			biggest = curr_scr_win;
1935 		if ((new->prev = biggest->prev) != NULL)
1936 			new->prev->next = new;
1937 		else
1938 			screen_set_window_list(get_current_screen(), new);
1939 		new->next = biggest;
1940 		biggest->prev = new;
1941 		new->top = biggest->top;
1942 		new->bottom = (biggest->top + biggest->bottom) / 2 -
1943 			new->double_status;
1944 		biggest->top = new->bottom + new->double_status + 1;
1945 		new->display_size = new->bottom - new->top -
1946 			SCROLL_DISPLAY_OFFSET;
1947 		biggest->display_size = biggest->bottom - biggest->top -
1948 			menu_lines(biggest->menu) -
1949 			SCROLL_DISPLAY_OFFSET;
1950 		new->update |= REDRAW_DISPLAY_FULL | REDRAW_STATUS;
1951 		biggest->update |= REDRAW_DISPLAY_FULL | REDRAW_STATUS;
1952 	}
1953 	return (new);
1954 }
1955 
1956 /*
1957  * remove_from_window_list: this removes the given window from the list of
1958  * visible windows.  It closes up the hole created by the windows absense in
1959  * a nice way
1960  */
1961 static void
remove_from_window_list(Window * window)1962 remove_from_window_list(Window *window)
1963 {
1964 	Window	*other;
1965 
1966 	/* find adjacent visible window to close up the screen */
1967 	for (other = window->next; other; other = other->next)
1968 	{
1969 		if (other->visible)
1970 		{
1971 			other->top = window->top;
1972 			break;
1973 		}
1974 	}
1975 	if (other == NULL)
1976 	{
1977 		for (other = window->prev; other; other = other->prev)
1978 		{
1979 			if (other->visible)
1980 			{
1981 				other->bottom = window->bottom + window->double_status - other->double_status;
1982 				break;
1983 			}
1984 		}
1985 	}
1986 	/* remove window from window list */
1987 	if (window->prev)
1988 		window->prev->next = window->next;
1989 	else
1990 		screen_set_window_list(get_current_screen(), window->next);
1991 	if (window->next)
1992 		window->next->prev = window->prev;
1993 	else
1994 		screen_set_window_list_end(get_current_screen(), window->prev);
1995 	if (window->visible)
1996 	{
1997 		decr_visible_windows();
1998 		other->display_size = other->bottom - other->top -
1999 			menu_lines(other->menu) - SCROLL_DISPLAY_OFFSET;
2000 		if (window == curr_scr_win)
2001 			set_current_window(NULL);
2002 		if (window->refnum == get_last_window_refnum())
2003 			set_last_window_refnum(curr_scr_win->refnum);
2004 	}
2005 }
2006 
2007 /*
2008  * window_check_servers: this checks the validity of the open servers vs the
2009  * current window list.  Every open server must have at least one window
2010  * associated with it.  If a window is associated with a server that's no
2011  * longer open, that window's server is set to the primary server.  If an
2012  * open server has no assicatiate windows, that server is closed.  If the
2013  * primary server is no more, a new primary server is picked from the open
2014  * servers
2015  */
2016 void
window_check_servers(void)2017 window_check_servers(void)
2018 {
2019 	Window	*tmp;
2020 	Win_Trav wt;
2021 	int	cnt, max, i, not_connected;
2022 	int	alive_servers = 0;
2023 	int	prime = -1;
2024 
2025 	max = number_of_servers();
2026 	for (i = 0; i < max; i++)
2027 	{
2028 		not_connected = !is_server_open(i);
2029 		cnt = 0;
2030 		wt.init = 1;
2031 		while ((tmp = window_traverse(&wt)) != NULL)
2032 		{
2033 			if (tmp->server == i)
2034 			{
2035 				if (not_connected)
2036 				{
2037 					tmp->server = get_primary_server();
2038 					if (tmp->current_channel)
2039 						new_free(&tmp->current_channel);
2040 				}
2041 				else
2042 				{
2043 					prime = tmp->server;
2044 					cnt++;
2045 				}
2046 			}
2047 		}
2048 		if (cnt == 0)
2049 		{
2050 #ifdef NON_BLOCKING_CONNECTS
2051 			if (!server_get_flag(i, CLOSE_PENDING))
2052 #endif /* NON_BLOCKING_CONNECTS */
2053 				close_server(i, empty_string());
2054 		}
2055 		else
2056 			alive_servers++;
2057 	}
2058 	if (!is_server_open(get_primary_server()))
2059 	{
2060 		wt.init = 1;
2061 		while ((tmp = window_traverse(&wt)) != NULL)
2062 			if (tmp->server == get_primary_server())
2063 			{
2064 				tmp->server = prime;
2065 			}
2066 		set_primary_server(prime);
2067 	}
2068 	set_connected_to_server(alive_servers);
2069 	update_all_status();
2070 	cursor_to_input();
2071 }
2072 
2073 /*
2074  * restore_previous_server: Attempts to restore all windows that were
2075  * associated with `server', that currently contain nothing, to said
2076  * server.
2077  */
2078 void
window_restore_server(int server)2079 window_restore_server(int server)
2080 {
2081 	Window	*tmp;
2082 	int	max = number_of_servers(),
2083 		i;
2084 
2085 	for (i = 0; i < max; i++)
2086 	{
2087 		Win_Trav wt;
2088 
2089 		wt.init = 1;
2090 		while ((tmp = window_traverse(&wt)) != NULL)
2091 		{
2092 			if (tmp->server == get_primary_server() &&
2093 			    tmp->prev_server == server)
2094 			{
2095 				tmp->server = tmp->prev_server;
2096 				realloc_channels(tmp);
2097 			}
2098 		}
2099 	}
2100 }
2101 
2102 /*
2103  * delete_window: This deletes the given window.  It frees all data and
2104  * structures associated with the window, and it adjusts the other windows so
2105  * they will display correctly on the screen.
2106  */
2107 void
delete_window(Window * window)2108 delete_window(Window *window)
2109 {
2110 	u_char	*tmp = NULL;
2111 
2112 	if (window == NULL)
2113 		return;
2114 	if (window->visible && number_of_windows() == 1)
2115 	{
2116 		if (invisible_list)
2117 		{
2118 			swap_window(window, invisible_list);
2119 			window = invisible_list;
2120 		}
2121 		else
2122 		{
2123 			say("You can't kill the last window!");
2124 			return;
2125 		}
2126 	}
2127 	if (window->name)
2128 		malloc_strcpy(&tmp, window->name);
2129 	else
2130 		malloc_snprintf(&tmp, "%u", window->refnum);
2131 	realloc_channels(window);
2132 	new_free(&window->status_line[0]);
2133 	new_free(&window->status_line[1]);
2134 	new_free(&window->query_nick);
2135 	new_free(&window->current_channel);
2136 	new_free(&window->logfile);
2137 	new_free(&window->name);
2138 	new_free(&window->menu);
2139 	free_display(window);
2140 	free_hold_info(&window->hold_info);
2141 	free_lastlog(window);
2142 	free_nicks(window);
2143 	if (window->visible)
2144 		remove_from_window_list(window);
2145 	else
2146 		remove_from_invisible_list(window);
2147 	new_free(&window);
2148 	window_check_servers();
2149 	do_hook(WINDOW_KILL_LIST, "%s", tmp);
2150 	new_free(&tmp);
2151 }
2152 
2153 /* delete_other_windows: zaps all visible windows except the current one */
2154 static	void
delete_other_windows(void)2155 delete_other_windows(void)
2156 {
2157 	Window	*tmp,
2158 		*cur,
2159 		*next;
2160 
2161 	cur = curr_scr_win;
2162 	tmp = screen_get_window_list(get_current_screen());
2163 	while (tmp)
2164 	{
2165 		next = tmp->next;
2166 		if (tmp != cur)
2167 		{
2168 			delete_window(tmp);
2169 			update_all_windows();
2170 		}
2171 		tmp = next;
2172 	}
2173 }
2174 
2175 /*
2176  * window_kill_swap:  Swaps with the last window that was hidden, then
2177  * kills the window that was swapped.  Give the effect of replacing the
2178  * current window with the last one, and removing it at the same time.
2179  */
2180 
2181 void
window_kill_swap(void)2182 window_kill_swap(void)
2183 {
2184 	if (invisible_list != NULL)
2185 	{
2186 		swap_last_window(0, NULL);
2187 		delete_window(get_window_by_refnum(get_last_window_refnum()));
2188 	}
2189 	else
2190 		say("There are no hidden windows!");
2191 }
2192 
2193 /*
2194  * unhold_windows: This is used by the main io loop to display held
2195  * information at an appropriate time.  Each time this is called, each
2196  * windows hold list is checked.  If there is info in the hold list and the
2197  * window is not held, the first line is displayed and removed from the hold
2198  * list.  Zero is returned if no infomation is displayed
2199  */
2200 int
unhold_windows(void)2201 unhold_windows(void)
2202 {
2203 	Window	*tmp;
2204 	Win_Trav wt;
2205 	u_char	*stuff;
2206 	int	hold_flag = 0;
2207 	int	logged;
2208 
2209 	wt.init = 1;
2210 	while ((tmp = window_traverse(&wt)) != NULL)
2211 	{
2212 		if (!window_hold_output(tmp) && (stuff = hold_queue(tmp->hold_info)))
2213 		{
2214 			logged = hold_queue_logged(tmp->hold_info);
2215 			if (rite(tmp, stuff, 1, 0, 0, logged) == 0)
2216 			{
2217 				remove_from_hold_list(tmp->hold_info);
2218 				hold_flag = 1;
2219 			}
2220 		}
2221 	}
2222 	return (hold_flag);
2223 }
2224 
2225 /*
2226  * update_window_status: This updates the status line for the given window.
2227  * If the refresh flag is true, the entire status line is redrawn.  If not,
2228  * only some of the changed portions are redrawn
2229  */
2230 void
update_window_status(Window * window,int refreshit)2231 update_window_status(Window *window, int refreshit)
2232 {
2233 	if (term_basic() || (!window->visible) || !status_update_flag || never_connected())
2234 		return;
2235 	if (window == NULL)
2236 		window = curr_scr_win;
2237 	if (refreshit)
2238 	{
2239 		new_free(&window->status_line[0]);
2240 		new_free(&window->status_line[1]);
2241 	}
2242 	make_status(window);
2243 }
2244 
2245 /*
2246  * redraw_all_status: This redraws all of the status lines for all of the
2247  * windows.
2248  */
2249 void
redraw_all_status(void)2250 redraw_all_status(void)
2251 {
2252 	Window	*tmp;
2253 
2254 	if (term_basic())
2255 		return;
2256 	for (tmp = screen_get_window_list(get_current_screen()); tmp; tmp = tmp->next)
2257 	{
2258 		new_free(&tmp->status_line[0]);
2259 		new_free(&tmp->status_line[1]);
2260 		make_status(tmp);
2261 	}
2262 	update_input(UPDATE_JUST_CURSOR);
2263 	term_flush();
2264 }
2265 
2266 /*
2267  * update_all_status: This updates all of the status lines for all of the
2268  * windows.  By updating, it only draws from changed portions of the status
2269  * line to the right edge of the screen
2270  */
2271 void
update_all_status(void)2272 update_all_status(void)
2273 {
2274 	Window	*window;
2275 	Screen	*screen;
2276 
2277 	if (term_basic() || !status_update_flag || never_connected())
2278 		return;
2279 	for (screen = screen_first(); screen; screen = screen_get_next(screen))
2280 	{
2281 		if (!screen_get_alive(screen))
2282 			continue;
2283 		for (window = screen_get_window_list(screen);window; window = window->next)
2284 			if (window->visible)
2285 				make_status(window);
2286 	}
2287 	update_input(UPDATE_JUST_CURSOR);
2288 	term_flush();
2289 }
2290 
2291 /*
2292  * status_update: sets the status_update_flag to whatever flag is.  This also
2293  * calls update_all_status(), which will update the status line if the flag
2294  * was true, otherwise it's just ignored
2295  */
2296 void
status_update(int flag)2297 status_update(int flag)
2298 {
2299 	status_update_flag = flag;
2300 	update_all_status();
2301 	cursor_to_input();
2302 }
2303 
2304 void
redraw_resized(Window * window,int bottom)2305 redraw_resized(Window *window, int bottom)
2306 {
2307 	if (bottom < 0)
2308 		term_scroll(window->top + window_menu_lines(window) + bottom,
2309 			window->top + window_menu_lines(window) +
2310 			window->display_size - 1,
2311 			bottom);
2312 	else if (bottom)
2313 		term_scroll(window->top + window_menu_lines(window),
2314 			window->top + window_menu_lines(window) +
2315 			window->display_size -1, bottom);
2316 }
2317 
2318 /*
2319  * resize_display: After determining that the screen has changed sizes, this
2320  * resizes all the internal stuff.  If the screen grew, this will add extra
2321  * empty display entries to the end of the display list.  If the screen
2322  * shrank, this will remove entries from the end of the display list.  By
2323  * doing this, we try to maintain as much of the display as possible.
2324  *
2325  * This has now been improved so that it returns enough information for
2326  * redraw_resized to redisplay the contents of the window without having
2327  * to redraw too much.
2328  */
2329 int
resize_display(Window * window)2330 resize_display(Window *window)
2331 {
2332 	int	cnt,
2333 		i;
2334 	Display *tmp, *pre_ip;
2335 	int	Wrapped = 0;
2336 	int	bottom;
2337 
2338 	bottom = 0;
2339 	if (term_basic())
2340 	{
2341 		return bottom;
2342 	}
2343 	if (!window->top_of_display)
2344 	{
2345 		window->top_of_display = new_malloc(sizeof(Display));
2346 		window->top_of_display->line = NULL;
2347 		window->top_of_display->linetype = 0;
2348 		window->top_of_display->next = window->top_of_display;
2349 		window->display_ip = window->top_of_display;
2350 		window->old_size = 1;
2351 	}
2352 	/* cnt = size - window->display_size; */
2353 	cnt = window->display_size - window->old_size;
2354 	if (cnt > 0)
2355 	{
2356 		Display *new = NULL;
2357 
2358 		/*
2359 		 * screen got bigger: got to last display entry and link
2360 		 * in new entries
2361 		 */
2362 		for (tmp = window->top_of_display, i = 0;
2363 		    i < (window->old_size - 1);
2364 		    i++, tmp = tmp->next);
2365 		for (i = 0; i < cnt; i++)
2366 		{
2367 			new = new_malloc(sizeof *new);
2368 			new->line = NULL;
2369 			new->linetype = 0;
2370 			new->next = tmp->next;
2371 			tmp->next = new;
2372 		}
2373 		if (window->display_ip == window->top_of_display &&
2374 		    window->top_of_display->line)
2375 			window->display_ip = new;
2376 		bottom = cnt;
2377 	}
2378 	else if (cnt < 0)
2379 
2380 	{
2381 		Display *ptr;
2382 		int	top = 0;
2383 
2384 		/*
2385 		 * screen shrank: find last display entry we want to keep,
2386 		 * and remove all after that point
2387 		 */
2388 		cnt = -cnt;
2389 		for (pre_ip = window->top_of_display;
2390 		    pre_ip->next != window->display_ip;
2391 		    pre_ip = pre_ip->next);
2392 		for (tmp = pre_ip->next, i = 0; i < cnt; i++, tmp = ptr)
2393 		{
2394 			ptr = tmp->next;
2395 			if (tmp == window->top_of_display)
2396 
2397 			{
2398 				if (tmp->line)
2399 					Wrapped = 1;
2400 				window->top_of_display = ptr;
2401 			}
2402 			if (Wrapped)
2403 				top--;
2404 			else
2405 				bottom--;
2406 			new_free(&(tmp->line));
2407 			new_free(&tmp);
2408 		}
2409 		window->display_ip = pre_ip->next = tmp;
2410 		window->cursor += top;
2411 		if (!window->scroll)
2412 		{
2413 			if (window->cursor == window->display_size)
2414 				window->cursor = 0;
2415 			new_free(&window->display_ip->line);
2416 		}
2417 	}
2418 	window->update |= REDRAW_DISPLAY_FULL | REDRAW_STATUS;
2419 	window->old_size = window->display_size;
2420 	return bottom;
2421 }
2422 
2423 /*
2424  * helper for recalculate_windows(): set the sizes for one window.
2425  */
2426 static void
window_set_one_size(Window * window,int size,int top)2427 window_set_one_size(Window *window, int size, int top)
2428 {
2429 	window->update |= REDRAW_DISPLAY_FULL | REDRAW_STATUS;
2430 	window->display_size = size - window_menu_lines(window)
2431 		- window->double_status - SCROLL_DISPLAY_OFFSET;
2432 	if (window->display_size <= 0)
2433 		window->display_size = 1;
2434 	window->top = top;
2435 	window->bottom = top + size - window->double_status;
2436 
2437 	Debug(DB_WINDOW, "size %d top %d set refnum %d display_size %d bottom %d",
2438 	      size, top, window->refnum, window->display_size, window->bottom);
2439 	return;
2440 }
2441 
2442 /*
2443  * helper for recalculate_windows(): hide one window
2444  */
2445 static void
hide_window_recalc(Window * window)2446 hide_window_recalc(Window *window)
2447 {
2448 	remove_from_window_list(window);
2449 	add_to_invisible_list(window);
2450 	window->display_size = get_li() - 2 - SCROLL_DISPLAY_OFFSET;
2451 	if (window == curr_scr_win)
2452 		set_current_window(NULL);
2453 }
2454 
2455 /*
2456  * recalculate_windows: this is called when the terminal size changes (as
2457  * when an xterm window size is changed).  It recalculates the sized and
2458  * positions of all the windows.
2459  *
2460  * XXX currently still buggy.
2461  */
2462 void
recalculate_windows(void)2463 recalculate_windows(void)
2464 {
2465 	Window	*window, *last_window, *next_window;
2466 	int	total_size = 0, total_menu_size = 0, total_status_size = 0;
2467 	int	win_count = 0;
2468 	int	lines, old_lines;
2469 	int	top, extra = 0;
2470 	int	recalc_failed = 0;
2471 	double	change;
2472 
2473 	if (term_basic() || number_of_windows() == 0)
2474 		return;
2475 
2476 	/*
2477 	 * Calculate the totals we have right now.
2478 	 */
2479 	for (window = screen_get_window_list(get_current_screen());
2480 	     window; window = window_get_next(window))
2481 	{
2482 		total_status_size += window->double_status - SCROLL_DISPLAY_OFFSET;
2483 		total_size += window->display_size;
2484 		total_menu_size += window_menu_lines(window);
2485 		win_count++;
2486 	}
2487 	Debug(DB_WINDOW, "old total size %d menu lines %d wincount %d",
2488 	      total_size, total_menu_size, win_count);
2489 
2490 	old_lines = screen_get_old_li() - 2;
2491 	lines = get_li() - 2;
2492 
2493 	if (win_count == 1)
2494 	{
2495 		window = screen_get_window_list(get_current_screen());
2496 		window_set_one_size(window, lines, 0);
2497 		return;
2498 	}
2499 
2500 	/*
2501 	 * Check everything still fits.  If not, hide windows until they do.
2502 	 */
2503 	if (total_status_size + win_count > lines) {
2504 		for (window = screen_get_window_list(get_current_screen());
2505 		     window; window = next_window)
2506 		{
2507 			next_window = window_get_next(window);
2508 
2509 			Debug(DB_WINDOW, "hiding window %d", window->refnum);
2510 			total_status_size -= window->double_status - SCROLL_DISPLAY_OFFSET;
2511 			win_count--;
2512 
2513 			hide_window_recalc(window);
2514 
2515 			if (total_status_size + win_count <= lines)
2516 				break;
2517 		}
2518 		/* Now we've hidden a bunch, re-balance the rest */
2519 		balance_windows();
2520 		return;
2521 	}
2522 
2523 	change = lines;
2524 	change /= old_lines;
2525 
2526 	Debug(DB_WINDOW, "change %lf (old %d / new %d)", change, old_lines, lines);
2527 
2528 	for (top = 0, window = screen_get_window_list(get_current_screen());
2529 	     window;
2530 	     last_window = window, window = next_window)
2531 	{
2532 		int new_size;
2533 		double adjsize; /* could use fixed-point */
2534 
2535 		next_window = window_get_next(window);
2536 
2537 		adjsize = window->display_size;
2538 		adjsize *= change;
2539 		new_size = (int)adjsize;
2540 		if (new_size == 0)
2541 			new_size = 1;
2542 
2543 		if (lines - (top + new_size) < 0)
2544 		{
2545 			Debug(DB_WINDOW, "hiding window %d", window->refnum);
2546 			hide_window_recalc(window);
2547 			recalc_failed = 1;
2548 			win_count--;
2549 			continue;
2550 		}
2551 
2552 		Debug(DB_WINDOW, "refnum %d new display size %d (old %d)",
2553 		      window->refnum, new_size, window->display_size);
2554 
2555 		/*
2556 		 * calculate the extra lines when we're at the last window.
2557 		 */
2558 		if (--win_count == 0 && (top + new_size != lines))
2559 		{
2560 			extra = lines - (top + new_size);
2561 			Debug(DB_WINDOW, "top[%d] + new_size[%d] != lines[%d], "
2562 					 "saving extra = %d",
2563 			      top, new_size, lines, extra);
2564 		}
2565 
2566 		window_set_one_size(window, new_size, top);
2567 		top += new_size + 1;
2568 	}
2569 
2570 	/*
2571 	 * If we failed while recalculating, fall back to balance.
2572 	 */
2573 	if (recalc_failed)
2574 	{
2575 		balance_windows();
2576 		return;
2577 	}
2578 
2579 	if (!extra)
2580 		return;
2581 
2582 	/* if extra is negative, we've really gone wrong .. */
2583 	if (extra < 0)
2584 		abort();
2585 
2586 	/*
2587 	 * if we had extra, we distribute it out to the windows from the
2588 	 * bottom up, adjusting them as we go.
2589 	 */
2590 	for (window = last_window; extra; extra--, window = window_get_prev(window))
2591 	{
2592 		if (window == NULL)
2593 			window = last_window;
2594 		window->display_size++;
2595 		window->top += extra - 1;
2596 		window->bottom += extra;
2597 		Debug(DB_WINDOW, "refnum %d now top = %d bottom = %d display_size = %d",
2598 		      window->refnum, window->top, window->bottom, window->display_size);
2599 	}
2600 }
2601 
2602 /*
2603  * balance_windows: back end for /window balance.  window sizes are
2604  * spread as evenly as possible.
2605  */
2606 void
balance_windows(void)2607 balance_windows(void)
2608 {
2609 	int	base_size,
2610 		size,
2611 		top,
2612 		extra;
2613 	Window	*tmp;
2614 
2615 	if (term_basic() || number_of_windows() == 0)
2616 		return;
2617 
2618 	base_size = ((get_li() - 1) / number_of_windows()) - 1;
2619 	extra = (get_li() - 1) - ((base_size + 1) * number_of_windows());
2620 	top = 0;
2621 	for (tmp = screen_get_window_list(get_current_screen()); tmp; tmp = window_get_next(tmp))
2622 	{
2623 		tmp->update |= REDRAW_DISPLAY_FULL | REDRAW_STATUS;
2624 		if (extra)
2625 		{
2626 			extra--;
2627 			size = base_size + 1;
2628 		}
2629 		else
2630 			size = base_size;
2631 		tmp->display_size = size - window_menu_lines(tmp)
2632 			- tmp->double_status - SCROLL_DISPLAY_OFFSET;
2633 		if (tmp->display_size <= 0)
2634 			tmp->display_size = 1;
2635 		tmp->top = top;
2636 		tmp->bottom = top + size - tmp->double_status;
2637 		top += size + 1;
2638 	}
2639 }
2640 
2641 /*
2642  * clear_window: This clears the display list for the given window, or
2643  * current window if null is given.
2644  */
2645 void
clear_window(Window * window)2646 clear_window(Window *window)
2647 {
2648 	int	i,
2649 		cnt;
2650 
2651 	if (term_basic())
2652 		return;
2653 	if (window == NULL)
2654 		window = curr_scr_win;
2655 	erase_display(window);
2656 	term_move_cursor(0, window->top + window_menu_lines(window));
2657 	cnt = window->bottom - window->top - window_menu_lines(window);
2658 	for (i = 0; i < cnt; i++)
2659 	{
2660 		if (term_clear_to_eol())
2661 			term_space_erase(0);
2662 		term_newline();
2663 	}
2664 	term_flush();
2665 }
2666 
2667 /* clear_all_windows: This clears all *visible* windows */
2668 void
clear_all_windows(int unhold)2669 clear_all_windows(int unhold)
2670 {
2671 	Window	*tmp;
2672 
2673 	for (tmp = screen_get_window_list(get_current_screen()); tmp; tmp = window_get_next(tmp))
2674 	{
2675 		if (unhold)
2676 			window_hold_mode(tmp, OFF, 1);
2677 		clear_window(tmp);
2678 	}
2679 }
2680 
2681 /*
2682  * redraw_window: This redraws the display list for the given window. Some
2683  * special considerations are made if you are just redrawing one window as
2684  * opposed to using this routine to redraw the whole screen one window at a
2685  * time
2686  *
2687  * A negative value in just_one indicates not all of the window needs to
2688  * be redrawn.
2689  */
2690 static void
redraw_window(Window * window,int just_one,int backscroll)2691 redraw_window(Window *window, int just_one, int backscroll)
2692 {
2693 	Display *tmp;
2694 	int	i;
2695 	int	StartPoint;
2696 	int	yScr;
2697 
2698 	if (term_basic() || !window->visible)
2699 		return;
2700 	window = window ? window : curr_scr_win;
2701 	if (just_one < 0)
2702 	{
2703 		/* This part of the window is scrolling into view */
2704 		StartPoint = -just_one;
2705 		just_one = 0;
2706 	}
2707 	else
2708 	{
2709 		StartPoint = 0;
2710 		if (window->scrolled_lines)
2711 			display_lastlog_lines(window->scrolled_lines - window->display_size,
2712 				window->scrolled_lines, window);
2713 	}
2714 	if (menu_active(window_get_menu(window)))
2715 		show_menu_by_window(window, just_one ? SMF_ERASE : 0);
2716 	if (window->scrolled_lines + StartPoint < window->display_size)
2717 		yScr = window->scrolled_lines + StartPoint;
2718 	else
2719 		yScr = 0;
2720 	term_move_cursor(0, window->top+window_menu_lines(window)+yScr);
2721 	/*
2722 	 * if (term_clear_to_eol())
2723 	 *	{ term_space_erase(0); term_cr(); }
2724 	 */
2725 	for (tmp = window->top_of_display, i = 0; i < window->display_size-window->scrolled_lines; i++, tmp = tmp->next)
2726 	{
2727 		if (i < StartPoint)
2728 			continue;
2729 		if (tmp->line)
2730 			rite(window, tmp->line, 1, 1, backscroll, 0);
2731 		else
2732 		{
2733 			if (just_one)
2734 			{
2735 				if (term_clear_to_eol())
2736 					term_space_erase(0);
2737 			}
2738 			term_newline();
2739 		}
2740 	}
2741 	term_flush();
2742 }
2743 
2744 /*
2745  * recalculate_window_positions: This runs through the window list and
2746  * re-adjusts the top and bottom fields of the windows according to their
2747  * current positions in the window list.  This doesn't change any sizes of
2748  * the windows
2749  */
2750 void
recalculate_window_positions(void)2751 recalculate_window_positions(void)
2752 {
2753 	Window	*tmp;
2754 	int	top;
2755 
2756 	top = 0;
2757 	for (tmp = screen_get_window_list(get_current_screen()); tmp; tmp = window_get_next(tmp))
2758 	{
2759 		tmp->update |= REDRAW_DISPLAY_FULL | REDRAW_STATUS;
2760 		tmp->top = top;
2761 		tmp->bottom = top + tmp->display_size + window_menu_lines(tmp);
2762 		top += tmp->display_size + window_menu_lines(tmp) + 1 +
2763 			tmp->double_status;
2764 	}
2765 }
2766 
2767 /*
2768  * redraw_all_windows: This basically clears and redraws the entire display
2769  * portion of the screen.  All windows and status lines are draws.  This does
2770  * nothing for the input line of the screen.  Only visible windows are drawn
2771  */
2772 void
redraw_all_windows(void)2773 redraw_all_windows(void)
2774 {
2775 	Window	*tmp;
2776 
2777 	if (term_basic())
2778 		return;
2779 	for (tmp = screen_get_window_list(get_current_screen()); tmp; tmp = window_get_next(tmp))
2780 		tmp->update |= REDRAW_STATUS | REDRAW_DISPLAY_FAST;
2781 }
2782 
2783 /*
2784  * is_current_channel: Returns true is channel is a current channel for any
2785  * window.  If the delete_window is not 0, then unset channel as the current
2786  * channel and attempt to replace it by a non-current channel or the
2787  * current_channel of window specified by value of delete
2788  */
2789 int
is_current_channel(u_char * channel,int server,int delete)2790 is_current_channel(u_char *channel, int server, int delete)
2791 {
2792 	Window	*tmp,
2793 		*found_window = NULL;
2794 	Win_Trav wt;
2795 	int	found = 0;
2796 
2797 	wt.init = 1;
2798 	while ((tmp = window_traverse(&wt)) != NULL)
2799 	{
2800 		u_char	*c = tmp->current_channel;
2801 
2802 		if (c && !my_stricmp(channel, c) && tmp->server == server)
2803 		{
2804 			found_window = tmp;
2805 			found = 1;
2806 			if (delete)
2807 			{
2808 				new_free(&tmp->current_channel);
2809 				tmp->update |= UPDATE_STATUS;
2810 			}
2811 		}
2812 	}
2813 	if (found && delete)
2814 		found = channel_is_on_window(channel, server, found_window, delete);
2815 
2816 	return found;
2817 }
2818 
2819 Window *
is_bound(u_char * channel,int server)2820 is_bound(u_char *channel, int server)
2821 {
2822 	Win_Trav wt;
2823 	Window *tmp;
2824 
2825 	wt.init = 1;
2826 	while ((tmp = window_traverse(&wt)))
2827 	{
2828 		if (tmp->server == server && tmp->bound_channel &&
2829 		    !my_stricmp(channel, tmp->bound_channel))
2830 			return tmp;
2831 	}
2832 
2833 	return NULL;
2834 }
2835 
2836 static void
bind_channel(u_char * channel,Window * window)2837 bind_channel(u_char *channel, Window *window)
2838 {
2839 	Win_Trav wt;
2840 	Window *tmp;
2841 
2842 	/* check it isn't bound on this server elsewhere */
2843 	wt.init = 1;
2844 	while ((tmp = window_traverse(&wt)))
2845 	{
2846 		if (tmp->server != window->server && tmp == window)
2847 			continue;
2848 		if (!my_stricmp(tmp->bound_channel, channel) && tmp != window)
2849 		{
2850 			say("Channel %s is already bound to window %d", channel, tmp->refnum);
2851 			return;
2852 		}
2853 	}
2854 	if (is_on_channel(channel, window->server, server_get_nickname(window->server)))
2855 	{
2856 		is_current_channel(channel, window->server, (int)window->refnum);
2857 		set_channel_by_refnum(0, channel);
2858 	}
2859 	/* XXX fix this */
2860 #if 0
2861 	else
2862 	{
2863 		int	server, sg = -1, fsg = -2;	/* different */
2864 		u_char	*group;
2865 
2866 		server = set_from_server(window->server);
2867 
2868 		group = server_get_server_group(server);
2869 		if (group)
2870 			sg = find_server_group(group, 0);
2871 
2872 		if (sg == 0 || fsg == 0)
2873 			yell("--- huh. coudn't find server groups");
2874 
2875 		if (sg == fsg)
2876 		{
2877 			switch (server_get_version(window->server)) {
2878 			case ServerICB:
2879 				icb_put_group(channel);
2880 				break;
2881 			default:
2882 				send_to_server("JOIN %s", channel);
2883 			}
2884 			add_channel(channel, 0, get_from_server(), CHAN_JOINING, NULL);
2885 		}
2886 		set_from_server(server);
2887 	}
2888 #endif
2889 	malloc_strcpy(&window->bound_channel, channel);
2890 	say("Channel %s bound to window %d", channel, window->refnum);
2891 }
2892 
2893 static void
unbind_channel(u_char * channel,Window * window)2894 unbind_channel(u_char *channel, Window *window)
2895 {
2896 
2897 	window = is_bound(channel, window->server);
2898 	if (!window)
2899 		return;
2900 	new_free(&window->bound_channel);
2901 }
2902 
2903 /*
2904  * get_window_server: returns the server index for the window with the given
2905  * refnum
2906  */
2907 int
get_window_server(unsigned refnum)2908 get_window_server(unsigned refnum)
2909 {
2910 	Window	*tmp;
2911 
2912 	if ((tmp = get_window_by_refnum(refnum)) == NULL)
2913 		tmp = curr_scr_win;
2914 	return (tmp->server);
2915 }
2916 
2917 /*
2918  * window_set_server:  This sets the server of the given window to server.
2919  * If refnum is -1 then we are setting the primary server and all windows
2920  * that are set to the current primary server are changed to server.  The misc
2921  * flag is ignored in this case.  If refnum is not -1, then that window is
2922  * set to the given server.  If WIN_ALL is set in misc, then all windows
2923  * with the same server as refnum are set to the new server as well.
2924  * If the window is in a group, all the group is set to the new server.
2925  * WIN_TRANSFER will move the channels to the new server, WIN_FORCE will
2926  * force a 'sticky' behaviour of the window. -Sol
2927  */
2928 void
window_set_server(int refnum,int server,int misc)2929 window_set_server(int refnum, int server, int misc)
2930 {
2931 	int	old_serv = -2; // -2 for unset
2932 	Window	*window = 0, *ptr, *new_win = NULL;
2933 	int	moved = 0;
2934 	Win_Trav wt;
2935 
2936 	if (refnum == -1)
2937 	{
2938 		old_serv = get_primary_server();
2939 		set_primary_server(server);
2940 		misc |= WIN_ALL;
2941 	}
2942 	else
2943 	{
2944 		window = get_window_by_refnum((u_int)refnum);
2945 		if (window)
2946 		{
2947 			old_serv = window->server;
2948 		}
2949 	}
2950 
2951 	if (server == old_serv)
2952 		return;
2953 
2954 	/* Moving all windows associated with old_serv -Sol */
2955 	if (misc & WIN_ALL)
2956 	{
2957 		if ((misc & WIN_TRANSFER) && (old_serv >= 0))
2958 		{
2959 			moved = channels_move_server_simple(old_serv, server);
2960 
2961 #ifdef NON_BLOCKING_CONNECTS
2962 			if (server_get_flag(old_serv, CLOSE_PENDING))
2963 				server_set_flag(old_serv, CLEAR_PENDING, 1);
2964 			else
2965 #endif /* NON_BLOCKING_CONNECTS */
2966 				clear_channel_list(old_serv);
2967 		}
2968 		wt.init = 1;
2969 		while ((ptr = window_traverse(&wt)) != NULL)
2970 			if (ptr->server == old_serv)
2971 			{
2972 				ptr->server = server;
2973 				/*
2974 				 * XXX we could save this to old_current_channel and use
2975 				 * that after other checks to decide where a channel should
2976 				 * go, maybe??
2977 				 */
2978 				if (ptr->current_channel)
2979 					new_free(&ptr->current_channel);
2980 			}
2981 		window_check_servers();
2982 		return;
2983 	}
2984 
2985 	/*
2986 	 * We are setting only some windows of the old server : let's look
2987 	 * for a window of that server that is not being moved.
2988 	 * refnum == -1 has been dealt with above so window is defined. -Sol
2989 	 */
2990 
2991 	wt.init = 1;
2992 	while ((ptr = window_traverse(&wt)) != NULL)
2993 		if (ptr != window &&
2994 		    (!ptr->server_group || (ptr->server_group != window->server_group)) &&
2995 		    ptr->server == old_serv)
2996 		{
2997 			/* Possible relocation -Sol */
2998 			new_win = ptr;
2999 
3000 			/* Immediately retain window if no group -Sol */
3001 			if (!ptr->server_group)
3002 				break;
3003 		}
3004 
3005 	/* No relocation : we're closing last windows for old_serv -Sol */
3006 	if (!new_win)
3007 	{
3008 		window_set_server(refnum, server, misc | WIN_ALL);
3009 		return;
3010 	}
3011 
3012 	/*
3013 	 * Now that we know that server still has at least one window open,
3014 	 * move what we're supposed to -Sol
3015 	 */
3016 
3017 	if ((misc & WIN_TRANSFER) && (old_serv >= 0) && server_get_version(old_serv) != ServerICB)
3018 		channels_move_server_complex(window, new_win, old_serv, server, misc, moved);
3019 
3020 	wt.init = 1;
3021 	while ((ptr = window_traverse(&wt)) != NULL)
3022 		if ((ptr == window) || (ptr->server_group && (ptr->server_group == window->server_group)))
3023 		{
3024 			ptr->server = server;
3025 			if (ptr->current_channel)
3026 				new_free(&ptr->current_channel);
3027 		}
3028 	window_check_servers();
3029 }
3030 
3031 /*
3032  * set_channel_by_refnum: This sets the current channel for the current
3033  * window. It returns the current channel as its value.  If channel is null,
3034  * the * current channel is not changed, but simply reported by the function
3035  * result.  This treats as a special case setting the current channel to
3036  * channel "0".  This frees the current_channel for the
3037  * get_current_screen()->current_window, * setting it to null
3038  */
3039 u_char	*
set_channel_by_refnum(unsigned refnum,u_char * channel)3040 set_channel_by_refnum(unsigned refnum, u_char *channel)
3041 {
3042 	Window	*tmp;
3043 	Window *tmp2;
3044 	Win_Trav wt;
3045 
3046 	if ((tmp = get_window_by_refnum(refnum)) == NULL)
3047 		tmp = curr_scr_win;
3048 	if (channel && my_strcmp(channel, zero()) == 0)
3049 		channel = NULL;
3050 
3051 	wt.init = 1;
3052 	while ((tmp2 = window_traverse(&wt)))
3053 		if (tmp2->server == tmp->server && my_stricmp(tmp2->current_channel, channel) == 0)
3054 			new_free(&tmp2->current_channel);
3055 
3056 	malloc_strcpy(&tmp->current_channel, channel);
3057 	tmp->update |= UPDATE_STATUS;
3058 	set_channel_window(tmp, channel, tmp->server);
3059 	return (channel);
3060 }
3061 
3062 /* get_channel_by_refnum: returns the current channel for window refnum */
3063 u_char	*
get_channel_by_refnum(u_int refnum)3064 get_channel_by_refnum(u_int refnum)
3065 {
3066 	Window	*tmp;
3067 
3068 	if ((tmp = get_window_by_refnum(refnum)) == NULL)
3069 		tmp = curr_scr_win;
3070 	return (tmp->current_channel);
3071 }
3072 
3073 /* current_refnum: returns the reference number for the current window */
3074 unsigned int
current_refnum(void)3075 current_refnum(void)
3076 {
3077 	return (curr_scr_win->refnum);
3078 }
3079 
3080 /* query_nick: Returns the query nick for the current channel */
3081 u_char	*
query_nick(void)3082 query_nick(void)
3083 {
3084 	return (curr_scr_win->query_nick);
3085 }
3086 
3087 /* get_prompt_by_refnum: returns the prompt for the given window refnum */
3088 u_char	*
get_prompt_by_refnum(u_int refnum)3089 get_prompt_by_refnum(u_int refnum)
3090 {
3091 	Window	*tmp;
3092 
3093 	if ((tmp = get_window_by_refnum(refnum)) == NULL)
3094 		tmp = curr_scr_win;
3095 	if (tmp->prompt)
3096 		return (tmp->prompt);
3097 	else
3098 		return (empty_string());
3099 }
3100 
3101 /*
3102  * get_target_by_refnum: returns the target for the window with the given
3103  * refnum (or for the current window).  The target is either the query nick
3104  * or current channel for the window
3105  */
3106 u_char	*
get_target_by_refnum(u_int refnum)3107 get_target_by_refnum(u_int refnum)
3108 {
3109 	Window	*tmp;
3110 
3111 	if ((tmp = get_window_by_refnum(refnum)) == NULL)
3112 		tmp = curr_scr_win;
3113 	if (tmp->query_nick)
3114 		return tmp->query_nick;
3115 	else if (tmp->current_channel)
3116 		return tmp->current_channel;
3117 	else
3118 		return NULL;
3119 }
3120 
3121 /* set_query_nick: sets the query nick for the current channel to nick */
3122 void
set_query_nick(u_char * nick)3123 set_query_nick(u_char *nick)
3124 {
3125 	if (curr_scr_win->query_nick)
3126 	{
3127 		new_free(&curr_scr_win->query_nick);
3128 		curr_scr_win->update |= UPDATE_STATUS;
3129 	}
3130 
3131 	if (nick)
3132 	{
3133 		malloc_strcpy(&curr_scr_win->query_nick, nick);
3134 		curr_scr_win->update |= UPDATE_STATUS;
3135 	}
3136 	update_window_status(curr_scr_win, 0);
3137 }
3138 
3139 /*
3140  * irc_goto_window: This will switch the current window to the window numbered
3141  * "which", where which is 0 through the number of visible windows on the
3142  * screen.  The which has nothing to do with the windows refnum.
3143  */
3144 static	void
irc_goto_window(int which)3145 irc_goto_window(int which)
3146 {
3147 	Window	*tmp;
3148 	int	i;
3149 
3150 
3151 	if (which == 0)
3152 		return;
3153 	if ((which < 0) || (which > number_of_windows()))
3154 	{
3155 		say("GOTO: Illegal value");
3156 		return;
3157 	}
3158 	tmp = screen_get_window_list(get_current_screen());
3159 	for (i = 1; tmp && (i != which); tmp = tmp->next, i++)
3160 		;
3161 	set_current_window(tmp);
3162 }
3163 
3164 /*
3165  * hide_window: sets the given window to invisible and recalculates remaing
3166  * windows to fill the entire screen
3167  */
3168 static void
hide_window(Window * window)3169 hide_window(Window *window)
3170 {
3171 	if (number_of_windows() == 1)
3172 	{
3173 		say("You can't hide the last window.");
3174 		return;
3175 	}
3176 	if (window->visible)
3177 	{
3178 		remove_from_window_list(window);
3179 		add_to_invisible_list(window);
3180 		window->display_size = get_li() - 2 - SCROLL_DISPLAY_OFFSET;
3181 		set_current_window(NULL);
3182 	}
3183 }
3184 
3185 /* hide_other_windows: makes all visible windows but the current one hidden */
3186 static void
hide_other_windows(void)3187 hide_other_windows(void)
3188 {
3189 	Window	*tmp,
3190 		*cur,
3191 		*next;
3192 
3193 	cur = curr_scr_win;
3194 	tmp = screen_get_window_list(get_current_screen());
3195 	while (tmp)
3196 	{
3197 		next = tmp->next;
3198 		if (tmp != cur)
3199 			hide_window(tmp);
3200 		tmp = next;
3201 	}
3202 }
3203 
3204 #define WIN_FORM "%%-4s %%-%u.%us %%-%u.%us  %%-%u.%us %%-9.9s %%-10.10s %%s%%s"
3205 #define WIN_FORM_HOOK "%d %s %s %s %s %s %s %s %s"
3206 
3207 static	void
list_a_window(Window * window,int len,int clen)3208 list_a_window(Window *window, int len, int clen)
3209 {
3210 	u_char	tmp[10];
3211 
3212 	snprintf(CP(tmp), sizeof tmp, "%-4u", window->refnum);
3213 	if (do_hook(WINDOW_LIST_LIST, WIN_FORM_HOOK,
3214 		    len,
3215 		    tmp,
3216 		    window->server ?
3217 			server_get_nickname(window->server) : (u_char *) "<None>",
3218 		    window->name ?
3219 			window->name : (u_char *) "<None>",
3220 		    window->current_channel ?
3221 			window->current_channel : (u_char *) "<None>",
3222 		    window->query_nick ?
3223 			window->query_nick : (u_char *) "<None>",
3224 		    window->server != -1 ?
3225 			server_get_itsname(window->server) : (u_char *) "<None>",
3226 		    bits_to_lastlog_level(window->window_level),
3227 		    (window->visible) ?
3228 			"" : " Hidden"))
3229 	{
3230 		const	unsigned old_nick_len = 9;
3231 		u_char	*buffer = NULL;
3232 
3233 		malloc_snprintf(&buffer, WIN_FORM, old_nick_len,
3234 			old_nick_len, len, len, clen, clen);
3235 		say(CP(buffer), tmp,
3236 		    window->server ?
3237 			server_get_nickname(window->server) : (u_char *) "<None>",
3238 		    window->name ?
3239 			window->name : (u_char *) "<None>",
3240 		    window->current_channel ?
3241 			window->current_channel : (u_char *) "<None>",
3242 		    window->query_nick ?
3243 			window->query_nick : (u_char *) "<None>",
3244 		    window->server != -1 ?
3245 			server_get_itsname(window->server) : (u_char *) "<None>",
3246 		    bits_to_lastlog_level(window->window_level),
3247 		    (window->visible) ?
3248 			"" : " Hidden");
3249 		new_free(&buffer);
3250 	}
3251 }
3252 
3253 /*
3254  * list_windows: This Gives a terse list of all the windows, visible or not,
3255  * by displaying their refnums, current channel, and current nick
3256  */
3257 static	void
list_windows(void)3258 list_windows(void)
3259 {
3260 	Window	*tmp;
3261 	Win_Trav wt;
3262 	int	len = 4;
3263 	int	clen = get_int_var(CHANNEL_NAME_WIDTH_VAR);
3264 	int	check_clen = clen == 0;
3265 
3266 	wt.init = 1;
3267 	while ((tmp = window_traverse(&wt)) != NULL)
3268 	{
3269 		if (tmp->name && ((int) my_strlen(tmp->name) > len))
3270 			len = my_strlen(tmp->name);
3271 		if (check_clen == 0)
3272 			continue;
3273 		if (tmp->current_channel &&
3274 		    ((int) my_strlen(tmp->current_channel) > clen))
3275 			clen = my_strlen(tmp->current_channel);
3276 	}
3277 	if (do_hook(WINDOW_LIST_LIST, WIN_FORM_HOOK, len,
3278 		    "Ref", "Nick", "Name", "Channel", "Query",
3279 		    "Server", "Level", empty_string()))
3280 	{
3281 		const	unsigned old_nick_len = 9;
3282 		u_char	*buffer = NULL;
3283 
3284 		malloc_snprintf(&buffer, WIN_FORM, old_nick_len,
3285 			old_nick_len, len, len, clen, clen);
3286 		say(CP(buffer),
3287 		    "Ref", "Nick", "Name", "Channel", "Query",
3288 		    "Server", "Level", empty_string());
3289 		new_free(&buffer);
3290 	}
3291 	wt.init = 1;
3292 	while ((tmp = window_traverse(&wt)) != NULL)
3293 		list_a_window(tmp, len, clen);
3294 }
3295 
3296 /* show_window: This makes the given window visible.  */
3297 static	void
show_window(Window * window)3298 show_window(Window *window)
3299 {
3300 	if (window->visible)
3301 	{
3302 		set_current_window(window);
3303 		return;
3304 	}
3305 	remove_from_invisible_list(window);
3306 	if (add_to_window_list(window))
3307 		set_current_window(window);
3308 	else
3309 		add_to_invisible_list(window);
3310 }
3311 
3312 /* push_window_by_refnum:  This pushes the given refnum onto the window stack */
3313 static	void
push_window_by_refnum(u_int refnum)3314 push_window_by_refnum(u_int refnum)
3315 {
3316 	WindowStack *new;
3317 
3318 	new = new_malloc(sizeof *new);
3319 	new->refnum = refnum;
3320 	new->next = get_window_stack();
3321 	set_window_stack(new);
3322 }
3323 
3324 /*
3325  * pop_window: this pops the top entry off the window stack and sets the
3326  * current window to that window.  If the top of the window stack is no
3327  * longer a valid window, then that entry is discarded and the next entry
3328  * down is tried (as so on).  If the stack is empty, the current window is
3329  * left unchanged
3330  */
3331 static	void
pop_window(void)3332 pop_window(void)
3333 {
3334 	int	refnum;
3335 	WindowStack *tmp;
3336 	Window	*win;
3337 
3338 	while (1)
3339 	{
3340 		WindowStack *window_stack = get_window_stack();
3341 
3342 		if (window_stack)
3343 		{
3344 			refnum = window_stack->refnum;
3345 			tmp = window_stack->next;
3346 			new_free(&window_stack);
3347 			set_window_stack(tmp);
3348 			if ((win = get_window_by_refnum((u_int)refnum)) != NULL)
3349 			{
3350 				if (!win->visible)
3351 					show_window(win);
3352 				else
3353 					set_current_window(win);
3354 				break;
3355 			}
3356 		}
3357 		else
3358 		{
3359 			say("The window stack is empty!");
3360 			break;
3361 		}
3362 	}
3363 }
3364 
3365 /*
3366  * show_stack: displays the current window stack.  This also purges out of
3367  * the stack any window refnums that are no longer valid
3368  */
3369 static	void
show_stack(void)3370 show_stack(void)
3371 {
3372 	WindowStack	*last = NULL,
3373 			*tmp, *crap;
3374 	Window	*win;
3375 	Win_Trav wt;
3376 	int	len = 4;
3377 	int	clen = get_int_var(CHANNEL_NAME_WIDTH_VAR);
3378 	int	check_clen = clen == 0;
3379 
3380 	wt.init = 1;
3381 	while ((win = window_traverse(&wt)) != NULL)
3382 	{
3383 		if (win->name && ((int) my_strlen(win->name) > len))
3384 			len = my_strlen(win->name);
3385 		if (check_clen == 0)
3386 			continue;
3387 		if (win->current_channel && ((int) my_strlen(win->current_channel) > clen))
3388 			clen = my_strlen(win->current_channel);
3389 	}
3390 	say("Window stack:");
3391 	tmp = get_window_stack();
3392 	while (tmp)
3393 	{
3394 		if ((win = get_window_by_refnum(tmp->refnum)) != NULL)
3395 		{
3396 			list_a_window(win, len, clen);
3397 			tmp = tmp->next;
3398 		}
3399 		else
3400 		{
3401 			crap = tmp->next;
3402 			new_free(&tmp);
3403 			if (last)
3404 				last->next = crap;
3405 			else
3406 				set_window_stack(crap);
3407 			tmp = crap;
3408 		}
3409 	}
3410 }
3411 
3412 /*
3413  * create_refnum: this generates a reference number for a new window that is
3414  * not currently is use by another window.  A refnum of 0 is reserved (and
3415  * never returned by this routine).  Using a refnum of 0 in the message_to()
3416  * routine means no particular window (stuff goes to CRAP)
3417  */
3418 static	u_int
create_refnum(void)3419 create_refnum(void)
3420 {
3421 	unsigned int	new_refnum = 1;
3422 	Window	*tmp;
3423 	int	done = 0;
3424 
3425 	while (!done)
3426 	{
3427 		Win_Trav wt;
3428 
3429 		done = 1;
3430 		if (new_refnum == 0)
3431 			new_refnum++;
3432 
3433 		wt.init = 1;
3434 		while ((tmp = window_traverse(&wt)) != NULL)
3435 		{
3436 			if (window_get_refnum(tmp) == new_refnum)
3437 			{
3438 				done = 0;
3439 				new_refnum++;
3440 				break;
3441 			}
3442 		}
3443 	}
3444 	return (new_refnum);
3445 }
3446 
3447 /*
3448  * new_window: This creates a new window on the screen.  It does so by either
3449  * splitting the current window, or if it can't do that, it splits the
3450  * largest window.  The new window is added to the window list and made the
3451  * current window
3452  *
3453  * move this into window.c.
3454  */
3455 Window	*
new_window(void)3456 new_window(void)
3457 {
3458 	Window	*new;
3459 	static	int	no_screens = 1;
3460 
3461 	if (no_screens)
3462 	{
3463 		set_current_screen(create_new_screen());
3464 		set_main_screen(get_current_screen());
3465 		no_screens = 0;
3466 	}
3467 	if (term_basic() && (number_of_windows() == 1))
3468 		return NULL;
3469 	new = new_malloc(sizeof *new);
3470 	new->refnum = create_refnum();
3471 	if (curr_scr_win)
3472 		new->server = curr_scr_win->server;
3473 	else
3474 		new->server = get_primary_server();
3475 	new->prev_server = -1;
3476 	new->line_cnt = 0;
3477 	if (number_of_windows() == 0)
3478 		new->window_level = LOG_DEFAULT;
3479 	else
3480 		new->window_level = LOG_NONE;
3481 	new->hold_mode = get_int_var(HOLD_MODE_VAR);
3482 	new->hold_info = alloc_hold_info();
3483 	new->scroll = get_int_var(SCROLL_VAR);
3484 	new->lastlog_info = lastlog_new_window();
3485 	new->nicks = 0;
3486 	new->name = 0;
3487 	new->prompt = 0;
3488 	new->current_channel = 0;
3489 	new->bound_channel = 0;
3490 	new->query_nick = 0;
3491 	new->hold_on_next_rite = 0;
3492 	new->status_line[0] = NULL;
3493 	new->status_line[1] = NULL;
3494 	new->double_status = 0;
3495 	new->top_of_display = 0;
3496 	new->display_ip = 0;
3497 	new->display_size = 1;
3498 	new->old_size = 1;
3499 	new->scrolled_lines = 0;
3500 	new->new_scrolled_lines = 0;
3501 	new->next = 0;
3502 	new->prev = 0;
3503 	new->cursor = 0;
3504 	new->visible = 1;
3505 	new->screen = get_current_screen();
3506 	new->logfile = 0;
3507 	new->log = 0;
3508 	new->log_fp = 0;
3509 	new->miscflags = 0;
3510 	new->update = 0;
3511 	new->menu = menu_init();
3512 	new->notify_level = real_notify_level();
3513 	new->server_group = 0;
3514 	new->sticky = 1;
3515 	resize_display(new);
3516 	if (add_to_window_list(new))
3517 		set_current_window(new);
3518 	term_flush();
3519 	return (new);
3520 }
3521 
3522 /*
3523  * is_window_name_unique: checks the given name vs the names of all the
3524  * windows and returns true if the given name is unique, false otherwise
3525  */
3526 static	int
is_window_name_unique(u_char * name)3527 is_window_name_unique(u_char *name)
3528 {
3529 	Window	*tmp;
3530 	Win_Trav wt;
3531 
3532 	if (name)
3533 	{
3534 		wt.init = 1;
3535 		while ((tmp = window_traverse(&wt)) != NULL)
3536 		{
3537 			if (tmp->name && (my_stricmp(tmp->name, name) == 0))
3538 				return (0);
3539 		}
3540 	}
3541 	return (1);
3542 }
3543 
3544 /*
3545  * free_display: This frees all memory for the display list for a given
3546  * window.  It resets all of the structures related to the display list
3547  * appropriately as well
3548  */
3549 void
free_display(Window * window)3550 free_display(Window *window)
3551 {
3552 	Display *tmp, *next;
3553 	int	i;
3554 
3555 	if (window == NULL)
3556 		window = curr_scr_win;
3557 	for (tmp = window->top_of_display, i = 0; i < window->display_size - window->double_status; i++, tmp = next)
3558 	{
3559 		next = tmp->next;
3560 		new_free(&(tmp->line));
3561 		new_free(&tmp);
3562 	}
3563 	window->top_of_display = NULL;
3564 	window->display_ip = NULL;
3565 	window->display_size = 0;
3566 }
3567 
3568 /*
3569  * erase_display: This effectively causes all members of the display list for
3570  * a window to be set to empty strings, thus "clearing" a window.  It sets
3571  * the cursor to the top of the window, and the display insertion point to
3572  * the top of the display. Note, this doesn't actually refresh the screen,
3573  * just cleans out the display list
3574  */
3575 void
erase_display(Window * window)3576 erase_display(Window *window)
3577 {
3578 	int	i;
3579 	Display *tmp;
3580 
3581 	if (term_basic())
3582 		return;
3583 	if (window == NULL)
3584 		window = curr_scr_win;
3585 	for (tmp = window->top_of_display, i = 0; i < window->display_size;
3586 			i++, tmp = tmp->next)
3587 		new_free(&(tmp->line));
3588 	window->cursor = 0;
3589 	window->line_cnt = 0;
3590 	window->hold_on_next_rite = 0;
3591 	window->display_ip = window->top_of_display;
3592 }
3593 
3594 void
window_add_display_line(Window * window,u_char * str,int logged)3595 window_add_display_line(Window *window, u_char *str, int logged)
3596 {
3597 	if (window->scroll)
3598 		scroll_window(window);
3599 	malloc_strcpy(&window->display_ip->line, str);
3600 	window->display_ip->linetype = logged;
3601 	window->display_ip = window->display_ip->next;
3602 	if (!window->scroll)
3603 		new_free(&window->display_ip->line);
3604 }
3605 
3606 /*
3607  * add_nicks_by_refnum:  This adds the given str to the nicklist of the
3608  * window refnum.  Only unique names are added to the list.  If add is zero
3609  * or the name is preceeded by a ^ it is removed from the list.  The str
3610  * may be a comma separated list of nicks, channels, etc .
3611  */
3612 static	void
add_nicks_by_refnum(u_int refnum,u_char * str,int add)3613 add_nicks_by_refnum(u_int refnum, u_char *str, int add)
3614 {
3615 	Window	*tmp;
3616 	u_char	*ptr;
3617 
3618 	if ((tmp = get_window_by_refnum(refnum)) != NULL)
3619 	{
3620 		while (str)
3621 		{
3622 			if ((ptr = my_index(str, ',')) != NULL)
3623 				*(ptr++) = '\0';
3624 			if (add == 0 || *str == '^')
3625 			{
3626 				if (add == 0 && *str == '^')
3627 					str++;
3628 				if (nicks_remove_from_window(tmp, str))
3629 					say("%s removed from window name list", str);
3630 				else
3631 					say("%s is not on the list for this window!", str);
3632 			}
3633 			else
3634 			{
3635 				if (nicks_add_to_window(tmp, str))
3636 					say("%s add to window name list", str);
3637 				else
3638 					say("%s already on window name list", str);
3639 			}
3640 			str = ptr;
3641 		}
3642 	}
3643 	else
3644 		say("No such window!");
3645 }
3646 
3647 /* below is stuff used for parsing of WINDOW command */
3648 
3649 /*
3650  * get_window_by_name: returns a pointer to a window with a matching logical
3651  * name or null if no window matches
3652  */
3653 Window	*
get_window_by_name(u_char * name)3654 get_window_by_name(u_char *name)
3655 {
3656 	Window	*tmp;
3657 	Win_Trav wt;
3658 
3659 	wt.init = 1;
3660 	while ((tmp = window_traverse(&wt)) != NULL)
3661 	{
3662 		if (tmp->name && (my_stricmp(tmp->name, name) == 0))
3663 			return (tmp);
3664 	}
3665 	return (NULL);
3666 }
3667 
3668 /*
3669  * get_window: this parses out any window (visible or not) and returns a
3670  * pointer to it
3671  */
3672 static	Window	*
get_window(u_char * name,u_char ** args)3673 get_window(u_char *name, u_char **args)
3674 {
3675 	u_char	*arg;
3676 	Window	*tmp;
3677 
3678 	if ((arg = next_arg(*args, args)) != NULL)
3679 	{
3680 		if (is_number(arg))
3681 		{
3682 			if ((tmp = get_window_by_refnum((u_int)my_atoi(arg))) != NULL)
3683 				return (tmp);
3684 		}
3685 		if ((tmp = get_window_by_name(arg)) != NULL)
3686 			return (tmp);
3687 		say("%s: No such window: %s", name, arg);
3688 	}
3689 	else
3690 		say("%s: Please specify a window refnum or name", name);
3691 	return (NULL);
3692 }
3693 
3694 /*
3695  * get_invisible_window: parses out an invisible window by reference number.
3696  * Returns the pointer to the window, or null.  The args can also be "LAST"
3697  * indicating the top of the invisible window list (and thus the last window
3698  * made invisible)
3699  */
3700 static	Window	*
get_invisible_window(u_char * name,u_char ** args)3701 get_invisible_window(u_char *name, u_char **args)
3702 {
3703 	u_char	*arg;
3704 	Window	*tmp;
3705 
3706 	if ((arg = next_arg(*args, args)) != NULL)
3707 	{
3708 		if (my_strnicmp(arg, UP("LAST"), my_strlen(arg)) == 0)
3709 		{
3710 			if (invisible_list == NULL)
3711 				say("%s: There are no hidden windows", name);
3712 			return (invisible_list);
3713 		}
3714 		if ((tmp = get_window(name, &arg)) != NULL)
3715 		{
3716 			if (!tmp->visible)
3717 				return (tmp);
3718 			else
3719 			{
3720 				if (tmp->name)
3721 					say("%s: Window %s is not hidden!",
3722 						name, tmp->name);
3723 				else
3724 					say("%s: Window %d is not hidden!",
3725 						name, tmp->refnum);
3726 			}
3727 		}
3728 	}
3729 	else
3730 		say("%s: Please specify a window refnum or LAST", name);
3731 	return (NULL);
3732 }
3733 
3734 /* get_number: parses out an integer number and returns it */
3735 static	int
get_number(u_char * name,u_char ** args)3736 get_number(u_char *name, u_char **args)
3737 {
3738 	u_char	*arg;
3739 
3740 	if ((arg = next_arg(*args, args)) != NULL)
3741 		return (my_atoi(arg));
3742 	else
3743 		say("%s: You must specify the number of lines", name);
3744 	return (0);
3745 }
3746 
3747 /*
3748  * get_boolean: parses either ON, OFF, or TOGGLE and sets the var
3749  * accordingly.  Returns 0 if all went well, -1 if a bogus or missing value
3750  * was specified
3751  */
3752 static	int
get_boolean(u_char * name,u_char ** args,int * var)3753 get_boolean(u_char *name, u_char **args, int *var)
3754 {
3755 	u_char	*arg;
3756 
3757 	if (((arg = next_arg(*args, args)) == NULL) || do_boolean(arg, var))
3758 	{
3759 		say("Value for %s must be ON, OFF, or TOGGLE", name);
3760 		return (-1);
3761 	}
3762 	else
3763 	{
3764 		say("Window %s is %s", name, var_settings(*var));
3765 		return (0);
3766 	}
3767 }
3768 
3769 void
windowcmd(u_char * command,u_char * args,u_char * subargs)3770 windowcmd(u_char *command, u_char *args, u_char *subargs)
3771 {
3772 	u_char	*arg;
3773 	int	no_args = 1;
3774 	Window	*window;
3775 
3776 	update_all_windows();
3777 	save_message_from();
3778 	message_from(NULL, LOG_CURRENT);
3779 	window = curr_scr_win;
3780 	while ((arg = next_arg(args, &args)) != NULL)
3781 	{
3782 		size_t	len;
3783 		Window	*tmp;
3784 		u_char	*cmd = NULL;
3785 
3786 		no_args = 0;
3787 		len = my_strlen(arg);
3788 		malloc_strcpy(&cmd, arg);
3789 		upper(cmd);
3790 		if (my_strncmp("NEW", cmd, len) == 0)
3791 		{
3792 			if ((tmp = new_window()) != NULL)
3793 				window = tmp;
3794 		}
3795 #ifdef WINDOW_CREATE
3796 		else if (my_strncmp("CREATE", cmd, len) == 0)
3797 		{
3798 			int type;
3799 
3800 			if (*args == '-' &&
3801 			    (arg = next_arg(args, &args)) != NULL)
3802 			{
3803 				if (my_stricmp(arg, UP("-SCREEN")) == 0)
3804 					type = ST_SCREEN;
3805 				else if (my_stricmp(arg, UP("-XTERM")) == 0)
3806 					type = ST_XTERM;
3807 				else {
3808 					say("Unknown /WINDOW CREATE option");
3809 					continue;
3810 				}
3811 			}
3812 			else
3813 				type = ST_NOTHING;
3814 			if ((tmp = create_additional_screen(type)) != NULL)
3815 				window = tmp;
3816 			else
3817 				say("Cannot create new screen!");
3818 		}
3819 		else if (!my_strncmp("DELETE", cmd, len))
3820 			kill_screen(get_current_screen());
3821 #endif /* WINODW_CREATE */
3822 		else if (my_strncmp("REFNUM", cmd, len) == 0)
3823 		{
3824 			if ((tmp = get_window(UP("REFNUM"), &args)) != NULL)
3825 			{
3826 				if (tmp->screen && tmp->screen !=window->screen)
3827 					say("Window in another screen!");
3828 				else if (tmp->visible)
3829 				{
3830 					set_current_window(tmp);
3831 					window = tmp;
3832 				}
3833 				else
3834 					say("Window not visible!");
3835 			}
3836 			else
3837 			{
3838 				say("No such window!");
3839 				new_free(&cmd);
3840 				goto out;
3841 			}
3842 		}
3843 		else if (my_strncmp("KILL", cmd, len) == 0)
3844 			delete_window(window);
3845 		else if (my_strncmp("SHRINK", cmd, len) == 0)
3846 			grow_window(window, -get_number(UP("SHRINK"), &args));
3847 		else if (my_strncmp("GROW", cmd, len) == 0)
3848 			grow_window(window, get_number(UP("SHRINK"), &args));
3849 		else if (my_strncmp("SCROLL", cmd, len) == 0)
3850 			get_boolean(UP("SCROLL"), &args, &(window->scroll));
3851 		else if (my_strncmp("STICKY", cmd, len) == 0)
3852 			get_boolean(UP("STICKY"), &args, &(window->sticky));
3853 		else if (my_strncmp("LOG", cmd, len) == 0)
3854 		{
3855 			if (get_boolean(UP("LOG"), &args, &(window->log)))
3856 				break;
3857 			else
3858 			{
3859 				u_char	*buffer = NULL;
3860 				u_char	*logfile;
3861 				int	add_ext = 1;
3862 
3863 				if ((logfile = window->logfile) != NULL)
3864 					add_ext = 0;
3865 				else if (!(logfile = get_string_var(LOGFILE_VAR)))
3866 					logfile = empty_string();
3867 				if (!add_ext)
3868 					malloc_snprintf(&buffer, "%s", logfile);
3869 				else if (window->current_channel)
3870 					malloc_snprintf(&buffer, "%s.%s", logfile, window->current_channel);
3871 				else if (window->query_nick)
3872 					malloc_snprintf(&buffer, "%s.%s", logfile, window->query_nick);
3873 				else
3874 					malloc_snprintf(&buffer, "%s.Window_%d", logfile, window->refnum);
3875 				do_log(window->log, buffer, &window->log_fp);
3876 				new_free(&buffer);
3877 				if (window->log_fp == NULL)
3878 					window->log = 0;
3879 			}
3880 		}
3881 		else if (my_strncmp("HOLD_MODE", cmd, len) == 0)
3882 			get_boolean(UP("HOLD_MODE"), &args, &window->hold_mode);
3883 		else if (my_strncmp("LASTLOG_LEVEL", cmd, len) == 0)
3884 		{
3885 			if ((arg = next_arg(args, &args)) != NULL)
3886 			{
3887 				int lastlog_level = parse_lastlog_level(arg);
3888 				lastlog_set_level(window->lastlog_info,
3889 						  lastlog_level);
3890 				say("Lastlog level is %s",
3891 				    bits_to_lastlog_level(lastlog_level));
3892 			}
3893 			else
3894 				say("Level required");
3895 		}
3896 		else if (my_strncmp("LEVEL", cmd, len) == 0)
3897 		{
3898 			if ((arg = next_arg(args, &args)) != NULL)
3899 			{
3900 				window->window_level = parse_lastlog_level(arg);
3901 				say("Window level is %s",
3902 				   bits_to_lastlog_level(window->window_level));
3903 				revamp_window_levels(window);
3904 			}
3905 			else
3906 				say("LEVEL: Level required");
3907 		}
3908 		else if (my_strncmp("BALANCE", cmd, len) == 0)
3909 			balance_windows();
3910 		else if (my_strncmp("NAME", cmd, len) == 0)
3911 		{
3912 			if ((arg = next_arg(args, &args)) != NULL)
3913 			{
3914 				if (is_window_name_unique(arg))
3915 				{
3916 					malloc_strcpy(&window->name, arg);
3917 					window->update |= UPDATE_STATUS;
3918 				}
3919 				else
3920 					say("%s is not unique!", arg);
3921 			}
3922 			else
3923 				say("You must specify a name for the window!");
3924 		}
3925 		else if (my_strncmp("PROMPT", cmd, len) == 0)
3926 		{
3927 			if ((arg = next_arg(args, &args)) != NULL)
3928 			{
3929 				malloc_strcpy(&window->prompt, arg);
3930 				window->update |= UPDATE_STATUS;
3931 			}
3932 			else
3933 				say("You must specify a prompt for the window!");
3934 		}
3935 		else if (my_strncmp("GOTO", cmd, len) == 0)
3936 		{
3937 			irc_goto_window(get_number(UP("GOTO"), &args));
3938 			window = curr_scr_win;
3939 		}
3940 		else if (my_strncmp("LAST", cmd, len) == 0)
3941 			set_current_window(NULL);
3942 		else if (my_strncmp("MOVE", cmd, len) == 0)
3943 		{
3944 			move_window(window, get_number(UP("MOVE"), &args));
3945 			window = curr_scr_win;
3946 		}
3947 		else if (my_strncmp("SWAP", cmd, len) == 0)
3948 		{
3949 			if ((tmp = get_invisible_window(UP("SWAP"), &args)) != NULL)
3950 				swap_window(window, tmp);
3951 		}
3952 		else if (my_strncmp("HIDE", cmd, len) == 0)
3953 			hide_window(window);
3954 		else if (my_strncmp("PUSH", cmd, len) == 0)
3955 			push_window_by_refnum(window->refnum);
3956 		else if (my_strncmp("POP", cmd, len) == 0)
3957 			pop_window();
3958 		else if (my_strncmp("ADD", cmd, len) == 0)
3959 		{
3960 			if ((arg = next_arg(args, &args)) != NULL)
3961 				add_nicks_by_refnum(window->refnum, arg, 1);
3962 			else
3963 				say("ADD: Do something!  Geez!");
3964 		}
3965 		else if (my_strncmp("REMOVE", cmd, len) == 0)
3966 		{
3967 			if ((arg = next_arg(args, &args)) != NULL)
3968 				add_nicks_by_refnum(window->refnum, arg, 0);
3969 			else
3970 				say("REMOVE: Do something!  Geez!");
3971 		}
3972 		else if (my_strncmp("STACK", cmd, len) == 0)
3973 			show_stack();
3974 		else if (my_strncmp("LIST", cmd, len) == 0)
3975 			list_windows();
3976 		else if (my_strncmp("SERVER", cmd, len) == 0)
3977 		{
3978 			if ((arg = next_arg(args, &args)) != NULL)
3979 			{
3980 				u_char	*group = 0,
3981 					*proxy_name = NULL,
3982 					*proxy_port_str;
3983 				int	type = Server2_8;
3984 				int	proxy_port = 0;
3985 				server_ssl_level level = SSL_OFF;
3986 
3987 				while (*arg == '-')
3988 				{
3989 					if (my_stricmp(UP("-ICB"), arg) == 0)
3990 						type = ServerICB;
3991 					else if (my_stricmp(UP("-IRC"), arg) == 0)
3992 						type = Server2_8;
3993 					else if (my_stricmp(UP("-SSL"), arg) == 0)
3994 						level = SSL_VERIFY;
3995 					else if (my_stricmp(UP("-SSLNOCHECK"), arg) == 0)
3996 						level = SSL_ON;
3997 					else if (my_stricmp(UP("-NOSSL"), arg) == 0)
3998 						level = SSL_OFF;
3999 					else if (my_stricmp(UP("-GROUP"), arg) == 0)
4000 					{
4001 						if ((group = next_arg(args, &args)) == NULL)
4002 						{
4003 							say("SERVER -GROUP needs <group> and <server>");
4004 							new_free(&cmd);
4005 							goto out;
4006 						}
4007 					}
4008 					else if (my_stricmp(UP("-PROXY"), arg) == 0)
4009 					{
4010 						if ((proxy_name = next_arg(args, &args)) == NULL ||
4011 						    (proxy_port_str = next_arg(args, &args)) == NULL)
4012 						{
4013 							say("SERVER -PROXY needs <proxy> and <host>");
4014 							new_free(&cmd);
4015 							goto out;
4016 						}
4017 						proxy_port = my_atoi(proxy_port_str);
4018 					}
4019 					else
4020 						say("SERVER: %s: unknown flag", arg);
4021 					if ((arg = next_arg(args, &args)) == NULL)
4022 						say("SERVER: You must specify a server");
4023 				}
4024 				window_get_connected(window, arg, -1, args,
4025 					proxy_name, proxy_port, group, type, level);
4026 			}
4027 			else
4028 				say("SERVER: You must specify a server");
4029 		}
4030 		else if (my_strncmp("SHOW", cmd, len) == 0)
4031 		{
4032 			if ((tmp = get_window(UP("SHOW"), &args)) != NULL)
4033 			{
4034 				show_window(tmp);
4035 				window = curr_scr_win;
4036 			}
4037 		}
4038 		else if (my_strncmp("HIDE_OTHERS", cmd, len) == 0)
4039 			hide_other_windows();
4040 		else if (my_strncmp("KILL_OTHERS", cmd, len) == 0)
4041 			delete_other_windows();
4042 		else if (my_strncmp("NOTIFY", cmd, len) == 0)
4043 		{
4044 			window->miscflags ^= WINDOW_NOTIFY;
4045 			say("Notification when hidden set to %s",
4046 			    (window->miscflags & WINDOW_NOTIFY)? "ON" : "OFF");
4047 		}
4048 		else if (my_strncmp("WHERE", cmd, len) == 0)
4049 			window_list_channels(curr_scr_win);
4050 		else if (my_strncmp("QUERY", cmd, len) == 0)
4051 		{
4052 			u_char *a = 0;
4053 
4054 			a = next_arg(args, &args);
4055 			query(cmd, a, 0);
4056 		}
4057 		else if (my_strncmp("CHANNEL", cmd, len) == 0)
4058 		{
4059 			if ((arg = next_arg(args, &args)) != NULL)
4060 			{
4061 				u_char *key, *t;
4062 
4063 				t = arg;
4064 				arg = my_strsep(&t, UP(","));
4065 				if ((key = my_strsep(&t, UP(", "))) == 0)
4066 					key = 0;
4067 
4068 				if (is_bound(arg, window->server))
4069 				{
4070 					say("Channel %s is bound", arg);
4071 				}
4072 				else
4073 				{
4074 					if (is_on_channel(arg, window->server,
4075 						server_get_nickname(window->server)))
4076 					{
4077 						is_current_channel(arg, window->server,
4078 							(int)window->refnum);
4079 						say("You are now talking to channel %s", arg);
4080 						set_channel_by_refnum(0, arg);
4081 					}
4082 					else if (*arg == '0' && !*(arg + 1))
4083 						set_channel_by_refnum(0, NULL);
4084 					else
4085 					{
4086 						int	server;
4087 
4088 						server = set_from_server(window->server);
4089 						switch (server_get_version(window->server)) {
4090 						case ServerICB:
4091 							icb_put_group(arg);
4092 							break;
4093 						default:
4094 							send_to_server("JOIN %s%s%s", arg,
4095 							    key ? (u_char *) " " : empty_string(),
4096 							    key ? key : empty_string());
4097 						}
4098 						add_channel(arg, key, window->server, CHAN_JOINING, NULL);
4099 						set_from_server(server);
4100 					}
4101 				}
4102 			}
4103 			else
4104 				set_channel_by_refnum(0, zero());
4105 		}
4106 		else if (my_strncmp("PREVIOUS", cmd, len) == 0)
4107 		{
4108 			swap_previous_window(0, NULL);
4109 		}
4110 		else if (my_strncmp("NEXT", cmd, len) == 0)
4111 		{
4112 			swap_next_window(0, NULL);
4113 		}
4114 		else if (my_strncmp("BACK", cmd, len) == 0)
4115 		{
4116 			back_window(0, NULL);
4117 		}
4118 		else if (my_strncmp("KILLSWAP", cmd, len) == 0)
4119 		{
4120 			window_kill_swap();
4121 		}
4122 		else if (my_strncmp("LOGFILE", cmd, len) == 0)
4123 		{
4124 			if ((arg = next_arg(args, &args)) != NULL)
4125 			{
4126 				malloc_strcpy(&window->logfile, arg);
4127 				say("Window LOGFILE set to %s", arg);
4128 			}
4129 			else
4130 				say("No LOGFILE given");
4131 		}
4132 		else if (my_strncmp("NOTIFY_LEVEL", cmd, len) == 0)
4133 		{
4134 			if ((arg = next_arg(args, &args)) != NULL)
4135 			{
4136 				window->notify_level = parse_lastlog_level(arg);
4137 				say("Window notify level is %s",
4138 				   bits_to_lastlog_level(window->notify_level));
4139 			}
4140 			else
4141 				say("Level missing");
4142 		}
4143 		else if (my_strncmp("NUMBER", cmd, len) == 0)
4144 		{
4145 			if ((arg = next_arg(args, &args)) != NULL)
4146 			{
4147 				int	i;
4148 				Window	*wtmp;
4149 
4150 				i = my_atoi(arg);
4151 				if (i > 0)
4152 				{
4153 					/* check if window number exists */
4154 
4155 					wtmp = get_window_by_refnum((u_int)i);
4156 					if (!wtmp)
4157 						window->refnum = i;
4158 					else
4159 					{
4160 						wtmp->refnum = window->refnum;
4161 						window->refnum = i;
4162 					}
4163 					update_all_status();
4164 				}
4165 				else
4166 					say("Window number must be greater "
4167 					    "than 1");
4168 			}
4169 			else
4170 				say("Window number missing");
4171 		}
4172 		else if (my_strncmp("BIND", cmd, len) == 0)
4173 		{
4174 			if ((arg = next_arg(args, &args)) != NULL)
4175 			{
4176 				if (!is_channel(arg))
4177 					say("BIND: %s is not a valid "
4178 					    "channel name", arg);
4179 				else
4180 				{
4181 					bind_channel(arg, window);
4182 				}
4183 			}
4184 			else
4185 				if (window->bound_channel)
4186 					say("Channel %s is bound to window %d",
4187 					    window->bound_channel,
4188 					    window->refnum);
4189 		}
4190 		else if (my_strncmp("UNBIND", cmd, len) == 0)
4191 		{
4192 			if ((arg = next_arg(args, &args)) != NULL)
4193 			{
4194 				if (is_bound(arg, window->server))
4195 				{
4196 					say("Channel %s is no longer bound",
4197 					    arg);
4198 					unbind_channel(arg, window);
4199 				}
4200 				else
4201 					say("Channel %s is not bound", arg);
4202 			}
4203 			else
4204 				say("UNBIND: You must specify a channel name");
4205 		}
4206 		else if (my_strncmp("ADDGROUP", cmd, len) == 0)
4207 		{
4208 			if ((arg = next_arg(args, &args)) != NULL)
4209 				add_window_to_server_group(window, arg);
4210 			else
4211 				say("WINDOW ADDGROUP requires a group name");
4212 		}
4213 		else if (my_strncmp("DELGROUP", cmd, len) == 0)
4214 		{
4215 			window->server_group = 0;
4216 			say("Window no longer has a server group");
4217 			update_window_status(window, 1);
4218 		}
4219 		else if (my_strncmp("DOUBLE", cmd, len) == 0)
4220 		{
4221 			int current = window->double_status;
4222 
4223 			if (get_boolean(UP("DOUBLE"), &args,
4224 					&window->double_status) == 0)
4225 			{
4226 				window->display_size += current -
4227 					window->double_status;
4228 				recalculate_window_positions();
4229 				update_all_windows();
4230 				build_status((u_char *) NULL);
4231 			}
4232 		}
4233 		else if (my_strncmp("NOSTATUS", cmd, len) == 0)
4234 		{
4235 			int current = window->double_status;
4236 
4237 			window->double_status = -1;
4238 			window->display_size += current - window->double_status;
4239 			recalculate_window_positions();
4240 			update_all_windows();
4241 			build_status((u_char *) NULL);
4242 		}
4243 		else
4244 			say("Unknown WINDOW command: %s", arg);
4245 		new_free(&cmd);
4246 	}
4247 	if (no_args)
4248 	{
4249 		if (window->name)
4250 			say("Window %s (%u)", window->name, window->refnum);
4251 		else
4252 			say("Window %u", window->refnum);
4253 		if (window->server == -1)
4254 			say("\tServer: <None>");
4255 		else
4256 			say("\tServer: %s", server_get_name(window->server));
4257 		say("\tCurrent channel: %s",
4258 		    window->current_channel ?
4259 			window->current_channel : UP("<None>"));
4260 		say("\tQuery User: %s",
4261 		    window->query_nick ? window->query_nick : UP("<None>"));
4262 		say("\tPrompt: %s",
4263 		    window->prompt ?  window->prompt : (u_char *) "<None>");
4264 		say("\tSecond status line is %s",
4265 		    var_settings(window->double_status));
4266 		say("\tScrolling is %s", var_settings(window->scroll));
4267 		say("\tLogging is %s", var_settings(window->log));
4268 		if (window->logfile)
4269 			say("\tLogfile is %s", window->logfile);
4270 		else
4271 			say("\tNo logfile given");
4272 		say("\tNotification is %s",
4273 		    var_settings(window->miscflags & WINDOW_NOTIFY));
4274 		say("\tHold mode is %s", var_settings(window->hold_mode));
4275 		say("\tSticky behaviour is %s", var_settings(window->sticky));
4276 		say("\tWindow level is %s",
4277 		    bits_to_lastlog_level(window->window_level));
4278 		say("\tLastlog level is %s",
4279 		    bits_to_lastlog_level(lastlog_get_level(window->lastlog_info)));
4280 		say("\tNotify level is %s",
4281 		    bits_to_lastlog_level(window->notify_level));
4282 		if (window->server_group)
4283 			say("\tServer Group is (%d) %s", window->server_group,
4284 			    find_server_group_name(window->server_group));
4285 		if (window->bound_channel)
4286 			say("\tBound Channel is %s", window->bound_channel);
4287 		display_nicks_info(window);
4288 	}
4289 out:
4290 	restore_message_from();
4291 	update_all_windows();
4292 	cursor_to_input();
4293 }
4294 
4295 int
number_of_windows(void)4296 number_of_windows(void)
4297 {
4298 	return screen_get_visible_windows(get_current_screen());
4299 }
4300 
4301 void
unstop_all_windows(u_int key,u_char * ptr)4302 unstop_all_windows(u_int key, u_char *ptr)
4303 {
4304 	Window	*tmp;
4305 
4306 	for (tmp = screen_get_window_list(get_current_screen()); tmp;
4307 	     tmp = tmp->next)
4308 		window_hold_mode(tmp, OFF, 1);
4309 }
4310 
4311 /* this will make underline toggle between 2 and -1 and never let it get to 0 */
4312 void
set_underline_video(int value)4313 set_underline_video(int value)
4314 {
4315 	if (value == OFF)
4316 		set_underline(-1);
4317 	else
4318 		set_underline(1);
4319 }
4320 
4321 /*
4322  * if "arg" is NULL, nargs is a server to connect to.
4323  */
4324 void
window_get_connected(Window * window,u_char * arg,int narg,u_char * args,u_char * proxy_name,int proxy_port,u_char * group,int type,server_ssl_level level)4325 window_get_connected(Window *window, u_char *arg, int narg, u_char *args,
4326 		     u_char *proxy_name, int proxy_port,
4327 		     u_char *group, int type, server_ssl_level level)
4328 {
4329 	int	i,
4330 		port_num,
4331 		new_server_flags = WIN_TRANSFER;
4332 	u_char	*port,
4333 		*password = NULL,
4334 		*nick = NULL,
4335 		*extra = NULL,
4336 		*icbmode = NULL;
4337 
4338 	if (arg)
4339 	{
4340 		if (*arg == '=')
4341 		{
4342 			new_server_flags |= WIN_ALL;
4343 			arg++;
4344 		}
4345 		else if (*arg == '~')
4346 		{
4347 			new_server_flags |= WIN_FORCE;
4348 			arg++;
4349 		}
4350 		/*
4351 		 * work in progress.. window->prev_server needs to be set for
4352 		 * all windows that used to be associated with a server as it
4353 		 * switches [successfully] to a new server.
4354 		 * this'll be fun since that can happen in server.c and
4355 		 * window.c and non-blocking-connects will throw yet another
4356 		 * wrench into things since we only want it to happen on
4357 		 * a successful connect. - gkm
4358 		 */
4359 		else if (*arg == '.')
4360 		{
4361 			if (*(++arg))
4362 			{
4363 				say("syntax error - nothing may be specified "
4364 				    "after the '.'");
4365 				return;
4366 			}
4367 			if (window->prev_server != -1)
4368 			{
4369 				if (group)
4370 					add_server_to_server_group(
4371 						window->prev_server, group);
4372 
4373 				window_restore_server(window->prev_server);
4374 				if (!proxy_name)
4375 					proxy_name = server_get_proxy_name(
4376 						window->prev_server, 0);
4377 				if (proxy_port == 0)
4378 					proxy_port = server_get_proxy_port(
4379 						window->prev_server, 0);
4380 				window_get_connected(window, NULL,
4381 					window->server, NULL,
4382 					proxy_name, proxy_port,
4383 					group, type, level);
4384 			}
4385 			else
4386 				say("No server previously in use in this window");
4387 			return;
4388 		}
4389 		parse_server_info(&arg, &port, &password, &nick,
4390 		    group ? 0 : &group, &extra, &type, &level,
4391 		    &proxy_name, &proxy_port);
4392 		if (port)
4393 		{
4394 			port_num = my_atoi(port);
4395 			if (!port_num)
4396 				port_num = -1;
4397 		}
4398 		else
4399 			port_num = -1;
4400 		if (extra)
4401 		{
4402 			if (type == ServerICB)
4403 			{
4404 				if ((icbmode = my_index(extra, ':')) && icbmode[1])
4405 					*icbmode++ = 0;
4406 				else
4407 					icbmode = NULL;
4408 			}
4409 			/* XXX should handle extra as :#chan:#chan2:etc for IRC */
4410 		}
4411 		/* relies on parse_server_info putting a null in */
4412 		/* This comes first for "/serv +1" -Sol */
4413 		if ((i = parse_server_index(arg)) != -1)
4414 		{
4415 			if (port_num == -1) /* Could be "/serv +1:6664" -Sol */
4416 				port_num = server_get_port(i);
4417 			if (nick == NULL)
4418 				nick = server_get_nickname(i);
4419 		}
4420 		else if ((i = find_in_server_list(arg, port_num, nick)) != -1)
4421 			port_num = server_get_port(i);
4422 	}
4423 	else
4424 	{
4425 		i = narg;
4426 		port_num = server_get_port(i);
4427 		arg = server_get_name(i);
4428 		if (!proxy_name)
4429 			proxy_name = server_get_proxy_name(i, 0);
4430 		if (proxy_port == 0)
4431 			proxy_port = server_get_proxy_port(i, 0);
4432 	}
4433 
4434 	if (!(new_server_flags & WIN_ALL))
4435 	{	/* Test if last window -Sol */
4436 		Win_Trav wt;
4437 		Window	*ptr, *new_win = NULL;
4438 
4439 		wt.init = 1;
4440 		while ((ptr = window_traverse(&wt)) != NULL)
4441 			if ((ptr != window) &&
4442 			    (!ptr->server_group ||
4443 			      (ptr->server_group != window->server_group)) &&
4444 			    (ptr->server == window->server))
4445 			{
4446 				new_win = ptr;
4447 				break;
4448 			}
4449 		if (!new_win)
4450 			new_server_flags |= WIN_ALL;
4451 	}
4452 
4453 	if (-1 == i)
4454 	{
4455 		if (!nick)
4456 			nick = my_nickname();
4457 		if (port_num == -1)
4458 			port_num = CHOOSE_PORT(type);
4459 
4460 		add_to_server_list(arg, port_num, proxy_name, proxy_port,
4461 				   password, nick, -1, type,
4462 				   ssl_level_to_sa_flags(level));
4463 
4464 		if (group && *group)
4465 			server_set_server_group(get_from_server(),
4466 						find_server_group(group, 1));
4467 
4468 		if (extra && type == ServerICB)
4469 		{
4470 			u_char	*newmode;
4471 
4472 			if ((newmode = my_index(extra, ':')))
4473 			{
4474 				*newmode++ = 0;
4475 				server_set_icbmode(get_from_server(), newmode);
4476 			}
4477 			server_set_icbgroup(get_from_server(), extra);
4478 		}
4479 	}
4480 	else
4481 	{
4482 		if (nick && *nick)
4483 			server_set_nickname(i, nick);
4484 		if (password && *password)
4485 			server_set_password(i, password);
4486 		if (extra && *extra)
4487 			server_set_icbgroup(i, extra);
4488 		if (icbmode && *icbmode)
4489 			server_set_icbmode(i, icbmode);
4490 		if (group && *group)
4491 			server_set_server_group(i, find_server_group(group, 1));
4492 		/* proxy_name & proxy_port? */
4493 
4494 		i = find_in_server_list(server_get_name(i), port_num, nick);
4495 		if ((i != -1) && is_server_connected(i))
4496 			new_server_flags &= ~WIN_TRANSFER;
4497 
4498 		arg = server_get_name(i);
4499 		port_num = server_get_port(i);
4500 	}
4501 
4502 	if (!connect_to_server(arg, port_num, nick,
4503 			(new_server_flags & WIN_ALL) ? window->server : -1))
4504 	{
4505 		window_set_server((int)window->refnum, get_from_server(),
4506 				  new_server_flags);
4507 		update_all_status();
4508 	}
4509 	window_check_servers();
4510 }
4511 
4512 void
window_copy_prev_server(int server)4513 window_copy_prev_server(int server)
4514 {
4515 	Win_Trav wt;
4516 	Window *tmp;
4517 
4518 	wt.init = 1;
4519 	while ((tmp = window_traverse(&wt)))
4520 		if (tmp->server == server)
4521 			tmp->prev_server = server;
4522 }
4523 
4524 int
window_get_server(Window * window)4525 window_get_server(Window *window)
4526 {
4527 	return window->server;
4528 }
4529 
4530 int
window_get_server_group(Window * window)4531 window_get_server_group(Window *window)
4532 {
4533 	return window->server_group;
4534 }
4535 
4536 void
window_server_delete(int deleted_server)4537 window_server_delete(int deleted_server)
4538 {
4539 	Window	*tmp;
4540 	Win_Trav wt;
4541 
4542 	wt.init = 1;
4543 	while ((tmp = window_traverse(&wt)) != NULL)
4544 		if (tmp->server > deleted_server && tmp->server > 0)
4545 			tmp->server--;
4546 }
4547 
4548 unsigned int
window_get_refnum(Window * window)4549 window_get_refnum(Window *window)
4550 {
4551 	return window->refnum;
4552 }
4553 
4554 int
window_get_sticky(Window * window)4555 window_get_sticky(Window *window)
4556 {
4557 	return window->sticky;
4558 }
4559 
4560 void
window_set_sticky(Window * window,int sticky)4561 window_set_sticky(Window *window, int sticky)
4562 {
4563 	window->sticky = sticky;
4564 }
4565 
4566 Window *
window_get_next(Window * window)4567 window_get_next(Window *window)
4568 {
4569 	return window->next;
4570 }
4571 
4572 Window *
window_get_prev(Window * window)4573 window_get_prev(Window *window)
4574 {
4575 	return window->prev;
4576 }
4577 
4578 Screen *
window_get_screen(Window * window)4579 window_get_screen(Window *window)
4580 {
4581 	return window->screen;
4582 }
4583 
4584 int
window_is_current(Window * window)4585 window_is_current(Window *window)
4586 {
4587 	return screen_get_current_window(window->screen) == window ? 1 : 0;
4588 }
4589 
4590 u_char *
window_get_name(Window * window)4591 window_get_name(Window *window)
4592 {
4593 	return window->name;
4594 }
4595 
4596 int
window_get_prev_server(Window * window)4597 window_get_prev_server(Window *window)
4598 {
4599 	return window->prev_server;
4600 }
4601 
4602 int
window_get_notify_level(Window * window)4603 window_get_notify_level(Window *window)
4604 {
4605 	return window->notify_level;
4606 }
4607 
4608 void
window_set_notify_level(Window * window,int level)4609 window_set_notify_level(Window *window, int level)
4610 {
4611 	window->notify_level = level;
4612 }
4613 
4614 u_char *
window_get_query_nick(Window * window)4615 window_get_query_nick(Window *window)
4616 {
4617 	return window->query_nick;
4618 }
4619 
4620 void
add_to_window_log(Window * window,u_char * str)4621 add_to_window_log(Window *window, u_char *str)
4622 {
4623 	add_to_log(window->log_fp, str);
4624 }
4625 
4626 LastlogInfo *
window_get_lastlog_info(Window * window)4627 window_get_lastlog_info(Window *window)
4628 {
4629 	return window->lastlog_info;
4630 }
4631 
4632 int
window_get_lastlog_size(Window * window)4633 window_get_lastlog_size(Window *window)
4634 {
4635 	return lastlog_get_size(window->lastlog_info);
4636 }
4637 
4638 
4639 WindowMenu *
window_get_menu(Window * window)4640 window_get_menu(Window *window)
4641 {
4642 	return window->menu;
4643 }
4644 
4645 int
window_menu_lines(Window * window)4646 window_menu_lines(Window *window)
4647 {
4648 	return menu_lines(window->menu);
4649 }
4650 
4651 int
window_get_window_level(Window * window)4652 window_get_window_level(Window *window)
4653 {
4654 	return window->window_level;
4655 }
4656 
4657 u_char *
window_get_current_channel(Window * window)4658 window_get_current_channel(Window *window)
4659 {
4660 	return window->current_channel;
4661 }
4662 
4663 void
window_set_current_channel(Window * window,u_char * channel)4664 window_set_current_channel(Window *window, u_char *channel)
4665 {
4666 	if (channel)
4667 		malloc_strcpy(&window->current_channel, channel);
4668 	else
4669 		new_free(&window->current_channel);
4670 }
4671 
4672 unsigned
window_get_miscflags(Window * window)4673 window_get_miscflags(Window *window)
4674 {
4675 	return window->miscflags;
4676 }
4677 
4678 void
window_set_miscflags(Window * window,unsigned setflags,unsigned unsetflags)4679 window_set_miscflags(Window *window, unsigned setflags, unsigned unsetflags)
4680 {
4681 	window->miscflags &= ~unsetflags;
4682 	window->miscflags |= setflags;
4683 }
4684 
4685 int
window_get_all_scrolled_lines(Window * window)4686 window_get_all_scrolled_lines(Window *window)
4687 {
4688 	return window->scrolled_lines + window->new_scrolled_lines;
4689 }
4690 
4691 int
window_get_scrolled_lines(Window * window)4692 window_get_scrolled_lines(Window *window)
4693 {
4694 	return window->scrolled_lines;
4695 }
4696 
4697 int
window_held_lines(Window * window)4698 window_held_lines(Window *window)
4699 {
4700 	return held_lines(window->hold_info);
4701 }
4702 
4703 void
window_remove_from_hold_list(Window * window)4704 window_remove_from_hold_list(Window *window)
4705 {
4706 	remove_from_hold_list(window->hold_info);
4707 }
4708 
4709 void
window_hold_mode(Window * window,int flag,int update)4710 window_hold_mode(Window *window, int flag, int update)
4711 {
4712 	if (window == NULL)
4713 		window = curr_scr_win;
4714 	hold_mode(window, window->hold_info, flag, update);
4715 }
4716 
4717 int
window_hold_output(Window * window)4718 window_hold_output(Window *window)
4719 {
4720 	if (!window)
4721 		window = curr_scr_win;
4722 	return hold_output(window, window->hold_info);
4723 }
4724 
4725 int
window_held(Window * window)4726 window_held(Window *window)
4727 {
4728 	return hold_is_held(window->hold_info);
4729 }
4730 
4731 void
window_add_new_scrolled_line(Window * window)4732 window_add_new_scrolled_line(Window *window)
4733 {
4734 	window->new_scrolled_lines++;
4735 }
4736 
4737 int
window_get_hold_mode(Window * window)4738 window_get_hold_mode(Window *window)
4739 {
4740 	return window->hold_mode;
4741 }
4742 
4743 void
window_set_hold_mode(Window * window,int val)4744 window_set_hold_mode(Window *window, int val)
4745 {
4746 	window->hold_mode = val;
4747 }
4748 
4749 int
window_get_hold_on_next_rite(Window * window)4750 window_get_hold_on_next_rite(Window *window)
4751 {
4752 	return window->hold_on_next_rite;
4753 }
4754 
4755 void
window_set_hold_on_next_rite(Window * window,int val)4756 window_set_hold_on_next_rite(Window *window, int val)
4757 {
4758 	window->hold_on_next_rite = val;
4759 }
4760 
4761 int
window_get_double_status(Window * window)4762 window_get_double_status(Window *window)
4763 {
4764 	return window->double_status;
4765 }
4766 
4767 void
window_set_status_line(Window * window,int line,u_char * str)4768 window_set_status_line(Window *window, int line, u_char *str)
4769 {
4770 	if (line < ARRAY_SIZE(window->status_line) || line < 0)
4771 	{
4772 		if (str)
4773 			malloc_strcpy(&window->status_line[line], str);
4774 		else
4775 			new_free(&window->status_line[line]);
4776 	}
4777 	else
4778 		yell("-- window_set_status_line() called with line = %d", line);
4779 }
4780 
4781 void
window_set_update(Window * window,unsigned setflags,unsigned unsetflags)4782 window_set_update(Window *window, unsigned setflags, unsigned unsetflags)
4783 {
4784 	window->update &= ~unsetflags;
4785 	window->update |= setflags;
4786 }
4787 
4788 int
window_get_visible(Window * window)4789 window_get_visible(Window *window)
4790 {
4791 	return window->visible;
4792 }
4793 
4794 int
window_get_scroll(Window * window)4795 window_get_scroll(Window *window)
4796 {
4797 	return window->scroll;
4798 }
4799 
4800 int
window_get_display_size(Window * window)4801 window_get_display_size(Window *window)
4802 {
4803 	return window->display_size;
4804 }
4805 
4806 int
window_get_line_cnt(Window * window)4807 window_get_line_cnt(Window *window)
4808 {
4809 	return window->line_cnt;
4810 }
4811 
4812 void
window_set_line_cnt(Window * window,int line_cnt)4813 window_set_line_cnt(Window *window, int line_cnt)
4814 {
4815 	window->line_cnt = line_cnt;
4816 }
4817 
4818 int
window_get_cursor(Window * window)4819 window_get_cursor(Window *window)
4820 {
4821 	return window->cursor;
4822 }
4823 
4824 void
window_set_cursor(Window * window,int cursor)4825 window_set_cursor(Window *window, int cursor)
4826 {
4827 	window->cursor = cursor;
4828 }
4829 
4830 int
window_get_top(Window * window)4831 window_get_top(Window *window)
4832 {
4833 	return window->top;
4834 }
4835 
4836 int
window_get_bottom(Window * window)4837 window_get_bottom(Window *window)
4838 {
4839 	return window->bottom;
4840 }
4841 
4842 NickList **
window_get_nicks(Window * window)4843 window_get_nicks(Window *window)
4844 {
4845 	return &window->nicks;
4846 }
4847 
4848 HoldInfo *
window_get_hold_info(Window * window)4849 window_get_hold_info(Window *window)
4850 {
4851 	return window->hold_info;
4852 }
4853 
4854 int
window_has_who_from(Window * window)4855 window_has_who_from(Window *window)
4856 {
4857 	return nicks_has_who_from(&window->nicks);
4858 }
4859 
4860 int
current_who_level(void)4861 current_who_level(void)
4862 {
4863 	return who_level;
4864 }
4865 
4866 u_char *
current_who_from(void)4867 current_who_from(void)
4868 {
4869 	return who_from;
4870 }
4871