client_sigwinch_handler(int sig)1 static void client_sigwinch_handler(int sig) {
2 	client.need_resize = true;
3 }
4 
client_send_packet(Packet * pkt)5 static bool client_send_packet(Packet *pkt) {
6 	print_packet("client-send:", pkt);
7 	if (send_packet(server.socket, pkt))
8 		return true;
9 	debug("FAILED\n");
10 	server.running = false;
11 	return false;
12 }
13 
client_recv_packet(Packet * pkt)14 static bool client_recv_packet(Packet *pkt) {
15 	if (recv_packet(server.socket, pkt)) {
16 		print_packet("client-recv:", pkt);
17 		return true;
18 	}
19 	debug("client-recv: FAILED\n");
20 	server.running = false;
21 	return false;
22 }
23 
client_restore_terminal(void)24 static void client_restore_terminal(void) {
25 	if (has_term)
26 		tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_term);
27 	if (alternate_buffer) {
28 		printf("\033[?25h\033[?1049l");
29 		fflush(stdout);
30 		alternate_buffer = false;
31 	}
32 }
33 
client_setup_terminal(void)34 static void client_setup_terminal(void) {
35 	atexit(client_restore_terminal);
36 
37 	cur_term = orig_term;
38 	cur_term.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON|IXOFF);
39 	cur_term.c_oflag &= ~(OPOST);
40 	cur_term.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
41 	cur_term.c_cflag &= ~(CSIZE|PARENB);
42 	cur_term.c_cflag |= CS8;
43 	cur_term.c_cc[VLNEXT] = _POSIX_VDISABLE;
44 	cur_term.c_cc[VMIN] = 1;
45 	cur_term.c_cc[VTIME] = 0;
46 	tcsetattr(STDIN_FILENO, TCSANOW, &cur_term);
47 
48 	if (!alternate_buffer) {
49 		printf("\033[?1049h\033[H");
50 		fflush(stdout);
51 		alternate_buffer = true;
52 	}
53 }
54 
client_mainloop(void)55 static int client_mainloop(void) {
56 	sigset_t emptyset, blockset;
57 	sigemptyset(&emptyset);
58 	sigemptyset(&blockset);
59 	sigaddset(&blockset, SIGWINCH);
60 	sigprocmask(SIG_BLOCK, &blockset, NULL);
61 
62 	client.need_resize = true;
63 	Packet pkt = {
64 		.type = MSG_ATTACH,
65 		.u.i = client.flags,
66 		.len = sizeof(pkt.u.i),
67 	};
68 	client_send_packet(&pkt);
69 
70 	while (server.running) {
71 		fd_set fds;
72 		FD_ZERO(&fds);
73 		FD_SET(STDIN_FILENO, &fds);
74 		FD_SET(server.socket, &fds);
75 
76 		if (client.need_resize) {
77 			struct winsize ws;
78 			if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) != -1) {
79 				Packet pkt = {
80 					.type = MSG_RESIZE,
81 					.u = { .ws = ws },
82 					.len = sizeof(ws),
83 				};
84 				if (client_send_packet(&pkt))
85 					client.need_resize = false;
86 			}
87 		}
88 
89 		if (pselect(server.socket+1, &fds, NULL, NULL, NULL, &emptyset) == -1) {
90 			if (errno == EINTR)
91 				continue;
92 			die("client-mainloop");
93 		}
94 
95 		if (FD_ISSET(server.socket, &fds)) {
96 			Packet pkt;
97 			if (client_recv_packet(&pkt)) {
98 				switch (pkt.type) {
99 				case MSG_CONTENT:
100 					write_all(STDOUT_FILENO, pkt.u.msg, pkt.len);
101 					break;
102 				case MSG_RESIZE:
103 					client.need_resize = true;
104 					break;
105 				case MSG_EXIT:
106 					client_send_packet(&pkt);
107 					close(server.socket);
108 					return pkt.u.i;
109 				}
110 			}
111 		}
112 
113 		if (FD_ISSET(STDIN_FILENO, &fds)) {
114 			Packet pkt = { .type = MSG_CONTENT };
115 			ssize_t len = read(STDIN_FILENO, pkt.u.msg, sizeof(pkt.u.msg));
116 			if (len == -1 && errno != EAGAIN && errno != EINTR)
117 				die("client-stdin");
118 			if (len > 0) {
119 				debug("client-stdin: %c\n", pkt.u.msg[0]);
120 				pkt.len = len;
121 				if (KEY_REDRAW && pkt.u.msg[0] == KEY_REDRAW) {
122 					client.need_resize = true;
123 				} else if (pkt.u.msg[0] == KEY_DETACH) {
124 					pkt.type = MSG_DETACH;
125 					pkt.len = 0;
126 					client_send_packet(&pkt);
127 					close(server.socket);
128 					return -1;
129 				} else if (!(client.flags & CLIENT_READONLY)) {
130 					client_send_packet(&pkt);
131 				}
132 			}
133 		}
134 	}
135 
136 	return -EIO;
137 }
138