1 /******************************************************************************
2 *   This file is part of TinTin++                                             *
3 *                                                                             *
4 *   Copyright 2004-2019 Igor van den Hoven                                    *
5 *                                                                             *
6 *   TinTin++ is free software; you can redistribute it and/or modify          *
7 *   it under the terms of the GNU General Public License as published by      *
8 *   the Free Software Foundation; either version 3 of the License, or         *
9 *   (at your option) any later version.                                       *
10 *                                                                             *
11 *   This program is distributed in the hope that it will be useful,           *
12 *   but WITHOUT ANY WARRANTY; without even the implied warranty of            *
13 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
14 *   GNU General Public License for more details.                              *
15 *                                                                             *
16 *                                                                             *
17 *   You should have received a copy of the GNU General Public License         *
18 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
19 ******************************************************************************/
20 
21 /******************************************************************************
22 *               (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t                  *
23 *                                                                             *
24 *                     coded by Igor van den Hoven 2007                        *
25 ******************************************************************************/
26 
27 #include "tintin.h"
28 
29 #ifdef HAVE_PTY_H
30 #include <pty.h>
31 #else
32 #ifdef HAVE_UTIL_H
33 #include <util.h>
34 #endif
35 #endif
36 #include <fcntl.h>
37 #include <dirent.h>
38 #include <termios.h>
39 #include <sys/un.h>
40 #include <sys/wait.h>
41 #include <signal.h>
42 
DO_COMMAND(do_run)43 DO_COMMAND(do_run)
44 {
45 	char temp[BUFFER_SIZE];
46 	int desc, pid;
47 	struct winsize size;
48 
49 	char *argv[4] = {"sh", "-c", "", NULL};
50 
51 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
52 	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
53 	arg = sub_arg_in_braces(ses, arg, arg3, GET_ONE, SUB_VAR|SUB_FUN);
54 
55 	if (*arg1 == 0 || *arg2 == 0)
56 	{
57 		show_error(ses, LIST_COMMAND, "#SYNTAX: #RUN {NAME} {SYSTEM SHELL COMMAND}");
58 
59 		return ses;
60 	}
61 
62 	size.ws_row = get_scroll_rows(ses);
63 	size.ws_col = get_scroll_cols(ses);
64 	size.ws_ypixel = size.ws_row * gtd->screen->char_height;
65 	size.ws_xpixel = size.ws_col * gtd->screen->char_width;
66 
67 	pid = forkpty(&desc, temp, &gtd->old_terminal, &size);
68 
69 	switch (pid)
70 	{
71 		case -1:
72 			syserr_printf(ses, "do_run: forkpty");
73 			break;
74 
75 		case 0:
76 			sprintf(temp, "exec %s", arg2);
77 			argv[2] = temp;
78 			execv("/bin/sh", argv);
79 			break;
80 
81 		default:
82 /*
83 			if (fcntl(desc, F_SETFD, FD_CLOEXEC) == -1)
84 			{
85 				syserr_printf(ses, "do_run: fcntl");
86 			}
87 */
88 			sprintf(temp, "{%s} {%d} {%s}", arg2, pid, arg3);
89 			ses = new_session(ses, arg1, temp, desc, 0);
90 			break;
91 	}
92 	return ses;
93 }
94 
95 
DO_COMMAND(do_script)96 DO_COMMAND(do_script)
97 {
98 	char *cptr, buf[BUFFER_SIZE], var[BUFFER_SIZE], tmp[BUFFER_SIZE];
99 	FILE *script;
100 	int index;
101 
102 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
103 	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
104 
105 	if (*arg1 == 0)
106 	{
107 		show_error(ses, LIST_COMMAND, "#SCRIPT: ONE ARGUMENT REQUIRED.");
108 	}
109 	else if (*arg2 == 0)
110 	{
111 		script = popen(arg1, "r");
112 
113 		if (script)
114 		{
115 			while (fgets(buf, BUFFER_SIZE - 1, script))
116 			{
117 				cptr = strchr(buf, '\n');
118 
119 				if (cptr)
120 				{
121 					*cptr = 0;
122 				}
123 
124 				ses = script_driver(ses, LIST_COMMAND, buf);
125 			}
126 
127 			pclose(script);
128 		}
129 		else
130 		{
131 			syserr_printf(ses, "do_script: popen 1");
132 		}
133 	}
134 	else
135 	{
136 		index = 1;
137 
138 		script = popen(arg2, "r");
139 
140 		if (script)
141 		{
142 			var[0] = 0;
143 
144 			while (fgets(buf, BUFFER_SIZE - 1, script))
145 			{
146 				cptr = strchr(buf, '\n');
147 
148 				if (cptr)
149 				{
150 					*cptr = 0;
151 				}
152 
153 				substitute(ses, buf, tmp, SUB_SEC);
154 
155 				cat_sprintf(var, "{%d}{%s}", index++, tmp);
156 			}
157 
158 			set_nest_node_ses(ses, arg1, "%s", var);
159 
160 			pclose(script);
161 		}
162 		else
163 		{
164 			syserr_printf(ses, "do_script: popen 2");
165 		}
166 	}
167 	refresh_session_terminal(ses);
168 
169 	return ses;
170 }
171 
172 
DO_COMMAND(do_suspend)173 DO_COMMAND(do_suspend)
174 {
175 	print_stdout(0, 0, "\e[?1049l\e[r\e[%d;%dH", gtd->screen->rows, 1);
176 
177 	fflush(NULL);
178 
179 	reset_terminal(gtd->ses);
180 
181 	kill(0, SIGSTOP);
182 
183 	init_terminal(gtd->ses);
184 
185 	dirty_screen(gtd->ses);
186 
187 	tintin_printf(gtd->ses, "#RETURNING BACK TO TINTIN++.");
188 
189 	return ses;
190 }
191 
192 // use #run + waitpid() ?
193 
194 /*
195 DO_COMMAND(do_system)
196 {
197 	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE], temp[BUFFER_SIZE], buffer[BUFFER_SIZE];
198 	int desc, pid;
199 	struct winsize size;
200 	char *argv[4] = {"sh", "-c", "", NULL};
201 	int filedes[2];
202 
203 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
204 
205 	if (*arg1 == 0)
206 	{
207 		show_error(ses, LIST_COMMAND, "#SYNTAX: #SYSTEM {SHELL COMMAND}");
208 
209 		return ses;
210 	}
211 
212 	size.ws_row = get_scroll_rows(ses);
213 	size.ws_col = get_scroll_cols(ses);
214 	size.ws_ypixel = size.ws_row * gtd->screen->char_height;
215 	size.ws_xpixel = size.ws_col * gtd->screen->char_width;
216 
217 	if (pipe(filedes) == -1)
218 	{
219 		perror("pipe");
220 
221 		return ses;
222 	}
223 
224 	pid = fork();
225 
226 	switch (pid)
227 	{
228 		case -1:
229 			syserr_printf(ses, "do_system: forkpty");
230 			break;
231 
232 		case 0:
233 			while ((dup2(filedes[1], STDOUT_FILENO) == -1) && (errno == EINTR)) {}
234 			close(filedes[1]);
235 			close(filedes[0]);
236 
237 			sprintf(temp, "exec %s", arg1);
238 			argv[2] = temp;
239 			execv("/bin/sh", argv);
240 			perror("execv");
241 			break;
242 
243 		default:
244 			close(filedes[1]);
245 
246 			while (TRUE)
247 			{
248 				ssize_t count = read(filedes[0], buffer, sizeof(buffer));
249 
250 				if (count == -1)
251 				{
252 					if (errno == EINTR)
253 					{
254 						continue;
255 					}
256 					else
257 					{
258 						perror("read");
259 					}
260 					return ses;
261 				}
262 				else if (count == 0)
263 				{
264 					break;
265 				}
266 				else
267 				{
268 					tintin_printf2(ses, "%s", buffer);
269 				}
270 			}
271 			close(filedes[0]);
272 			wait(0);
273 			break;
274 	}
275 	return ses;
276 }
277 */
278 
DO_COMMAND(do_system)279 DO_COMMAND(do_system)
280 {
281 	sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
282 
283 	if (*arg1 == 0)
284 	{
285 		show_error(ses, LIST_COMMAND, "#SYNTAX: #SYSTEM {COMMAND}.");
286 
287 		return ses;
288 	}
289 
290 	show_message(ses, LIST_COMMAND, "#OK: EXECUTING '%s'", arg1);
291 
292 	if (!HAS_BIT(gtd->ses->flags, SES_FLAG_READMUD) && IS_SPLIT(gtd->ses))
293 	{
294 		save_pos(gtd->ses);
295 
296 		goto_pos(gtd->ses, gtd->ses->split->bot_row, 1);
297 	}
298 
299 	if (system(arg1) == -1)
300 	{
301 		syserr_printf(ses, "do_system: system:");
302 	}
303 
304 	if (!HAS_BIT(gtd->ses->flags, SES_FLAG_READMUD) && IS_SPLIT(gtd->ses))
305 	{
306 		restore_pos(gtd->ses);
307 	}
308 
309 	refresh_session_terminal(gtd->ses);
310 
311 	return ses;
312 }
313 
314 
DO_COMMAND(do_textin)315 DO_COMMAND(do_textin)
316 {
317 	FILE *fp;
318 	char buffer[BUFFER_SIZE], *cptr;
319 
320 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
321 	arg = get_arg_in_braces(ses, arg, arg2, GET_ALL);
322 
323 	if ((fp = fopen(arg1, "r")) == NULL)
324 	{
325 		show_error(ses, LIST_COMMAND, "#ERROR: #TEXTIN {%s} - FILE NOT FOUND.", arg1);
326 
327 		return ses;
328 	}
329 
330 	while (fgets(buffer, BUFFER_SIZE - 1, fp))
331 	{
332 		cptr = strchr(buffer, '\n');
333 
334 		if (cptr)
335 		{
336 			*cptr = 0;
337 		}
338 
339 		write_mud(ses, buffer, SUB_EOL);
340 
341 		if (*arg2)
342 		{
343 			usleep((long long) (get_number(ses, arg2) * 1000000));
344 		}
345 	}
346 	fclose(fp);
347 
348 	show_message(ses, LIST_COMMAND, "#TEXTIN {%s} - FILE READ.", arg1);
349 
350 	return ses;
351 }
352