/* 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 #include #include #include #ifdef HAVE_POLL #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #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 '
' or ''\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; }