/* Copyright (c) 2002
* Marko Boomstra (m.boomstra@chello.nl). All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <conf.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#ifdef HAVE_POLL
#include <sys/poll.h>
#endif
#include <netinet/in.h>
#include <arpa/telnet.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <fcntl.h>
#include <netdb.h>
#include <unistd.h>
#include <ctype.h>
#include <errno.h>
#include <ncurses.h>
#include <panel.h>
#include "mudix.h"
/*
* Locals
*/
bool read_desc (int desc);
void exit_mudix (int status);
void new_term_set (void);
void res_term_set (void);
void do_connect (int sock, struct sockaddr *server, int size);
int init_socket (struct sockaddr_in *server);
void init_handler (void);
time_t current_time;
struct hostent *host;
char connect_name [MAX_STRING];
char connect_addr [MAX_STRING];
#ifdef HAVE_POLL
#define POLL_NR 2
enum pfds_types {
PFDS_SOCK, PFDS_INPUT
};
#endif
/*
* Globals, visible in all sources
*/
char outbuf [OUTBUF_LENGTH];
char inbuf [MAX_STRING];
char send_buffer [MAX_STRING];
char *pOut = outbuf;
char *pEndIn = inbuf;
char *pCursor = inbuf;
bool fProcessData = FALSE;
bool fDown = FALSE;
bool fEchoIn = TRUE;
bool fEchoOut = TRUE;
bool fReconnect = FALSE;
bool fPrintTime = TRUE;
bool fKeypadWalk = FALSE;
bool fStatusReport = TRUE;
bool fPanelHidden = 0;
int statusTimer = 0;
long total_sent = 0;
long total_recv = 0;
int len_col;
int len_row;
WINDOW *wTerm;
WINDOW *wMain;
WINDOW *wBanner;
WINDOW *wInput;
WINDOW *wMsg;
WINDOW *wStatus;
WINDOW *wScroll;
WINDOW *wDialog;
PANEL *pMain;
PANEL *pBanner;
PANEL *pInput;
PANEL *pMsg;
PANEL *pStatus;
PANEL *pScroll;
PANEL *pDialog;
/*
* Externals
*/
extern void init_history (void);
/*
* Main loop
*/
int main(int argc, char *argv[])
{
int sock;
struct sockaddr_in server;
struct timeval tv;
struct timeval last_time;
#ifdef HAVE_POLL
struct pollfd pfds[POLL_NR];
#else
fd_set fd_read, fd_exc;
#endif
if (argc != 3 && argc != 2) {
fprintf(stdout, "Syntax: %s '<address> <port>' or '<file>'\n", argv[0]);
exit(1);
}
init_handler();
init_settings(argc, argv);
gettimeofday(&last_time, NULL);
current_time = (time_t)last_time.tv_sec;
sock = init_socket(&server);
new_term_set();
create_banner();
do_connect(sock, (struct sockaddr *)&server, sizeof(server));
init_history();
create_banner();
send_buffer[0] = '\0';
tv.tv_sec = tv.tv_usec = 0;
#ifdef HAVE_POLL
pfds[PFDS_SOCK].fd = sock;
pfds[PFDS_SOCK].events = POLLIN | POLLHUP | POLLERR;
pfds[PFDS_INPUT].fd = STDIN;
pfds[PFDS_INPUT].events = POLLIN;
#endif
while (!fDown) {
#ifdef HAVE_POLL
if (poll(pfds, POLL_NR, 0) < 0) {
do_status("Poll: fatal error, exiting...", 1);
break;
}
#else
FD_ZERO(&fd_read);
FD_ZERO(&fd_exc);
FD_SET(sock, &fd_read);
FD_SET(sock, &fd_exc);
FD_SET(STDIN, &fd_read);
if (select(sock+1, &fd_read, NULL, &fd_exc, &tv) < 0) {
do_status("Select: fatal error, exiting...", 1);
break;
}
#endif
#ifdef HAVE_POLL
if ((pfds[PFDS_SOCK].revents & POLLHUP) ||
(pfds[PFDS_SOCK].revents & POLLERR)) {
#else
if (FD_ISSET(sock, &fd_exc)) {
FD_CLR(sock, &fd_exc);
#endif
break;
}
#ifdef HAVE_POLL
if ((pfds[PFDS_SOCK].revents & POLLIN)) {
#else
if (FD_ISSET(sock, &fd_read)) {
FD_CLR(sock, &fd_read);
#endif
if (!read_desc(sock))
break;
}
if (fProcessData)
process_buffer();
#ifdef HAVE_POLL
if ((pfds[PFDS_INPUT].revents & POLLIN)) {
#else
if (FD_ISSET(STDIN, &fd_read)) {
FD_CLR(STDIN, &fd_read);
#endif
read_input();
}
if (send_buffer[0]) {
if (!write_desc(sock)) {
do_status("Error writing data to socket! :(", 1);
break;
}
}
touchwin(wInput);
update_panels();
doupdate();
/*
* Sleep
*/
usleep(1);
gettimeofday(&last_time, NULL);
if (current_time != (time_t)last_time.tv_sec) {
if (statusTimer && --statusTimer == 0)
hide_panel(pStatus);
current_time = (time_t)last_time.tv_sec;
create_banner();
}
if (fReconnect) {
fReconnect = FALSE;
init_settings(argc, argv);
close(sock);
sock = init_socket(&server);
do_connect(sock, (struct sockaddr *)&server, sizeof(server));
}
}
do_status("Connection closed.", 1);
update_panels();
doupdate();
close_log();
connect_name[0] = '\0';
create_banner();
exit_mudix(0);
return 0;
}
void exit_mudix(int status)
{
res_term_set();
if (settings->sock)
close(settings->sock);
exit(status);
}
void init_handler(void)
{
signal(SIGHUP, exit_mudix);
signal(SIGINT, exit_mudix);
signal(SIGQUIT, exit_mudix);
signal(SIGILL, exit_mudix);
signal(SIGTRAP, exit_mudix);
signal(SIGABRT, exit_mudix);
signal(SIGIOT, exit_mudix);
signal(SIGFPE, exit_mudix);
signal(SIGKILL, exit_mudix);
signal(SIGUSR1, exit_mudix);
signal(SIGSEGV, exit_mudix);
signal(SIGUSR2, exit_mudix);
signal(SIGPIPE, exit_mudix);
signal(SIGTERM, exit_mudix);
#ifdef SIGSTKFLT
signal(SIGSTKFLT, exit_mudix);
#endif
signal(SIGCHLD, exit_mudix);
signal(SIGCONT, exit_mudix);
signal(SIGSTOP, exit_mudix);
signal(SIGTSTP, exit_mudix);
signal(SIGTTIN, exit_mudix);
signal(SIGTTOU, exit_mudix);
}
bool read_desc(int desc)
{
int nRead;
nRead = read(desc, pOut, OUTBUF_LENGTH - (pOut - outbuf));
if (nRead > 0) {
pOut += nRead;
total_recv += nRead;
fProcessData = TRUE;
return TRUE;
}
else if (nRead == 0 || errno == EWOULDBLOCK || errno == EAGAIN)
return TRUE;
else
do_status("Read: fatal error encountered, exiting...", 1);
return FALSE;
}
bool write_desc(int desc)
{
static int cntWrite;
int nrWrite;
int toWrite = strlen(send_buffer);
if ((nrWrite = write(desc, send_buffer+cntWrite, toWrite-cntWrite)) < 0)
return FALSE;
total_sent += nrWrite;
if ((nrWrite+cntWrite) != toWrite)
cntWrite += nrWrite;
else {
cntWrite = 0;
send_buffer[0] = '\0'; /* clear the buffer */
}
return TRUE;
}
void new_term_set(void)
{
wTerm = initscr();
start_color();
cbreak();
noecho();
nonl();
intrflush(stdscr, FALSE);
keypad(stdscr, TRUE);
getmaxyx(wTerm, LEN_ROW, LEN_COL);
scroll_setup(MAX_LINES);
wMain = newwin(LEN_ROW-2, LEN_COL, 0, 0);
wBanner = newwin(1, LEN_COL, LEN_ROW-2, 0);
wInput = newwin(1, LEN_COL, LEN_ROW-1, 0);
wMsg = newwin(0, 0, 2, 7);
wStatus = newwin(8, LEN_COL, 0, 0);
wScroll = newwin(SCROLL_SIZE+1, LEN_COL, 0, 0);
wDialog = newwin(3, LEN_COL, 0, 0);
if (!wMain || !wBanner
|| !wInput
|| !wMsg
|| !wStatus
|| !wDialog
|| !wScroll ) {
endwin();
fprintf(stdout, "Failed to create windows! :(\n");
exit(1);
}
pMain = new_panel(wMain);
pBanner = new_panel(wBanner);
pInput = new_panel(wInput);
pMsg = new_panel(wMsg);
pStatus = new_panel(wStatus);
pScroll = new_panel(wScroll);
pDialog = new_panel(wDialog);
if (!pMain || !pBanner
|| !pInput
|| !pMsg
|| !pStatus
|| !pDialog
|| !pScroll ) {
endwin();
fprintf(stdout, "Failed to create panels! :(\n");
exit(1);
}
idlok(wMain, TRUE);
scrollok(wMain, TRUE);
idlok(wStatus, TRUE);
scrollok(wStatus, TRUE);
idlok(wScroll, TRUE);
scrollok(wScroll, TRUE);
idlok(wMsg, TRUE);
scrollok(wMsg, TRUE);
init_pair(COL_BLACK, COLOR_BLACK, COLOR_BLACK);
init_pair(COL_RED, COLOR_RED, COLOR_BLACK);
init_pair(COL_GREEN, COLOR_GREEN, COLOR_BLACK);
init_pair(COL_YELLOW, COLOR_YELLOW, COLOR_BLACK);
init_pair(COL_BLUE, COLOR_BLUE, COLOR_BLACK);
init_pair(COL_MAGENTA, COLOR_MAGENTA, COLOR_BLACK);
init_pair(COL_CYAN, COLOR_CYAN, COLOR_BLACK);
init_pair(COL_WHITE, COLOR_WHITE, COLOR_BLACK);
init_pair(COL_BANNER, COLOR_YELLOW, COLOR_BLUE);
init_pair(COL_MSG, COLOR_WHITE, COLOR_RED);
init_pair(COL_STATUS, COLOR_WHITE, COLOR_BLUE);
init_pair(COL_SCRL_BANNER, COLOR_WHITE, COLOR_CYAN);
init_pair(COL_DIALOG, COLOR_WHITE, COLOR_GREEN);
wattrset(wBanner, A_BOLD|COLOR_PAIR(COL_BANNER));
wattrset(wStatus, A_BOLD|COLOR_PAIR(COL_STATUS));
wattrset(wMsg, A_BOLD|COLOR_PAIR(COL_MSG));
wattrset(wDialog, A_BOLD|COLOR_PAIR(COL_DIALOG));
wbkgdset(wStatus, getbkgd(wStatus)|A_BOLD|COLOR_PAIR(COL_STATUS));
wbkgdset(wMsg, getbkgd(wMsg)|A_BOLD|COLOR_PAIR(COL_MSG));
wbkgdset(wDialog, getbkgd(wDialog)|A_BOLD|COLOR_PAIR(COL_DIALOG));
wclear(wMain);
wclear(wInput);
wclear(wStatus);
wclear(wScroll);
wclear(wMsg);
wclear(wDialog);
hide_panel(pMsg);
hide_panel(pStatus);
hide_panel(pScroll);
hide_panel(pDialog);
/* Somehow this was changed in the panel library */
if (panel_hidden(pMsg) != PANEL_HIDDEN)
{
PANEL_HIDDEN ^= 1; /* toggle */
}
update_panels();
doupdate();
}
void res_term_set(void)
{
endwin();
return;
}
void do_connect(int sock, struct sockaddr *server, int size)
{
char buf[MAX_STRING];
sprintf(buf, "Trying: %s (%d).", connect_addr, settings->port);
do_status(buf, 4);
update_panels();
doupdate();
if (connect(sock, server, size) == -1) {
perror("%% Connect");
exit_mudix(1);
}
sprintf(buf, "Connected to: %s.", host->h_name);
do_status(buf, 4);
update_panels();
doupdate();
sprintf(connect_name, "%s", host->h_name);
if (fcntl(sock, F_SETFL, O_NDELAY) == -1) {
perror("fcntl: O_NDELAY");
exit_mudix(1);
}
return;
}
int init_socket(struct sockaddr_in *server)
{
int sock, addr;
if (!(host = gethostbyname(settings->site))) {
perror(settings->site);
exit(1);
}
if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
perror("socket creation");
exit(1);
}
memcpy(&server->sin_addr, host->h_addr, host->h_length);
server->sin_family = host->h_addrtype;
server->sin_port = htons(settings->port);
addr = ntohl(server->sin_addr.s_addr);
sprintf(connect_addr, "%d.%d.%d.%d",
(addr >> 24) & 0xFF, (addr >> 16) & 0xFF,
(addr >> 8) & 0xFF, (addr ) & 0xFF);
connect_name[0] = '\0';
setbuf(stdin, NULL);
setbuf(stdout, NULL);
if (fcntl(STDIN, F_SETFL, O_NDELAY) == -1) {
perror("fcntl: O_NDELAY");
exit(1);
}
settings->sock = sock;
return sock;
}
syntax highlighted by Code2HTML, v. 0.9.1