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 Peter Unold 1992                           *
25 *                    recoded by Igor van den Hoven 2004                       *
26 ******************************************************************************/
27 
28 #include "tintin.h"
29 
30 #include <signal.h>
31 
32 #ifdef HAVE_SYS_STAT_H
33 #include <sys/stat.h>
34 #endif
35 
36 /*************** globals ******************/
37 
38 struct session *gts;
39 struct tintin_data *gtd;
40 
pipe_handler(int signal)41 void pipe_handler(int signal)
42 {
43 	syserr_printf(gtd->ses, "pipe_handler");
44 }
45 
xfsz_handler(int signal)46 void xfsz_handler(int signal)
47 {
48 	syserr_printf(gtd->ses, "xfsz_handler");
49 }
50 
hub_handler(int signal)51 void hub_handler(int signal)
52 {
53 	syserr_printf(gtd->ses, "hub_handler");
54 }
55 
ttin_handler(int signal)56 void ttin_handler(int signal)
57 {
58 	syserr_printf(gtd->ses, "ttin_handler");
59 }
60 
ttou_handler(int signal)61 void ttou_handler(int signal)
62 {
63 	syserr_printf(gtd->ses, "ttou_handler");
64 }
65 
usr_handler(int signal)66 void usr_handler(int signal)
67 {
68 	check_all_events(gts, EVENT_FLAG_SYSTEM, 0, 1, "SIGUSR", signal == SIGUSR1 ? "1" : "2");
69 }
70 
71 /*
72 	when the screen size changes, take note of it
73 */
74 
winch_handler(int signal)75 void winch_handler(int signal)
76 {
77 	SET_BIT(gtd->flags, TINTIN_FLAG_WINCHUPDATE);
78 
79 	gtd->time_session = gtd->time;
80 }
81 
82 
abort_handler(int signal)83 void abort_handler(int signal)
84 {
85 	syserr_fatal(signal, "abort_handler");
86 }
87 
child_handler(int signal)88 void child_handler(int signal)
89 {
90 	return;
91 
92 	syserr_printf(gtd->ses, "child_handler");
93 }
94 /*
95 void interrupt_handler(int signal)
96 {
97 	if (gtd->ses->connect_retry > utime())
98 	{
99 		gtd->ses->connect_retry = 0;
100 	}
101 	else if (HAS_BIT(gtd->ses->telopts, TELOPT_FLAG_SGA) && !HAS_BIT(gtd->ses->telopts, TELOPT_FLAG_ECHO))
102 	{
103 		socket_printf(gtd->ses, 1, "\004");
104 	}
105 	else if (gtd->attach_sock)
106 	{
107 		gtd->attach_sock = close(gtd->attach_sock);
108 
109 		show_message(gtd->ses, LIST_COMMAND, "#REDETACHING PROCESS TO {%s}", gtd->attach_file);
110 	}
111 	else
112 	{
113 		cursor_delete_or_exit(gtd->ses, "");
114 	}
115 }
116 */
suspend_handler(int signal)117 void suspend_handler(int signal)
118 {
119 	show_message(gtd->ses, LIST_COMMAND, "#SIGNAL: SIGTSTP");
120 
121 	if (gtd->attach_sock)
122 	{
123 		show_message(gtd->ses, LIST_COMMAND, "#DAEMON {%s} WANTS TO DETACH.", gtd->attach_file);
124 
125 		gtd->attach_sock = close(gtd->attach_sock);
126 
127 		return;
128 	}
129 }
130 
trap_handler(int signal)131 void trap_handler(int signal)
132 {
133 	syserr_fatal(signal, "trap_handler");
134 }
135 
136 
137 /****************************************************************************/
138 /* main() - show title - setup signals - init lists - readcoms - mainloop() */
139 /****************************************************************************/
140 
141 
main(int argc,char ** argv)142 int main(int argc, char **argv)
143 {
144 	int c, i = 0, greeting = 0;
145 
146 	char arg[BUFFER_SIZE];
147 
148 	#ifdef SOCKS
149 		SOCKSinit(argv[0]);
150 	#endif
151 
152 	if (signal(SIGTERM, trap_handler) == BADSIG)
153 	{
154 		syserr_fatal(-1, "signal SIGTERM");
155 	}
156 
157 	if (signal(SIGSEGV, trap_handler) == BADSIG)
158 	{
159 		syserr_fatal(-1, "signal SIGSEGV");
160 	}
161 
162 	if (signal(SIGHUP, trap_handler) == BADSIG)
163 	{
164 		syserr_fatal(-1, "signal SIGHUP");
165 	}
166 
167 	if (signal(SIGABRT, abort_handler) == BADSIG)
168 	{
169 		syserr_fatal(-1, "signal SIGTERM");
170 	}
171 
172 /*	if (signal(SIGCHLD, child_handler) == BADSIG)
173 	{
174 		syserr_fatal(-1, "signal SIGCHLD");
175 	}
176 */
177 /*
178 	if (signal(SIGINT, interrupt_handler) == BADSIG)
179 	{
180 		syserr_fatal(-1, "signal SIGINT");
181 	}
182 */
183 
184 	if (signal(SIGTSTP, suspend_handler) == BADSIG)
185 	{
186 		syserr_fatal(-1, "signal SIGTSTP");
187 	}
188 /*
189 	if (signal(SIGPIPE, pipe_handler) == BADSIG)
190 	{
191 		syserr_fatal(-1, "signal SIGPIPE");
192 	}
193 
194 	if (signal(SIGXFSZ, xfsz_handler) == BADSIG)
195 	{
196 		syserr_fatal(-1, "signal SIGXFSZ");
197 	}
198 
199 	if (signal(SIGHUP, hub_handler) == BADSIG)
200 	{
201 		syserr_fatal(-1, "signal SIGHUP");
202 	}
203 
204 	if (signal(SIGTTIN, hub_handler) == BADSIG)
205 	{
206 		syserr_fatal(-1, "signal SIGTTIN");
207 	}
208 
209 	if (signal(SIGTTOU, hub_handler) == BADSIG)
210 	{
211 		syserr_fatal(-1, "signal SIGTTOU");
212 	}
213 */
214 	if (signal(SIGUSR1, usr_handler) == BADSIG)
215 	{
216 		syserr_fatal(-1, "signal SIGUSR1");
217 	}
218 
219 	if (signal(SIGUSR2, usr_handler) == BADSIG)
220 	{
221 		syserr_fatal(-1, "signal SIGUSR1");
222 	}
223 
224 	if (signal(SIGWINCH, winch_handler) == BADSIG)
225 	{
226 		syserr_fatal(-1, "signal SIGWINCH");
227 	}
228 
229 	signal(SIGPIPE, SIG_IGN);
230 
231 	for (c = 0 ; c < argc ; c++)
232 	{
233 		if (c)
234 		{
235 			cat_sprintf(arg, " %s", argv[c]);
236 		}
237 		{
238 			strcpy(arg, argv[0]);
239 		}
240 	}
241 
242 	if (argc > 1)
243 	{
244 		while ((c = getopt(argc, argv, "a: e: g G h M:: r: R:: s t: T v V")) != EOF)
245 		{
246 			switch (c)
247 			{
248 				case 'h':
249 					printf("Usage: %s [OPTION]... [FILE]...\n", argv[0]);
250 					printf("\n");
251 					printf("  -a  Set argument for PROGRAM START event.\n");
252 					printf("  -e  Execute given command.\n");
253 					printf("  -g  Enable the startup user interface.\n");
254 					printf("  -G  Don't show the greeting screen.\n");
255 					printf("  -h  This help section.\n");
256 					printf("  -M  Matrix Digital Rain.\n");
257 					printf("  -r  Read given file.\n");
258 					printf("  -R  Reattach to daemonized process.\n");
259 					printf("  -s  Enable screen reader mode.\n");
260 					printf("  -t  Set given title.\n");
261 					printf("  -T  Don't set the default title.\n");
262 					printf("  -v  Enable verbose mode.\n");
263 					printf("  -V  Show version information.\n");
264 
265 					exit(1);
266 
267 				case 'M':
268 				case 'G':
269 					SET_BIT(greeting, STARTUP_FLAG_NOGREETING);
270 					break;
271 
272 				case 's':
273 					SET_BIT(greeting, STARTUP_FLAG_SCREENREADER);
274 					break;
275 
276 				case 'v':
277 					SET_BIT(greeting, STARTUP_FLAG_VERBOSE);
278 					break;
279 
280 				case 'V':
281 					printf("\nTinTin++ " CLIENT_VERSION "\n");
282 					printf("\n(C) 2004-2019 Igor van den Hoven\n");
283 					printf("\nLicense GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n\n");
284 					exit(1);
285 			}
286 		}
287 	}
288 
289 	init_tintin(greeting);
290 
291 
292 	RESTRING(gtd->vars[1], argv[0]);
293 
294 	if (argc > 1)
295 	{
296 		optind = 1;
297 
298 		RESTRING(gtd->vars[2], argv[1]);
299 
300 		while ((c = getopt(argc, argv, "a: e: g G h M:: r: R:: s t: T v")) != EOF)
301 		{
302 			switch (c)
303 			{
304 				case 'a':
305 					RESTRING(gtd->vars[0], argv[2]);
306 					SET_BIT(greeting, STARTUP_FLAG_ARGUMENT);
307 					break;
308 
309 				case 'e':
310 					gtd->level->input++;
311 					gtd->ses = script_driver(gtd->ses, LIST_COMMAND, optarg);
312 					gtd->level->input--;
313 					break;
314 
315 				case 'g':
316 					gtd->ses = command(gtd->ses, do_banner, "gui");
317 					break;
318 
319 				case 'G':
320 					break;
321 
322 				case 'M':
323 					command(gts, do_test, "rain %s", optarg ? optarg : "");
324 					break;
325 
326 				case 'r':
327 //					gtd->level->input++;
328 					gtd->ses = command(gtd->ses, do_read, "%s", optarg);
329 //					gtd->level->input--;
330 					break;
331 
332 				case 'R':
333 					SET_BIT(gtd->flags, TINTIN_FLAG_DAEMONIZE);
334 					command(gtd->ses, do_daemon, "attach {%s}", optarg ? optarg : "");
335 					break;
336 
337 				case 's':
338 					break;
339 
340 				case 't':
341 					SET_BIT(greeting, STARTUP_FLAG_NOTITLE);
342 					print_stdout(0, 0, "\e]0;%s\007", optarg);
343 					break;
344 
345 				case 'T':
346 					SET_BIT(greeting, STARTUP_FLAG_NOTITLE);
347 					break;
348 
349 				case 'v':
350 //					do_configure(gtd->ses, "{VERBOSE} {ON}");
351 					break;
352 
353 				default:
354 //					tintin_printf2(NULL, "Unknown option '%c'.", c);
355 					break;;
356 			}
357 		}
358 	}
359 
360 	if (!HAS_BIT(greeting, STARTUP_FLAG_NOTITLE))
361 	{
362 		command(gts, do_screen, "LOAD BOTH");
363 		command(gts, do_screen, "SAVE BOTH");
364 		command(gts, do_screen, "SET BOTH TinTin++");
365 	}
366 
367 	gtd->system->exec = strdup(argv[0]);
368 
369 	if (argc > 2)
370 	{
371 		RESTRING(gtd->vars[3], argv[2]);
372 
373 		for (i = 3 ; i <= optind ; i++)
374 		{
375 			RESTRING(gtd->vars[i+1], argv[i] ? argv[i] : "");
376 		}
377 
378 		arg[0] = 0;
379 
380 		for (i = optind + 1 ; i < argc ; i++)
381 		{
382 			if (*arg)
383 			{
384 				strcat(arg, " ");
385 			}
386 			strcat(arg, argv[i]);
387 
388 			if (i < 100)
389 			{
390 				RESTRING(gtd->vars[i+1], argv[i]);
391 			}
392 		}
393 
394 		if (!HAS_BIT(greeting, STARTUP_FLAG_ARGUMENT))
395 		{
396 			RESTRING(gtd->vars[0], arg);
397 		}
398 	}
399 
400 	if (argv[optind] != NULL)
401 	{
402 		if (!strncasecmp(argv[optind], "telnet://", 9))
403 		{
404 			gtd->ses = command(gtd->ses, do_session, "%s", argv[optind]);
405 		}
406 		else
407 		{
408 			gtd->level->input++;
409 
410 			gtd->ses = command(gtd->ses, do_read, "%s", argv[optind]);
411 
412 			gtd->level->input--;
413 		}
414 	}
415 
416 	check_all_events(gts, EVENT_FLAG_SYSTEM, 0, 0, "PROGRAM START");
417 
418 	mainloop();
419 
420 	return 0;
421 }
422 
init_tintin(int greeting)423 void init_tintin(int greeting)
424 {
425 	char filename[PATH_SIZE];
426 	int index;
427 
428 	gtd                 = (struct tintin_data *) calloc(1, sizeof(struct tintin_data));
429 
430 	init_memory();
431 
432 	push_call("init_tintin(%d)",greeting);
433 
434 	gtd->level          = (struct level_data *) calloc(1, sizeof(struct level_data));
435 
436 	gtd->buf            = str_alloc(BUFFER_SIZE);
437 	gtd->out            = str_alloc(BUFFER_SIZE);
438 
439 	gtd->flags          = TINTIN_FLAG_INHERITANCE;
440 
441 	gtd->mccp_len       = 10000;
442 	gtd->mccp_buf       = (unsigned char *) calloc(1, gtd->mccp_len);
443 
444 	gtd->mud_output_max = 16384;
445 	gtd->mud_output_buf = (char *) calloc(1, gtd->mud_output_max);
446 
447 	// WSL: /proc/sys/kernel/osrelease
448 
449 	gtd->system         = (struct system_data *) calloc(1, sizeof(struct system_data));
450 
451 	gtd->system->os     = strdup(getenv("OS")   ? getenv("OS")   : "UNKNOWN");
452 	gtd->system->home   = strdup(getenv("HOME") ? getenv("HOME") : "~/");
453 	gtd->system->lang   = strdup(getenv("LANG") ? getenv("LANG") : "UNKNOWN");
454 	gtd->system->term   = strdup(getenv("TERM") ? getenv("TERM") : "UNKNOWN");
455 
456 	gtd->system->tt_dir = restringf(gtd->system->tt_dir, "%s/%s", gtd->system->home, TINTIN_DIR);
457 
458 	if (mkdir(gtd->system->tt_dir, 0755) && errno != EEXIST)
459 	{
460 		gtd->system->tt_dir = restringf(gtd->system->tt_dir, "%s", TINTIN_DIR);
461 
462 		mkdir(gtd->system->tt_dir, 0755);
463 	}
464 
465 	gtd->detach_file    = strdup("");
466 	gtd->attach_file    = strdup("");
467 
468 	gtd->tintin_char    = '#';
469 
470 	gtd->time           = time(NULL);
471 	gtd->utime          = utime();
472 
473 	for (index = 0 ; index < 100 ; index++)
474 	{
475 		gtd->vars[index] = strdup("");
476 		gtd->cmds[index] = strdup("");
477 	}
478 
479 	for (index = 1 ; index ; index++)
480 	{
481 		if (*event_table[index].name == 0)
482 		{
483 			break;
484 		}
485 
486 		if (strcmp(event_table[index - 1].name, event_table[index].name) > 0)
487 		{
488 			print_stdout(0, 0, "\e[1;31minit_tintin() unsorted event table %s vs %s.", event_table[index - 1].name, event_table[index].name);
489 
490 			break;
491 		}
492 	}
493 
494 	init_commands();
495 
496 	gtd->screen = calloc(1, sizeof(struct screen_data));
497 
498 	gtd->screen->rows   = SCREEN_HEIGHT;
499 	gtd->screen->cols   = SCREEN_WIDTH;
500 	gtd->screen->height = SCREEN_HEIGHT * 16;
501 	gtd->screen->width  = SCREEN_WIDTH * 10;
502 	gtd->screen->focus  = 1;
503 
504 	gtd->dispose_list   = init_list(NULL, 0, 32);
505 
506 	init_msdp_table();
507 
508 	// global tintin session
509 
510 	gts = (struct session *) calloc(1, sizeof(struct session));
511 
512 	gts->created        = gtd->time;
513 	gts->name           = strdup("gts");
514 	gts->group          = strdup("");
515 	gts->session_host   = strdup("");
516 	gts->session_ip     = strdup("");
517 	gts->session_port   = strdup("");
518 	gts->cmd_color      = strdup("");
519 	gts->telopts        = TELOPT_FLAG_ECHO;
520 	gts->config_flags   = CONFIG_FLAG_MCCP;
521 	gts->socket         = 1;
522 	gts->read_max       = 16384;
523 
524 	gts->more_output    = str_dup("");
525 
526 	gtd->ses = gts;
527 
528 	for (index = 0 ; index < LIST_MAX ; index++)
529 	{
530 		gts->list[index] = init_list(gts, index, 32);
531 	}
532 
533 	gtd->banner_list    = init_list(gts, LIST_CONFIG, 32);
534 
535 	gts->log            = calloc(1, sizeof(struct log_data));
536 	gts->input          = calloc(1, sizeof(struct input_data));
537 	gts->scroll         = calloc(1, sizeof(struct scroll_data));
538 	gts->split          = calloc(1, sizeof(struct split_data));
539 
540 	init_local(gts);
541 
542 	init_terminal_size(gts);
543 
544 	init_log(gts);
545 
546 	init_input(gts, 0, 0, 0, 0);
547 
548 	init_buffer(gts, 10000);
549 
550 	if (HAS_BIT(greeting,  STARTUP_FLAG_VERBOSE))
551 	{
552 		gtd->level->verbose++;
553 	}
554 
555 	gtd->level->input++;
556 
557 	command(gts, do_configure, "{AUTO TAB}         {5000}");
558 	command(gts, do_configure, "{BUFFER SIZE}     {10000}");
559 	command(gts, do_configure, "{COLOR MODE}         {ON}");
560 	command(gts, do_configure, "{COLOR PATCH}       {OFF}");
561 	command(gts, do_configure, "{COMMAND COLOR}   {<078>}");
562 	command(gts, do_configure, "{COMMAND ECHO}       {ON}");
563 	command(gts, do_configure, "{CONNECT RETRY}       {0}");
564 	command(gts, do_configure, "{CHARSET}          {AUTO}");
565 	command(gts, do_configure, "{HISTORY SIZE}     {1000}");
566 	command(gts, do_configure, "{LOG MODE}          {RAW}");
567 	command(gts, do_configure, "{MOUSE}             {OFF}");
568 	command(gts, do_configure, "{PACKET PATCH}     {AUTO}");
569 	command(gts, do_configure, "{RANDOM SEED}      {AUTO}");
570 	command(gts, do_configure, "{REPEAT CHAR}         {!}");
571 	command(gts, do_configure, "{REPEAT ENTER}      {OFF}");
572 	command(gts, do_configure, "{SCREEN READER}      {%s}", HAS_BIT(greeting, STARTUP_FLAG_SCREENREADER) ? "ON" : "OFF");
573 	command(gts, do_configure, "{SCROLL LOCK}        {ON}");
574 	command(gts, do_configure, "{SPEEDWALK}         {OFF}");
575 	command(gts, do_configure, "{TAB WIDTH}        {AUTO}");
576 	command(gts, do_configure, "{TELNET}             {ON}");
577 	command(gts, do_configure, "{TINTIN CHAR}         {#}");
578 	command(gts, do_configure, "{VERBATIM}          {OFF}");
579 	command(gts, do_configure, "{VERBATIM CHAR}      {\\}");
580 	command(gts, do_configure, "{VERBOSE}            {%s}", HAS_BIT(greeting, STARTUP_FLAG_VERBOSE) ? "ON" : "OFF");
581 	command(gts, do_configure, "{WORDWRAP}           {ON}");
582 
583 	command(gts, do_pathdir, " n  s  1");
584 	command(gts, do_pathdir, " e  w  2");
585 	command(gts, do_pathdir, " s  n  4");
586 	command(gts, do_pathdir, " w  e  8");
587 	command(gts, do_pathdir, " u  d 16");
588 	command(gts, do_pathdir, " d  u 32");
589 	command(gts, do_pathdir, "ne sw  3");
590 	command(gts, do_pathdir, "nw se  9");
591 	command(gts, do_pathdir, "se nw  6");
592 	command(gts, do_pathdir, "sw ne 12");
593 
594 	sprintf(filename, "%s/%s", gtd->system->tt_dir, HISTORY_FILE);
595 
596 	if (access(filename, F_OK ) != -1)
597 	{
598 		command(gts, do_history, "read %s", filename);
599 	}
600 
601 	gtd->level->input--;
602 
603 	if (HAS_BIT(greeting,  STARTUP_FLAG_VERBOSE))
604 	{
605 		gtd->level->verbose--;
606 	}
607 
608 	init_terminal(gts);
609 
610 	reset_screen(gts);
611 
612 	command(gts, do_banner, "INIT");
613 
614 	if (!HAS_BIT(greeting, STARTUP_FLAG_NOGREETING))
615 	{
616 		if (HAS_BIT(greeting, STARTUP_FLAG_SCREENREADER))
617 		{
618 			tintin_printf2(gts, "Welcome to TinTin Plus Plus. Don't know which MUD to play? How about the following MUD.");
619 
620 			command(gts, do_banner, "RANDOM");
621 
622 			tintin_printf2(gts, "You're using TinTin Plus Plus version %s written by Peter Unold, Bill Reis, and Igor van den Hoven.", CLIENT_VERSION);
623 
624 			tintin_printf2(gts, "");
625 
626 			tintin_printf2(gts, "For help and requests visit the Discord channel at https://discord.gg/gv7a37n");
627 		}
628 		else
629 		{
630 			command(gts, do_banner, "RANDOM");
631 
632 			if (gtd->screen->cols >= 80)
633 			{
634 				command(gts, do_help, "GREETING");
635 			}
636 			else
637 			{
638 				tintin_printf2(gts, "\e[0;37mT I N T I N + +   %s", CLIENT_VERSION);
639 
640 				tintin_printf2(gts, "");
641 
642 //				tintin_printf2(gts, "\e[0;36mT\e[0;37mhe K\e[0;36mi\e[0;37mcki\e[0;36mn\e[0;37m \e[0;36mT\e[0;37mickin D\e[0;36mi\e[0;37mkuMUD Clie\e[0;36mn\e[0;37mt");
643 
644 				tintin_printf2(gts, "Code by Peter Unold, Bill Reis, and Igor van den Hoven");
645 			}
646 		}
647 	}
648 	pop_call();
649 	return;
650 }
651 
652 
quitmsg(char * message)653 void quitmsg(char *message)
654 {
655 	struct session *ses;
656 	static char crashed = FALSE;
657 
658 	if (crashed++)
659 	{
660 		print_stdout(0, 0, "quitmsg(crashed)\n");
661 
662 		fflush(NULL);
663 
664 		exit(-1);
665 	}
666 
667 	SET_BIT(gtd->flags, TINTIN_FLAG_TERMINATE);
668 
669 	for (ses = gts->next ; ses ; ses = gts->next)
670 	{
671 		cleanup_session(ses);
672 	}
673 
674 	if (gtd->chat)
675 	{
676 		chat_uninitialize("", "");
677 	}
678 
679 	check_all_events(gts, EVENT_FLAG_SYSTEM, 0, 1, "PROGRAM TERMINATION", message ? message : "");
680 
681 	if (gtd->history_size)
682 	{
683 		command(gts, do_history, "write %s/%s", gtd->system->tt_dir, HISTORY_FILE);
684 	}
685 
686 	reset_daemon();
687 
688 	reset_terminal(gts);
689 
690 	reset_screen(gts);
691 
692 	if (message == NULL || *message)
693 	{
694 		if (message)
695 		{
696 			print_stdout(0, 0, "\n\e[0m%s", message);
697 		}
698 		print_stdout(0, 0, "\nGoodbye from TinTin++\n\n");
699 	}
700 	fflush(stdout);
701 
702 	exit(0);
703 }
704 
syserr_printf(struct session * ses,char * fmt,...)705 void syserr_printf(struct session *ses, char *fmt, ...)
706 {
707 	char buf[BUFFER_SIZE], name[BUFFER_SIZE], *errstr;
708 
709 	errstr = strerror(errno);
710 
711 	va_list args;
712 
713 	va_start(args, fmt);
714 	vsprintf(buf, fmt, args);
715 	va_end(args);
716 
717 	if (ses)
718 	{
719 		sprintf(name, "(%s)", ses->name);
720 	}
721 	else
722 	{
723 		sprintf(name, "(null)");
724 	}
725 
726 	check_all_events(ses, SUB_SEC|EVENT_FLAG_SYSTEM, 0, 4, "SYSTEM ERROR", name, buf, ntos(errno), errstr);
727 
728 	if (!check_all_events(ses, SUB_SEC|EVENT_FLAG_SYSTEM, 0, 4, "CATCH SYSTEM ERROR", name, buf, ntos(errno), errstr))
729 	{
730 		if (gts)
731 		{
732 			tintin_printf2(gts, "#SYSTEM ERROR %s %s (%d: %s)\e[0m", name, buf, errno, errstr);
733 		}
734 
735 		if (ses && ses != gts)
736 		{
737 			tintin_printf2(ses, "#SYSTEM ERROR: %s %s (%d: %s)\e[0m", name, buf, errno, errstr);
738 		}
739 
740 		if (ses && gtd->ses != ses && gtd->ses != gts)
741 		{
742 			tintin_printf2(gtd->ses, "#SYSTEM ERROR: %s %s (%d: %s)\e[0m", name, buf, errno, errstr);
743 		}
744 	}
745 }
746 
syserr_signal(int signal,char * msg)747 void syserr_signal(int signal, char *msg)
748 {
749 	char buf[256];
750 	static char crashed = FALSE;
751 
752 	if (crashed++)
753 	{
754 		print_stdout(0, 0, "syserr_signal(crashed)\n");
755 
756 		fflush(NULL);
757 
758 		exit(-1);
759 	}
760 
761 	reset_terminal(gts);
762 
763 	reset_screen(gts);
764 
765 	fflush(NULL);
766 
767 	dump_stack();
768 
769 	sprintf(buf, "\e[1;31mFATAL SIGNAL FROM (%s): %s\e[0m\n", msg, strsignal(signal));
770 
771 	print_stdout(0, 0, "%s", buf);
772 
773 	fflush(NULL);
774 
775 	abort();
776 }
777 
syserr_fatal(int signal,char * msg)778 void syserr_fatal(int signal, char *msg)
779 {
780 	char buf[256], errstr[128];
781 	static char crashed = FALSE;
782 
783 	if (crashed++)
784 	{
785 		print_stdout(0, 0, "syserr_fatal(crashed)");
786 
787 		fflush(NULL);
788 
789 		exit(-1);
790 	}
791 
792 	if (signal == SIGHUP)
793 	{
794 		crashed--;
795 
796 		check_all_events(gts, SUB_SEC|EVENT_FLAG_SYSTEM, 0, 0, "SIGHUB");
797 
798 		crashed++;
799 	}
800 
801 	if (signal <= 0)
802 	{
803 		sprintf(errstr, "(error %d: %s", errno, strerror(errno));
804 	}
805 	else
806 	{
807 		sprintf(errstr, "(signal %d: %s)", signal, strsignal(signal));
808 	}
809 
810 	check_all_events(NULL, SUB_SEC|EVENT_FLAG_SYSTEM, 0, 1, "SYSTEM CRASH", errstr);
811 
812 	if (gtd->level->quiet)
813 	{
814 		gtd->level->quiet = 0;
815 	}
816 
817 	reset_terminal(gts);
818 
819 	reset_screen(gts);
820 
821 	print_stdout(0, 0, "\e[?1049l\e[r");
822 
823 	dump_stack();
824 
825 	sprintf(buf, "\n\e[1;31mFATAL ERROR \e[1;32m%s %s\e[0m\n", msg, errstr);
826 
827 	print_stdout(0, 0, "%s", buf);
828 
829 	reset_daemon();
830 
831 	fflush(NULL);
832 
833 	abort();
834 }
835