1/*
2 * Copyright (c) 1983, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include <sys/cdefs.h>
35
36#ifndef __APPLE__
37__FBSDID("$FreeBSD: src/usr.bin/talk/init_disp.c,v 1.14 2004/04/19 21:37:28 cognet Exp $");
38
39#ifndef lint
40static const char sccsid[] = "@(#)init_disp.c	8.2 (Berkeley) 2/16/94";
41#endif
42#endif /* __APPLE__ */
43
44/*
45 * Initialization code for the display package,
46 * as well as the signal handling routines.
47 */
48
49#include <sys/stat.h>
50#ifdef __APPLE__
51#include <sys/ioctl.h>
52#endif
53
54#include <err.h>
55#include <signal.h>
56#include <stdlib.h>
57#include <unistd.h>
58#include <termios.h>
59
60#include "talk.h"
61
62extern volatile sig_atomic_t gotwinch;
63
64/*
65 * Make sure the callee can write to the screen
66 */
67void
68check_writeable()
69{
70	char *tty;
71	struct stat sb;
72
73	if ((tty = ttyname(STDERR_FILENO)) == NULL)
74		err(1, "ttyname");
75	if (stat(tty, &sb) < 0)
76		err(1, "%s", tty);
77	if (!(sb.st_mode & S_IWGRP))
78		errx(1, "The callee cannot write to this terminal, use \"mesg y\".");
79}
80
81/*
82 * Set up curses, catch the appropriate signals,
83 * and build the various windows.
84 */
85void
86init_display()
87{
88	struct sigaction sa;
89
90	if (initscr() == NULL)
91		errx(1, "Terminal type unset or lacking necessary features.");
92	(void) sigaction(SIGTSTP, (struct sigaction *)0, &sa);
93	sigaddset(&sa.sa_mask, SIGALRM);
94	(void) sigaction(SIGTSTP, &sa, (struct sigaction *)0);
95	curses_initialized = 1;
96	clear();
97	refresh();
98	noecho();
99	crmode();
100	signal(SIGINT, sig_sent);
101	signal(SIGPIPE, sig_sent);
102	signal(SIGWINCH, sig_winch);
103	/* curses takes care of ^Z */
104	my_win.x_nlines = LINES / 2;
105	my_win.x_ncols = COLS;
106	my_win.x_win = newwin(my_win.x_nlines, my_win.x_ncols, 0, 0);
107	idlok(my_win.x_win, TRUE);
108	scrollok(my_win.x_win, TRUE);
109	wclear(my_win.x_win);
110
111	his_win.x_nlines = LINES / 2 - 1;
112	his_win.x_ncols = COLS;
113	his_win.x_win = newwin(his_win.x_nlines, his_win.x_ncols,
114	    my_win.x_nlines+1, 0);
115	idlok(my_win.x_win, TRUE);
116	scrollok(his_win.x_win, TRUE);
117	wclear(his_win.x_win);
118
119	line_win = newwin(1, COLS, my_win.x_nlines, 0);
120#if defined(hline) || defined(whline) || defined(NCURSES_VERSION)
121	whline(line_win, 0, COLS);
122#else
123	box(line_win, '-', '-');
124#endif
125	wrefresh(line_win);
126	/* let them know we are working on it */
127	current_state = "No connection yet";
128}
129
130/*
131 * Trade edit characters with the other talk. By agreement
132 * the first three characters each talk transmits after
133 * connection are the three edit characters.
134 */
135void
136set_edit_chars()
137{
138	char buf[3];
139	int cc;
140	struct termios tio;
141
142	tcgetattr(0, &tio);
143	my_win.cerase = tio.c_cc[VERASE];
144	my_win.kill = tio.c_cc[VKILL];
145	my_win.werase = tio.c_cc[VWERASE];
146	if (my_win.cerase == (char)_POSIX_VDISABLE)
147		my_win.kill = CERASE;
148	if (my_win.kill == (char)_POSIX_VDISABLE)
149		my_win.kill = CKILL;
150	if (my_win.werase == (char)_POSIX_VDISABLE)
151		my_win.werase = CWERASE;
152	buf[0] = my_win.cerase;
153	buf[1] = my_win.kill;
154	buf[2] = my_win.werase;
155	cc = write(sockt, buf, sizeof(buf));
156	if (cc != sizeof(buf) )
157		p_error("Lost the connection");
158	cc = read(sockt, buf, sizeof(buf));
159	if (cc != sizeof(buf) )
160		p_error("Lost the connection");
161	his_win.cerase = buf[0];
162	his_win.kill = buf[1];
163	his_win.werase = buf[2];
164}
165
166/* ARGSUSED */
167void
168sig_sent(signo)
169	int signo __unused;
170{
171
172	message("Connection closing. Exiting");
173	quit();
174}
175
176void
177sig_winch(int dummy)
178{
179
180	gotwinch = 1;
181}
182
183/*
184 * All done talking...hang up the phone and reset terminal thingy's
185 */
186void
187quit()
188{
189
190	if (curses_initialized) {
191		wmove(his_win.x_win, his_win.x_nlines-1, 0);
192		wclrtoeol(his_win.x_win);
193		wrefresh(his_win.x_win);
194		endwin();
195	}
196	if (invitation_waiting)
197		send_delete();
198	exit(0);
199}
200
201/*
202 * If we get SIGWINCH, recompute both window sizes and refresh things.
203 */
204void
205resize_display(void)
206{
207	struct winsize ws;
208
209	if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0 ||
210	    (ws.ws_row == LINES && ws.ws_col == COLS))
211		return;
212
213	/* Update curses' internal state with new window size. */
214	resizeterm(ws.ws_row, ws.ws_col);
215
216	/*
217	 * Resize each window but wait to refresh the screen until
218	 * everything has been drawn so the cursor is in the right spot.
219	 */
220	my_win.x_nlines = LINES / 2;
221	my_win.x_ncols = COLS;
222	wresize(my_win.x_win, my_win.x_nlines, my_win.x_ncols);
223	mvwin(my_win.x_win, 0, 0);
224	clearok(my_win.x_win, TRUE);
225
226	his_win.x_nlines = LINES / 2 - 1;
227	his_win.x_ncols = COLS;
228	wresize(his_win.x_win, his_win.x_nlines, his_win.x_ncols);
229	mvwin(his_win.x_win, my_win.x_nlines + 1, 0);
230	clearok(his_win.x_win, TRUE);
231
232	wresize(line_win, 1, COLS);
233	mvwin(line_win, my_win.x_nlines, 0);
234#if defined(NCURSES_VERSION) || defined(whline)
235	whline(line_win, '-', COLS);
236#else
237	wmove(line_win, my_win.x_nlines, 0);
238	box(line_win, '-', '-');
239#endif
240
241	/* Now redraw the screen. */
242	wrefresh(his_win.x_win);
243	wrefresh(line_win);
244	wrefresh(my_win.x_win);
245}
246