/***************************************************************************** * * $Id$ * Purpose ...............: tty I/O for mbsebbs and mbnewusr * ***************************************************************************** * Copyright (C) 1997-2004 * * Michiel Broek FIDO: 2:280/2802 * Beekmansbos 10 * 1971 BV IJmuiden * the Netherlands * * This file is part of MBSE BBS. * * This BBS 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, or (at your option) any * later version. * * MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *****************************************************************************/ #include "../config.h" #include "../lib/mbselib.h" #include "ttyio.h" extern int hanged_up; extern char *inetaddr; #define TT_BUFSIZ 1024 #define NUMTIMERS 3 int tty_status = 0; int f_flags; static char buffer[TT_BUFSIZ]; static char *next; static int left = 0; static time_t timer[NUMTIMERS]; char *ttystat[]= {(char *)"Ok", (char *)"Error", (char *)"TimeOut", (char *)"EOF", (char *)"Hangup", (char *)"Empty", (char *)"UnCompress"}; int tty_resettimer(int tno); void tty_resettimers(void); int tty_settimer(int,int); int tty_expired(int); int tty_running(int); #define RESETTIMER(x) tty_resettimer(x) #define RESETTIMERS() tty_resettimers() #define SETTIMER(x,y) tty_settimer(x,y) #define EXPIRED(x) tty_expired(x) #define RUNNING(x) tty_running(x) /* * timer functions */ int tty_resettimer(int tno) { if (tno >= NUMTIMERS) { errno = EINVAL; WriteError("ttyio: invalid timer No for resettimer(%d)", tno); return -1; } timer[tno] = (time_t) 0; return 0; } void tty_resettimers(void) { int i; for (i = 0; i < NUMTIMERS; i++) timer[i] = (time_t)0; } int tty_settimer(int tno, int interval) { if (tno >= NUMTIMERS) { errno = EINVAL; WriteError("ttyio: invalid timer No for settimer(%d)", tno); return -1; } timer[tno]=time((time_t*)NULL)+interval; return 0; } int tty_expired(int tno) { time_t now; if (tno >= NUMTIMERS) { errno = EINVAL; WriteError("ttyio: invalid timer No for expired(%d)", tno); return -1; } /* * Check if timer is running */ if (timer[tno] == (time_t) 0) return 0; now = time(NULL); return (now >= timer[tno]); } int tty_running(int tno) { if (tno > NUMTIMERS) { errno = EINVAL; WriteError("ttyio: invalid timer for tty_running(%d)", tno); return -1; } /* * check if timer is running */ if (timer[tno] == (time_t) 0) return 0; else return 1; } /* * private r/w functions */ static int tty_read(char *buf, int size, int tot) { time_t timeout, now; int i, rc; fd_set readfds, writefds, exceptfds; struct timeval seltimer; if (size == 0) return 0; tty_status = 0; now = time(NULL); timeout = (time_t)300; /* maximum of 5 minutes */ for (i = 0; i < NUMTIMERS; i++) { if (timer[i]) { if (now >= timer[i]) { tty_status=STAT_TIMEOUT; Syslog('!', "tty_read: timer %d already expired, return", i); return -tty_status; } else { if (timeout > (timer[i]-now)) timeout=timer[i]-now; } } } if ((tot != -1) && (timeout > tot)) timeout=tot; FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds); FD_SET(0,&readfds); FD_SET(0,&exceptfds); seltimer.tv_sec=timeout; seltimer.tv_usec=0; rc = select(1,&readfds,&writefds,&exceptfds,&seltimer); if (rc < 0) { if (hanged_up) { tty_status=STAT_HANGUP; WriteError("tty_read: hanged_up flag"); } else { WriteError("$tty_read: select for read failed"); tty_status = STAT_ERROR; } } else if (rc == 0) { tty_status = STAT_TIMEOUT; } else { /* rc > 0 */ if (FD_ISSET(0,&exceptfds)) { Syslog('!', "$tty_read: exeption error"); tty_status = STAT_ERROR; } } if (tty_status) { return -tty_status; } if (!FD_ISSET(0,&readfds)) { WriteError("tty_read: Cannot be: select returned but read fd not set"); tty_status = STAT_ERROR; return -tty_status; } rc = read(0,buf,size); if (rc <= 0) { Syslog('t', "tty_read: return %d",rc); if (hanged_up || (errno == EPIPE) || (errno == ECONNRESET)) { tty_status = STAT_HANGUP; WriteError("tty_read: hanged_up flag"); } else { tty_status = STAT_ERROR; Syslog('!', "tty_read: error flag"); } rc=-tty_status; } return rc; } int tty_write(char *buf, int size) { int result; tty_status=0; result = write(1, buf, size); if (result != size) { if (hanged_up || (errno == EPIPE) || (errno == ECONNRESET)) { tty_status = STAT_HANGUP; WriteError("tty_write: hanged_up flag"); } else { tty_status=STAT_ERROR; Syslog('!', "tty_write: error flag"); } } if (tty_status) Syslog('t', "tty_write: error %s", ttystat[tty_status]); return -tty_status; } /* public r/w functions */ /* * Check if there is data available on stdin. */ int tty_check(void) { int rc; // try to read available (timeout = 0) data if we have no data in // our buffer if (!left) { rc = tty_read(buffer, TT_BUFSIZ, 0); if (rc > 0) { left = rc; } } return (left > 0); } int tty_putcheck(int size) { fd_set set; struct timeval timeout; /* * Initialize the file descriptor set. */ FD_ZERO(&set); FD_SET(1, &set); /* * Initialize the timeout data structure. */ timeout.tv_sec = 0; timeout.tv_usec = 0; /* * `select' returns 0 if timeout, 1 if input available, -1 if error. */ return select(FD_SETSIZE, NULL, &set, NULL, &timeout); } int tty_waitputget(int tot) { int i, rc; time_t timeout, now; fd_set readfds, writefds, exceptfds; struct timeval seltimer; tty_status=0; now = time(NULL); timeout=(time_t)300; /* maximum of 5 minutes */ for (i = 0; i < NUMTIMERS; i++) { if (timer[i]) { if (now >= timer[i]) { tty_status = STAT_TIMEOUT; WriteError("tty_waitputget: timer %d already expired, return",i); return -tty_status; } else { if (timeout > (timer[i]-now)) timeout = timer[i]-now; } } } if ((tot != -1) && (timeout > tot)) timeout=tot; Syslog('t', "tty_waitputget: timeout=%d",timeout); /* * Initialize the file descriptor set. */ FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds); FD_SET(0, &readfds); FD_SET(1, &writefds); FD_SET(0, &exceptfds); FD_SET(1, &exceptfds); /* * Initialize the timeout data structure. */ seltimer.tv_sec = timeout; seltimer.tv_usec = 0; /* * `select' returns 0 if timeout, 1 if input available, -1 if error. */ rc = select(FD_SETSIZE, &readfds, &writefds, &exceptfds, &seltimer); if (rc < 0) { if (hanged_up) { tty_status=STAT_HANGUP; WriteError("tty_waitputget: hanged_up flag"); } else { WriteError("$tty_waitputget: select failed"); tty_status=STAT_ERROR; } } else if (rc == 0) { tty_status=STAT_TIMEOUT; } else { /* rc > 0 */ if ((FD_ISSET(0,&exceptfds)) || (FD_ISSET(1,&exceptfds))) { WriteError("$tty_waitputget: exeption error"); tty_status=STAT_ERROR; } } if (tty_status) { Syslog('t', "tty_waitputget: return after select status %s",ttystat[tty_status]); return -tty_status; } rc = 0; if (FD_ISSET(0,&readfds)) rc |= 1; if (FD_ISSET(1,&writefds)) rc |= 2; return rc; } /* * Discard all available input characters */ void tty_flushin(void) { tcflush(0, TCIFLUSH); } /* * Discard all available characters in output buffer. */ void tty_flushout(void) { tcflush(1, TCOFLUSH); } int tty_ungetc(int c) { if (next == buffer) { if (left >= TT_BUFSIZ) { return -1; } next = buffer + TT_BUFSIZ - left; memcpy(next, buffer, left); } next--; *next = c; left++; return 0; } int tty_getc(int tot) { if (!left) { left=tty_read(buffer,TT_BUFSIZ,tot); next=buffer; } if (left <= 0) { left=0; return -tty_status; } else { left--; return (*next++)&0xff; } } int tty_get(char *buf, int size, int tot) { int result=0; if (left >= size) { memcpy(buf,next,size); next += size; left -= size; return 0; } if (left > 0) { memcpy(buf,next,left); buf += left; next += left; size -= left; left=0; } while ((result=tty_read(buf,size,tot)) > 0) { buf += result; size -= result; } return result; } int tty_putc(int c) { char buf = c; return tty_write(&buf,1); } int tty_put(char *buf, int size) { return tty_write(buf,size); } int tty_putget(char **obuf, int *osize, char **ibuf, int *isize) { time_t timeout, now; int i, rc; fd_set readfds, writefds, exceptfds; struct timeval seltimer; tty_status = 0; now = time(NULL); timeout = (time_t)300; /* maximum of 5 minutes */ for (i = 0; i < NUMTIMERS; i++) { if (timer[i]) { if (now >= timer[i]) { tty_status = STAT_TIMEOUT; WriteError("tty_putget: timer %d already expired, return",i); return -tty_status; } else { if (timeout > (timer[i]-now)) timeout=timer[i]-now; } } } Syslog('t', "tty_putget: timeout=%d",timeout); FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds); FD_SET(0,&readfds); FD_SET(1,&writefds); FD_SET(0,&exceptfds); FD_SET(1,&exceptfds); seltimer.tv_sec=timeout; seltimer.tv_usec=0; rc=select(2,&readfds,&writefds,&exceptfds,&seltimer); if (rc < 0) { if (hanged_up) { tty_status=STAT_HANGUP; WriteError("tty_putget: hanged_up flag"); } else { WriteError("$tty_putget: select failed"); tty_status=STAT_ERROR; } } else if (rc == 0) { tty_status=STAT_TIMEOUT; } else { /* rc > 0 */ if ((FD_ISSET(0,&exceptfds)) || (FD_ISSET(1,&exceptfds))) { WriteError("$tty_putget: exeption error"); tty_status=STAT_ERROR; } } if (tty_status) { Syslog('t', "tty_putget: return after select status %s",ttystat[tty_status]); return -tty_status; } if (FD_ISSET(0,&readfds) && *isize) { rc = read(0, *ibuf, *isize); if (rc < 0) { WriteError("$tty_putget: read failed"); tty_status=STAT_ERROR; } else { (*ibuf)+=rc; (*isize)-=rc; } } if (FD_ISSET(1,&writefds) && *osize) { rc=write(1, *obuf, *osize); if (rc < 0) { WriteError("$tty_putget: write failed"); tty_status=STAT_ERROR; } else { (*obuf)+=rc; (*osize)-=rc; } } if (tty_status) return -tty_status; else return ((*isize == 0) | ((*osize == 0) << 1)); }