/******************************************************************************
* TinTin++ *
* Copyright (C) 2004 (See CREDITS file) *
* *
* This program is protected under the GNU GPL (See COPYING) *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
*******************************************************************************/
/******************************************************************************
* (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t *
* *
* coded by Peter Unold 1992 *
******************************************************************************/
#include "tintin.h"
#include <signal.h>
#include <sys/socket.h>
/*************** globals ******************/
struct session *gts;
struct tintin_data *gtd;
void pipe_handler(int signal)
{
restore_terminal();
clean_screen(gtd->ses);
tintin_printf(NULL, "broken_pipe: dumping stack");
dump_stack();
}
/*
when the screen size changes, take note of it
*/
void winch_handler(int signal)
{
struct session *ses;
init_screen_size(gts);
for (ses = gts->next ; ses ; ses = ses->next)
{
init_screen_size(ses);
if (HAS_BIT(ses->telopts, TELOPT_FLAG_NAWS))
{
send_sb_naws(ses, 0, NULL);
}
}
/*
we have to reinitialize the signals for sysv machines
if (signal(SIGWINCH, winch_handler) == BADSIG)
{
syserr("signal SIGWINCH");
}
*/
}
void abort_handler(int signal)
{
static char crashed = FALSE;
if (crashed)
{
exit(-1);
}
crashed = TRUE;
restore_terminal();
clean_screen(gtd->ses);
dump_stack();
fflush(NULL);
exit(-1);
if (gtd->ses->connect_retry > utime())
{
gtd->ses->connect_retry = 0;
}
else if (HAS_BIT(gtd->ses->telopts, TELOPT_FLAG_SGA) && !HAS_BIT(gtd->ses->telopts, TELOPT_FLAG_ECHO))
{
socket_printf(gtd->ses, 1, "%c", 3);
}
else
{
do_zap(gtd->ses, "");
}
}
void suspend_handler(int signal)
{
printf("\033[r\033[%d;%dH", gtd->ses->rows, 1);
fflush(stdout);
restore_terminal();
kill(0, SIGSTOP);
dirty_screen(gtd->ses);
init_terminal();
tintin_puts(NULL, "#RETURNING BACK TO TINTIN++.");
}
void trap_handler(int signal)
{
static char crashed = FALSE;
if (crashed)
{
exit(-1);
}
crashed = TRUE;
restore_terminal();
clean_screen(gtd->ses);
dump_stack();
fflush(NULL);
exit(-1);
}
/****************************************************************************/
/* main() - show title - setup signals - init lists - readcoms - mainloop() */
/****************************************************************************/
int main(int argc, char **argv)
{
int greeting = TRUE;
#ifdef SOCKS
SOCKSinit(argv[0]);
#endif
if (signal(SIGTERM, trap_handler) == BADSIG)
{
syserr("signal SIGTERM");
}
if (signal(SIGSEGV, trap_handler) == BADSIG)
{
syserr("signal SIGSEGV");
}
if (signal(SIGHUP, trap_handler) == BADSIG)
{
syserr("signal SIGHUP");
}
if (signal(SIGABRT, abort_handler) == BADSIG)
{
syserr("signal SIGTERM");
}
if (signal(SIGINT, abort_handler) == BADSIG)
{
syserr("signal SIGINT");
}
if (signal(SIGTSTP, suspend_handler) == BADSIG)
{
syserr("signal SIGSTOP");
}
if (signal(SIGPIPE, pipe_handler) == BADSIG)
{
syserr("signal SIGPIPE");
}
if (signal(SIGWINCH, winch_handler) == BADSIG)
{
syserr("signal SIGWINCH");
}
/*
if (getenv("HOME") != NULL)
{
char filename[256];
sprintf(filename, "%s/%s", getenv("HOME"), HISTORY_FILE);
read_history(gts, filename);
}
*/
srand48(time(NULL));
if (argc > 1)
{
int c;
while ((c = getopt(argc, argv, "e: G h r: t: v")) != EOF)
{
if (c == 'G')
{
greeting = FALSE;
}
}
optind = 1;
}
init_tintin(greeting);
if (argc > 1)
{
int c;
optind = 1;
while ((c = getopt(argc, argv, "e: G h r: t: v")) != EOF)
{
switch (c)
{
case 'e':
gtd->ses = script_driver(gtd->ses, -1, optarg);
break;
case 'G':
break;
case 'h':
tintin_printf(NULL, "Usage: %s [OPTION]... [FILE]...", argv[0]);
tintin_printf(NULL, "");
tintin_printf(NULL, " -e Execute given command.");
tintin_printf(NULL, " -G Don't show the greeting screen.");
tintin_printf(NULL, " -h This help section.");
tintin_printf(NULL, " -r Read given file.");
tintin_printf(NULL, " -t Set given title.");
tintin_printf(NULL, " -v Enable verbose mode.");
restore_terminal();
exit(1);
break;
case 'r':
gtd->ses = do_read(gtd->ses, optarg);
break;
case 't':
printf("\033]0;%s\007", optarg);
break;
case 'v':
do_configure(gtd->ses, "{VERBOSE} {ON}");
break;
default:
tintin_printf(NULL, "Unknown option '%c'.", c);
break;
}
}
if (argv[optind] != NULL)
{
gtd->ses = do_read(gtd->ses, argv[optind]);
}
}
check_all_events(gts, 0, 2, "PROGRAM START", CLIENT_NAME, CLIENT_VERSION);
check_all_events(gts, 0, 2, "SCREEN RESIZE", ntos(gts->cols), ntos(gts->rows));
mainloop();
return 0;
}
void init_tintin(int greeting)
{
int ref, index;
gts = (struct session *) calloc(1, sizeof(struct session));
for (index = 0 ; index < LIST_MAX ; index++)
{
gts->list[index] = init_list(gts, index, 32);
}
gts->name = strdup("gts");
gts->group = strdup("");
gts->host = strdup("");
gts->port = strdup("");
gts->cmd_color = strdup("");
gts->telopts = TELOPT_FLAG_ECHO;
gts->flags = SES_FLAG_MCCP;
gts->socket = 1;
gts->read_max = 16384;
gtd = (struct tintin_data *) calloc(1, sizeof(struct tintin_data));
gtd->ses = gts;
gtd->str_hash_size = sizeof(struct str_hash_data);
gtd->mccp_len = 4096;
gtd->mccp_buf = (unsigned char *) calloc(1, gtd->mccp_len);
gtd->mud_output_max = 16384;
gtd->mud_output_buf = (char *) calloc(1, gtd->mud_output_max);
gtd->input_off = 1;
for (index = 0 ; index < 100 ; index++)
{
gtd->vars[index] = strdup("");
gtd->cmds[index] = strdup("");
}
for (ref = 0 ; ref < 26 ; ref++)
{
for (index = 0 ; *command_table[index].name != 0 ; index++)
{
if (*command_table[index].name == 'a' + ref)
{
gtd->command_ref[ref] = index;
break;
}
}
}
init_screen_size(gts);
printf("\033="); // set application keypad mode
gts->input_level++;
do_configure(gts, "{AUTO TAB} {5000}");
do_configure(gts, "{BUFFER SIZE} {20000}");
do_configure(gts, "{COMMAND COLOR} {<078>}");
do_configure(gts, "{COMMAND ECHO} {ON}");
do_configure(gts, "{CONNECT RETRY} {15}");
do_configure(gts, "{HISTORY SIZE} {1000}");
do_configure(gts, "{LOG} {RAW}");
do_configure(gts, "{PACKET PATCH} {0.00}");
do_configure(gts, "{REPEAT CHAR} {!}");
do_configure(gts, "{REPEAT ENTER} {OFF}");
do_configure(gts, "{SCROLL LOCK} {ON}");
do_configure(gts, "{SPEEDWALK} {OFF}");
do_configure(gts, "{TINTIN CHAR} {#}");
do_configure(gts, "{VERBATIM} {OFF}");
do_configure(gts, "{VERBATIM CHAR} {\\}");
do_configure(gts, "{VERBOSE} {OFF}");
do_configure(gts, "{WORDWRAP} {ON}");
gts->input_level--;
insert_node_list(gts->list[LIST_PATHDIR], "n", "s", "1");
insert_node_list(gts->list[LIST_PATHDIR], "e", "w", "2");
insert_node_list(gts->list[LIST_PATHDIR], "s", "n", "4");
insert_node_list(gts->list[LIST_PATHDIR], "w", "e", "8");
insert_node_list(gts->list[LIST_PATHDIR], "u", "d", "16");
insert_node_list(gts->list[LIST_PATHDIR], "d", "u", "32");
insert_node_list(gts->list[LIST_PATHDIR], "ne", "sw", "3");
insert_node_list(gts->list[LIST_PATHDIR], "nw", "se", "9");
insert_node_list(gts->list[LIST_PATHDIR], "se", "nw", "6");
insert_node_list(gts->list[LIST_PATHDIR], "sw", "ne", "12");
init_terminal();
if (greeting)
{
do_advertise(gts, "");
do_help(gts, "GREETING");
}
}
void quitmsg(char *message)
{
struct session *ses;
SET_BIT(gtd->flags, TINTIN_FLAG_TERMINATE);
while ((ses = gts->next) != NULL)
{
cleanup_session(ses);
}
if (gtd->chat)
{
close(gtd->chat->fd);
}
check_all_events(gts, 0, 0, "PROGRAM TERMINATION");
/*
if (gtd->history_size)
{
char filename[BUFFER_SIZE];
sprintf(filename, "%s/%s", getenv("HOME"), HISTORY_FILE);
history_write(gts, filename);
}
*/
restore_terminal();
clean_screen(gts);
if (message)
{
printf("\n%s\n", message);
}
printf("\nGoodbye from TinTin++\n\n");
fflush(NULL);
exit(0);
}