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
8  * Modified 1996 Colten Edwards
9  */
10 
11 
12 #include "irc.h"
13 static char cvsrevision[] = "$Id: window.c 440 2013-11-11 13:24:38Z keaston $";
14 CVS_REVISION(window_c)
15 #include "struct.h"
16 
17 #include "screen.h"
18 #include "commands.h"
19 #include "exec.h"
20 #include "window.h"
21 #include "vars.h"
22 #include "server.h"
23 #include "list.h"
24 #include "ircterm.h"
25 #include "names.h"
26 #include "ircaux.h"
27 #include "input.h"
28 #include "status.h"
29 #include "output.h"
30 #include "log.h"
31 #include "hook.h"
32 #include "misc.h"
33 #include "cset.h"
34 #include "module.h"
35 #include "gui.h"
36 #define MAIN_SOURCE
37 #include "modval.h"
38 
39 /* Resize relatively or absolutely? */
40 #define RESIZE_REL 1
41 #define RESIZE_ABS 2
42 
43 Window	*invisible_list = NULL;		/* list of hidden windows */
44 
45 const char	*who_from = NULL;
46 unsigned long	who_level = LOG_CRAP;		/* Log level of message being displayed */
47 
48 int	in_window_command = 0;		/* set to true if we are in window().  This
49 					 * is used if a put_it() is called within the
50 					 * window() command.  We make sure all
51 					 * windows are fully updated before doing the
52 					 * put_it().
53 					 */
54 extern	int	dead;
55 static char *onoff[] = {"OFF", "ON"};
56 
57 extern unsigned long current_window_level;
58 
59 #ifdef WANT_DLL
60 WindowDll *dll_window = NULL;
61 #endif
62 
63 /*
64  * window_display: this controls the display, 1 being ON, 0 being OFF.  The
65  * DISPLAY var sets this.
66  */
67 unsigned int	window_display = 1;
68 
69 /*
70  * status_update_flag: if 1, the status is updated as normal.  If 0, then all
71  * status updating is suppressed
72  */
73 	int	status_update_flag = 1;
74 
75 
76 static 	void 	remove_from_invisible_list (Window *window);
77 static 	void 	swap_window (Window *v_window, Window *window);
78 static	Window	*get_next_window  (Window *);
79 static	Window	*get_previous_window (Window *);
80 static 	void 	revamp_window_levels (Window *window);
81 static	void	resize_window_display (Window *window);
82 static	Window	*window_next (Window *window, char **args, char *usage);
83 static	Window	*window_previous (Window *window, char **args, char *usage);
84 
85 
86 /*
87  * this is set to the window output should appear in.
88  */
89 	Window	*target_window = NULL;
90 
91 	Window	*current_window = NULL;
92 
93 void *default_output_function = BX_add_to_window;
94 
95 
96 #ifdef GUI
97 MenuStruct *findmenu(char *menuname);
98 #endif /* GUI */
99 
100 /*
101  * new_window: This creates a new window on the screen.  It does so by either
102  * splitting the current window, or if it can't do that, it splits the
103  * largest window.  The new window is added to the window list and made the
104  * current window
105  */
BX_new_window(Screen * screen)106 Window	*BX_new_window(Screen *screen)
107 {
108 	Window	*new;
109 	Window	*tmp = NULL;
110 	unsigned int new_refnum = 1;
111 
112 	if (dumb_mode && current_window)
113 		return NULL;
114 
115 	new = (Window *) new_malloc(sizeof(Window));
116 
117 	new->output_func = default_output_function;
118 	new->update_status = NULL;
119 
120 	tmp = NULL;
121 	while ((traverse_all_windows(&tmp)))
122 	{
123 		if (tmp->refnum == new_refnum)
124 		{
125 			new_refnum++;
126 			tmp = NULL;
127 		}
128 	}
129 	new->refnum = new_refnum;
130 	new->name = NULL;
131 
132 	if (current_window)
133 		new->server = current_window->server;
134 	else
135 		new->server = primary_server;
136 
137 
138 #if 0
139 	if (!current_window)
140 		new->window_level = LOG_ALL;
141 	else
142 #endif
143 		new->window_level = LOG_NONE;
144 
145 	new->lastlog_level = real_lastlog_level();
146 	new->lastlog_max = get_int_var(LASTLOG_VAR);
147 	new->status_split = 1;
148 	new->scratch_line = -1;
149 
150 #ifdef DEFAULT_DOUBLE_STATUS
151 	new->double_status = DEFAULT_DOUBLE_STATUS;
152 #else
153  	if (new->refnum == 1)
154   		new->double_status = 1;
155   	else
156   		new->double_status = 0;
157 #endif
158 
159 #ifdef DEFAULT_STATUS_LINES
160 	new->status_lines = DEFAULT_STATUS_LINES;
161 #endif
162 
163 	new->display_size = 1;
164 	new->old_size = 1;
165 	new->visible = 1;
166 	new->repaint_start = 0;
167 	new->repaint_end = -1;
168 
169 	new->screen = screen;
170 	new->next = new->prev = NULL;
171 
172 	new->notify_level = real_notify_level();
173 
174 	new->display_buffer_max = get_int_var(SCROLLBACK_VAR);
175 	new->hold_mode = get_int_var(HOLD_MODE_VAR);
176 
177 	new->mangler = logfile_line_mangler;
178 
179 	create_wsets_for_window(new);
180 	if (screen)
181 	{
182 		if (add_to_window_list(screen, new))
183 		{
184 			set_screens_current_window(screen, new);
185 			term_flush();
186 			do_hook(WINDOW_CREATE_LIST, "%d", new->refnum);
187 
188 		}
189 		else
190 		{
191 			new_free(&new);
192 			return NULL;
193 		}
194 	}
195 	else
196 		add_to_invisible_list(new);
197 	build_status(new, NULL, 0);
198 
199 	make_window_current(new);
200 	resize_window_display(new);
201 	return (new);
202 }
203 
204 /*
205  * delete_window: This deletes the given window.  It frees all data and
206  * structures associated with the window, and it adjusts the other windows so
207  * they will display correctly on the screen.
208  */
BX_delete_window(Window * window)209 void BX_delete_window(Window *window)
210 {
211 	char	buffer[BIG_BUFFER_SIZE + 1];
212 
213 	if (window == NULL)
214 		window = current_window;
215 	if (window->screen && (window->screen->visible_windows == 1))
216 	{
217 		if (invisible_list)
218 		{
219 			window->deceased = 1;
220 			swap_window(window, invisible_list);
221 			window = invisible_list;
222 		}
223 		else if (!dead)
224 		{
225 			if (!get_int_var(WINDOW_QUIET_VAR))
226 				say("You can't kill the last window!");
227 			return;
228 		}
229 		else
230 		{
231 			window->deceased = 1;
232 			set_screens_current_window(window->screen, NULL);
233 		}
234 	}
235 	if (window->name)
236 		strlcpy(buffer, window->name, sizeof buffer);
237 	else
238 		snprintf(buffer, sizeof buffer, "%u", window->refnum);
239 
240 	/*
241 	 * If this window is the "previous" window, then we make the current
242 	 * window the "previous" window.  Um. right.
243 	 */
244 	if (!dead && window->screen && window->screen->last_window_refnum == window->refnum)
245 		window->screen->last_window_refnum = window->screen->current_window->refnum;
246 
247 	move_window_channels(window);
248 
249 	new_free(&window->query_nick);
250 	new_free(&window->query_host);
251 	new_free(&window->query_cmd);
252 	new_free(&window->current_channel);
253 	new_free(&window->bind_channel);
254 	new_free(&window->waiting_channel);
255 	new_free(&window->logfile);
256 	new_free(&window->name);
257 
258 	/*
259 	 * Free off the display
260 	 */
261 	{
262 		Display *next;
263 		while (window->top_of_scrollback)
264 		{
265 			next = window->top_of_scrollback->next;
266 			new_free(&window->top_of_scrollback->line);
267 			new_free((char **)&window->top_of_scrollback);
268 			window->display_buffer_size--;
269 			window->top_of_scrollback = next;
270 		}
271 		window->display_ip = NULL;
272 		if (window->display_buffer_size != 0)
273 			ircpanic("display_buffer size is %d. should be 0", window->display_buffer_size);
274 	}
275 
276 	/*
277 	 * Free off the lastlog
278 	 */
279 	while (window->lastlog_size)
280 		remove_from_lastlog(window);
281 
282 	/*
283 	 * Free off the nick list
284 	 */
285 	{
286 		NickList *next;
287 
288 		while (window->nicks)
289 		{
290 			next = window->nicks->next;
291 			new_free(&window->nicks->nick);
292 			new_free(&window->nicks->host);
293 			new_free((char **)&window->nicks);
294 			window->nicks = next;
295 		}
296 	}
297 
298 	free_formats(window);
299 
300 	if (window->screen)
301 		remove_window_from_screen(window);
302 	else
303 		remove_from_invisible_list(window);
304 
305   	/*
306 	 * If its the current window, choose another one.
307 	 */
308 	if (window->screen && window->screen->current_window == window)
309 		set_screens_current_window(window->screen, NULL);
310 	if (window == current_window)
311 	{
312 		if (window == last_input_screen->current_window)
313 			make_window_current(last_input_screen->window_list);
314 		else
315 			make_window_current(NULL);
316 	}
317 	if (target_window && (window == target_window))
318 		target_window = NULL;
319 	new_free((char **)&window);
320 	window_check_servers(current_window->server);
321 	do_hook(WINDOW_KILL_LIST, "%s", buffer);
322 	set_input_prompt(current_window, get_string_var(INPUT_PROMPT_VAR), 0);
323 	update_input(UPDATE_ALL);
324 }
325 
326   /*
327  * new_traverse_all_windows: Based on the idea from phone that you should
328  * be able to do more than one iteration simultaneously.
329  *
330  * To initialize, *ptr should be NULL.  The function will return 1 each time
331  * *ptr is set to the next valid window.  When the function returns 0, then
332  * you have iterated all windows.
333  */
BX_traverse_all_windows(Window ** ptr)334 int BX_traverse_all_windows (Window **ptr)
335 {
336 	/*
337 	 * If this is the first time through...
338 	 */
339 	if (!*ptr)
340 	{
341 		Screen *screen = screen_list;
342 		while (screen && (!screen->alive || !screen->window_list))
343 			screen = screen->next;
344 
345 		if (!screen && !invisible_list)
346 			return 0;
347 		else if (!screen)
348 			*ptr = invisible_list;
349 		else
350  			*ptr = screen->window_list;
351 	}
352 
353 	/*
354 	 * As long as there is another window on this screen, keep going.
355 	 */
356 	else if ((*ptr)->next)
357 	{
358 		*ptr = (*ptr)->next;
359 	}
360 
361 	/*
362 	 * If there are no more windows on this screen, but we do belong to
363 	 * a screen (eg, we're not invisible), try the next screen
364 	 */
365 	else if ((*ptr)->screen)
366 	{
367 		/*
368 		 * Skip any dead screens
369 		 */
370 		Screen *ns = (*ptr)->screen->next;
371 		while (ns && (!ns->alive || !ns->window_list))
372 			ns = ns->next;
373 
374 		/*
375 		 * If there are no other screens, then if there is a list
376 		 * of hidden windows, try that.  Otherwise we're done.
377 		 */
378 		if (!ns && !invisible_list)
379 			return 0;
380 		else if (!ns)
381 			*ptr = invisible_list;
382 		else
383 			*ptr = ns->window_list;
384 	}
385 
386 	/*
387 	 * Otherwise there are no other windows, and we're not on a screen
388 	 * (eg, we're hidden), so we're all done here.
389 	 */
390 	else
391 		return 0;
392 
393 	/*
394 	 * If we get here, we're in business!
395 	 */
396 	return 1;
397 }
398 
remove_from_invisible_list(Window * window)399 static	void remove_from_invisible_list(Window *window)
400 {
401 
402 	if (window->prev)
403 		window->prev->next = window->next;
404 	else
405 		invisible_list = window->next;
406 	if (window->next)
407 		window->next->prev = window->prev;
408 }
409 
BX_add_to_invisible_list(Window * window)410 void BX_add_to_invisible_list(Window *window)
411 {
412 	if ((window->next = invisible_list) != NULL)
413 		invisible_list->prev = window;
414 	invisible_list = window;
415 	window->prev = NULL;
416 	window->visible = 0;
417 	if (window->screen)
418 		window->columns = window->screen->co;
419 	else
420 		window->columns = current_term->TI_cols;
421 	window->screen = NULL;
422 }
423 
424 /*
425  * add_to_window_list: This inserts the given window into the visible window
426  * list (and thus adds it to the displayed windows on the screen).  The
427  * window is added by splitting the current window.  If the current window is
428  * too small, the next largest window is used.  The added window is returned
429  * as the function value or null is returned if the window couldn't be added
430  */
BX_add_to_window_list(Screen * screen,Window * new)431 Window	*BX_add_to_window_list(Screen *screen, Window *new)
432 {
433 	Window	*biggest = NULL,
434 		*tmp;
435 
436 	screen->visible_windows++;
437 	new->screen = screen;
438 	new->visible = 1;
439 	new->miscflags &= ~WINDOW_NOTIFIED;
440 	if (!screen->current_window)
441 	{
442 		screen->window_list_end = screen->window_list = new;
443 		if (dumb_mode)
444 		{
445 			new->display_size = 24;	/* what the hell */
446 			set_screens_current_window(screen, new);
447 			return (new);
448 		}
449 		recalculate_windows(screen);
450 	}
451 	else
452 	{
453 		/* split current window, or find a better window to split */
454 		if ((screen->current_window->display_size < 4) ||
455 			get_int_var(ALWAYS_SPLIT_BIGGEST_VAR))
456 		{
457 			int	size = 0;
458 
459 			for (tmp = screen->window_list; tmp; tmp = tmp->next)
460 			{
461 				if (tmp->absolute_size)
462 					continue;
463 				if (tmp->display_size > size)
464 				{
465 					size = tmp->display_size;
466 					biggest = tmp;
467 				}
468 			}
469 			if (!biggest/* || size < 4 */)
470 			{
471 				if (!get_int_var(WINDOW_QUIET_VAR))
472 					say("Not enough room for another window!");
473 				screen->visible_windows--;
474 				return (NULL);
475 			}
476 		}
477 		else
478 			biggest = screen->current_window;
479 
480 		if ((new->prev = biggest->prev) != NULL)
481 			new->prev->next = new;
482 		else
483 			screen->window_list = new;
484 
485 		new->next = biggest;
486 		biggest->prev = new;
487 		biggest->display_size /= 2;
488 		new->display_size = biggest->display_size;
489 		recalculate_windows(screen);
490 	}
491 	return (new);
492 }
493 
494 /*
495  * remove_from_window_list: this removes the given window from the list of
496  * visible windows.  It closes up the hole created by the windows abnsense in
497  * a nice way
498  */
BX_remove_window_from_screen(Window * window)499 void BX_remove_window_from_screen(Window *window)
500 {
501 	if (!window->visible || !window->screen)
502 		ircpanic("This window is not on a screen");
503 
504 	/*
505 	 * We  used to go to greath lengths to figure out how to fill
506 	 * in the space vacated by this window.  Now we dont sweat that.
507 	 * we just blow away the window and then recalculate the entire
508 	 * screen.
509 	 */
510 	if (window->prev)
511 		window->prev->next = window->next;
512 	else
513 		window->screen->window_list = window->next;
514 
515 	if (window->next)
516 		window->next->prev = window->prev;
517 	else
518 		window->screen->window_list_end = window->prev;
519 
520 	if (!--window->screen->visible_windows)
521 		return;
522 
523 	if (window->screen->current_window == window)
524 		set_screens_current_window(window->screen, NULL);
525 
526 	if (window->refnum == window->screen->last_window_refnum)
527 		window->screen->last_window_refnum = window->screen->current_window->refnum;
528 
529 	if (window == window->screen->current_window)
530 		make_window_current(last_input_screen->window_list);
531 	else
532 		make_window_current(NULL);
533 
534 	recalculate_windows(window->screen);
535 }
536 
537 /*
538  * recalculate_window_positions: This runs through the window list and
539  * re-adjusts the top and bottom fields of the windows according to their
540  * current positions in the window list.  This doesn't change any sizes of
541  * the windows
542  */
BX_recalculate_window_positions(Screen * screen)543 void BX_recalculate_window_positions(Screen *screen)
544 {
545 	Window	*tmp;
546 	int	top;
547 
548 	if (!screen)
549 		return;
550 	top = 0;
551 	for (tmp = screen->window_list; tmp; tmp = tmp->next)
552 	{
553 		tmp->update |= REDRAW_DISPLAY_FULL | REDRAW_STATUS;
554 		tmp->top = top;
555 		tmp->bottom = top + tmp->display_size + tmp->status_lines;
556 		top += tmp->display_size + tmp->status_lines + 1 + tmp->double_status;
557 	}
558 }
559 
560 /*
561  * swap_window: This swaps the given window with the current window.  The
562  * window passed must be invisible.  Swapping retains the positions of both
563  * windows in their respective window lists, and retains the dimensions of
564  * the windows as well
565  */
swap_window(Window * v_window,Window * window)566 static	void swap_window(Window *v_window, Window *window)
567 {
568 	if (!window)
569 	{
570 		if (!get_int_var(WINDOW_QUIET_VAR))
571 			say("The window to be swapped in does not exist.");
572 		return;
573 	}
574 
575 	if (window->visible || !v_window->visible)
576 	{
577 		if (!get_int_var(WINDOW_QUIET_VAR))
578 			say("You can only SWAP a hidden window with a visible window.");
579 		return;
580 	}
581 
582 	v_window->screen->last_window_refnum = v_window->refnum;
583 	remove_from_invisible_list(window);
584 
585 	window->top = v_window->top;
586 
587 	window->display_size = v_window->display_size +
588 				v_window->double_status -
589 				window->double_status;
590 
591 	window->bottom = window->top + window->display_size + window->status_lines;
592 
593 	window->visible = 1;
594 	window->screen = v_window->screen;
595 
596 	if (v_window->screen->current_window == v_window)
597 		v_window->screen->current_window = window;
598 
599 	/*
600 	 * Put the window to be swapped into the screen list
601 	 */
602 	if ((window->prev = v_window->prev))
603 		window->prev->next = window;
604 	else
605 		window->screen->window_list = window;
606 
607 	if ((window->next = v_window->next))
608 		window->next->prev = window;
609 	else
610 		window->screen->window_list_end = window;
611 	add_to_invisible_list(v_window);
612 
613 	if (v_window == current_window)
614 		make_window_current(window);
615 
616 	window->update |= REDRAW_DISPLAY_FULL | REDRAW_STATUS;
617 	window->miscflags &= ~WINDOW_NOTIFIED;
618 	update_input(UPDATE_ALL);
619 	set_screens_current_window(window->screen, window);
620 	recalculate_windows(window->screen);
621 	reset_display_target();
622 	do_hook(WINDOW_SWAP_LIST, "%d %d", v_window->refnum, window->refnum);
623 }
624 
625 /*
626  * move_window: This moves a window offset positions in the window list. This
627  * means, of course, that the window will move on the screen as well
628  */
BX_move_window(Window * window,int offset)629 void BX_move_window(Window *window, int offset)
630 {
631 	Window	*tmp,
632 	    *last;
633 	int	win_pos,
634 	pos;
635 
636 	if (offset == 0 || !window->screen)
637 		return;
638 	last = NULL;
639 	for (win_pos = 0, tmp = window->screen->window_list; tmp;
640 	    tmp = tmp->next, win_pos++)
641 	{
642 		if (window == tmp)
643 			break;
644 		last = tmp;
645 	}
646 	if (!tmp)
647 		return;
648 	if (!last)
649 		window->screen->window_list = tmp->next;
650 	else
651 		last->next = tmp->next;
652 	if (tmp->next)
653 		tmp->next->prev = last;
654 	else
655 		window->screen->window_list_end = last;
656 
657 	win_pos = (offset + win_pos) % window->screen->visible_windows;
658 	if (win_pos < 0)
659 		win_pos = window->screen->visible_windows + win_pos;
660 
661 	last = NULL;
662 	for (pos = 0, tmp = window->screen->window_list;
663 	    pos != win_pos; tmp = tmp->next, pos++)
664 		last = tmp;
665 	if (!last)
666 		window->screen->window_list = window;
667 	else
668 		last->next = window;
669 
670 	if (tmp)
671 		tmp->prev = window;
672 	else
673 		window->screen->window_list_end = window;
674 
675 	window->prev = last;
676 	window->next = tmp;
677 	recalculate_window_positions(window->screen);
678 }
679 
680 /*
681  * resize_window: if 'how' is RESIZE_REL, then this will increase or decrease
682  * the size of the given window by offset lines (positive offset increases,
683  * negative decreases).  If 'how' is RESIZE_ABS, then this will set the
684  * absolute size of the given window.
685  * Obviously, with a fixed terminal size, this means that some other window
686  * is going to have to change size as well.  Normally, this is the next
687  * window in the window list (the window below the one being changed) unless
688  * the window is the last in the window list, then the previous window is
689  * changed as well
690  */
BX_resize_window(int how,Window * window,int offset)691 void BX_resize_window(int how, Window *window, int offset)
692 {
693 	Window	*other;
694 	int	after,
695 		window_size,
696 		other_size;
697 
698 	if (!window)
699 		window = current_window;
700 
701 	if (!window->visible)
702 	{
703 		if (!get_int_var(WINDOW_QUIET_VAR))
704 			say("You cannot change the size of hidden windows!");
705 		return;
706 	}
707 
708 	if (how == RESIZE_ABS)
709 	{
710 		offset -= window->display_size;
711 		how = RESIZE_REL;
712 	}
713 
714 	after = 1;
715 	other = window;
716 
717 	do
718 	{
719 		if (other->next)
720 			other = other->next;
721 		else
722 		{
723 			other = window->screen->window_list;
724 			after = 0;
725 		}
726 
727 		if (other == window)
728 		{
729 			say("Can't change the size of this window!");
730 			return;
731 		}
732 
733 		if (other->absolute_size)
734 			continue;
735 	}
736 	while (/*other->absolute_size || */other->display_size < offset);
737 
738 	window_size = window->display_size + offset;
739 	other_size = other->display_size - offset;
740 
741 #if 0
742 	if (how == RESIZE_REL)
743 	{
744 		window_size = window->display_size + offset;
745 		other_size = other->display_size - offset;
746 	}
747 	else /* absolute size */
748 	{
749 		/*
750 		 * How much its growing/shrinking by.  if
751 		 * offset > display_size, then window_size < 0.
752 		 * and other window is shrinking.  If offset < display_size,
753 		 * the window_size > 0, and other_window is growing.
754 		 */
755 		window_size = offset;
756 		offset -= window->display_size;
757 		other_size = other->display_size - offset;
758 	}
759 #endif
760 
761 	if ((window_size < 0) || (other_size < 0))
762 	{
763 		if (!get_int_var(WINDOW_QUIET_VAR))
764 			say("Not enough room to resize this window!");
765 		return;
766 	}
767 
768 	window->display_size = window_size;
769 	other->display_size = other_size;
770 	recalculate_windows(window->screen);
771 }
772 
773 /*
774  * resize_display: After determining that the screen has changed sizes, this
775  * resizes all the internal stuff.  If the screen grew, this will add extra
776  * empty display entries to the end of the display list.  If the screen
777  * shrank, this will remove entries from the end of the display list.  By
778  * doing this, we try to maintain as much of the display as possible.
779  *
780  * This has now been improved so that it returns enough information for
781  * redraw_resized to redisplay the contents of the window without having
782  * to redraw too much.
783  */
resize_window_display(Window * window)784 void resize_window_display(Window *window)
785 {
786 	int	cnt = 0, i;
787 	Display *tmp;
788 
789 	if (dumb_mode)
790 		return;
791 	/*
792 	 * This is called in new_window to initialize the
793 	 * display the first time
794 	 */
795 	if (!window->top_of_scrollback)
796 	{
797 		window->top_of_scrollback = new_display_line(NULL);
798 		window->top_of_scrollback->line = NULL;
799 		window->top_of_scrollback->next = NULL;
800 		window->display_buffer_size = 1;
801 		window->display_ip = window->top_of_scrollback;
802 		window->top_of_display = window->top_of_scrollback;
803 		window->ceiling_of_display = window->top_of_display;
804 		window->old_size = 1;
805 	}
806 	else if (window->scrollback_point)
807 		;
808 	else
809 	{
810 
811 		/*
812 		 * Find out how much the window has changed by
813 		 */
814 		cnt = window->display_size - window->old_size;
815 		tmp = window->top_of_display;
816 
817 		/*
818 		 * If it got bigger, move the top_of_display back.
819 		 */
820 		if (cnt > 0)
821 		{
822 			for (i = 0; i < cnt; i++)
823 			{
824 				if (!tmp || !tmp->prev || tmp == window->ceiling_of_display)
825 					break;
826 				tmp = tmp->prev;
827 			}
828 		}
829 
830 		/*
831 		 * If it got smaller, then move the top_of_display up
832 		 */
833 		else if (cnt < 0)
834 		{
835 			/* Use any whitespace we may have lying around */
836 			cnt += (window->old_size - window->distance_from_display);
837 			for (i = 0; i > cnt; i--)
838 			{
839 				if (tmp == window->display_ip)
840 					break;
841 				tmp = tmp->next;
842 			}
843 		}
844 		window->top_of_display = tmp;
845 		recalculate_window_cursor(window);
846 	}
847 
848 	/*
849 	 * Mark the window for redraw and store the new window size.
850 	 */
851 	window->update |= REDRAW_DISPLAY_FULL | REDRAW_STATUS;
852 	window->old_size = window->display_size;
853 	return;
854 }
855 
856 /*
857  * redraw_all_windows: This basically clears and redraws the entire display
858  * portion of the screen.  All windows and status lines are draws.  This does
859  * nothing for the input line of the screen.  Only visible windows are drawn
860  */
BX_redraw_all_windows(void)861 void BX_redraw_all_windows(void)
862 {
863 	Window	*tmp = NULL;
864 
865 	if (dumb_mode)
866 		return;
867 	while (traverse_all_windows(&tmp))
868 		tmp->update = REDRAW_STATUS | REDRAW_DISPLAY_FAST;
869 }
870 
871 /*
872  * Rebalance_windows: this is called when you want all the windows to be
873  * rebalanced, except for those who have a set size.
874  */
BX_rebalance_windows(Screen * screen)875 void BX_rebalance_windows (Screen *screen)
876 {
877 	Window *tmp;
878 	int each, extra;
879 	int window_resized = 0, window_count = 0;
880 
881 	if (dumb_mode)
882 		return;
883 
884 	/*
885 	 * Two passes -- first figure out how much we need to balance,
886 	 * and how many windows there are to balance
887 	 */
888 	for (tmp = screen->window_list; tmp; tmp = tmp->next)
889 	{
890 		if (tmp->absolute_size)
891 			continue;
892 		window_resized += tmp->display_size;
893 		window_count++;
894 	}
895 
896 	if (!window_count)
897 	{
898 		yell("All the windows on this screen are fixed");
899 		return;
900 	}
901 
902 	each = window_resized / window_count;
903 	extra = window_resized % window_count;
904 
905 	/*
906 	 * And then go through and fix everybody
907 	 */
908 	for (tmp = screen->window_list; tmp; tmp = tmp->next)
909 	{
910 		if (tmp->absolute_size)
911 			;
912 		else
913 		{
914 			tmp->display_size = each;
915 			if (extra)
916 				tmp->display_size++, extra--;
917 		}
918 	}
919 	recalculate_window_positions(screen);
920 }
921 
922 
923 
924 /*
925  * recalculate_windows: this is called when the terminal size changes (as
926  * when an xterm window size is changed).  It recalculates the sized and
927  * positions of all the windows.  Currently, all windows are rebalanced and
928  * window size proportionality is lost
929  */
BX_recalculate_windows(Screen * screen)930 void BX_recalculate_windows (Screen *screen)
931 {
932 	int	old_li = 1;
933 	int	excess_li = 0;
934 	Window	*tmp;
935 	int	window_count = 0;
936 	int	window_resized = 0;
937 	int	offset;
938 	int	split = 0;
939 
940 	if (dumb_mode)
941 		return;
942 #ifdef GUI
943 	current_term->TI_lines = screen->li;
944 	current_term->TI_cols = screen->co;
945 #endif
946 
947 	if (!screen) /* it's a hidden window. ignore this */
948 		return;
949 	/*
950 	 * If its a new window, just set it and be done with it.
951 	 */
952 	if (screen && !screen->current_window)
953 	{
954 		screen->window_list->top = 0;
955 		screen->window_list->display_size = current_term->TI_lines - 2 - screen->window_list->double_status;
956 		screen->window_list->bottom = current_term->TI_lines - 2 - screen->window_list->double_status;
957 		old_li = current_term->TI_lines;
958 		return;
959 	}
960 
961 	/*
962 	 * Expanding the screen takes two passes.  In the first pass,
963 	 * We figure out how many windows will be resized.  If none can
964 	 * be rebalanced, we add the whole shebang to the last one.
965 	 */
966 	for (tmp = screen->window_list; tmp; tmp = tmp->next)
967 	{
968 		old_li += tmp->display_size + tmp->double_status + 1;
969 		if (tmp->absolute_size && (window_count || tmp->next))
970 			continue;
971 		window_resized += tmp->display_size;
972 		window_count++;
973 		if (tmp->status_lines)
974 			split += tmp->status_lines;
975 	}
976 
977 	excess_li = current_term->TI_lines - old_li - split;
978 
979 	for (tmp = screen->window_list; tmp; tmp = tmp->next)
980 	{
981 		if (tmp->absolute_size && tmp->next)
982 			;
983 		else
984 		{
985 			/*
986 			 * The number of lines this window gets is:
987 			 * The number of lines available for resizing times
988 			 * the percentage of the resizeable screen the window
989 			 * covers.
990 			 */
991 			if (tmp->next && window_resized)
992 				offset = (tmp->display_size * excess_li) / window_resized;
993 			else
994 				offset = excess_li;
995 
996 			tmp->display_size += offset;
997 			if (tmp->display_size < 0)
998 				tmp->display_size = 1;
999 			excess_li -= offset;
1000 			tmp->bottom = tmp->bottom - tmp->status_lines;
1001 		}
1002 	}
1003 
1004 	recalculate_window_positions(screen);
1005 }
1006 
1007 /*
1008  * update_all_windows: This goes through each visible window and draws the
1009  * necessary portions according the the update field of the window.
1010  */
BX_update_all_windows()1011 void BX_update_all_windows()
1012 {
1013 	Window	*tmp = NULL;
1014 	if (in_window_command)
1015 		return;
1016 
1017 	while (traverse_all_windows(&tmp))
1018 	{
1019 		if (tmp->display_size != tmp->old_size)
1020 			resize_window_display(tmp);
1021 		if (tmp->visible && tmp->update)
1022 		{
1023 			int fast_window = tmp->update & REDRAW_DISPLAY_FAST;
1024 			int full_window = tmp->update & REDRAW_DISPLAY_FULL;
1025 			int r_status = tmp->update & REDRAW_STATUS;
1026 			int u_status = tmp->update & UPDATE_STATUS;
1027 
1028 			if (full_window || fast_window)
1029 				repaint_window(tmp, tmp->repaint_start, tmp->repaint_end);
1030 
1031 			if (tmp->update_status)
1032 				(tmp->update_status)(tmp);
1033 			else if (r_status)
1034 				update_window_status(tmp, 1);
1035 			else if (u_status)
1036 				update_window_status(tmp, 0);
1037 		}
1038 		tmp->update = 0;
1039 		tmp->repaint_start = 0;
1040 		tmp->repaint_end = -1;
1041 	}
1042 	update_input(UPDATE_JUST_CURSOR);
1043 }
1044 
1045 /*
1046  * goto_window: This will switch the current window to the window numbered
1047  * "which", where which is 0 through the number of visible windows on the
1048  * screen.  The which has nothing to do with the windows refnum.
1049  */
BX_goto_window(Screen * s,int which)1050 void BX_goto_window(Screen *s, int which)
1051 {
1052 	Window	*tmp;
1053 	int	i;
1054 
1055 
1056 	if (!s || which == 0)
1057 		return;
1058 
1059 	if ((which < 0) || (which > s->visible_windows))
1060 	{
1061 		if (!get_int_var(WINDOW_QUIET_VAR))
1062 			say("GOTO: Illegal value");
1063 		return;
1064 	}
1065 	tmp = s->window_list;
1066 	for (i = 1; i < which; i++)
1067 		tmp = tmp->next;
1068 
1069 	set_screens_current_window(s, tmp);
1070 	make_window_current(tmp);
1071 }
1072 
1073 /*
1074  * hide_window: sets the given window to invisible and recalculates remaing
1075  * windows to fill the entire screen
1076  */
BX_hide_window(Window * window)1077 void BX_hide_window(Window *window)
1078 {
1079 	if (!window->screen)
1080 	{
1081 		say("You can't hide an invisible window.");
1082 		return;
1083 	}
1084 	if (window->screen->visible_windows == 1)
1085 	{
1086 		if (!get_int_var(WINDOW_QUIET_VAR))
1087 			say("You can't hide the last window.");
1088 		return;
1089 	}
1090 	if (window->screen)
1091 	{
1092 		remove_window_from_screen(window);
1093 		add_to_invisible_list(window);
1094 	}
1095 }
1096 
1097 /*
1098  * swap_last_window:  This swaps the current window with the last window
1099  * that was hidden.
1100  */
1101 
BX_swap_last_window(char key,char * ptr)1102 void BX_swap_last_window(char key, char *ptr)
1103 {
1104 	if (!invisible_list || !current_window->screen)
1105 		return;
1106 
1107 	swap_window(current_window, invisible_list);
1108 	reset_display_target();
1109 	update_all_windows();
1110 	cursor_to_input();
1111 }
1112 
1113 /*
1114  * swap_next_window:  This swaps the current window with the next hidden
1115  * window.
1116  */
1117 
BX_swap_next_window(char key,char * ptr)1118 void BX_swap_next_window(char key, char *ptr)
1119 {
1120 	window_next(current_window, NULL, NULL);
1121 	update_all_windows();
1122 }
1123 
1124 /*
1125  * swap_previous_window:  This swaps the current window with the next
1126  * hidden window.
1127  */
1128 
BX_swap_previous_window(char key,char * ptr)1129 void BX_swap_previous_window(char key, char *ptr)
1130 {
1131 	window_previous(current_window, NULL, NULL);
1132 	cursor_to_input();
1133 	update_all_windows();
1134 }
1135 
1136 /* show_window: This makes the given window visible.  */
BX_show_window(Window * window)1137 void BX_show_window(Window *window)
1138 {
1139 	if (!window->screen)
1140 	{
1141 		remove_from_invisible_list(window);
1142 		if ((window == current_window) && !current_window->screen)
1143 			window->screen = last_input_screen; /* What the hey */
1144 		if (!add_to_window_list(current_window->screen, window))
1145 			add_to_invisible_list(window);
1146 	}
1147 	make_window_current(window);
1148 	if (!window->screen)
1149 	{
1150 		yell("ERROR ERROR ERROR. screen == NULL");
1151 		return;
1152 	}
1153 	set_screens_current_window(window->screen, window);
1154 	return;
1155 }
1156 
1157 /*
1158  * XXXX i have no idea if this belongs here.
1159  */
BX_get_status_by_refnum(unsigned refnum,unsigned line)1160 char *BX_get_status_by_refnum(unsigned refnum, unsigned line)
1161 {
1162 	Window *the_window;
1163 
1164 	if ((the_window = get_window_by_refnum(refnum)))
1165 	{
1166 		if (line > the_window->double_status)
1167 			return empty_string;
1168 
1169 		return the_window->wset->status_line[line];
1170 	}
1171 	else
1172 		return empty_string;
1173 }
1174 
1175 /*
1176  * get_window_by_desc: Given either a refnum or a name, find that window
1177  */
BX_get_window_by_desc(const char * stuff)1178 Window *BX_get_window_by_desc (const char *stuff)
1179 {
1180 Window *w = NULL;
1181 	do
1182 	{
1183 		if ((w = get_window_by_name(stuff)))
1184 			break;
1185 		if (is_number(stuff) && (w = get_window_by_refnum(my_atol(stuff))))
1186 			break;
1187 		if (*stuff == '#')
1188 		{
1189 			stuff++;
1190 			continue;
1191 		}
1192 	} while (0);
1193 	return w;
1194 }
1195 
1196 /*
1197  * get_window_by_refnum: Given a reference number to a window, this returns a
1198  * pointer to that window if a window exists with that refnum, null is
1199  * returned otherwise.  The "safe" way to reference a window is throught the
1200  * refnum, since a window might be delete behind your back and and Window
1201  * pointers might become invalid.
1202  */
BX_get_window_by_refnum(unsigned int refnum)1203 Window	* BX_get_window_by_refnum(unsigned int refnum)
1204 {
1205 	Window	*tmp = NULL;
1206 
1207 	if (refnum < 0)
1208 		return NULL;
1209 	if (refnum == 0)
1210 		return current_window;
1211 	else while ((traverse_all_windows(&tmp)))
1212 	{
1213 		if (tmp->refnum == refnum)
1214 			return (tmp);
1215 	}
1216 	return NULL;
1217 }
1218 
1219 /*
1220  * get_window: this parses out any window (visible or not) and returns a
1221  * pointer to it
1222  */
BX_get_visible_by_refnum(char * args)1223 int BX_get_visible_by_refnum (char *args)
1224 {
1225 	char	*arg;
1226 	Window	*tmp;
1227 
1228 	if ((arg = next_arg(args, &args)) != NULL)
1229 	{
1230 		if (is_number(arg))
1231 		{
1232 			if ((tmp = get_window_by_refnum(my_atol(arg))) != NULL)
1233 				return tmp->visible;
1234 		}
1235 		if ((tmp = get_window_by_name(arg)) != NULL)
1236 			return tmp->visible;
1237 
1238 		return -1;
1239 	}
1240 	return -1;
1241 }
1242 
1243 /*
1244  * get_window_by_name: returns a pointer to a window with a matching logical
1245  * name or null if no window matches
1246  */
BX_get_window_by_name(const char * name)1247 Window	* BX_get_window_by_name(const char *name)
1248 {
1249 	Window	*tmp = NULL;
1250 
1251 	while ((traverse_all_windows(&tmp)))
1252 	{
1253 		if (tmp->name && (my_stricmp(tmp->name, name) == 0))
1254 			return (tmp);
1255 	}
1256 	return (NULL);
1257 }
1258 
1259 
1260 /*
1261  * get_next_window: This returns a pointer to the next *visible* window in
1262  * the window list.  It automatically wraps at the end of the list back to
1263  * the beginning of the list
1264  */
get_next_window(Window * w)1265 static	Window	* get_next_window (Window *w)
1266 {
1267 	Window *last = w;
1268 	Window *new = w;
1269 
1270 	if (!w || !w->screen)
1271 		last = new = w = current_window;
1272 
1273 	do
1274 	{
1275 		if (new->next)
1276 			new = new->next;
1277 		else
1278 			new = w->screen->window_list;
1279 	}
1280 	while (new && new->skip && new != last);
1281 	return new;
1282 }
1283 
1284 /*
1285  * get_previous_window: this returns the previous *visible* window in the
1286  * window list.  This automatically wraps to the last window in the window
1287  * list
1288  */
get_previous_window(Window * w)1289 static	Window	* get_previous_window (Window *w)
1290 {
1291 	Window *last = w;
1292 	Window *new = w;
1293 
1294 	if (!w || !w->screen)
1295 		last = new = w = current_window;
1296 
1297 	do
1298 	{
1299 		if (new->prev)
1300 			new = new->prev;
1301 		else
1302 			new = w->screen->window_list_end;
1303 	}
1304 	while (new->skip && new != last);
1305 
1306 	return new;
1307 }
1308 
1309 /*
1310  * next_window: This switches the current window to the next visible window
1311  */
BX_next_window(char key,char * ptr)1312 void BX_next_window(char key, char *ptr)
1313 {
1314 	Window *w;
1315 	if (!last_input_screen)
1316 		return;
1317 	if (last_input_screen->visible_windows == 1)
1318 		return;
1319 	w = get_next_window(last_input_screen->current_window);
1320 	make_window_current(w);
1321 	set_screens_current_window(last_input_screen, w);
1322 	update_all_windows();
1323 	set_input_prompt(current_window, get_string_var(INPUT_PROMPT_VAR), 0);
1324 }
1325 
1326 
1327 /*
1328  * previous_window: This switches the current window to the previous visible
1329  * window
1330  */
BX_previous_window(char key,char * ptr)1331 void BX_previous_window(char key, char *ptr)
1332 {
1333 	Window *w;
1334 
1335 	if (!last_input_screen || last_input_screen->visible_windows == 1)
1336 		return;
1337 	w = get_previous_window(last_input_screen->current_window);
1338 	make_window_current(w);
1339 	set_screens_current_window(last_input_screen, w);
1340 	update_all_windows();
1341 	set_input_prompt(current_window, get_string_var(INPUT_PROMPT_VAR), 0);
1342 }
1343 
1344 
1345 
1346 /*
1347  * update_window_status: This updates the status line for the given window.
1348  * If the refresh flag is true, the entire status line is redrawn.  If not,
1349  * only some of the changed portions are redrawn
1350  */
BX_update_window_status(Window * window,int refresh)1351 void BX_update_window_status(Window *window, int refresh)
1352 {
1353 	if (!window)
1354 		window = current_window;
1355 	if (!window || !window->visible || !status_update_flag || never_connected)
1356 		return;
1357 	if (refresh)
1358 	{
1359 		new_free(&(window->wset->status_line[0]));
1360 		new_free(&(window->wset->status_line[1]));
1361 		new_free(&(window->wset->status_line[2]));
1362 	}
1363 	make_status(window);
1364 }
1365 
1366 /*
1367  * update_all_status: This updates all of the status lines for all of the
1368  * windows.  By updating, it only draws from changed portions of the status
1369  * line to the right edge of the screen
1370  */
BX_update_all_status(Window * win,char * unused,int unused1)1371 void BX_update_all_status(Window *win, char *unused, int unused1)
1372 {
1373 	Window	*window = NULL;
1374 	extern	int foreground;
1375 
1376 	if (dumb_mode || !status_update_flag || never_connected || !foreground)
1377 		return;
1378 	while (traverse_all_windows(&window))
1379 	{
1380 #if 0
1381 		if (window->update & UPDATE_STATUS)
1382 			continue;
1383 #endif
1384 		if (!window->visible)
1385 			break;
1386 		make_status(window);
1387 	}
1388 	update_input(UPDATE_JUST_CURSOR);
1389 }
1390 
BX_update_window_status_all(void)1391 void BX_update_window_status_all(void)
1392 {
1393 Window *win  = NULL;
1394 	while ((traverse_all_windows(&win)))
1395 	{
1396 		remove_wsets_for_window(win);
1397 		win->wset = create_wsets_for_window(win);
1398 	}
1399 	update_all_status(win, NULL, 0);
1400 	update_all_windows();
1401 }
1402 
1403 
1404 /*
1405  * status_update: sets the status_update_flag to whatever flag is.  This also
1406  * calls update_all_status(), which will update the status line if the flag
1407  * was true, otherwise it's just ignored
1408  */
BX_status_update(int flag)1409 int BX_status_update(int flag)
1410 {
1411 	int old_flag = status_update_flag;
1412 	status_update_flag = flag;
1413 	update_all_status(current_window, NULL, 0);
1414 	cursor_to_input();
1415 	return old_flag;
1416 }
1417 
1418 
1419 /*
1420  * set_prompt_by_refnum: changes the prompt for the given window.  A window
1421  * prompt will be used as the target in place of the query user or current
1422  * channel if it is set
1423  */
BX_set_prompt_by_refnum(unsigned int refnum,char * prompt)1424 void BX_set_prompt_by_refnum(unsigned int refnum, char *prompt)
1425 {
1426 	Window	*tmp;
1427 
1428 	if (!(tmp = get_window_by_refnum(refnum)))
1429 		tmp = current_window;
1430 	malloc_strcpy(&(tmp->prompt), prompt);
1431 }
1432 
1433 /* get_prompt_by_refnum: returns the prompt for the given window refnum */
BX_get_prompt_by_refnum(unsigned int refnum)1434 char	*BX_get_prompt_by_refnum(unsigned int refnum)
1435 {
1436 	Window	*tmp;
1437 
1438 	if (!(tmp = get_window_by_refnum(refnum)))
1439 		tmp = current_window;
1440 	if (tmp->prompt)
1441 		return (tmp->prompt);
1442 	else
1443 		return (empty_string);
1444 }
1445 
1446 /*
1447  * get_target_by_refnum: returns the target for the window with the given
1448  * refnum (or for the current window).  The target is either the query nick
1449  * or current channel for the window
1450  */
BX_get_target_by_refnum(unsigned int refnum)1451 char	*BX_get_target_by_refnum(unsigned int refnum)
1452 {
1453 	Window	*tmp;
1454 
1455 	if (!(tmp = get_window_by_refnum(refnum)))
1456 		if (!(tmp = last_input_screen->current_window))
1457 			return NULL;
1458 	if (tmp->query_nick)
1459 		return tmp->query_nick;
1460 	else if (tmp->current_channel)
1461 		return tmp->current_channel;
1462 
1463 	return NULL;
1464 }
1465 
BX_get_target_cmd_by_refnum(unsigned int refnum)1466 char	*BX_get_target_cmd_by_refnum(unsigned int refnum)
1467 {
1468 	Window *tmp;
1469 	if (!(tmp = get_window_by_refnum(refnum)))
1470 		if (!(tmp = last_input_screen->current_window))
1471 			return NULL;
1472 	return tmp->query_cmd ? tmp->query_cmd : NULL;
1473 }
1474 
BX_get_window_target_by_desc(char * name)1475 Window *BX_get_window_target_by_desc(char *name)
1476 {
1477 Window *tmp = NULL;
1478 unsigned long level = 0;
1479 	level = parse_lastlog_level(name, 0);
1480 	while ((traverse_all_windows(&tmp)))
1481 	{
1482 		if (is_channel(name) && tmp->server != -1)
1483 		{
1484 			ChannelList *chan, *chan2;
1485 			chan2 = get_server_channels(tmp->server);
1486 			if ((chan = (ChannelList *)find_in_list((List **)&chan2, (char *)name, 0)))
1487 				if (chan->window && (chan->window == tmp))
1488 					return tmp;
1489 		}
1490 		else if (tmp->query_nick && !my_stricmp(tmp->query_nick, name))
1491 			return tmp;
1492 		else if (find_in_list((List **)&tmp->nicks, (char *)who_from, 0))
1493 			return tmp;
1494 		else if (level && tmp->window_level && (tmp->window_level & level))
1495 			return tmp;
1496 	}
1497 	return NULL;
1498 }
1499 
1500 #if 0
1501 /* set_query_nick: sets the query nick for the current channel to nick */
1502 void set_query_nick(char *nick, char *host, char *cmd)
1503 {
1504 	NickList *tmp;
1505 	char	*old_nick;
1506 	if (!nick && !host && cmd)
1507 	{
1508 		malloc_strcpy(&current_window->query_cmd, cmd);
1509 		return;
1510 	}
1511 	if ((old_nick = current_window->query_nick))
1512 	{
1513 		char	*n;
1514 		while ((n = next_in_comma_list(old_nick, &old_nick)))
1515 		{
1516 			if (!*n)
1517 				break;
1518 			if ((tmp = (NickList *) remove_from_list((List **) &(current_window->nicks), n)) != NULL)
1519 			{
1520 				new_free(&tmp->nick);
1521 				new_free(&tmp->host);
1522 				new_free((char **)&tmp);
1523 			}
1524 		}
1525 		new_free(&current_window->query_nick);
1526 		new_free(&current_window->query_host);
1527 		new_free(&current_window->query_cmd);
1528 	}
1529 	if (nick)
1530 	{
1531 		malloc_strcpy(&current_window->query_nick, nick);
1532 		malloc_strcpy(&current_window->query_host, host);
1533 		if (cmd)
1534 			malloc_strcpy(&current_window->query_cmd, cmd);
1535 		current_window->update |= UPDATE_STATUS;
1536 		while ((old_nick = next_in_comma_list(nick, &nick)))
1537 		{
1538 			if (!*old_nick)
1539 				break;
1540 			tmp = (NickList *) new_malloc(sizeof(NickList));
1541 			malloc_strcpy(&tmp->nick, old_nick);
1542 			malloc_strcpy(&tmp->host, host);
1543 			add_to_list((List **) &(current_window->nicks), (List *) tmp);
1544 		}
1545 	}
1546 	update_window_status(current_window, 0);
1547 }
1548 #endif
1549 /*
1550  * is_current_channel: Returns true is channel is a current channel for any
1551  * winDow.  If the delete flag is not 0, then unset channel as the current
1552  * channel and attempt to replace it by a non-current channel or the
1553  * current_channel of window specified by value of delete
1554  */
BX_is_current_channel(char * channel,int server,int delete)1555 int BX_is_current_channel(char *channel, int server, int delete)
1556 {
1557 
1558 	Window	*tmp = NULL;
1559 	int	found = 0;
1560 
1561 	while ((traverse_all_windows(&tmp)))
1562 	{
1563 		if (tmp->current_channel &&
1564 		    !my_stricmp(channel, tmp->current_channel) &&
1565 		    (tmp->server == from_server))
1566 		{
1567 			found = 1;
1568 			if (delete)
1569 			{
1570 				new_free(&(tmp->current_channel));
1571 				tmp->update |= UPDATE_STATUS;
1572 			}
1573 		}
1574 	}
1575 	return (found);
1576 }
1577 
1578 /*
1579  * set_current_channel_by_refnum: This sets the current channel for the current
1580  * window. It returns the current channel as it's value.  If channel is null,
1581  * the * current channel is not changed, but simply reported by the function
1582  * result.  This treats as a special case setting the current channel to
1583  * channel "0".  This frees the current_channel for the
1584  * output_screen->current_window, * setting it to null
1585  */
BX_set_current_channel_by_refnum(unsigned int refnum,char * channel)1586 const char	*BX_set_current_channel_by_refnum(unsigned int refnum, char *channel)
1587 {
1588 	Window	*tmp;
1589 	char *oldc;
1590 	if ((tmp = get_window_by_refnum(refnum)) == NULL)
1591 		tmp = current_window;
1592 
1593 	oldc = tmp->current_channel;
1594 	if (!channel || (channel && !strcmp(channel, zero)))
1595 		tmp->current_channel = NULL;
1596 	else
1597 		tmp->current_channel = m_strdup(channel);
1598 
1599 	new_free(&tmp->waiting_channel);
1600 	tmp->update |= UPDATE_STATUS;
1601 	set_channel_window(tmp, tmp->current_channel, tmp->server);
1602 	do_hook(SWITCH_CHANNELS_LIST, "%d %s %s", refnum,
1603 			oldc ? oldc : zero,
1604 			tmp->current_channel ? tmp->current_channel : zero);
1605 #ifdef GUI
1606 	if(tmp->current_channel)
1607 		gui_update_nicklist(tmp->current_channel);
1608 #endif
1609 	new_free(&oldc);
1610 	return (channel);
1611 }
1612 
1613 /* get_current_channel_by_refnum: returns the current channel for window refnum */
BX_get_current_channel_by_refnum(unsigned int refnum)1614 char	* BX_get_current_channel_by_refnum(unsigned int refnum)
1615 {
1616 	Window	*tmp;
1617 
1618 	if ((tmp = get_window_by_refnum(refnum)) == NULL)
1619 		tmp = current_window;
1620 	return (tmp ? tmp->current_channel : NULL);
1621 }
1622 
BX_get_refnum_by_window(const Window * w)1623 char *BX_get_refnum_by_window(const Window *w)
1624 {
1625 	return w ? ltoa(w->refnum) : NULL;
1626 }
1627 
1628 
BX_is_bound_to_window(const Window * window,const char * channel)1629 int	BX_is_bound_to_window (const Window *window, const char *channel)
1630 {
1631 	if (window->bind_channel)
1632 	{
1633 		char *p, *q;
1634 		q = p = LOCAL_COPY(window->bind_channel);
1635 		while ((p = next_in_comma_list(q, &q)))
1636 		{
1637 			if (!p || !*p) break;
1638 			if (!my_stricmp(p, channel))
1639 				return 1;
1640 		}
1641 	}
1642 	return 0;
1643 }
1644 
BX_get_window_bound_channel(const char * channel)1645 Window *BX_get_window_bound_channel (const char *channel)
1646 {
1647 	Window *tmp = NULL;
1648 
1649 	while ((traverse_all_windows(&tmp)))
1650 	{
1651 		if (tmp->bind_channel)
1652 		{
1653 			char *p, *q;
1654 			if (!channel)
1655 				return tmp;
1656 			q = p = LOCAL_COPY(tmp->bind_channel);
1657 			while ((p = next_in_comma_list(q, &q)))
1658 			{
1659 				if (!p || !*p) break;
1660 				if (!my_stricmp(p, channel))
1661 					return tmp;
1662 			}
1663 		}
1664 	}
1665 	return NULL;
1666 }
1667 
BX_is_bound_anywhere(const char * channel)1668 int BX_is_bound_anywhere (const char *channel)
1669 {
1670 	Window *tmp = NULL;
1671 
1672 	while ((traverse_all_windows(&tmp)))
1673 	{
1674 		if (tmp->bind_channel)
1675 		{
1676 			char *p, *q;
1677 			q = p = LOCAL_COPY(tmp->bind_channel);
1678 			while ((p = next_in_comma_list(q, &q)))
1679 			{
1680 				if (!p || !*p) break;
1681 				if (!my_stricmp(p, channel))
1682 					return 1;
1683 			}
1684 		}
1685 	}
1686 	return 0;
1687 }
1688 
BX_is_bound(const char * channel,int server)1689 extern int BX_is_bound (const char *channel, int server)
1690 {
1691 	Window *tmp = NULL;
1692 
1693 	while ((traverse_all_windows(&tmp)))
1694 	{
1695 		if (tmp->server == server && tmp->bind_channel)
1696 		{
1697 			char *p, *q;
1698 			q = p = LOCAL_COPY(tmp->bind_channel);
1699 			while ((p = next_in_comma_list(q, &q)))
1700 			{
1701 				if (!p || !*p) break;
1702 				if (!my_stricmp(p, channel))
1703 					return 1;
1704 			}
1705 		}
1706 	}
1707 	return 0;
1708 }
1709 
BX_unbind_channel(const char * channel,int server)1710 void BX_unbind_channel (const char *channel, int server)
1711 {
1712 	Window *tmp = NULL;
1713 
1714 	while ((traverse_all_windows(&tmp)))
1715 	{
1716 		if (tmp->server == server && tmp->bind_channel)
1717 		{
1718 			char *p, *q, *new_bind = NULL;
1719 			if (!strchr(tmp->bind_channel, ','))
1720 			{
1721 				new_free(&tmp->bind_channel);
1722 				tmp->bind_channel = NULL;
1723 				return;
1724 			}
1725 			q = p = LOCAL_COPY(tmp->bind_channel);
1726 			while ((p = next_in_comma_list(q, &q)))
1727 			{
1728 				if (!p || !*p)
1729 					break;
1730 				if (!my_stricmp(p, channel))
1731 					continue;
1732 				m_s3cat(&new_bind, comma, p);
1733 			}
1734 			malloc_strcpy(&tmp->bind_channel, new_bind);
1735 			new_free(&new_bind);
1736 			return;
1737 		}
1738 	}
1739 }
1740 
BX_get_bound_channel(Window * window)1741 char *BX_get_bound_channel (Window *window)
1742 {
1743 	return window ? window->bind_channel : NULL;
1744 }
1745 
1746 /*
1747  * get_
1748  window_server: returns the server index for the window with the given
1749  * refnum
1750  */
BX_get_window_server(unsigned int refnum)1751 int BX_get_window_server(unsigned int refnum)
1752 {
1753 	Window	*tmp;
1754 
1755 	if ((tmp = get_window_by_refnum(refnum)) == NULL)
1756 		tmp = current_window;
1757 	return tmp ? tmp->server : -1;
1758 }
1759 
1760 /*
1761  * set_window_server:  This sets the server of the given window to server.
1762  * If refnum is -1 then we are setting the primary server and all windows
1763  * that are set to the current primary server are changed to server.  The misc
1764  * flag is ignored in this case.  If refnum is not -1, then that window is
1765  * set to the given server.  If the misc flag is set as well, then all windows
1766  * with the same server as renum are set to the new server as well
1767  * if refnum == -2, then, we are setting the server group passed in the misc
1768  * variable to the server.
1769  */
BX_set_window_server(int refnum,int server,int misc)1770 void BX_set_window_server(int refnum, int server, int misc)
1771 {
1772 	Window	*tmp = NULL,
1773 		*window;
1774 	int	old;
1775 
1776 	if (refnum == -1)
1777 	{
1778 		while ((traverse_all_windows(&tmp)))
1779 		{
1780 			if (tmp->server == primary_server)
1781 				tmp->server = server;
1782 		}
1783 		window_check_servers(server);
1784 		primary_server = server;
1785 	}
1786 	else
1787 	{
1788 		if ((window = get_window_by_refnum(refnum)) == NULL)
1789 			window = current_window;
1790 		old = window->server;
1791 		if (misc || old == WINDOW_SERVER_CLOSED)
1792 		{
1793 			while ((traverse_all_windows(&tmp)))
1794 			{
1795 				if (tmp->server == old)
1796 					tmp->server = server;
1797 			}
1798 		}
1799 		else
1800 			window->server = server;
1801 		window_check_servers(window->server);
1802 	}
1803 }
1804 
1805 /*
1806  * window_check_servers: this checks the validity of the open servers vs the
1807  * current window list.  Every open server must have at least one window
1808  * associated with it.  If a window is associated with a server that's no
1809  * longer open, that window's server is set to the primary server.  If an
1810  * open server has no assicatiate windows, that server is closed.  If the
1811  * primary server is no more, a new primary server is picked from the open
1812  * servers
1813  */
1814 
BX_window_check_servers(int unused)1815 void BX_window_check_servers(int unused)
1816 {
1817 	Window	*tmp;
1818 	int	cnt, max, i, not_connected, prime = -1;
1819 
1820 	connected_to_server = 0;
1821 	max = server_list_size();
1822 	for (i = 0; i < max; i++)
1823 	{
1824 		not_connected = !is_server_open(i);
1825 		tmp = NULL;
1826 		cnt = 0;
1827 		while ((traverse_all_windows(&tmp)))
1828 		{
1829 			if (tmp->server == i)
1830 			{
1831 				if (not_connected)
1832 					tmp->server = primary_server;
1833 				else
1834 				{
1835 					prime = tmp->server;
1836 					cnt++;
1837 				}
1838 			}
1839 		}
1840 		if (cnt == 0)
1841 		{
1842 			if(!not_connected)
1843 			{
1844 				if(!get_server_change_pending(i))
1845 					close_server(i, "No windows for this server");
1846 				else
1847 					close_unattached_server(i);
1848 			}
1849 		}
1850 		else
1851 			connected_to_server++;
1852 	}
1853 
1854 
1855 	if (!is_server_open(primary_server))
1856 	{
1857 		tmp = NULL;
1858 		while ((traverse_all_windows(&tmp)))
1859 			if (tmp->server == primary_server)
1860 				tmp->server = prime;
1861 		primary_server = prime;
1862 	}
1863 	update_all_status(current_window, NULL, 0);
1864 	cursor_to_input();
1865 }
1866 
1867 /*
1868  * Changes any windows that are currently using "old_server" to instead
1869  * use "new_server".
1870  */
BX_change_window_server(int old_server,int new_server)1871 void	BX_change_window_server (int old_server, int new_server)
1872 {
1873 	Window *tmp = NULL;
1874 
1875 	while (traverse_all_windows(&tmp))
1876 	{
1877 		if (tmp->server == old_server)
1878 			tmp->server = new_server;
1879 	}
1880 	window_check_servers(old_server);
1881 }
1882 
1883 /*
1884  * set_level_by_refnum: This sets the window level given a refnum.  It
1885  * revamps the windows levels as well using revamp_window_levels()
1886  */
BX_set_level_by_refnum(unsigned int refnum,unsigned long level)1887 void BX_set_level_by_refnum(unsigned int refnum, unsigned long level)
1888 {
1889 	Window	*tmp;
1890 
1891 	if ((tmp = get_window_by_refnum(refnum)) == NULL)
1892 		tmp = current_window;
1893 	tmp->window_level = level;
1894 	revamp_window_levels(tmp);
1895 }
1896 
1897 /*
1898  * revamp_window_levels: Given a level setting for the current window, this
1899  * makes sure that that level setting is unused by any other window. Thus
1900  * only one window in the system can be set to a given level.  This only
1901  * revamps levels for windows with servers matching the given window
1902  * it also makes sure that only one window has the level `DCC', as this is
1903  * not dependant on a server.
1904  */
revamp_window_levels(Window * window)1905 void revamp_window_levels(Window *window)
1906 {
1907 	Window	*tmp = NULL;
1908 	int	got_dcc;
1909 
1910 	got_dcc = (LOG_DCC & window->window_level) ? 1 : 0;
1911 	while ((traverse_all_windows(&tmp)))
1912 	{
1913 		if (tmp == window)
1914 			continue;
1915 		if (LOG_DCC & tmp->window_level)
1916 		{
1917 			if (0 != got_dcc)
1918 				tmp->window_level &= ~LOG_DCC;
1919 			got_dcc = 1;
1920 		}
1921 		if (window->server == tmp->server)
1922 			tmp->window_level ^= (tmp->window_level & window->window_level);
1923 	}
1924 }
1925 
1926 /*
1927  * message_to: This allows you to specify a window (by refnum) as a
1928  * destination for messages.  Used by EXEC routines quite nicely
1929  */
BX_message_to(unsigned long refnum)1930 void BX_message_to(unsigned long refnum)
1931 {
1932 	target_window = (refnum) ? get_window_by_refnum(refnum) : NULL;
1933 }
1934 
1935 #if 0
1936 /*
1937  * save_message_from: this is used to save (for later restoration) the
1938  * who_from variable.  This comes in handy very often when a routine might
1939  * call another routine that might change who_from.
1940  */
1941 void save_message_from(char **saved_who_from, unsigned long *saved_who_level)
1942 {
1943 	*saved_who_from = who_from;
1944 	*saved_who_level = who_level;
1945 }
1946 
1947 /* restore_message_from: restores a previously saved who_from variable */
1948 void restore_message_from (char *saved_who_from, unsigned long saved_who_level)
1949 {
1950 	who_from = saved_who_from;
1951 	who_level = saved_who_level;
1952 }
1953 
1954 /*
1955  * message_from: With this you can the who_from variable and the who_level
1956  * variable, used by the display routines to decide which window messages
1957  * should go to.
1958  */
1959 void message_from(char *who, unsigned long level)
1960 {
1961 	static unsigned long saved_lastlog_level = LOG_ALL;
1962 
1963 	if (level == LOG_CURRENT)
1964 		set_lastlog_msg_level(saved_lastlog_level);
1965 	else
1966 		saved_lastlog_level = set_lastlog_msg_level(level);
1967 	who_from = who;
1968 	who_level = level;
1969 }
1970 
1971 /*
1972  * message_from_level: Like set_lastlog_msg_level, except for message_from.
1973  * this is needed by XECHO, because we could want to output things in moRe
1974  * than one level.
1975  */
1976 int message_from_level(unsigned long level)
1977 {
1978 	int	temp;
1979 
1980 	temp = who_level;
1981 	who_level = level;
1982 	return temp;
1983 }
1984 #else
1985 
1986 /*
1987  * save_message_from: this is used to save (for later restoration) the
1988  * who_from variable.  This is needed when a function (do_hook) is about
1989  * to call another function (parse_line) it knows will change who_from.
1990  * The values are saved on the stack so it will be recursive-safe.
1991  *
1992  * NO CHEATING when you call this function to get the value of who_from! ;-)
1993  */
BX_save_display_target(const char ** saved_from,unsigned long * saved_level)1994 void 	BX_save_display_target (const char **saved_from, unsigned long *saved_level)
1995 {
1996 	*saved_from = who_from;
1997 	*saved_level = who_level;
1998 }
1999 
2000 /* restore_message_from: restores a previously saved who_from variable */
BX_restore_display_target(const char * saved_from,unsigned long saved_level)2001 void 	BX_restore_display_target (const char *saved_from, unsigned long saved_level)
2002 {
2003 	who_from = saved_from;
2004 	who_level = saved_level;
2005 }
2006 
2007 /*
2008  * is "word" in comma-separated "list" ?
2009  *  --einride
2010  */
wordinlist(const char * word,const char * list)2011 int wordinlist(const char * word, const char * list)
2012 {
2013 	char * nw;
2014 	int wl;
2015 	if (!word || !list || !word[0] || !list[0])
2016 		return 0;
2017 	wl = strlen(word);
2018 	nw = (char *) list;
2019 	while (nw) {
2020 		if (!my_strnicmp(word, nw, wl) && (!nw[wl] || (nw[wl]==',')))
2021 			return 1;
2022 		nw = strchr(nw, ',');
2023 		if (nw)
2024 			nw++;
2025 	}
2026 	return 0;
2027 }
2028 
2029 /*
2030  * message_from: With this you can set the who_from variable and the
2031  * who_level variable, used by the display routines to decide which
2032  * window messages should go to.
2033  */
2034 static	unsigned long	saved_lastlog_level = -1;
2035 
BX_set_display_target(const char * who,unsigned long level)2036 void 	BX_set_display_target (const char *who, unsigned long level)
2037 {
2038 	Window	*tmp;
2039 
2040 #ifdef NO_CHEATING
2041 	if (who)
2042 		malloc_strcpy(&who_from, who);
2043 	else
2044 		new_free(&who_from);
2045 #else
2046 	who_from = who;
2047 #endif
2048 	who_level = level;
2049 	saved_lastlog_level = set_lastlog_msg_level(level);
2050 
2051 
2052 	/*
2053 	 * Now we try to find the window that this output level would
2054 	 * be directed to.  This was transplanted from add_to_screen.
2055 	 */
2056 
2057 	if (who_level == LOG_DEBUG && debugging_window)
2058 	{
2059 		target_window = debugging_window;
2060 		return;
2061 	}
2062 	/*
2063 	 * LOG_CURRENT means everything goes to the current window.
2064 	 */
2065 	if (who_level == LOG_CURRENT && current_window->server == from_server)
2066 	{
2067 		target_window = current_window;
2068 		return;
2069 	}
2070 	/*
2071 	 * Next priority is to honor who_from (using /window bind,
2072 	 * /window channel, or /window add)
2073 	 */
2074 	if (who_from)
2075 	{
2076 		tmp = NULL;
2077 		while (traverse_all_windows(&tmp))
2078 		{
2079 			/*
2080 			 * Check for /WINDOW CHANNELs that apply.
2081 			 * (Any current channel will do)
2082 			 */
2083 			if (tmp->server != from_server && level != LOG_DCC)
2084 				continue;
2085 			if ((tmp->window_level & LOG_DEBUG) == LOG_DEBUG)
2086 				continue;
2087 			if (tmp->current_channel &&
2088 				wordinlist(who_from, tmp->current_channel))
2089 			{
2090 				if (tmp->server == from_server)
2091 				{
2092 					target_window = tmp;
2093 					return;
2094 				}
2095 			}
2096 			if (tmp->bind_channel &&
2097 				wordinlist(who_from, tmp->bind_channel))
2098 			{
2099 				if (tmp->server == from_server)
2100 				{
2101 					target_window = tmp;
2102 					return;
2103 				}
2104 			}
2105 			/*
2106 			 * Check for /WINDOW QUERYs that apply.
2107 			 */
2108 			if (tmp->query_nick)
2109 			{
2110 			    if ((who_level == LOG_MSG || who_level == LOG_NOTICE
2111 				|| who_level == LOG_DCC || who_level == LOG_CTCP
2112 				|| who_level == LOG_ACTION)
2113 				&& wordinlist(who_from, tmp->query_nick)
2114 				&& from_server == tmp->server)
2115 			    {
2116 					target_window = tmp;
2117 					return;
2118 			    }
2119 			    if ((who_level == LOG_DCC || who_level == LOG_CTCP
2120 				|| who_level == LOG_ACTION)
2121 				&& (*tmp->query_nick == '=' || *tmp->query_nick == '-')
2122 				&& wordinlist(who_from, tmp->query_nick + 1))
2123 			    {
2124 					target_window = tmp;
2125 					return;
2126 			    }
2127 			    if ((who_level == LOG_DCC || who_level == LOG_CTCP
2128 			  	|| who_level == LOG_ACTION)
2129 				&& *tmp->query_nick == '='
2130 				&& wordinlist(who_from, tmp->query_nick))
2131 			    {
2132 					target_window = tmp;
2133 					return;
2134 			    }
2135 			}
2136 		}
2137 
2138 		/*
2139 		 * Check for /WINDOW NICKs that apply
2140 		 */
2141 		tmp = NULL;
2142 		while (traverse_all_windows(&tmp))
2143 		{
2144 			if (tmp->nicks && from_server == tmp->server)
2145 			{
2146 				if (find_in_list((List **)&(tmp->nicks),
2147 					(char *)who_from, !USE_WILDCARDS))
2148 				{
2149 					target_window = tmp;
2150 					return;
2151 				}
2152 			}
2153 		}
2154 
2155 		/*
2156 		 * We'd better check to see if this should go to a
2157 		 * specific window (i dont agree with this, though)
2158 		 */
2159 		if (is_channel((char *)who_from) && from_server > -1)
2160 		{
2161 			ChannelList *chan, *chan2;
2162 			chan2 = get_server_channels(from_server);
2163 			if ((chan = (ChannelList *)find_in_list((List **)&chan2,
2164 				(char *)who_from, !USE_WILDCARDS)))
2165 			{
2166 				tmp = NULL;
2167 				while ((traverse_all_windows(&tmp)))
2168 				{
2169 					if ((tmp->window_level & LOG_DEBUG) == LOG_DEBUG || !chan->window)
2170 						continue;
2171 					if (tmp->server != from_server)
2172 						continue;
2173 					if ((chan->refnum == tmp->refnum) && (tmp->server == chan->server))
2174 					{
2175 						target_window = tmp;
2176 						return;
2177 					}
2178 				}
2179 			}
2180 		}
2181 	}
2182 
2183 	/*
2184 	 * Check to see if this level should go to current window
2185 	 */
2186 	if ((current_window_level & who_level) &&
2187 		current_window->server == from_server)
2188 	{
2189 		target_window = current_window;
2190 		return;
2191 	}
2192 	/*
2193 	 * Check to see if any window can claim this level
2194 	 */
2195 	tmp = NULL;
2196 	while (traverse_all_windows(&tmp))
2197 	{
2198 		if ((tmp->window_level & LOG_DEBUG) == LOG_DEBUG)
2199 			continue;
2200 		/*
2201 		 * Check for /WINDOW LEVELs that apply
2202 		 */
2203 		if (((from_server == tmp->server) || (from_server <= -1)) &&
2204 		    (who_level & tmp->window_level))
2205 		{
2206 			target_window = tmp;
2207 			return;
2208 		}
2209 	}
2210 
2211 	/*
2212 	 * If all else fails, if the current window is connected to the
2213 	 * given server, use the current window.
2214 	 */
2215 	if (level == LOG_DCC || (from_server == current_window->server &&
2216 		(current_window->window_level & LOG_DEBUG) != LOG_DEBUG))
2217 	{
2218 		target_window = current_window;
2219 		return;
2220 	}
2221 
2222 	/*
2223 	 * And if that fails, look for ANY window that is bound to the
2224 	 * given server (this never fails if we're connected.)
2225 	 */
2226 	tmp = NULL;
2227 	while (traverse_all_windows(&tmp))
2228 	{
2229 		if ((tmp->window_level & LOG_DEBUG) == LOG_DEBUG)
2230 			continue;
2231 		if (tmp->server == from_server)
2232 		{
2233 			target_window = tmp;
2234 			return;
2235 		}
2236 	}
2237 
2238 	/*
2239 	 * No window found for a server is usually because we're
2240 	 * disconnected or not yet connected.
2241 	 */
2242 	target_window = current_window;
2243 	return;
2244 }
2245 
BX_reset_display_target(void)2246 void	BX_reset_display_target (void)
2247 {
2248 	set_display_target(NULL, LOG_CRAP);
2249 }
2250 
BX_set_display_target_by_desc(char * desc)2251 void	BX_set_display_target_by_desc (char *desc)
2252 {
2253 	if (!desc)
2254 		target_window = current_window;
2255 	else if (!strcmp(desc, "-1"))
2256 		return;
2257 	else if (!(target_window = get_window_by_desc(desc)))
2258 	{
2259 		say("Window [%s] does not exist", desc);
2260 		target_window = current_window;
2261 	}
2262 }
2263 
set_display_target_by_winref(unsigned int refnum)2264 void	set_display_target_by_winref (unsigned int refnum)
2265 {
2266 	Window *w;
2267 
2268 	if (refnum == -1)
2269 		return;
2270 	if (!(w = get_window_by_refnum(refnum)))
2271 		say("Window [%d] does not exist", refnum);
2272 	else
2273 		target_window = w;
2274 }
2275 
2276 #endif
2277 
2278 
2279 /*
2280  * message_from_level: Like set_lastlog_msg_level, except for message_from.
2281  * this is needed by XECHO, because we could want to output things in more
2282  * than one level.
2283  */
message_from_level(unsigned long level)2284 unsigned long message_from_level (unsigned long level)
2285 {
2286 	unsigned long temp;
2287 	temp = who_level;
2288 	who_level = level;
2289 	return temp;
2290 }
2291 
2292 
2293 
2294 /*
2295  * clear_window: This clears the display list for the given window, or
2296  * current window if null is given.
2297  */
BX_clear_window(Window * window)2298 void BX_clear_window(Window *window)
2299 {
2300 	if (dumb_mode)
2301 		return;
2302 	if (window->scratch_line != -1)
2303 	{
2304 		Display *curr_line;
2305 		 /* Just walk every line and nuke whatever is in it */
2306 		curr_line = window->top_of_display;
2307 		while (curr_line && curr_line != window->display_ip)
2308 		{
2309 			malloc_strcpy(&curr_line->line, empty_string);
2310 			curr_line = curr_line->next;
2311 		}
2312 	}
2313 	else
2314 	{
2315 		window->top_of_display = window->display_ip;
2316 		window->ceiling_of_display = window->top_of_display;
2317 		window->cursor = 0;
2318 		window->lines_scrolled_back = 0;
2319 		window->scrollback_point = NULL;
2320 		window->held_displayed = 0;
2321 		if (window->miscflags & WINDOW_NOTIFIED)
2322 			window->miscflags &= ~WINDOW_NOTIFIED;
2323 	}
2324 	repaint_window(window, 0, -1);
2325 	update_window_status(window, 1);
2326 #ifdef GUI
2327 	gui_activity(COLOR_INACTIVE);
2328 #endif
2329 }
2330 
2331 /* clear_all_windows: This clears all *visible* windows */
BX_clear_all_windows(int unhold,int scrollback)2332 void BX_clear_all_windows(int unhold, int scrollback)
2333 {
2334 	Window	*tmp = NULL;
2335 
2336 	while (traverse_all_windows(&tmp))
2337 	{
2338 		if (unhold)
2339 			set_hold_mode(tmp, OFF, 1);
2340 		if (scrollback)
2341 			clear_scrollback(tmp);
2342 		clear_window(tmp);
2343 	}
2344 }
2345 
2346 /*
2347  * clear_window_by_refnum: just like clear_window(), but it uses a refnum. If
2348  * the refnum is invalid, the current window is cleared.
2349  */
BX_clear_window_by_refnum(unsigned int refnum)2350 void BX_clear_window_by_refnum(unsigned int refnum)
2351 {
2352 	Window	*tmp;
2353 
2354 	if ((tmp = get_window_by_refnum(refnum)) == NULL)
2355 		tmp = current_window;
2356 	clear_window(tmp);
2357 }
2358 
unclear_window(Window * window)2359 static void	unclear_window (Window *window)
2360 {
2361 	int i;
2362 
2363 	if (dumb_mode)
2364 		return;
2365 	if (window->scratch_line != -1)
2366 		return;
2367 	window->top_of_display = window->display_ip;
2368 	for (i = 0; i < window->display_size; i++)
2369 	{
2370 		window->top_of_display = window->top_of_display->prev;
2371 		if (window->top_of_display == window->top_of_scrollback)
2372 			break;
2373 	}
2374 	window->ceiling_of_display = window->top_of_display;
2375 	repaint_window(window, 0, -1);
2376 	update_window_status(window, 0);
2377 }
2378 
unclear_all_windows(int unhold,int visible,int hidden)2379 void	unclear_all_windows (int unhold, int visible, int hidden)
2380 {
2381 	Window *tmp = NULL;
2382 
2383 	while (traverse_all_windows(&tmp))
2384 	{
2385 		if (visible && !hidden && !tmp->visible)
2386 			continue;
2387 		if (!visible && hidden && tmp->visible)
2388 			continue;
2389 
2390 		if (unhold)
2391 			set_hold_mode(tmp, OFF, 1);
2392 		unclear_window(tmp);
2393 	}
2394 }
2395 
BX_unclear_window_by_refnum(unsigned refnum)2396 void	BX_unclear_window_by_refnum (unsigned refnum)
2397 {
2398 	Window *tmp;
2399 
2400 	if (!(tmp = get_window_by_refnum(refnum)))
2401 		tmp = current_window;
2402 	unclear_window(tmp);
2403 }
2404 
2405 /*
2406  * set_scroll_lines: called by /SET SCROLL_LINES to check the scroll lines
2407  * value
2408  */
BX_set_scroll_lines(Window * win,char * unused,int size)2409 void BX_set_scroll_lines(Window *win, char *unused, int size)
2410 {
2411 	if (size == 0)
2412 	{
2413 		return;
2414 	}
2415 	else if (size > current_window->display_size)
2416 	{
2417 		say("Maximum lines that may be scrolled is %d",
2418 		    current_window->display_size);
2419 		set_int_var(SCROLL_LINES_VAR, current_window->display_size);
2420 	}
2421 }
2422 
2423 /*
2424  * set_continued_lines: checks the value of CONTINUED_LINE for validity,
2425  * altering it if its no good
2426  */
BX_set_continued_lines(Window * win,char * value,int unused)2427 void BX_set_continued_lines(Window *win, char *value, int unused)
2428 {
2429 	if (value && ((int) strlen(stripansicodes(value)) > (current_term->TI_cols / 2)))
2430 		value[current_term->TI_cols / 2] = '\0';
2431 }
2432 
2433 
2434 
BX_free_formats(Window * window)2435 void BX_free_formats(Window *window)
2436 {
2437 	remove_wsets_for_window(window);
2438 }
2439 
2440 /* current_refnum: returns the reference number for the current window */
BX_current_refnum(void)2441 unsigned int BX_current_refnum (void)
2442 {
2443 	return current_window->refnum;
2444 }
2445 
BX_number_of_windows_on_screen(Window * w)2446 int BX_number_of_windows_on_screen (Window *w)
2447 {
2448 	return w->screen->visible_windows;
2449 }
2450 
2451 /*
2452  * set_lastlog_size: sets up a lastlog buffer of size given.  If the lastlog
2453  * has gotten larger than it was before, all previous lastlog entry remain.
2454  * If it get smaller, some are deleted from the end.
2455  */
BX_set_scrollback_size(Window * w,char * unused,int size)2456 void    BX_set_scrollback_size (Window *w, char *unused, int size)
2457 {
2458         Window  *window = NULL;
2459 
2460         while (traverse_all_windows(&window))
2461         {
2462 		if (size < window->display_size * 2)
2463 			window->display_buffer_max = window->display_size * 2;
2464 		else
2465 			window->display_buffer_max = size;
2466         }
2467 }
2468 
2469 /*
2470  * is_window_name_unique: checks the given name vs the names of all the
2471  * windows and returns true if the given name is unique, false otherwise
2472  */
BX_is_window_name_unique(name)2473 int BX_is_window_name_unique(name)
2474 	char	*name;
2475 {
2476 	Window	*tmp = NULL;
2477 
2478 	if (name)
2479 	{
2480 		while ((traverse_all_windows(&tmp)))
2481 		{
2482 			if (tmp->name && !my_stricmp(tmp->name, name))
2483 				return (0);
2484 		}
2485 	}
2486 	return (1);
2487 }
2488 
BX_get_nicklist_by_window(Window * win)2489 char  *BX_get_nicklist_by_window (Window *win)
2490 {
2491 	NickList *nick = win->nicks;
2492 	char *stuff = NULL;
2493 	for (; nick; nick = nick->next)
2494 		m_s3cat(&stuff, space, nick->nick);
2495 	if (!stuff)
2496 		return m_strdup(empty_string);
2497 	return stuff;
2498 }
2499 
2500 
2501 #define WIN_FORM "%-4s %*.*s %*.*s %*.*s %-9.9s %-10.10s %s%s"
list_a_window(Window * window,int len)2502 static	void list_a_window(Window *window, int len)
2503 {
2504 	int	cnw = get_int_var(CHANNEL_NAME_WIDTH_VAR);
2505 
2506 	say(WIN_FORM,           ltoa(window->refnum),
2507 		      12, 12,   get_server_nickname(window->server),
2508 		      len, len, window->name ? window->name : "<None>",
2509 		      cnw, cnw, window->current_channel ? window->current_channel : "<None>",
2510 		                window->query_nick ? window->query_nick : "<None>",
2511 		                get_server_itsname(window->server) ? get_server_itsname(window->server) : "<None>",
2512 		                bits_to_lastlog_level(window->window_level),
2513 		                window->visible ? empty_string : " Hidden");
2514 }
2515 
2516 /* below is stuff used for parsing of WINDOW command */
2517 
2518 /*
2519  * get_window: this parses out any window (visible or not) and returns a
2520  * pointer to it
2521  */
get_window(char * name,char ** args)2522 static	Window	* get_window(char *name, char **args)
2523 {
2524 	char	*arg;
2525 	Window	*tmp;
2526 
2527 	if ((arg = next_arg(*args, args)) != NULL)
2528 	{
2529 		if (is_number(arg))
2530 		{
2531 			if ((tmp = get_window_by_refnum(my_atol(arg))) != NULL)
2532 				return tmp;
2533 		}
2534 		if ((tmp = get_window_by_name(arg)) != NULL)
2535 			return tmp;
2536 		if (!get_int_var(WINDOW_QUIET_VAR))
2537 			say("%s: No such window: %s", name, arg);
2538 	}
2539 	else
2540 		say("%s: Please specify a window refnum or name", name);
2541 	return NULL;
2542 }
2543 
2544 /*
2545  * get_invisible_window: parses out an invisible window by reference number.
2546  * Returns the pointer to the window, or null.  The args can also be "LAST"
2547  * indicating the top of the invisible window list (and thus the last window
2548  * made invisible)
2549  */
get_invisible_window(char * name,char ** args)2550 static Window	*get_invisible_window(char *name, char **args)
2551 {
2552 	char	*arg;
2553 	Window	*tmp;
2554 
2555 	if ((arg = next_arg(*args, args)) != NULL)
2556 	{
2557 		if (my_strnicmp(arg, "LAST", strlen(arg)) == 0)
2558 		{
2559 			if (invisible_list == NULL)
2560 			{
2561 				if (!get_int_var(WINDOW_QUIET_VAR))
2562 					say("%s: There are no hidden windows", name);
2563 			}
2564 			return invisible_list;
2565 		}
2566 		if ((tmp = get_window(name, &arg)) != NULL)
2567 		{
2568 			if (!tmp->visible)
2569 				return (tmp);
2570 			else if (!get_int_var(WINDOW_QUIET_VAR))
2571 			{
2572 				if (tmp->name)
2573 					say("%s: Window %s is not hidden!",
2574 						name, tmp->name);
2575 				else
2576 					say("%s: Window %d is not hidden!",
2577 						name, tmp->refnum);
2578 			}
2579 		}
2580 	}
2581 	else
2582 		say("%s: Please specify a window refnum or LAST", name);
2583 	return NULL;
2584 }
2585 
2586 /* get_number: parses out an integer number and returns it */
get_number(char * name,char ** args,char * msg)2587 static	int get_number(char *name, char **args, char *msg)
2588 {
2589 	char	*arg;
2590 
2591 	if ((arg = next_arg(*args, args)) != NULL)
2592 		return my_atol(arg);
2593 	else if (!get_int_var(WINDOW_QUIET_VAR))
2594 	{
2595 		if (msg)
2596 			say("%s: %s", name, msg);
2597 		else
2598 			say("%s: You must specify the number of lines", name);
2599 	}
2600 	return 0;
2601 }
2602 
2603 /*
2604  * get_boolean: parses either ON, OFF, or TOGGLE and sets the var
2605  * accordingly.  Returns 0 if all went well, -1 if a bogus or missing value
2606  * was specified
2607  */
get_boolean(char * name,char ** args,int * var)2608 static	int get_boolean(char *name, char **args, int *var)
2609 {
2610 	char	*arg;
2611 
2612 	if (((arg = next_arg(*args, args)) == NULL) || do_boolean(arg, var))
2613 	{
2614 		if (!get_int_var(WINDOW_QUIET_VAR))
2615 			say("Value for %s must be ON, OFF, or TOGGLE", name);
2616 		return (-1);
2617 	}
2618 	else
2619 	{
2620 		say("Window %s is %s", name, onoff[*var]);
2621 		return (0);
2622 	}
2623 }
2624 
2625 
2626 
2627 
2628 
2629 
2630 /*
2631  * /WINDOW ADD nick<,nick>
2632  * Adds a list of one or more nicknames to the current list of usupred
2633  * targets for the current window.  These are matched up with the nick
2634  * argument for message_from().
2635  */
window_add(Window * window,char ** args,char * usage)2636 static Window *window_add (Window *window, char **args, char *usage)
2637 {
2638 	char		*ptr;
2639 	NickList 	*new;
2640 	char 		*arg = next_arg(*args, args);
2641 
2642 	if (!arg)
2643 		say("ADD: Add nicknames to be redirected to this window");
2644 
2645 	else while (arg)
2646 	{
2647 		if ((ptr = strchr(arg, ',')))
2648 			*ptr++ = 0;
2649 		if (!find_in_list((List **)&window->nicks, arg, !USE_WILDCARDS))
2650 		{
2651 			say("Added %s to window name list", arg);
2652 			new = (NickList *)new_malloc(sizeof(NickList));
2653 			new->nick = m_strdup(arg);
2654 			add_to_list((List **)&(window->nicks), (List *)new);
2655 		}
2656 		else
2657 			say("%s already on window name list", arg);
2658 
2659 		arg = ptr;
2660 	}
2661 
2662 	return window;
2663 }
2664 
2665 /*
2666  * /WINDOW BACK
2667  * Changes the current window pointer to the window that was most previously
2668  * the current window.  If that window is now hidden, then it is swapped with
2669  * the current window.
2670  */
window_back(Window * window,char ** args,char * usage)2671 static Window *window_back (Window *window, char **args, char *usage)
2672 {
2673 	Window *tmp;
2674 
2675 	tmp = get_window_by_refnum(last_input_screen->last_window_refnum);
2676 	if (!tmp)
2677 		tmp = last_input_screen->window_list;
2678 
2679 	make_window_current(tmp);
2680 	if (tmp->visible)
2681 		set_screens_current_window(last_input_screen, tmp);
2682 	else
2683 	{
2684 		swap_window(window, tmp);
2685 		reset_display_target();
2686 	}
2687 
2688 	return window;
2689 }
2690 
2691 /*
2692  * /WINDOW BALANCE
2693  * Causes all of the windows on the current screen to be adjusted so that
2694  * the largest window on the screen is no more than one line larger than
2695  * the smallest window on the screen.
2696  */
window_balance(Window * window,char ** args,char * usage)2697 static Window *window_balance (Window *window, char **args, char *usage)
2698 {
2699 	if (window->screen)
2700 		rebalance_windows(window->screen);
2701 	else
2702 		yell("cannot rebalance invisible windows!");
2703 	return window;
2704 }
2705 
2706 /*
2707  * /WINDOW BEEP_ALWAYS ON|OFF
2708  * Indicates that when this window is HIDDEN (sorry, thats not what it seems
2709  * like it should do, but that is what it does), beeps to this window should
2710  * not be suppressed like they normally are for hidden windows.  The beep
2711  * occurs EVEN IF /set beep is OFF.
2712  */
window_beep_always(Window * window,char ** args,char * usage)2713 static Window *window_beep_always (Window *window, char **args, char *usage)
2714 {
2715 	if (get_boolean("BEEP_ALWAYS", args, &window->beep_always))
2716 		return NULL;
2717 	return window;
2718 }
2719 
2720 /*
2721  * /WINDOW BIND <#channel>
2722  * Indicates that the window should be "bound" to the specified channel.
2723  * "binding" a channel to a window means that the channel will always
2724  * belong to this window, no matter what.  For example, if a channel is
2725  * bound to a window, you can do a /join #channel in any window, and it
2726  * will always "join" in this window.  This is especially useful when
2727  * you are disconnected from a server, because when you reconnect, the client
2728  * often loses track of which channel went to which window.  Binding your
2729  * channels gives the client a hint where channels belong.
2730  *
2731  * You can rebind a channel to a new window, even after it has already
2732  * been bound elsewhere.
2733  */
window_bind(Window * window,char ** args,char * usage)2734 static Window *window_bind (Window *window, char **args, char *usage)
2735 {
2736 	char *arg;
2737 	Window *w = NULL;
2738 
2739 	if ((arg = next_arg(*args, args)))
2740 	{
2741 		char *channel;
2742 		channel = make_channel(arg);
2743 		if (!channel || !is_channel(channel))
2744 		{
2745 			say("BIND: %s is not a valid channel name", channel ? channel :"");
2746 			return window;
2747 		}
2748 		/*
2749 		 * If its already bound, no point in continuing.
2750 		 */
2751 		if (window->bind_channel && is_bound_to_window(window, channel))
2752 		{
2753 			say("Window is already bound to channel %s", channel);
2754 			return window;
2755 		}
2756 
2757 #if 0
2758 		/*
2759 		 * You must either bind the current channel to a window, or
2760 		 * you must be binding to a window without a current channel
2761 		 */
2762 		if (window->current_channel)
2763 		{
2764 			if (!my_stricmp(window->current_channel, channel))
2765 				m_s3cat(&window->bind_channel, comma, channel);
2766 			else
2767 				say("You may only /WINDOW BIND the current channel for this window");
2768 			return window;
2769 		}
2770 #endif
2771 
2772 		/*
2773 		 * So we know this window doesnt have a current channel.
2774 		 * So we have to find the window where it IS the current
2775 		 * channel (if it is at all)
2776 		 */
2777 		while (traverse_all_windows(&w))
2778 		{
2779 			/*
2780 			 * If we have found a window where this channel
2781 			 * is currently bound, then we unbind it from
2782 			 * that oTher window and bind it here.
2783 			 */
2784 			if (w->bind_channel && w->server && is_bound_to_window(w, channel))
2785 			{
2786 				char *p, *q, *new_bind = NULL;
2787 				m_s3cat(&window->bind_channel, comma, channel);
2788 				q = p = LOCAL_COPY(w->bind_channel);
2789 				while ((p = next_in_comma_list(q, &q)))
2790 				{
2791 					if (!p || !*p)
2792 						break;
2793 					if (!my_stricmp(p, channel))
2794 						continue;
2795 					m_s3cat(&new_bind, comma, p);
2796 				}
2797 				if (new_bind && *new_bind)
2798 					malloc_strcpy(&w->bind_channel, new_bind);
2799 				else
2800 					new_free(&w->bind_channel);
2801 				new_free(&new_bind);
2802 			}
2803 
2804 			/*
2805 			 * If we have found a window where this channel
2806 			 * is the current channel, then we make it so that
2807 			 * it is the current channel here.
2808 			 */
2809 			if (w->current_channel && w->server == window->server)
2810 			{
2811 				if (is_bound_to_window(w, channel))
2812 					unset_window_current_channel(w);
2813 			}
2814 		}
2815 
2816 		/*
2817 		 * Now we mark this channel as being bound here.
2818 		 * and as being our current channel.
2819 		 */
2820 		m_s3cat(&window->bind_channel, comma, channel);
2821 		say("Window is bound to channel %s", channel);
2822 
2823 		if (im_on_channel(channel, window->server))
2824 		{
2825 			set_current_channel_by_refnum(window->refnum, channel);
2826 			say("Current channel for window now %s", channel);
2827 		}
2828 	}
2829 
2830 	else if ((arg = get_bound_channel(window)))
2831 		say("Window is bound to channel %s", arg);
2832 	else
2833 		say("Window is not bound to any channel");
2834 
2835 	return window;
2836 }
2837 
2838 /*
2839  * /WINDOW CHANNEL <#channel>
2840  * Directs the client to make a specified channel the current channel for
2841  * the window -- it will JOIN the channel if you are not already on it.
2842  * If the channel you wish to activate is bound to a different window, you
2843  * will be notified.  If you are already on the channel in another window,
2844  * then the channel's window will be switched.  If you do not specify a
2845  * channel, or if you specify the channel "0", then the window will drop its
2846  * connection to whatever channel it is in.
2847  */
window_channel(Window * window,char ** args,char * usage)2848 Window *window_channel (Window *window, char **args, char *usage)
2849 {
2850 	char	*arg;
2851 
2852 	if ((arg = new_next_arg(*args, args)))
2853 	{
2854 		char *channel, *ch;
2855 		while ((ch = next_in_comma_list(arg, &arg)))
2856 		{
2857 			if (!my_strnicmp(ch, "-i", 2))
2858 			{
2859 				if (invite_channel)
2860 					ch = invite_channel;
2861 				else
2862 				{
2863 					say("You have not been invited to a channel!");
2864 					return window;
2865 				}
2866 			}
2867 			if (!ch || !*ch)
2868 				break;
2869 			if (!(channel = make_channel(ch)))
2870 				break;
2871 			if (is_bound(channel, window->server))
2872 				say("Channel %s is already bound elsewhere", channel);
2873 			else if (is_current_channel(channel, window->server, 1) ||
2874 				is_on_channel(channel, window->server, get_server_nickname(window->server)))
2875 			{
2876 				say("You are now talking to channel %s", channel);
2877 				set_current_channel_by_refnum(window->refnum, channel);
2878 			}
2879 			else if (channel[1] == '0' && channel[2] == 0)
2880 				set_current_channel_by_refnum(window->refnum, NULL);
2881 			else
2882 			{
2883 				my_send_to_server(window->server, "JOIN %s", channel);
2884 				malloc_strcpy(&window->waiting_channel, channel);
2885 			}
2886 		}
2887 	}
2888 	else
2889 		set_current_channel_by_refnum(window->refnum, zero);
2890 
2891 	return window;
2892 }
2893 
2894 /* For JOIN_NEW_WINDOW .... */
win_create(int var,int test)2895 void win_create(int var, int test)
2896 {
2897 	if (get_int_var(var) && (test ||
2898 		current_window->current_channel || current_window->query_nick))
2899 	{
2900 		char *args = NULL;
2901 		switch (var)
2902 		{
2903 			case JOIN_NEW_WINDOW_VAR:
2904 				args = LOCAL_COPY(SAFE(get_string_var(JOIN_NEW_WINDOW_TYPE_VAR)));
2905 			break;
2906 			case QUERY_NEW_WINDOW_VAR:
2907 				args = LOCAL_COPY(SAFE(get_string_var(QUERY_NEW_WINDOW_TYPE_VAR)));
2908 			break;
2909 			default:
2910 				return;
2911 			break;
2912 		}
2913 		if (args && *args)
2914 			windowcmd("WINDOW", args, empty_string, empty_string);
2915 	}
2916 }
2917 
2918 /*
2919  * /WINDOW CREATE
2920  * This directs the client to open up a new physical screen and create a
2921  * new window in it.  This feature depends on the external "wserv" utility
2922  * and requires a multi-processing system, since it actually runs the new
2923  * screen in a seperate process.  Please note that the external screen is
2924  * not actually controlled by the client, but rather by "wserv" which acts
2925  * as a pass-through filter on behalf of the client.
2926  *
2927  * Since the external screen is outside the client's process, it is not really
2928  * possible for the client to know when the external screen is resized, or
2929  * what that new size would be.  For this reason, you should not resize any
2930  * screen when you have external screens open.  If you do, the client will
2931  * surely become confused and the output will probably be garbled.  You can
2932  * restore some sanity by making sure that ALL external screens have the same
2933  * geometry, and then redrawing each screen.
2934  */
window_create(Window * window,char ** args,char * usage)2935 static Window *window_create (Window *window, char **args, char *usage)
2936 {
2937 #ifdef WINDOW_CREATE
2938 	Window *tmp;
2939 	if ((tmp = (Window *)create_additional_screen()))
2940 	{
2941 		last_input_screen = tmp->screen;
2942 		window = tmp;
2943 	}
2944 	else
2945 #endif
2946 		say("Cannot create new screen!");
2947 	return window;
2948 }
2949 
2950 /*
2951  * /WINDOW DELETE
2952  * This directs the client to close the current external physical screen
2953  * and to re-parent any windows onto other screens.  You are not allowed
2954  * to delete the "main" window because that window belongs to the process
2955  * group of the client itself.
2956  */
window_delete(Window * window,char ** args,char * usage)2957 static Window *window_delete (Window *window, char **args, char *usage)
2958 {
2959 #ifdef WINDOW_CREATE
2960 	if(window->screen)
2961 		kill_screen(window->screen);
2962 #endif
2963 	return current_window;
2964 }
2965 
2966 /*
2967  * /WINDOW DESCRIBE
2968  * Directs the client to tell you a bit about the current window.
2969  * This is the 'default' argument to the /window command.
2970  */
window_describe(Window * window,char ** args,char * usage)2971 static Window *window_describe (Window *window, char **args, char *usage)
2972 {
2973 	if (window->name)
2974 		say("Window %s (%u)", window->name, window->refnum);
2975 	else
2976 		say("Window %u", window->refnum);
2977 
2978 	say("\tServer: [%d] %s",
2979 				window->server,
2980 				window->server <= -1 ?
2981 				get_server_name(window->server) : "<None>");
2982 	say("\tScreen: %p", window->screen);
2983 	say("\tGeometry Info: [%d %d %d %d %d %d]",
2984 				window->top, window->bottom,
2985 				window->held_displayed, window->display_size,
2986 				window->cursor, window->distance_from_display);
2987 
2988 #ifndef GUI
2989 	say("\tCO, LI are [%d %d]", current_term->TI_cols, current_term->TI_lines);
2990 #else
2991 	say("\tCO, LI are [%d %d]", output_screen->co, output_screen->li);
2992 #endif
2993 	say("\tCurrent channel: %s",
2994 				window->current_channel ?
2995 				window->current_channel : "<None>");
2996 
2997 if (window->waiting_channel)
2998 	say("\tWaiting channel: %s",
2999 				window->waiting_channel);
3000 
3001 if (window->bind_channel)
3002 	say("\tBound channel: %s",
3003 				window->bind_channel);
3004 	say("\tQuery User: %s %s",
3005 				window->query_nick ?
3006 				window->query_nick : "<None>",
3007 				window->query_cmd ?
3008 				window->query_cmd : empty_string);
3009 	say("\tPrompt: %s",
3010 				window->prompt ?
3011 				window->prompt : "<None>");
3012 	say("\tSecond status line is %s", onoff[window->double_status]);
3013 	say("\tSplit line is %s triple is %s", onoff[window->status_split], onoff[window->status_lines]);
3014 	say("\tLogging is %s", 	 onoff[window->log]);
3015 
3016 	if (window->logfile)
3017 		say("\tLogfile is %s", window->logfile);
3018 	else
3019 		say("\tNo logfile given");
3020 
3021 	say("\tNotification is %s",
3022 			      onoff[window->miscflags & WINDOW_NOTIFY]);
3023 	say("\tHold mode is %s",
3024 				onoff[window->hold_mode]);
3025 	say("\tWindow level is %s",
3026 				bits_to_lastlog_level(window->window_level));
3027 	say("\tLastlog level is %s",
3028 				bits_to_lastlog_level(window->lastlog_level));
3029 	say("\tNotify level is %s",
3030 				bits_to_lastlog_level(window->notify_level));
3031 
3032 	if (window->nicks)
3033 	{
3034 		NickList *tmp;
3035 		say("\tName list:");
3036 		for (tmp = window->nicks; tmp; tmp = tmp->next)
3037 			say("\t  %s", tmp->nick);
3038 	}
3039 
3040 	return window;
3041 }
3042 
3043 /*
3044  * /WINDOW DISCON
3045  * This disassociates a window with all servers.
3046  */
window_discon(Window * window,char ** args,char * usage)3047 static Window *window_discon (Window *window, char **args, char *usage)
3048 {
3049 	if (window->server != -1)
3050 		server_disconnect(window->server, NULL);
3051 	window->server = -1;
3052 	return window;
3053 }
3054 
3055 /*
3056  * /WINDOW DOUBLE ON|OFF
3057  * This directs the client to enable or disable the supplimentary status bar.
3058  * When the "double status bar" is enabled, the status formats are taken from
3059  * /set STATUS_FORMAT1 or STATUS_FORMAT2.  When it is disabled, the format is
3060  * taken from /set STATUS_FORMAT.
3061  */
window_double(Window * window,char ** args,char * usage)3062 static Window *window_double (Window *window, char **args, char *usage)
3063 {
3064 	int current = window->double_status;
3065 
3066 	if (get_boolean("DOUBLE", args, &window->double_status))
3067 		return NULL;
3068 
3069 	window->display_size += current - window->double_status;
3070 	recalculate_window_positions(window->screen);
3071 	redraw_all_windows();
3072 	build_status(window, NULL, 0);
3073 	return window;
3074 }
3075 
3076 /*
3077  * alias wc {^window new double on split on hide_others}
3078  */
window_split(Window * window,char ** args,char * usage)3079 static Window *window_split (Window *window, char **args, char *usage)
3080 {
3081 int booya = window->status_lines;
3082 Window *tmp;
3083 	if (get_boolean("SPLIT", args, &booya))
3084 		return NULL;
3085 	for (tmp = screen_list->window_list; tmp; tmp = tmp->next)
3086 	{
3087 		if (tmp->status_lines && booya)
3088 		{
3089 			if (!get_int_var(WINDOW_QUIET_VAR))
3090 				yell("Already a split window");
3091 			return window;
3092 		}
3093 		else if (tmp->status_lines && !booya)
3094 			window = tmp;
3095 	}
3096 	window->status_lines = booya;
3097 	recalculate_window_positions(window->screen);
3098 	recalculate_windows(window->screen);
3099 	update_all_windows();
3100 	build_status (window, NULL, 0);
3101 	return window;
3102 }
3103 
window_triple(Window * window,char ** args,char * usage)3104 static Window *window_triple (Window *window, char **args, char *usage)
3105 {
3106 int booya = window->status_lines;
3107 	if (get_boolean("TRIPLE", args, &booya))
3108 		return NULL;
3109 	if (!booya)
3110 	{
3111 		window->status_split = 1;
3112 		window->status_lines = 0;
3113 	}
3114 	else
3115 	{
3116 		window->status_split = 0;
3117 		window->status_lines = 1;
3118 	}
3119 	recalculate_windows(window->screen);
3120 	update_all_windows();
3121 	build_status (window, NULL, 0);
3122 	return window;
3123 }
3124 
3125 /*
3126  * WINDOW ECHO <text>
3127  *
3128  * Text must either be surrounded with double-quotes (")'s or it is assumed
3129  * to terminate at the end of the argument list.  This sends the given text
3130  * to the current window.
3131  */
window_echo(Window * window,char ** args,char * usage)3132 static	Window *window_echo (Window *window, char **args, char *usage)
3133 {
3134 	const char *to_echo;
3135 
3136 	if (**args == '"')
3137 		to_echo = new_next_arg(*args, args);
3138 	else
3139 		to_echo = *args, *args = NULL;
3140 
3141 	add_to_window(window, (const unsigned char *)to_echo);
3142 	return window;
3143 }
3144 
3145 /*
3146  * /WINDOW FIXED (ON|OFF)
3147  *
3148  * When this is ON, then this window will never be used as the implicit
3149  * partner for a window resize.  That is to say, if you /window grow another
3150  * window, this window will not be considered for the corresponding shrink.
3151  * You may /window grow a fixed window, but if you do not have other nonfixed
3152  * windows, the grow will fail.
3153  */
window_fixed(Window * window,char ** args,char * usage)3154 static	Window *window_fixed (Window *window, char **args, char *usage)
3155 {
3156 	if (get_boolean("FIXED", args, &window->absolute_size))
3157 		return NULL;
3158 	return window;
3159 }
3160 
3161 /*
3162  * /WINDOW GOTO refnum
3163  * This switches the current window selection to the window as specified
3164  * by the numbered refnum.
3165  */
window_goto(Window * window,char ** args,char * usage)3166 static Window *window_goto (Window *window, char **args, char *usage)
3167 {
3168 	goto_window(window->screen, get_number("GOTO", args, NULL));
3169 	from_server = get_window_server(0);
3170 	return current_window;
3171 }
3172 
3173 /*
3174  * /WINDOW GROW lines
3175  * This directs the client to expand the specified window by the specified
3176  * number of lines.  The number of lines should be a positive integer, and
3177  * the window's growth must noT cause another window to be smaller than
3178  * the minimum of 3 lines.
3179  */
window_grow(Window * window,char ** args,char * usage)3180 static Window *window_grow (Window *window, char **args, char *usage)
3181 {
3182 	resize_window(RESIZE_REL, window, get_number("GROW", args, NULL));
3183 	return window;
3184 }
3185 
3186 /*
3187  * /WINDOW HIDE
3188  * This directs the client to remove the specified window from the current
3189  * (visible) screen and place the window on the client's invisible list.
3190  * A hidden window has no "screen", and so can not be seen, and does not
3191  * have a size.  It can be unhidden onto any screen.
3192  */
window_hide(Window * window,char ** args,char * usage)3193 static Window *window_hide (Window *window, char **args, char *usage)
3194 {
3195 	hide_window(window);
3196 	return current_window;
3197 }
3198 
3199 /*
3200  * /WINDOW HIDE_OTHERS
3201  * This directs the client to place *all* windows on the current screen,
3202  * except for the current window, onto the invisible list.
3203  */
window_hide_others(Window * window,char ** args,char * usage)3204 static Window *window_hide_others (Window *window, char **args, char *usage)
3205 {
3206 	Window *tmp, *next;
3207 
3208 	if (window->screen)
3209 		tmp = window->screen->window_list;
3210 	else
3211 		tmp = invisible_list;
3212 	while (tmp)
3213 	{
3214 		next = tmp->next;
3215 		if (tmp != window)
3216 			hide_window(tmp);
3217 		tmp = next;
3218 	}
3219 	return window;
3220 }
3221 
3222 /*
3223  * /WINDOW HOLD_MODE
3224  * This arranges for the window to "hold" any output bound for it once
3225  * a full page of output has been completed.  Setting the global value of
3226  * HOLD_MODE is truly bogus and should be changed. XXXX
3227  */
window_hold_mode(Window * window,char ** args,char * usage)3228 static Window *window_hold_mode (Window *window, char **args, char *usage)
3229 {
3230 	if (get_boolean("HOLD_MODE", args, &window->hold_mode))
3231 		return NULL;
3232 
3233 	set_int_var(HOLD_MODE_VAR, window->hold_mode);
3234 	return window;
3235 }
3236 
3237 /*
3238  * /WINDOW KILL
3239  * This arranges for the current window to be destroyed.  Once a window
3240  * is killed, it cannot be recovered.  Because every server must have at
3241  * least one window "connected" to it, if you kill the last window for a
3242  * server, the client will drop your connection to that server automatically.
3243  */
window_kill(Window * window,char ** args,char * usage)3244 static Window *window_kill (Window *window, char **args, char *usage)
3245 {
3246 	delete_window(window);
3247 	redraw_all_windows();
3248 	return current_window;
3249 }
3250 
3251 /*
3252  * /WINDOW KILL_OTHERS
3253  * This arranges for all windows on the current screen, other than the
3254  * current window to be destroyed.  Obviously, the current window will be
3255  * the only window left on the screen.  Connections to servers other than
3256  * the server for the current window will be implicitly closed.
3257  */
window_kill_others(Window * window,char ** args,char * usage)3258 static Window *window_kill_others (Window *window, char **args, char *usage)
3259 {
3260 	Window *tmp, *next;
3261 
3262 	if (window->screen)
3263 		tmp = window->screen->window_list;
3264 	else
3265 		tmp = invisible_list;
3266 	while (tmp)
3267 	{
3268 		next = tmp->next;
3269 		if (tmp != window)
3270 			delete_window(tmp);
3271 		tmp = next;
3272 	}
3273 	return window;
3274 }
3275 
3276 /*
3277  * /WINDOW KILLSWAP
3278  * This arranges for the current window to be replaced by the last window
3279  * to be hidden, and also destroys the current window.
3280  */
window_killswap(Window * window,char ** args,char * usage)3281 static Window *window_killswap (Window *window, char **args, char *usage)
3282 {
3283 	if (invisible_list)
3284 	{
3285 		swap_window(window, invisible_list);
3286 		delete_window(window);
3287 	}
3288 	else
3289 		say("There are no hidden windows!");
3290 
3291 	return current_window;
3292 }
3293 
3294 /*
3295  * /WINDOW LAST
3296  * This changes the current window focus to the window that was most recently
3297  * the current window *but only if that window is still visible*.  If the
3298  * window is no longer visible (having been HIDDEN), then the next window
3299  * following the current window will be made the current window.
3300  */
window_last(Window * window,char ** args,char * usage)3301 static Window *window_last (Window *window, char **args, char *usage)
3302 {
3303 	set_screens_current_window(window->screen, NULL);
3304 	return current_window;
3305 }
3306 
3307 /*
3308  * /WINDOW LASTLOG <size>
3309  * This changes the size of the window's lastlog buffer.  The default value
3310  * foR a window's lastlog is the value of /set LASTLOG, but each window may
3311  * be independantly tweaked with this command.
3312  */
window_lastlog(Window * window,char ** args,char * usage)3313 static Window *window_lastlog (Window *window, char **args, char *usage)
3314 {
3315 	char *arg = next_arg(*args, args);
3316 
3317 	if (arg)
3318 	{
3319 		int size = my_atol(arg);
3320 		if (window->lastlog_size > size)
3321 		{
3322 			int i, diff;
3323 			diff = window->lastlog_size - size;
3324 			for (i = 0; i < diff; i++)
3325 				remove_from_lastlog(window);
3326 		}
3327 		window->lastlog_max = size;
3328 	}
3329 	say("Lastlog size is %d", window->lastlog_max);
3330 	return window;
3331 }
3332 
3333 /*
3334  * /WINDOW LASTLOG_LEVEL <level-description>
3335  * This changes the types of lines that will be placed into this window's
3336  * lastlog.  It is useful to note that the window's lastlog will contain
3337  * a subset (possibly a complete subset) of the lines that have appeared
3338  * in the window.  This setting allows you to control which lines are
3339  * "thrown away" by the window.
3340  */
window_lastlog_level(Window * window,char ** args,char * usage)3341 static Window *window_lastlog_level (Window *window, char **args, char *usage)
3342 {
3343 	char *arg = next_arg(*args, args);;
3344 
3345 	if (arg)
3346 		window->lastlog_level = parse_lastlog_level(arg, 1);
3347 	say("Lastlog level is %s", bits_to_lastlog_level(window->lastlog_level));
3348 	return window;
3349 }
3350 
3351 /*
3352  * /WINDOW LEVEL <level-description>
3353  * This changes the types of output that will appear in the specified window.
3354  * Note that for the given set of windows connected to a server, each level
3355  * may only appear once in that set.  When you add a level to a given window,
3356  * then it will be removed from whatever window currently holds it.  The
3357  * exception to this is the "DCC" level, which may only be set to one window
3358  * for the entire client.
3359  */
window_level(Window * window,char ** args,char * usage)3360 static Window *window_level (Window *window, char **args, char *usage)
3361 {
3362 	char 	*arg;
3363 	int	add = 0;
3364 	int	newlevel = 0;
3365 
3366 	if ((arg = next_arg(*args, args)))
3367 	{
3368 		if (*arg == '+')
3369 			add = 1, arg++;
3370 		else if (*arg == '-')
3371 			add = -1, arg++;
3372 
3373 		newlevel = parse_lastlog_level(arg, 1);
3374 		if (add == 1)
3375 			window->window_level |= newlevel;
3376 		else if (add == 0)
3377 			window->window_level = newlevel;
3378 		else if (add == -1)
3379 			window->window_level &= ~newlevel;
3380 
3381 		revamp_window_levels(window);
3382 	}
3383 	say("Window level is %s", bits_to_lastlog_level(window->window_level));
3384 	return window;
3385 }
3386 
3387 /*
3388  * /WINDOW LIST
3389  * This lists all of the windows known to the client, and a breif summary
3390  * of their current state.
3391  */
window_list(Window * window,char ** args,char * usage)3392 Window *window_list (Window *window, char **args, char *usage)
3393 {
3394 	Window	*tmp = NULL;
3395 	int	len = 6;
3396 	int	cnw = get_int_var(CHANNEL_NAME_WIDTH_VAR);
3397 
3398 	while ((traverse_all_windows(&tmp)))
3399 	{
3400 		if (tmp->name && (strlen(tmp->name) > len))
3401 			len = strlen(tmp->name);
3402 	}
3403 
3404 	say(WIN_FORM,      	"Ref",
3405 		      12, 12,	"Nick",
3406 		      len, len, "Name",
3407 		      cnw, cnw, "Channel",
3408 				"Query",
3409 				"Server",
3410 				"Level",
3411 				empty_string);
3412 
3413 	tmp = NULL;
3414 	while ((traverse_all_windows(&tmp)))
3415 		list_a_window(tmp, len);
3416 
3417 	return window;
3418 }
3419 
3420 /*
3421  * /WINDOW LOG ON|OFF
3422  * This sets the current state of the logfile for the given window.  When the
3423  * logfile is on, then any lines that appear on the window are written to the
3424  * logfile 'as-is'.  The name of the logfile can be controlled with
3425  * /WINDOW LOGFILE.  The default logfile name is <windowname>.<target|refnum>
3426  */
window_log(Window * window,char ** args,char * usage)3427 static Window *window_log (Window *window, char **args, char *usage)
3428 {
3429 	char logfile[MAXPATHLEN];
3430 
3431 	if (get_boolean("LOG", args, &window->log))
3432 		return NULL;
3433 
3434 	if (window->logfile)
3435 	{
3436 		strlcpy(logfile, window->logfile, sizeof logfile);
3437 	}
3438 	else
3439 	{
3440 		char *logfile_base = get_string_var(LOGFILE_VAR);
3441 
3442 		if (!logfile_base)
3443 			logfile_base = empty_string;
3444 
3445 		if (window->current_channel)
3446 			snprintf(logfile, sizeof logfile, "%s.%s", logfile_base,
3447 				window->current_channel);
3448 		else if (window->query_nick)
3449 			snprintf(logfile, sizeof logfile, "%s.%s", logfile_base,
3450 				window->query_nick);
3451 		else
3452 			snprintf(logfile, sizeof logfile, "%s.Window_%u", logfile_base,
3453 				window->refnum);
3454 	}
3455 	strip_chars(logfile, "|\\:", '-');
3456 	do_log(window->log, logfile, &window->log_fp);
3457 	if (!window->log_fp)
3458 		window->log = 0;
3459 
3460 	return window;
3461 }
3462 
3463 /*
3464  * /WINDOW LOGFILE <filename>
3465  * This sets the current value of the log filename for the given window.
3466  * When you activate the log (with /WINDOW LOG ON), then any output to the
3467  * window also be written to the filename specified.
3468  */
window_logfile(Window * window,char ** args,char * usage)3469 static Window *window_logfile (Window *window, char **args, char *usage)
3470 {
3471 	char *arg = next_arg(*args, args);
3472 
3473 	if (arg)
3474 	{
3475 		malloc_strcpy(&window->logfile, arg);
3476 		say("Window LOGFILE set to %s", arg);
3477 	}
3478 	else if (window->logfile)
3479 		say("Window LOGFILE is %s", window->logfile);
3480 	else
3481 		say("Window LOGFILE is not set.");
3482 
3483 	return window;
3484 }
3485 
window_move(Window * window,char ** args,char * usage)3486 static Window *window_move (Window *window, char **args, char *usage)
3487 {
3488 	move_window(window, get_number("MOVE", args, NULL));
3489 	return window;
3490 }
3491 
window_name(Window * window,char ** args,char * usage)3492 static Window *window_name (Window *window, char **args, char *usage)
3493 {
3494 	char *arg;
3495 
3496 	if ((arg = next_arg(*args, args)))
3497 	{
3498 		if (is_window_name_unique(arg))
3499 		{
3500 			malloc_strcpy(&window->name, arg);
3501 			window->update |= UPDATE_STATUS;
3502 		}
3503 		else
3504 			say("%s is not unique!", arg);
3505 	}
3506 	else
3507 		say("You must specify a name for the window!");
3508 
3509 	return window;
3510 }
3511 
window_new(Window * window,char ** args,char * usage)3512 static Window *window_new (Window *window, char **args, char *usage)
3513 {
3514 	Window *tmp;
3515 	if ((tmp = new_window(window->screen)))
3516 		window = tmp;
3517 
3518 	return window;
3519 }
3520 
window_new_hide(Window * window,char ** args,char * usage)3521 static Window *window_new_hide (Window *window, char **args, char *usage)
3522 {
3523 	new_window(NULL);
3524 	return window;
3525 }
3526 
window_next(Window * window,char ** args,char * usage)3527 static Window *window_next (Window *window, char **args, char *usage)
3528 {
3529 	Window	*tmp;
3530 	Window	*next = NULL;
3531 	Window	*smallest = NULL;
3532 
3533 	if (!invisible_list)
3534 	{
3535 		say("There are no hidden windows");
3536 		return NULL;
3537 	}
3538 
3539 	smallest = window;
3540 	for (tmp = invisible_list; tmp; tmp = tmp->next)
3541 	{
3542 		if (tmp->refnum < smallest->refnum)
3543 			smallest = tmp;
3544 		if ((tmp->refnum > window->refnum)
3545 		    && (!next || (tmp->refnum < next->refnum)))
3546 			next = tmp;
3547 	}
3548 
3549 	if (!next)
3550 		next = smallest;
3551 
3552 	swap_window(window, next);
3553 	reset_display_target();
3554 	return current_window;
3555 }
3556 
window_noserv(Window * window,char ** args,char * usage)3557 static        Window *window_noserv (Window *window, char **args, char *usage)
3558 {
3559 	window->server = -1;
3560 	return window;
3561 }
3562 
window_notify(Window * window,char ** args,char * usage)3563 static Window *window_notify (Window *window, char **args, char *usage)
3564 {
3565 	window->miscflags ^= WINDOW_NOTIFY;
3566 	say("Notification when hidden set to %s",
3567 		window->miscflags & WINDOW_NOTIFY ? on : off);
3568 	return window;
3569 }
3570 
window_notify_level(Window * window,char ** args,char * usage)3571 static Window *window_notify_level (Window *window, char **args, char *usage)
3572 {
3573 	char *arg;
3574 
3575 	if ((arg = next_arg(*args, args)))
3576 		window->notify_level = parse_lastlog_level(arg, 1);
3577 	say("Window notify level is %s", bits_to_lastlog_level(window->notify_level));
3578 	return window;
3579 }
3580 
window_number(Window * window,char ** args,char * usage)3581 static Window *window_number (Window *window, char **args, char *usage)
3582 {
3583 	Window 	*tmp;
3584 	char 	*arg;
3585 	int 	i;
3586 
3587 	if ((arg = next_arg(*args, args)))
3588 	{
3589 		if ((i = my_atol(arg)) > 0)
3590 		{
3591 			if ((tmp = get_window_by_refnum(i)))
3592 				tmp->refnum = window->refnum;
3593 			window->refnum = i;
3594 		}
3595 		else
3596 			say("Window number must be greater than 0");
3597 	}
3598 	else
3599 		say("Window number missing");
3600 
3601 	return window;
3602 }
3603 
3604 /*
3605  * /WINDOW POP
3606  * This changes the current window focus to the most recently /WINDOW PUSHed
3607  * window that still exists.  If the window is hidden, then it will be made
3608  * visible.  Any windows that are found along the way that have been since
3609  * KILLed will be ignored.
3610  */
window_pop(Window * window,char ** args,char * usage)3611 static Window *window_pop (Window *window, char **args, char *usage)
3612 {
3613 	int 		refnum;
3614 	WindowStack 	*tmp;
3615 	Window		*win = NULL;
3616 
3617 	while (window->screen->window_stack)
3618 	{
3619 		refnum = window->screen->window_stack->refnum;
3620 		tmp = window->screen->window_stack->next;
3621 		new_free(&window->screen->window_stack);
3622 		window->screen->window_stack = tmp;
3623 
3624 		win = get_window_by_refnum(refnum);
3625 		if (!win)
3626 			continue;
3627 
3628 		if (win->visible)
3629 			set_screens_current_window(win->screen, win);
3630 		else
3631 			show_window(win);
3632 	}
3633 
3634 	if (!window->screen->window_stack && !win)
3635 		say("The window stack is empty!");
3636 
3637 	return win;
3638 }
3639 
window_previous(Window * window,char ** args,char * usage)3640 static Window *window_previous (Window *window, char **args, char *usage)
3641 {
3642 	Window	*tmp;
3643 	Window	*previous = NULL, *largest;
3644 
3645 	if (!invisible_list)
3646 	{
3647 		say("There are no hidden windows");
3648 		return NULL;
3649 	}
3650 
3651 	largest = window;
3652 	for (tmp = invisible_list; tmp; tmp = tmp->next)
3653 	{
3654 		if (tmp->refnum > largest->refnum)
3655 			largest = tmp;
3656 		if ((tmp->refnum < window->refnum)
3657 		    && (!previous || tmp->refnum > previous->refnum))
3658 			previous = tmp;
3659 	}
3660 
3661 	if (!previous)
3662 		previous = largest;
3663 
3664 	swap_window(window, previous);
3665 	reset_display_target();
3666 	return current_window;
3667 }
3668 
window_prompt(Window * window,char ** args,char * usage)3669 static Window *window_prompt (Window *window, char **args, char *usage)
3670 {
3671 	char *arg;
3672 
3673 	if ((arg = next_arg(*args, args)))
3674 	{
3675 		malloc_strcpy(&window->prompt, arg);
3676 		window->update |= UPDATE_STATUS;
3677 	}
3678 	else
3679 		say("You must specify a prompt for the window!");
3680 
3681 	return window;
3682 }
3683 
window_push(Window * window,char ** args,char * usage)3684 static Window *window_push (Window *window, char **args, char *usage)
3685 {
3686 	WindowStack *new;
3687 
3688 	new = (WindowStack *) new_malloc(sizeof(WindowStack));
3689 	new->refnum = window->refnum;
3690 	new->next = window->screen->window_stack;
3691 	window->screen->window_stack = new;
3692 	return window;
3693 }
3694 
window_query(Window * window,char ** args,char * usage)3695 Window *window_query (Window *window, char **args, char *usage)
3696 {
3697 	NickList *tmp;
3698 	char	  *nick = NULL;
3699 	char	  *host = NULL;
3700 	char	  *cmd = NULL;
3701 	char	  *ptr;
3702 
3703 	/*
3704 	 * Nuke the old query list
3705 	 */
3706 	if (*args && !my_strnicmp(*args, "-cmd", 4))
3707 	{
3708 		cmd = next_arg(*args, args);
3709 		cmd = next_arg(*args, args);
3710 	}
3711 	if ((nick = window->query_nick))
3712 	{
3713 		say("Ending conversation with %s", current_window->query_nick);
3714 		window->update |= UPDATE_STATUS;
3715 		while ((ptr = next_in_comma_list(nick, &nick)))
3716 		{
3717 			if (!ptr || !*ptr)
3718 				break;
3719 
3720 			if ((tmp = (NickList *)remove_from_list(
3721 					(List **)&window->nicks, ptr)))
3722 			{
3723 				new_free(&tmp->nick);
3724 				new_free(&tmp->host);
3725 				new_free((char **)&tmp);
3726 			}
3727 		}
3728 		new_free(&window->query_nick);
3729 		new_free(&window->query_host);
3730 		new_free(&window->query_cmd);
3731 	}
3732 
3733 	if (cmd)
3734 		malloc_strcpy(&window->query_cmd, cmd);
3735 
3736 	if ((nick = next_arg(*args, args)))
3737 	{
3738 
3739 		if (args && *args)
3740 			host = *args;
3741 		if (!strcmp(nick, "."))
3742 		{
3743 			if (!(nick = get_server_sent_nick(window->server)))
3744 				say("You have not messaged anyone yet");
3745 		}
3746 		else if (!strcmp(nick, ","))
3747 		{
3748 			if (!(nick = get_server_recv_nick(window->server)))
3749 				say("You have not recieved a message yet");
3750 		}
3751 		else if (!strcmp(nick, "*") &&
3752 			!(nick = get_current_channel_by_refnum(0)))
3753 		{
3754 			say("You are not on a channel");
3755 		}
3756 		else if (*nick == '%')
3757 		{
3758 			if (!is_valid_process(nick))
3759 				nick = NULL;
3760 		}
3761 
3762 		if (!nick)
3763 			return window;
3764 
3765 
3766 
3767 		/*
3768 		 * Create the new query list
3769 		 */
3770 		say("Starting conversation with %s", nick);
3771 		malloc_strcpy(&window->query_nick, nick);
3772 		malloc_strcpy(&window->query_host, host);
3773 
3774 		window->update |= UPDATE_STATUS;
3775 		ptr = nick;
3776 		while ((ptr = next_in_comma_list(nick, &nick)))
3777 		{
3778 			if (!ptr || !*ptr)
3779 				break;
3780 			tmp = (NickList *) new_malloc(sizeof(NickList));
3781 			tmp->nick = m_strdup(ptr);
3782 			if (host)
3783 				tmp->host = m_strdup(host);
3784 			add_to_list((List **)&window->nicks,(List *)tmp);
3785 		}
3786 	}
3787 	update_input(UPDATE_ALL);
3788 #ifdef GUI
3789 	xterm_settitle();
3790 #endif
3791 	return window;
3792 }
3793 
window_refresh(Window * window,char ** args,char * usage)3794 static Window *window_refresh (Window *window, char **args, char *usage)
3795 {
3796 	int oiwc = in_window_command;
3797 	in_window_command = 0;
3798 	update_all_windows();
3799 	update_all_status(window, NULL, 0);
3800 	in_window_command = oiwc;
3801 	return window;
3802 }
3803 
3804 
window_refnum(Window * window,char ** args,char * usage)3805 static Window *window_refnum (Window *window, char **args, char *usage)
3806 {
3807 	Window *tmp;
3808 	if ((tmp = get_window("REFNUM", args)))
3809 	{
3810 		window = tmp;
3811 		make_window_current(tmp);
3812 		if (tmp->visible)
3813 		{
3814 			set_screens_current_window(tmp->screen, tmp);
3815 			window = tmp;
3816 		}
3817 	}
3818 	else
3819 	{
3820 		say("No such window!");
3821 		window = NULL;
3822 	}
3823 	return window;
3824 }
3825 
window_remove(Window * window,char ** args,char * usage)3826 static Window *window_remove (Window *window, char **args, char *usage)
3827 {
3828 	char *arg;
3829 
3830 	if ((arg = next_arg(*args, args)))
3831 	{
3832 		char	*ptr;
3833 		NickList *new;
3834 
3835 		while (arg)
3836 		{
3837 			if ((ptr = strchr(arg, ',')) != NULL)
3838 				*ptr++ = 0;
3839 
3840 			if ((new = (NickList *)remove_from_list((List **)&(window->nicks), arg)))
3841 			{
3842 				say("Removed %s from window name list", new->nick);
3843 				new_free(&new->nick);
3844 				new_free((char **)&new);
3845 			}
3846 			else
3847 				say("%s is not on the list for this window!", arg);
3848 
3849 			arg = ptr;
3850 		}
3851 	}
3852 	else
3853 		say("REMOVE: Do something!  Geez!");
3854 
3855 	return window;
3856 }
3857 
BUILT_IN_WINDOW(window_server)3858 BUILT_IN_WINDOW(window_server)
3859 {
3860 	char *arg;
3861 #ifdef HAVE_SSL
3862   	int withSSL = 0;
3863 #endif
3864 
3865 	if ((arg = next_arg(*args, args)))
3866 	{
3867 #ifdef HAVE_SSL
3868 		if (!my_strnicmp(arg, "-SSL", strlen(arg)))
3869 		{
3870 			withSSL = 1;
3871 
3872 			arg = next_arg(*args, args);
3873 		}
3874 		if(arg)
3875 		{
3876 #endif
3877 			int i = find_server_refnum(arg, NULL);
3878 
3879 #ifdef HAVE_SSL
3880 			if(i != -1)
3881 			{
3882 				if(withSSL)
3883 					set_server_ssl(i, 1);
3884 				else
3885 					set_server_ssl(i, 0);
3886 			}
3887 #endif
3888 			close_unattached_servers();
3889 			set_server_old_server(i, -2);
3890 			set_server_try_once(i, 1);
3891 			set_server_change_refnum(i, window->refnum);
3892 			if (!connect_to_server_by_refnum(i, -1))
3893 			{
3894 #ifndef NON_BLOCKING_CONNECTS
3895 				set_window_server(window->refnum, from_server, 0);
3896 				set_level_by_refnum(window->refnum, new_server_lastlog_level);
3897 				if (window->current_channel)
3898 					new_free(&window->current_channel);
3899 #endif
3900 			}
3901 			window_check_servers(from_server);
3902 #ifdef HAVE_SSL
3903 		}
3904 #endif
3905 	}
3906 	else
3907 		say("SERVER: You must specify a server");
3908 
3909 	return window;
3910 }
3911 
window_show(Window * window,char ** args,char * usage)3912 static Window *window_show (Window *window, char **args, char *usage)
3913 {
3914 	Window *tmp;
3915 
3916 	if ((tmp = get_window("SHOW", args)))
3917 	{
3918 		show_window(tmp);
3919 		window = window->screen->current_window;
3920 		update_input(UPDATE_ALL);
3921 #ifdef GUI
3922                 gui_setfocus(tmp->screen);
3923 #endif
3924 	}
3925 	return window;
3926 }
3927 
window_scratch(Window * window,char ** args,char * usage)3928 static	Window *window_scratch (Window *window, char **args, char *usage)
3929 {
3930 	int scratch = 0;
3931 
3932 	if (get_boolean("SCRATCH", args, &scratch))
3933 		return NULL;
3934 
3935 	if (scratch == 1)
3936 		window->scratch_line = 0;
3937 	else
3938 	{
3939 		window->scratch_line = -1;
3940  		window->top_of_display = window->display_ip;
3941 		window->update |= REDRAW_DISPLAY_FULL | REDRAW_STATUS;
3942 	}
3943 	return window;
3944 }
3945 
window_scroll(Window * window,char ** args,char * usage)3946 Window *window_scroll (Window *window, char **args, char *usage)
3947 {
3948 	int scroll = 0;
3949 
3950 	if (get_boolean("SCROLL", args, &scroll))
3951 		return NULL;
3952 
3953 	if (scroll == 1 && window->scratch_line == -1)
3954 		return window;
3955 	if (scroll == 0 && window->scratch_line == 0)
3956 		return window;
3957 
3958 	if (scroll == 1)
3959 	{
3960 		window->scratch_line = -1;
3961 		window->top_of_display = window->display_ip;
3962 		window->update |= REDRAW_DISPLAY_FULL | REDRAW_STATUS;
3963 	}
3964 	else
3965 	{
3966 		window->scratch_line = 0;
3967 		window->noscroll = 1;
3968 	}
3969 	return window;
3970 }
3971 
window_scrollback(Window * window,char ** args,char * usage)3972 static	Window *window_scrollback (Window *window, char **args, char *usage)
3973 {
3974 	int val = get_number("SCROLLBACK", args, NULL);
3975 
3976 	if (!val)
3977 		return NULL;
3978 	if (val < window->display_size * 2)
3979 		window->display_buffer_max = window->display_size * 2;
3980 	else
3981 		window->display_buffer_max = val;
3982 
3983 	say("Window scrollback size set to %d", window->display_buffer_max);
3984 	return window;
3985 }
3986 
window_skip(Window * window,char ** args,char * usage)3987 static Window *window_skip (Window *window, char **args, char *usage)
3988 {
3989 	if (get_boolean("SKIP", args, &window->skip))
3990 		return NULL;
3991 
3992 	return window;
3993 }
3994 
window_show_all(Window * window,char ** args,char * usage)3995 static Window *window_show_all (Window *window, char **args, char *usage)
3996 {
3997 	while (invisible_list)
3998 		show_window(invisible_list);
3999 	return window;
4000 }
4001 
window_shrink(Window * window,char ** args,char * usage)4002 static Window *window_shrink (Window *window, char **args, char *usage)
4003 {
4004 	resize_window(RESIZE_REL, window, -get_number("SHRINK", args, NULL));
4005 	return window;
4006 }
4007 
window_size(Window * window,char ** args,char * usage)4008 static Window *window_size (Window *window, char **args, char *usage)
4009 {
4010 	char *ptr = *args;
4011 	int number;
4012 
4013 	number = parse_number(args);
4014 	if(ptr == *args)
4015 		say("Window size is %d", window->display_size);
4016 	else
4017 		resize_window(RESIZE_ABS, window, number);
4018 
4019 	return window;
4020 }
4021 
window_stack(Window * window,char ** args,char * usage)4022 static Window *window_stack (Window *window, char **args, char *usage)
4023 {
4024 	WindowStack 	*last, *tmp, *crap;
4025 	Window 		*win = NULL;
4026 	int		len = 4;
4027 
4028 	while ((traverse_all_windows(&win)))
4029 	{
4030 		if (win->name && (strlen(win->name) > len))
4031 			len = strlen(win->name);
4032 	}
4033 
4034 	say("Window stack:");
4035 	last = NULL;
4036 	tmp = window->screen->window_stack;
4037 	while (tmp)
4038 	{
4039 		if ((win = get_window_by_refnum(tmp->refnum)) != NULL)
4040 		{
4041 			list_a_window(win, len);
4042 			last = tmp;
4043 			tmp = tmp->next;
4044 		}
4045 		else
4046 		{
4047 			crap = tmp->next;
4048 			new_free((char **)&tmp);
4049 			if (last)
4050 				last->next = crap;
4051 			else
4052 				window->screen->window_stack = crap;
4053 
4054 			tmp = crap;
4055 		}
4056 	}
4057 
4058 	return window;
4059 }
4060 
window_status_special(Window * window,char ** args,char * usage)4061 static Window *window_status_special (Window *window, char **args, char *usage)
4062 {
4063 	char *arg;
4064 
4065 	arg = new_next_arg(*args, args);
4066 	if (window->wset)
4067 		malloc_strcpy(&window->wset->window_special_format, arg);
4068 	window->update |= REDRAW_STATUS;
4069 
4070 	return window;
4071 }
4072 
window_swap(Window * window,char ** args,char * usage)4073 static Window *window_swap (Window *window, char **args, char *usage)
4074 {
4075 	Window *tmp;
4076 
4077 	if ((tmp = get_invisible_window("SWAP", args)))
4078 		swap_window(window, tmp);
4079 
4080 	return current_window;
4081 }
4082 
window_unbind(Window * window,char ** args,char * usage)4083 static Window *window_unbind (Window *window, char **args, char *usage)
4084 {
4085 	char *arg, *channel;
4086 
4087 	if ((arg = next_arg(*args, args)))
4088 	{
4089 		channel = make_channel(arg);
4090 		if (channel && is_bound(channel, from_server))
4091 		{
4092 			say("Channel %s is no longer bound", channel);
4093 			unbind_channel(channel, from_server);
4094 		}
4095 		else
4096 			say("Channel %s is not bound", channel ? channel : empty_string);
4097 	}
4098 	else
4099 	{
4100 		say("Channel %s is no longer bound", window->bind_channel);
4101 		new_free(&window->bind_channel);
4102 	}
4103 	return window;
4104 }
4105 
window_set(Window * window,char ** args,char * usage)4106 static Window *window_set (Window *window, char **args, char *usage)
4107 {
4108 	wset_variable(NULL, *args, NULL, NULL);
4109 	*args = NULL;
4110 	return window;
4111 }
4112 
window_update(Window * window,char ** args,char * usage)4113 static Window *window_update (Window *window, char **args, char *usage)
4114 {
4115 	update_window_status_all();
4116 	return window;
4117 }
4118 
4119 
4120 /*
4121  * Associates a Menu with a Window
4122  */
4123 
window_menu(Window * window,char ** args,char * usage)4124 static Window *window_menu(Window *window, char **args, char *usage)
4125 {
4126 #ifdef GUI
4127 MenuStruct *menutoadd = NULL;
4128 Screen *menuscreen;
4129 char *addthismenu;
4130 
4131 	if(window->screen != NULL)
4132 		menuscreen=window->screen;
4133 	else
4134 		menuscreen=main_screen;
4135 
4136 	addthismenu = m_strdup(next_arg(*args, args));
4137 
4138 	if (my_stricmp(addthismenu, "-delete") && !(menutoadd = (MenuStruct *)findmenu(addthismenu)))
4139 	{
4140 		say("Menu not found!");
4141 		return window;
4142 	}
4143 
4144         gui_menu(menuscreen, addthismenu);
4145 #endif /* GUI */
4146 	return window;
4147 }
4148 
4149 #ifdef GUI
window_setpos(Window * window,char ** args,char * usage)4150 static Window *window_setpos(Window *window, char **args, char *usage)
4151 {
4152 int 	x = 0,
4153 	y = 0,
4154 	cx = 0,
4155 	cy = 0,
4156 	min = 0,
4157 	max = 0,
4158 	restore = 0,
4159 	activate = 0,
4160 	bottom = 0,
4161 	top = 0,
4162 	size = 0,
4163 	position = 0,
4164 	t = 0;
4165 char *tmp;
4166 
4167 	if (!(tmp = next_arg(*args, args)))
4168 		return window;
4169 	for (t = 0; t < strlen(tmp); t++)
4170 	{
4171 		switch (tmp[t])
4172 		{
4173 			case 's':
4174 				size = 1;
4175 				break;
4176 			case 'p':
4177 				position = 1;
4178 				break;
4179 			case 'm':
4180 				min = 1;
4181 				break;
4182 			case 'M':
4183 				max = 1;
4184 				break;
4185 			case 'r':
4186 				restore = 1;
4187 				break;
4188 			case 'a':
4189 				activate = 1;
4190 				break;
4191 			case 'T':
4192 				top = 1;
4193 				break;
4194 			case 'B':
4195 				bottom = 1;
4196 				break;
4197 		}
4198 	}
4199 	if (!(tmp = next_arg(*args, args)))
4200 		return window;
4201 	x = my_atol(tmp);
4202 
4203 	if (!(tmp = next_arg(*args, args)))
4204 		return window;
4205 	y = my_atol(tmp);
4206 
4207 	if (!(tmp = next_arg(*args, args)))
4208 		return window;
4209 	cx = my_atol(tmp);
4210 
4211 	if (!(tmp = next_arg(*args, args)))
4212 		return window;
4213 	cy = my_atol(tmp);
4214 
4215 	gui_setwindowpos(window->screen, x, y, cx, cy, top, bottom, min, max, restore, activate, size, position);
4216 	return window;
4217 }
4218 
window_font(Window * window,char ** args,char * usage)4219 static Window *window_font(Window *window, char **args, char *usage)
4220 {
4221 char *tmp;
4222 
4223 	if ((tmp = next_arg(*args, args)))
4224 		if (window && window->screen)
4225 			gui_font_set(tmp, window->screen);
4226 	return window;
4227 }
4228 
window_nicklist(Window * window,char ** args,char * usage)4229 static Window *window_nicklist(Window *window, char **args, char *usage)
4230 {
4231 char *tmp;
4232 
4233 	if ((tmp = next_arg(*args, args)))
4234 		if (window && window->screen)
4235 			gui_nicklist_width(my_atol(tmp), window->screen);
4236 	return window;
4237 }
4238 #endif
4239 
4240 static Window *window_help (Window *, char **, char *);
4241 
4242 static window_ops options [] = {
4243 	{ "ADD",		window_add, 		"[nick|#channel|nick1,nick2,...]\n- Adds [nick|#channel|nick1,nick2,...] to the nicks to display in a window" },
4244 	{ "BACK",		window_back, 		"\n- Moves you back one window" },
4245 	{ "BALANCE",		window_balance, 	"\n- Balances the displayed windows" },
4246 	{ "BEEP_ALWAYS",	window_beep_always, 	"[on|off|toggle]\n- Should this window beep always on/off/toggle" },
4247 	{ "BIND",		window_bind, 		"[#channel]\n- Binds a channel to a window" },
4248 	{ "CHANNEL",		window_channel, 	"[#channel|#chan1,#chan2,...]\n- Attempts to join a channel in current window" },
4249 	{ "CREATE",		window_create, 		"\n- Create a new screen using wserv in X-windows" },
4250 	{ "DELETE",		window_delete, 		"\n- Used to kill a screen (wserv) in X-windows" },
4251 	{ "DESCRIBE",		window_describe,	"[text]\n- Displays useful information about the current window" },
4252 	{ "DISCON",		window_discon,		"Disconnects window from a server" },
4253 	{ "DOUBLE",		window_double, 		"[on|off|toggle]\n- Turns double status bar on/off/toggle" },
4254 	{ "ECHO",		window_echo,		"[text]\n- echo [text] which is in quotes to a window" },
4255 	{ "FIXED",		window_fixed,		"[on|off|toggle]\n- Turns fixed window sizing on/off/toggle" },
4256 #ifdef GUI
4257         { "FONT",		window_font,		"[fontname]\n- Sets the font for the window" },
4258 #endif
4259 	{ "GOTO",		window_goto, 		"[refnum]\n- Go's to a N'th window" },
4260 	{ "GROW",		window_grow, 		"[number]\n- Grows the current window by # of lines" },
4261 	{ "HELP",		window_help,		"- All of this commands work on the current window" },
4262 	{ "HIDE",		window_hide, 		"\n- Hides the current window" },
4263 	{ "HIDE_OTHERS",	window_hide_others, 	"\n- Hides all windows except the current one" },
4264 	{ "HOLD_MODE",		window_hold_mode, 	"[on|off|toggle]\n- Sets the current window's hold mode status" },
4265 	{ "KILL",		window_kill, 		"\n- Kills the current window" },
4266 	{ "KILL_OTHERS",	window_kill_others, 	"\n- Kills all visible windows except the current one" },
4267 	{ "KILLSWAP",		window_killswap, 	"\n- Swaps the current window with the last one hidden and kills the swapped out window" },
4268 	{ "LAST", 		window_last, 		"\n- Places you in the last window you were in" },
4269 	{ "LASTLOG",		window_lastlog, 	"[number]\n- Sets this windows lastlog size to #" },
4270 	{ "LASTLOG_LEVEL",	window_lastlog_level, 	"[level]\n- Sets the current windows lastlog level to [levels]" },
4271 	{ "LEVEL",		window_level, 		"[level]\n- Sets the window's level to [levels]" },
4272 	{ "LIST",		window_list, 		"\n- Displays a list of windows" },
4273 	{ "LOG",		window_log, 		"[on|off|toggle]\n- Turns window logging on/off/toggle" },
4274 	{ "LOGFILE",		window_logfile, 	"[filename]\n- Sets the filename for the current windows logfile" },
4275 	{ "MENU",		window_menu,		"[name]\n- Associate a menu with a window"},
4276 	{ "MOVE",		window_move, 		"[number]\n- Moves the current window on the display [number] of times" },
4277 	{ "NAME",		window_name, 		"[text]\n- Sets the name for the current window" },
4278 	{ "NEW",		window_new, 		"\n- Creates a new window" },
4279 	{ "NEW_HIDE",		window_new_hide, 		"\n- Creates a new window" },
4280 	{ "NEXT",		window_next, 		"\n- Sets the current window to the next numbered window" },
4281 #ifdef GUI
4282 	{ "NICKLIST",		window_nicklist,       	"\n- Sets the current window nicklist width" },
4283 #endif
4284 	{ "NOSERV",		window_noserv,		"\n- turns the server off for this window" },
4285 	{ "NOTIFY",		window_notify, 		"[on|off|toggle]\n- Turns notification on/off/toggle for the current window." },
4286 	{ "NOTIFY_LEVEL",	window_notify_level, 	"[level]\n- Set's current window notification level to [level]" },
4287 	{ "NUMBER",		window_number, 		"[number]\n- Set's the current windows refnum to #" },
4288 	{ "POP",		window_pop, 		"\n- Pops the top window off the window stack. if hidden it's made visible" },
4289 	{ "PREVIOUS",		window_previous, 	"\n- Sets the current window to the previous numbered windows" },
4290 	{ "PROMPT",		window_prompt, 		"[text]\n- Sets the current input prompt to [text]" },
4291 	{ "PUSH",		window_push, 		"[refnum]\n- Places the current window or specified window on the window stack" },
4292 	{ "QUERY",		window_query,		"Adds/remove query for current window" },
4293 	{ "REFNUM",		window_refnum, 		"[refnum]\n- Changes the current window to [refnum]" },
4294 	{ "REFRESH",		window_refresh,		"refreshes the current window" },
4295 	{ "REMOVE",		window_remove, 		"[nick|#channel|nick1,nick2,...]\n- Removes nick|#channel from this window's display" },
4296 	{ "SERVER",		window_server, 		"[servername[:[<port>][:[<password>][:[<nickname>]]]]]\n- Attempts to connect current window with a new server" },
4297 	{ "SET",		window_set,		"[text]\n- Displays or sets window specific set's" },
4298 #ifdef GUI
4299 	{ "SETWINDOWPOS",	window_setpos,		"[options]\n- Set's windows size, position and state." },
4300 #endif
4301 	{ "SCRATCH",		window_scratch,		"\n- Create a scratch window. this window has no scrollback or scroll" },
4302 	{ "SCROLL",		window_scroll,		"\n- toggle scratch window non-scroll" },
4303 	{ "SCROLLBACK",		window_scrollback,	"[lines]\n- Sets the scrollback size for this window" },
4304 	{ "SHOW",		window_show, 		"[refnum]\n- Makes the specified [refnum] window visible again" },
4305 	{ "SHOW_ALL",		window_show_all,	"\n- Makes all hidden windows visibile again" },
4306 	{ "SHRINK",		window_shrink, 		"[lines]\n- Shrinks the current window by # of lines" },
4307 	{ "SIZE",		window_size, 		"[lines]\n- Set's the current window to # lines" },
4308 	{ "SKIP",		window_skip,		"[on|off|toggle]\n- Set's the current windows skip status on/off/toggle" },
4309 	{ "SPLIT",		window_split,		"[on|off|toggle]\n- Places a third status line at the top of the screen if possible on/off/toggle" },
4310 	{ "STACK",		window_stack, 		"\n- Shows the current window stack which have been added using /window push" },
4311 	{ "STATUS_SPECIAL",	window_status_special,	"[text]\n- A special window format"},
4312 	{ "SWAP",		window_swap, 		"[refnum]\n- Swap the current window with the specified hidden [refnum] window" },
4313 	{ "TRIPLE",		window_triple,		"[on|off|toggle]\n- Turns on/off/toggle a triple status bar" },
4314 	{ "UNBIND",		window_unbind, 		"[#channel]\n- Removes a channel bound to a window. If not specified then the current channel is used" },
4315 	{ "UPDATE",		window_update,		"\n- Updates the window status on all windows" },
4316 	{ NULL,			NULL, 			NULL }
4317 };
4318 
4319 
window_help(Window * window,char ** args,char * usage)4320 static Window *window_help (Window *window, char **args, char *usage)
4321 {
4322 	int i, c = 0, done = 0;
4323 	char *cmd;
4324 	char buffer[BIG_BUFFER_SIZE];
4325 
4326 	*buffer = 0;
4327 	cmd = next_arg(*args, args);
4328 	if (!cmd)
4329 	{
4330 		for (i = 0; options[i].command; i++)
4331 		{
4332 			strlcat(buffer, options[i].command, sizeof buffer);
4333 			strlcat(buffer, space, sizeof buffer);
4334 			if (++c == 5)
4335 			{
4336 				put_it("%s", convert_output_format("$G $[13]0 $[13]1 $[13]2 $[13]3 $[13]4", "%s", buffer));
4337 				*buffer = 0;
4338 				c = 0;
4339 			}
4340 		}
4341 		if (c)
4342 			put_it("%s", convert_output_format("$G $[13]0 $[13]1 $[13]2 $[13]3 $[13]4", "%s", buffer));
4343 		userage("WINDOW help", "%R[%ncommand%R]%n to get help on specific commands");
4344 	}
4345 	else
4346 	{
4347 		for (i = 0; options[i].command; i++)
4348 		{
4349 			if (!my_stricmp(options[i].command, cmd))
4350 			{
4351 				snprintf(buffer, sizeof buffer, "WINDOW %s", cmd);
4352 				userage(buffer, options[i].usage ? options[i].usage : " - No help available");
4353 				done++;
4354 			}
4355 		}
4356 		if (!done)
4357 			put_it("%s", convert_output_format("$G WINDOW - No such command", NULL, NULL));
4358 	}
4359 	return window;
4360 }
4361 
BUILT_IN_COMMAND(windowcmd)4362 BUILT_IN_COMMAND(windowcmd)
4363 {
4364 	char *arg;
4365 	int nargs = 0;
4366 	int old_status_update = status_update_flag;
4367 	Window *window;
4368 	int oiwc = in_window_command;
4369 #ifdef WANT_DLL
4370 	WindowDll *dll = NULL;
4371 #endif
4372 	in_window_command = 1;
4373 	reset_display_target();
4374 
4375 	window = current_window;
4376 
4377 	while ((arg = next_arg(args, &args)))
4378 	{
4379 		int i;
4380 		int len = strlen(arg);
4381 
4382 		if (*arg == '-' || *arg == '/')
4383 			arg++, len--;
4384 #ifdef WANT_DLL
4385 		if (dll_window && (dll = (WindowDll *)find_in_list((List **)&dll_window, arg, 0)))
4386 		{
4387 			window = dll->func(window, &args, dll->help);
4388 			nargs++;
4389 			if (!window)
4390 				args = NULL;
4391 		}
4392 		else
4393 #endif
4394 		{
4395 			for (i = 0; options[i].func ; i++)
4396 			{
4397 				if (!my_strnicmp(arg, options[i].command, len))
4398 				{
4399 					window = options[i].func(window, &args, options[i].usage);
4400 					nargs++;
4401 					if (!window)
4402 						args = NULL;
4403 					break;
4404 				}
4405 			}
4406 
4407 			if (!options[i].func)
4408 			{
4409 				Window *s_window;
4410 				if ((s_window = get_window_by_desc(arg)))
4411 				{
4412 					nargs++;
4413 					window = s_window;
4414 				}
4415 				else
4416 					yell("WINDOW: Invalid option: [%s]", arg);
4417 			}
4418 		}
4419 	}
4420 
4421 	if (!nargs)
4422 		window_describe(current_window, NULL, NULL);
4423 	in_window_command = oiwc;
4424 	status_update_flag = old_status_update;
4425 
4426 	update_all_windows();
4427 	update_all_status(window, NULL, 0);
4428 	update_input(UPDATE_ALL);
4429 	cursor_to_input();
4430 }
4431 
4432 
4433 
4434 /* * * * * * * * * * * SCROLLBACK BUFFER * * * * * * * * * * * * * * */
4435 /*
4436  * XXXX Dont you DARE touch this XXXX
4437  *
4438  * Most of the time, a delete_display_line() is followed somewhat
4439  * immediately by a new_display_line().  So most of the time we just
4440  * cache that one item and re-use it.  That saves us thousands of
4441  * malloc()s.  In the cases where its not, then we just do things the
4442  * normal way.
4443  */
4444 static Display *recycle = NULL;
4445 
delete_display_line(Display * stuff)4446 void 	delete_display_line (Display *stuff)
4447 {
4448 	if (recycle == stuff)
4449 		ircpanic("error in delete_display_line");
4450 	if (recycle)
4451 		new_free(&recycle);
4452 
4453 	recycle = stuff;
4454 	new_free(&recycle->line);
4455 }
4456 
new_display_line(Display * prev)4457 Display *new_display_line (Display *prev)
4458 {
4459 	Display *stuff;
4460 
4461 	if (recycle)
4462 	{
4463 		stuff = recycle;
4464 		recycle = NULL;
4465 	}
4466 	else
4467 		stuff = (Display *)new_malloc(sizeof(Display));
4468 
4469 	stuff->line = NULL;
4470 	stuff->prev = prev;
4471 	stuff->next = NULL;
4472 	return stuff;
4473 }
4474 
4475 /* * * * * * * * * * * Scrollback functionality * * * * * * * * * * */
BX_scrollback_backwards_lines(int lines)4476 void 	BX_scrollback_backwards_lines (int lines)
4477 {
4478 	Window	*window = current_window;
4479 	Display *new_top = window->top_of_display;
4480 	int	new_lines;
4481 #ifdef GUI
4482 	int position;
4483 	float bleah = get_int_var(SCROLLBACK_VAR);
4484 #endif
4485 
4486 	if (new_top == window->top_of_scrollback)
4487 	{
4488 #ifndef GUI
4489 		term_beep();
4490 #endif
4491 		return;
4492 	}
4493 
4494 	if (!window->scrollback_point)
4495 		window->scrollback_point = window->top_of_display;
4496 
4497 	for (new_lines = 0; new_lines < lines; new_lines++)
4498 	{
4499 		if (new_top == window->top_of_scrollback)
4500 			break;
4501 		new_top = new_top->prev;
4502 	}
4503 
4504 	window->top_of_display = new_top;
4505 	window->lines_scrolled_back += new_lines;
4506 
4507 	recalculate_window_cursor(window);
4508 	repaint_window(window, 0, -1);
4509 	update_window_status(window, 0);
4510 	cursor_not_in_display(window->screen);
4511 	update_input(UPDATE_JUST_CURSOR);
4512 #ifdef GUI
4513 	position = (int)(bleah-((((float)(window->distance_from_display-window->display_size))/(float)(window->display_buffer_size-window->display_size))*bleah));
4514 	gui_scrollerchanged(window->screen, position);
4515 #endif
4516 }
4517 
BX_scrollback_forwards_lines(int lines)4518 void 	BX_scrollback_forwards_lines (int lines)
4519 {
4520 	Window	*window = current_window;
4521 	Display *new_top = window->top_of_display;
4522 	int	new_lines = 0;
4523 #ifdef GUI
4524 	int position;
4525 	float bleah = get_int_var(SCROLLBACK_VAR);
4526 #endif
4527 
4528 	if (new_top == window->display_ip || !window->scrollback_point)
4529 	{
4530 #ifndef GUI
4531 		term_beep();
4532 #endif
4533 		return;
4534 	}
4535 
4536 	for (new_lines = 0; new_lines < lines; new_lines++)
4537 	{
4538 		if (new_top == window->scrollback_point/*display_ip*/)
4539 			break;
4540 		new_top = new_top->next;
4541 	}
4542 
4543 	window->top_of_display = new_top;
4544 	window->lines_scrolled_back -= new_lines;
4545 	recalculate_window_cursor(window);
4546 	repaint_window(window, 0, -1);
4547 	update_window_status(window, 0);
4548 	cursor_not_in_display(window->screen);
4549 	update_input(UPDATE_JUST_CURSOR);
4550 	if (window->lines_scrolled_back <= 0)
4551 		scrollback_end (0, NULL);
4552 #ifdef GUI
4553 	position = (int)(bleah-((((float)(window->distance_from_display-window->display_size))/(float)(window->display_buffer_size-window->display_size))*bleah));
4554 	gui_scrollerchanged(window->screen, position);
4555 #endif
4556 }
4557 
BX_scrollback_forwards(char dumb,char * dumber)4558 void 	BX_scrollback_forwards (char dumb, char *dumber)
4559 {
4560 	int 	ratio = get_int_var(SCROLLBACK_RATIO_VAR);
4561 	int	lines;
4562 
4563 	if (ratio < 10 )
4564 		ratio = 10;
4565 	if (ratio > 100)
4566 		ratio = 100;
4567 
4568 	lines = current_window->display_size * ratio / 100;
4569 	scrollback_forwards_lines(lines);
4570 }
4571 
BX_scrollback_backwards(char dumb,char * dumber)4572 void 	BX_scrollback_backwards (char dumb, char *dumber)
4573 {
4574 	int 	ratio = get_int_var(SCROLLBACK_RATIO_VAR);
4575 	int	lines;
4576 
4577 	if (ratio < 10 )
4578 		ratio = 10;
4579 	if (ratio > 100)
4580 		ratio = 100;
4581 
4582 	lines = current_window->display_size * ratio / 100;
4583 	scrollback_backwards_lines(lines);
4584 }
4585 
4586 
BX_scrollback_end(char dumb,char * dumber)4587 void 	BX_scrollback_end (char dumb, char *dumber)
4588 {
4589 	Window	*window = current_window;
4590 
4591 	if (!window->scrollback_point)
4592 	{
4593 		term_beep();
4594 		return;
4595 	}
4596 
4597 	/* Adjust the top of window only if we would move forward. */
4598 	if (window->lines_scrolled_back > 0)
4599 		window->top_of_display = window->scrollback_point;
4600 
4601 	window->lines_scrolled_back = 0;
4602 	window->scrollback_point = NULL;
4603 	repaint_window(window, 0, -1);
4604 	update_window_status(window, 0);
4605 	cursor_not_in_display(window->screen);
4606 	update_input(UPDATE_JUST_CURSOR);
4607 #ifdef GUI
4608 	gui_scrollerchanged(window->screen, get_int_var(SCROLLBACK_VAR));
4609 #endif
4610 }
4611 
BX_scrollback_start(char dumb,char * dumber)4612 void 	BX_scrollback_start (char dumb, char *dumber)
4613 {
4614 	Window	*window = current_window;
4615 
4616 	if (window->display_buffer_size <= window->display_size)
4617 	{
4618 		term_beep();
4619 		return;
4620 	}
4621 
4622 	if (!window->scrollback_point)
4623 		window->scrollback_point = window->top_of_display;
4624 
4625 	while (window->top_of_display != window->top_of_scrollback)
4626 	{
4627 		window->top_of_display = window->top_of_display->prev;
4628 		window->lines_scrolled_back++;
4629 	}
4630 
4631 	repaint_window(window, 0, -1);
4632 	update_window_status(window, 0);
4633 	cursor_not_in_display(window->screen);
4634 	update_input(UPDATE_JUST_CURSOR);
4635 #ifdef GUI
4636 	gui_scrollerchanged(window->screen, 0);
4637 #endif
4638 }
4639 
4640 
4641 /* HOLD MODE STUFF */
4642 /*
4643  * hold_mode: sets the "hold mode".  Really.  If the update flag is true,
4644  * this will also update the status line, if needed, to display the hold mode
4645  * state.  If update is false, only the internal flag is set.
4646  */
BX_set_hold_mode(Window * window,int flag,int update)4647 void	BX_set_hold_mode (Window *window, int flag, int update)
4648 {
4649 	if (window == NULL)
4650 		window = current_window;
4651 
4652 	if (flag != ON && window->scrollback_point)
4653 		return;
4654 
4655 	if (flag == TOGGLE)
4656 	{
4657 		if (window->hold_mode == OFF)
4658 			window->hold_mode = ON;
4659 		else
4660 			window->hold_mode = OFF;
4661 	}
4662 	else
4663 		window->hold_mode = flag;
4664 
4665 
4666 	if (update)
4667 	{
4668 		if (window->lines_held != window->last_lines_held)
4669 		{
4670 			window->last_lines_held = window->lines_held;
4671 			update_window_status(window, 0);
4672 			if (window->update | UPDATE_STATUS)
4673 				window->update -= UPDATE_STATUS;
4674 			cursor_in_display(window);
4675 			update_input(NO_UPDATE);
4676 		}
4677 	}
4678 	else
4679 		window->last_lines_held = -1;
4680 }
4681 
4682 /*
4683  * This checks to see if any windows need to be unheld or not
4684  */
BX_unhold_windows(void)4685 int	BX_unhold_windows(void)
4686 {
4687 	Window 	*w = NULL;
4688 	int	retval = 0;
4689 
4690 	while (traverse_all_windows(&w))
4691 	{
4692 		if (!w->hold_mode && w->lines_held)
4693 		{
4694 			if ((unhold_a_window(w)))
4695 				retval++;
4696 		}
4697 	}
4698 
4699 	return retval;
4700 }
4701 
BX_unstop_all_windows(char dumb,char * dumber)4702 void 	BX_unstop_all_windows (char dumb, char *dumber)
4703 {
4704 	Window	*tmp = NULL;
4705 
4706 	while (traverse_all_windows(&tmp))
4707 		set_hold_mode(tmp, OFF, 1);
4708 }
4709 
4710 /*
4711  * reset_line_cnt: called by /SET HOLD_MODE to reset the line counter so we
4712  * always get a held screen after the proper number of lines
4713  */
BX_reset_line_cnt(Window * win,char * unused,int value)4714 void 	BX_reset_line_cnt (Window *win, char *unused, int value)
4715 {
4716 	win->hold_mode = value;
4717 	win->held_displayed = 0;
4718 	if (!win->hold_mode && win->in_more)
4719 		reset_hold_mode(win);
4720 }
4721 
4722 /* toggle_stop_screen: the BIND function TOGGLE_STOP_SCREEN */
BX_toggle_stop_screen(char unused,char * not_used)4723 void 	BX_toggle_stop_screen (char unused, char *not_used)
4724 {
4725 	set_hold_mode(NULL, TOGGLE, 1);
4726 	update_all_windows();
4727 }
4728 
4729 /*
4730  * If "scrollback_point" is set, then anything below the bottom of the screen
4731  * at that point gets nuked.
4732  * If "scrollback_point" is not set, anything below the current position of
4733  * the screen gets nuked.
4734  */
BX_flush_everything_being_held(Window * window)4735 void 	BX_flush_everything_being_held (Window *window)
4736 {
4737 	Display *ptr, *save;
4738 	int count;
4739 
4740 	if (!window)
4741 		window = current_window;
4742 
4743 	count = window->display_size;
4744 
4745 	if (window->scrollback_point)
4746 		ptr = window->scrollback_point;
4747 	else
4748 		ptr = window->top_of_display;
4749 
4750 	while (--count > 0)
4751 	{
4752 		ptr = ptr->next;
4753 		if (ptr == window->display_ip)
4754 			return;		/* Nothing to flush */
4755 	}
4756 	save = ptr->next;
4757 	ptr->next = window->display_ip;
4758 	window->display_ip->prev = ptr;
4759 	ptr = save;
4760 
4761 	while (ptr != window->display_ip)
4762 	{
4763 		Display *next = ptr->next;
4764 		delete_display_line(ptr);
4765 		window->lines_held--;
4766 		ptr = next;
4767 	}
4768 
4769 	if (window->lines_held != 0)
4770 		ircpanic("erf. fix this.");
4771 
4772 	window->holding_something = 0;
4773 	set_hold_mode(window, OFF, 1);
4774 }
4775 
4776 
4777 /*
4778  * This adjusts the viewport up one full screen.  This calls rite()
4779  * indirectly, because repaint_window() uses rite() to do the work.
4780  * This belongs somewhere else.
4781  */
BX_unhold_a_window(Window * window)4782 int	BX_unhold_a_window (Window *window)
4783 {
4784 	int amount = window->display_size;
4785 
4786 	if (window->holding_something &&
4787 		(window->distance_from_display < window->display_size))
4788 	{
4789 		window->holding_something = 0;
4790 		window->lines_held = 0;
4791 	}
4792 
4793 	if (!window->lines_held || window->scrollback_point)
4794 		return 0;		/* Right. */
4795 
4796 	if (window->lines_held < amount)
4797 		amount = window->lines_held;
4798 
4799 	window->lines_held -= amount;
4800 	window->held_displayed = 0;
4801 
4802 	if (!window->lines_held)
4803 		window->holding_something = 0;
4804 
4805 	if (!amount)
4806 		return 0;		/* Whatever */
4807 
4808 	while (amount--)
4809 		window->top_of_display = window->top_of_display->next;
4810 
4811 	repaint_window(window, 0, -1);
4812 	update_window_status(window, 0);
4813 	return 1;
4814 }
4815 
BX_recalculate_window_cursor(Window * window)4816 void BX_recalculate_window_cursor (Window *window)
4817 {
4818 	Display *tmp;
4819 
4820 	window->cursor = window->distance_from_display = 0;
4821 	for (tmp = window->top_of_display; tmp != window->display_ip;
4822 				tmp = tmp->next)
4823 		window->cursor++, window->distance_from_display++;
4824 
4825 	if (window->cursor > window->display_size)
4826  		window->cursor = window->display_size;
4827 }
4828 
BX_set_screens_current_window(Screen * screen,Window * window)4829 void BX_set_screens_current_window (Screen *screen, Window *window)
4830 {
4831 	if (!window)
4832 	{
4833 		window = get_window_by_refnum(screen->last_window_refnum);
4834 		if (window && window->screen != screen)
4835 			window = NULL;
4836 	}
4837 	if (!window)
4838 		window = screen->window_list;
4839 	if (window->deceased)
4840 		ircpanic("This window is dead");
4841 	if (window->screen != screen || !screen)
4842 		ircpanic("The window is not on that screen");
4843 
4844 	if (screen->current_window != window)
4845 	{
4846 		if (screen->current_window)
4847 		{
4848 			screen->current_window->update |= UPDATE_STATUS;
4849 			screen->last_window_refnum = screen->current_window->refnum;
4850 		}
4851 		screen->current_window = window;
4852 		screen->current_window->update |= UPDATE_STATUS;
4853 	}
4854 	if (current_window != window)
4855 		make_window_current(window);
4856 	update_all_windows();
4857 	xterm_settitle();
4858 }
4859 
BX_make_window_current(Window * window)4860 void BX_make_window_current (Window *window)
4861 {
4862 	Window *old_current_window = current_window;
4863 	int	old_screen, old_win;
4864 	int	new_screen, new_win;
4865 
4866 	if (!window)
4867 		current_window = last_input_screen->current_window;
4868 	else if (current_window != window)
4869  		current_window = window;
4870 	if (current_window->deceased)
4871 		ircpanic("This window is dead. Cannot continue.");
4872 
4873 	if (current_window == old_current_window)
4874 		return;
4875 
4876 	if (!old_current_window)
4877 		old_screen = old_win = -1;
4878 	else if (!old_current_window->screen)
4879 		old_screen = -1, old_win = old_current_window->refnum;
4880 	else
4881 		old_screen = old_current_window->screen->screennum,
4882 		old_win = old_current_window->refnum;
4883 
4884 	new_win = current_window->refnum;
4885 	if (!current_window->screen)
4886 		new_screen = -1;
4887 	else
4888 		new_screen = current_window->screen->screennum;
4889 
4890         do_hook(WINDOW_FOCUS_LIST, "%d %d %d %d",
4891         		old_screen, old_win,
4892 			new_screen, new_win);
4893 }
4894 
BX_clear_scrollback(Window * window)4895 void BX_clear_scrollback(Window *window)
4896 {
4897 	while (window->display_buffer_size > 0)
4898 	{
4899 		Display *next;
4900 		if (window->top_of_scrollback)
4901 		{
4902 			next = window->top_of_scrollback->next;
4903 			new_free(&window->top_of_scrollback->line);
4904 			new_free(&window->top_of_scrollback);
4905 			window->top_of_scrollback = next;
4906 		}
4907 		window->display_buffer_size--;
4908 	}
4909 	window->cursor = window->distance_from_display = 0;
4910 	resize_window_display(window);
4911 }
4912 
make_to_window_by_desc(char * desc)4913 void	make_to_window_by_desc (char *desc)
4914 {
4915 	Window	*new_win = get_window_by_desc(desc);
4916 
4917 	if (new_win)
4918 		target_window = new_win;
4919 	else
4920 		say("Window [%s] doesn't exist any more.  Punting.", desc);
4921 }
4922 
get_current_winref(void)4923 int	get_current_winref (void)
4924 {
4925 	return current_window->refnum;
4926 }
4927 
get_winref_by_desc(const char * desc)4928 int	get_winref_by_desc (const char *desc)
4929 {
4930 	Window *w;
4931 
4932 	if ((w = get_window_by_desc(desc)))
4933 		return w->refnum;
4934 
4935 	return -1;
4936 }
4937 
make_window_current_by_desc(char * desc)4938 void	make_window_current_by_desc (char *desc)
4939 {
4940 	Window	*new_win = get_window_by_desc(desc);
4941 
4942 	if (new_win)
4943 		make_window_current(new_win);
4944 	else
4945 		say("Window [%s] doesn't exist any more.  Punting.", desc);
4946 }
4947 
make_window_current_by_winref(int refnum)4948 void	make_window_current_by_winref (int refnum)
4949 {
4950 	Window	*new_win;
4951 
4952 	if (refnum == -1)
4953 		return;
4954 
4955 	if ((new_win = get_window_by_refnum(refnum)))
4956 		make_window_current(new_win);
4957 	else
4958 		say("Window [%d] doesn't exist any more.  Punting.", refnum);
4959 }
4960 
4961 
4962