/***************************************************************************** * * $Id$ * File ..................: mbcico/openport.c * Purpose ...............: Fidonet mailer * ***************************************************************************** * 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/libs.h" #include "../lib/structs.h" #include "../lib/common.h" #include "../lib/clcomm.h" #include "ulock.h" #include "ttyio.h" #include "mbcico.h" #include "openport.h" static char *openedport = NULL, *pname; static int need_detach = 1; extern int f_flags; static speed_t transpeed(int); int hanged_up = 0; void linedrop(int sig) { Syslog('+', "openport: Lost Carrier"); hanged_up=1; return; } void sigpipe(int sig) { Syslog('+', "openport: Got SIGPIPE"); hanged_up=1; return; } void interrupt(int sig) { Syslog('+', "openport: Got SIGINT"); signal(SIGINT,interrupt); return; } int openport(char *port, int speed) { int rc, rc2, fd, outflags; char *errtty=NULL; Syslog('t', "Try opening port \"%s\" at %d",MBSE_SS(port),speed); if (openedport) free(openedport); openedport = NULL; if (port[0] == '/') openedport = xstrcpy(port); else { openedport = xstrcpy((char *)"/dev/"); openedport = xstrcat(openedport, port); } pname = strrchr(openedport, '/'); if ((rc = lock(pname))) { Syslog('+', "Port %s is locked (rc = %d)", port, rc); free(openedport); openedport = NULL; return rc; } if (need_detach) { fflush(stdin); fflush(stdout); setbuf(stdin, NULL); setbuf(stdout, NULL); close(0); close(1); /* * If we were manual started the error tty must be closed. */ if ((errtty = ttyname(2))) { Syslog('t', "openport: stderr was on \"%s\", closing",errtty); fflush(stderr); close(2); } } tty_status = 0; hanged_up = 0; Syslog('t', "SIGHUP => linedrop()"); signal(SIGHUP, linedrop); Syslog('t', "SIGPIPE => sigpipe()"); signal(SIGPIPE, sigpipe); Syslog('t', "SIGINT => interrupt()"); signal(SIGINT, interrupt); rc = 0; rc2 = 0; if ((fd = open(openedport,O_RDONLY|O_NONBLOCK)) != 0) { rc = 1; Syslog('+', "$Cannot open \"%s\" as stdin",MBSE_SS(openedport)); fd = open("/dev/null",O_RDONLY); } if ((fd = open(openedport,O_WRONLY|O_NONBLOCK)) != 1) { rc = 1; Syslog('+', "$Cannot open \"%s\" as stdout",MBSE_SS(openedport)); fd = open("/dev/null",O_WRONLY); } clearerr(stdin); clearerr(stdout); if (need_detach) { #ifdef TIOCSCTTY if ((rc2 = ioctl(0,TIOCSCTTY,1L)) < 0) { Syslog('t', "$TIOCSCTTY failed rc = %d", rc2); } #endif if (errtty) { rc = rc || (open(errtty,O_WRONLY) != 2); } need_detach=0; } if (rc) Syslog('+', "cannot switch i/o to port \"%s\"",MBSE_SS(openedport)); else { if (tty_raw(speed)) { WriteError("$cannot set raw mode for \"%s\"",MBSE_SS(openedport)); rc=1; } if (((f_flags = fcntl(0, F_GETFL, 0L)) == -1) || ((outflags = fcntl(1, F_GETFL, 0L)) == -1)) { rc = 1; WriteError("$GETFL error"); f_flags = 0; outflags = 0; } else { Syslog('t', "Return to blocking mode"); f_flags &= ~O_NONBLOCK; outflags &= ~O_NONBLOCK; if ((fcntl(0, F_SETFL, f_flags) != 0) || (fcntl(1, F_SETFL, outflags) != 0)) { rc = 1; WriteError("$SETFL error"); } } Syslog('t', "File flags: stdin: 0x%04x, stdout: 0x%04x", f_flags,outflags); } if (rc) closeport(); else SetTTY(port); return rc; } /* * Set port to local, hangup using DTR drop. */ void localport(void) { Syslog('t', "Setting port \"%s\" local",MBSE_SS(openedport)); Syslog('t', "SIGHUP => SIG_IGN"); signal(SIGHUP, SIG_IGN); Syslog('t', "SIGPIPE => SIG_IGN"); signal(SIGPIPE, SIG_IGN); if (isatty(0)) tty_local(); return; } void nolocalport(void) { Syslog('t', "Setting port \"%s\" non-local",MBSE_SS(openedport)); if (isatty(0)) tty_nolocal(); return; } int rawport(void) { tty_status = 0; Syslog('t', "SIGHUP => linedrop()"); signal(SIGHUP, linedrop); Syslog('t', "SIGPIPE => sigpipe()"); signal(SIGPIPE, sigpipe); if (isatty(0)) return tty_raw(0); else return 0; } int cookedport(void) { Syslog('t', "SIGHUP => SIG_IGN"); signal(SIGHUP, SIG_IGN); Syslog('t', "SIGPIPE => SIG_IGN"); signal(SIGPIPE, SIG_IGN); if (isatty(0)) return tty_cooked(); else return 0; } void closeport(void) { if (openedport == NULL) return; Syslog('t', "Closing port \"%s\"",MBSE_SS(openedport)); fflush(stdin); fflush(stdout); tty_cooked(); close(0); close(1); ulock(pname); if (openedport) free(openedport); openedport = NULL; SetTTY((char *)"-"); return; } void sendbrk(void) { Syslog('t', "Send break"); if (isatty(0)) { #if (defined(TIOCSBRK)) Syslog('t', "TIOCSBRK"); ioctl(0, TIOCSBRK, 0L); #elif (defined(TCSBRK)) Syslog('t', "TCSBRK"); ioctl(0, TCSBRK, 0L); #else /* any ideas about BSD? */ ; #endif } } char *bstr(speed_t); char *bstr(speed_t sp) { #ifdef CBAUD switch(sp & CBAUD) { #else switch(sp) { #endif case 0: return (char *)"0"; #if defined(B50) case B50: return (char *)"50"; #endif #if defined(B75) case B75: return (char *)"75"; #endif #if defined(B110) case B110: return (char *)"110"; #endif #if defined(B134) case B134: return (char *)"134"; #endif #if defined(B150) case B150: return (char *)"150"; #endif #if defined(B200) case B200: return (char *)"200"; #endif #if defined(B300) case B300: return (char *)"300"; #endif #if defined(B600) case B600: return (char *)"600"; #endif #if defined(B1200) case B1200: return (char *)"1.200"; #endif #if defined(B1800) case B1800: return (char *)"1.800"; #endif #if defined(B2400) case B2400: return (char *)"2.400"; #endif #if defined(B4800) case B4800: return (char *)"4.800"; #endif #if defined(B9600) case B9600: return (char *)"9.600"; #endif #if defined(B19200) case B19200: return (char *)"19.200"; #endif #if defined(B38400) case B38400: return (char *)"38.400"; #endif #if defined(B57600) case B57600: return (char *)"57.600"; #endif #if defined(B115200) case B115200: return (char *)"115.200"; #endif #if defined(B230400) case B230400: return (char *)"230.400"; #endif #if defined(B460800) case B460800: return (char *)"460.800"; #endif #if defined(B500000) case B500000: return (char *)"500.000"; #endif #if defined(B576000) case B576000: return (char *)"576.000"; #endif #if defined(B921600) case B921600: return (char *)"921.600"; #endif #if defined(B1000000) case B1000000: return (char *)"1.000.000"; #endif #if defined(B1152000) case B1152000: return (char *)"1.152.000"; #endif #if defined(B1500000) case B1500000: return (char *)"1.500.000"; #endif #if defined(B2000000) case B2000000: return (char *)"2.000.000"; #endif #if defined(B2500000) case B2500000: return (char *)"2.500.000"; #endif #if defined(B3000000) case B3000000: return (char *)"3.000.000"; #endif #if defined(B3500000) case B3500000: return (char *)"3.500.000"; #endif #if defined(B4000000) case B4000000: return (char *)"4.000.000"; #endif default: return (char *)"Unknown"; } } static struct termios savetios; static struct termios tios; int tty_raw(int speed) { int rc; speed_t tspeed, is, os; Syslog('t', "Set tty raw"); tspeed = transpeed(speed); if ((rc = tcgetattr(0,&savetios))) { WriteError("$tcgetattr(0,save) return %d",rc); return rc; } tios = savetios; tios.c_iflag = 0; tios.c_oflag = 0; tios.c_cflag &= ~(CSTOPB | PARENB | PARODD); tios.c_cflag |= CS8 | CREAD | HUPCL | CLOCAL; tios.c_lflag = 0; tios.c_cc[VMIN] = 1; tios.c_cc[VTIME] = 0; if (tspeed) { cfsetispeed(&tios,tspeed); cfsetospeed(&tios,tspeed); } if ((rc = tcsetattr(0,TCSADRAIN,&tios))) WriteError("$tcsetattr(0,TCSADRAIN,raw) return %d",rc); is = cfgetispeed(&tios); os = cfgetospeed(&tios); return rc; } int tty_local(void) { struct termios Tios; tcflag_t cflag; speed_t ispeed, ospeed; int rc; if ((rc = tcgetattr(0,&Tios))) { WriteError("$tcgetattr(0,save) return %d",rc); return rc; } Syslog('+', "Lowering DTR to hangup"); cflag = Tios.c_cflag | CLOCAL; ispeed = cfgetispeed(&tios); ospeed = cfgetospeed(&tios); cfsetispeed(&Tios,0); cfsetospeed(&Tios,0); if ((rc = tcsetattr(0,TCSADRAIN,&Tios))) WriteError("$tcsetattr(0,TCSADRAIN,hangup) return %d",rc); sleep(1); /* as far as I notice, DTR goes back high on next op. */ Tios.c_cflag = cflag; cfsetispeed(&Tios,ispeed); cfsetospeed(&Tios,ospeed); if ((rc = tcsetattr(0,TCSADRAIN,&Tios))) Syslog('t', "$tcsetattr(0,TCSADRAIN,clocal) return %d",rc); return rc; } int tty_nolocal(void) { struct termios Tios; int rc; if ((rc = tcgetattr(0,&Tios))) { WriteError("$tcgetattr(0,save) return %d",rc); return rc; } Tios.c_cflag &= ~CLOCAL; Tios.c_cflag |= CRTSCTS; if ((rc = tcsetattr(0,TCSADRAIN,&Tios))) Syslog('t', "$tcsetattr(0,TCSADRAIN,clocal) return %d",rc); return rc; } int tty_cooked(void) { int rc; if ((rc = tcsetattr(0,TCSAFLUSH,&savetios))) Syslog('t', "$tcsetattr(0,TCSAFLUSH,save) return %d",rc); return rc; } speed_t transpeed(int speed) { speed_t tspeed; switch (speed) { case 0: tspeed=0; break; #if defined(B50) case 50: tspeed=B50; break; #endif #if defined(B75) case 75: tspeed=B75; break; #endif #if defined(B110) case 110: tspeed=B110; break; #endif #if defined(B134) case 134: tspeed=B134; break; #endif #if defined(B150) case 150: tspeed=B150; break; #endif #if defined(B200) case 200: tspeed=B200; break; #endif #if defined(B300) case 300: tspeed=B300; break; #endif #if defined(B600) case 600: tspeed=B600; break; #endif #if defined(B1200) case 1200: tspeed=B1200; break; #endif #if defined(B1800) case 1800: tspeed=B1800; break; #endif #if defined(B2400) case 2400: tspeed=B2400; break; #endif #if defined(B4800) case 4800: tspeed=B4800; break; #endif #if defined(B7200) case 7200: tspeed=B7200; break; #endif #if defined(B9600) case 9600: tspeed=B9600; break; #endif #if defined(B12000) case 12000: tspeed=B12000; break; #endif #if defined(B14400) case 14400: tspeed=B14400; break; #endif #if defined(B19200) case 19200: tspeed=B19200; break; #elif defined(EXTA) case 19200: tspeed=EXTA; break; #endif #if defined(B38400) case 38400: tspeed=B38400; break; #elif defined(EXTB) case 38400: tspeed=EXTB; break; #endif #if defined(B57600) case 57600: tspeed=B57600; break; #endif #if defined(B115200) case 115200: tspeed=B115200; break; #endif #if defined(B230400) case 230400: tspeed=B230400; break; #endif #if defined(B460800) case 460800: tspeed=B460800; break; #endif #if defined(B500000) case 500000: tspeed=B500000; break; #endif #if defined(B576000) case 576000: tspeed=B576000; break; #endif #if defined(B921600) case 921600: tspeed=B921600; break; #endif #if defined(B1000000) case 1000000: tspeed=B1000000; break; #endif #if defined(B1152000) case 1152000: tspeed=B1152000; break; #endif #if defined(B1500000) case 1500000: tspeed=B1500000; break; #endif #if defined(B2000000) case 2000000: tspeed=B2000000; break; #endif #if defined(B2500000) case 2500000: tspeed=B2500000; break; #endif #if defined(B3000000) case 3000000: tspeed=B3000000; break; #endif #if defined(B3500000) case 3500000: tspeed=B3500000; break; #endif #if defined(B4000000) case 4000000: tspeed=B4000000; break; #endif default: WriteError("requested invalid speed %d",speed); tspeed=0; break; } return tspeed; }