From ea0327e05b462a9c7cf2d9134e621ba5d7defa20 Mon Sep 17 00:00:00 2001 From: Michael 'Ghandi' Herold Date: Wed, 17 Jun 1998 16:38:56 +0000 Subject: [PATCH] - First part of the automake/autoconf implementation. Currently vbox will *not* compile! --- vbox3/vboxgetty/Makefile.am | 27 ++ vbox3/vboxgetty/config.h | 17 + vbox3/vboxgetty/libvboxmodem.c | 314 +++++++++++++++++ vbox3/vboxgetty/libvboxmodem.h | 46 +++ vbox3/vboxgetty/log.c | 217 ++++++++++++ vbox3/vboxgetty/log.h | 37 ++ vbox3/vboxgetty/modem.c | 550 +++++++++++++++++++++++++++++ vbox3/vboxgetty/modem.h | 50 +++ vbox3/vboxgetty/rc.c | 176 ++++++++++ vbox3/vboxgetty/rc.h | 25 ++ vbox3/vboxgetty/stringutils.c | 42 +++ vbox3/vboxgetty/stringutils.h | 15 + vbox3/vboxgetty/tclscript.c | 284 +++++++++++++++ vbox3/vboxgetty/tclscript.h | 39 +++ vbox3/vboxgetty/vboxgetty.c | 608 +++++++++++++++++++++++++++++++++ vbox3/vboxgetty/vboxgetty.h | 51 +++ vbox3/vboxgetty/voice.c | 219 ++++++++++++ vbox3/vboxgetty/voice.h | 32 ++ 18 files changed, 2749 insertions(+) create mode 100644 vbox3/vboxgetty/Makefile.am create mode 100644 vbox3/vboxgetty/config.h create mode 100644 vbox3/vboxgetty/libvboxmodem.c create mode 100644 vbox3/vboxgetty/libvboxmodem.h create mode 100644 vbox3/vboxgetty/log.c create mode 100644 vbox3/vboxgetty/log.h create mode 100644 vbox3/vboxgetty/modem.c create mode 100644 vbox3/vboxgetty/modem.h create mode 100644 vbox3/vboxgetty/rc.c create mode 100644 vbox3/vboxgetty/rc.h create mode 100644 vbox3/vboxgetty/stringutils.c create mode 100644 vbox3/vboxgetty/stringutils.h create mode 100644 vbox3/vboxgetty/tclscript.c create mode 100644 vbox3/vboxgetty/tclscript.h create mode 100644 vbox3/vboxgetty/vboxgetty.c create mode 100644 vbox3/vboxgetty/vboxgetty.h create mode 100644 vbox3/vboxgetty/voice.c create mode 100644 vbox3/vboxgetty/voice.h diff --git a/vbox3/vboxgetty/Makefile.am b/vbox3/vboxgetty/Makefile.am new file mode 100644 index 00000000..058dca74 --- /dev/null +++ b/vbox3/vboxgetty/Makefile.am @@ -0,0 +1,27 @@ + +CLEANFILES = *~ +MAINTAINERCLEANFILES = Makefile.in + + + + +INCLUDES = $(all_includes) + +noinst_LIBRARIES = libvboxmodem.a + +libvboxmodem_a_SOURCES = libvboxmodem.c libvboxmodem.h + + + + + +##vboxgetty_LDFLAGS = $(all_libraries) +##vboxgetty_LDADD = -L. -lvboxmodem +## +##vboxgetty_SOURCE = log.c log.h \ +## modem.c modem.h \ +## rc.c rc.h \ +## stringutils.c stringutils.h \ +## tclscript.c tclscript.h \ +## vboxgetty.c vboxgetty.h \ +## voice.c voice.h diff --git a/vbox3/vboxgetty/config.h b/vbox3/vboxgetty/config.h new file mode 100644 index 00000000..8aec8c5e --- /dev/null +++ b/vbox3/vboxgetty/config.h @@ -0,0 +1,17 @@ +/* +** $Id$ +** +** Copyright 1997-1998 by Michael 'Ghandi' Herold +*/ + +#ifndef _VBOX_CONFIG_H +#define _VBOX_CONFIG_H 1 + +#define VBOX_LOGDIR "/var/log" +#define VBOX_LCKDIR "/var/lock" +#define VBOX_ETCDIR "/usr/local/etc" +#define VBOX_LIBDIR "/usr/local/lib" + +#define VERSION "2.1.1" + +#endif /* VBOX_CONFIG_H */ diff --git a/vbox3/vboxgetty/libvboxmodem.c b/vbox3/vboxgetty/libvboxmodem.c new file mode 100644 index 00000000..cbe16c52 --- /dev/null +++ b/vbox3/vboxgetty/libvboxmodem.c @@ -0,0 +1,314 @@ +/* +** $Id$ +** +** Copyright 1997-1998 by Michael Herold +** +** $Log$ +** Revision 1.1 1998/06/10 13:31:50 michael +** Source added. +** +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libvboxmodem.h" + +/** Prototypes ***********************************************************/ + +static void vboxmodem_sane_mode(TIO *, int); +static void vboxmodem_raw_mode(TIO *); +static void vboxmodem_speed(TIO *); +static void vboxmodem_flowcontrol(TIO *); +static void vboxmodem_check_nocarrier(struct vboxmodem *, unsigned char); + +/** Variables ************************************************************/ + +static unsigned char lastmodemerrmsg[255 + 1]; + +/*************************************************************************/ +/** vboxmodem_open(): This function initialize the modem structure, **/ +/** opens the device and does some needed setup. **/ +/*************************************************************************/ +/** => vbm Pointer to the modem structure **/ +/** => devicename Name of the device to open **/ +/** <= 0 on success or -1 on error **/ +/*************************************************************************/ + +int vboxmodem_open(struct vboxmodem *vbm, unsigned char *devicename) +{ + TIO devicetio; + + vbm->fd = -1; + vbm->devicename = strdup(devicename); + vbm->input = malloc(VBOXMODEM_BUFFER_SIZE + 1); + vbm->inputpos = 0; + vbm->inputlen = 0; + vbm->nocarrier = 0; + vbm->nocarrierpos = 0; + vbm->nocarriertxt = strdup("NO CARRIER"); + + if ((!vbm->devicename) || (!vbm->input) || (!vbm->nocarriertxt)) + { + set_modem_error("Not enough memory to allocate modem structure"); + vboxmodem_close(vbm); + + return(-1); + } + + /* Open, setup and initialize the modem device. Also set */ + /* speed and handshake. */ + + if ((vbm->fd = open(vbm->devicename, O_RDWR|O_NDELAY)) == -1) + { + set_modem_error("Can't open modem device"); + vboxmodem_close(vbm); + + return(-1); + } + + if (fcntl(vbm->fd, F_SETFL, O_RDWR) == -1) + { + set_modem_error("Can't setup modem device"); + vboxmodem_close(vbm); + + return(-1); + } + + vboxmodem_sane_mode(&devicetio, 1); + vboxmodem_speed(&devicetio); + vboxmodem_raw_mode(&devicetio); + vboxmodem_flowcontrol(&devicetio); + + if (vboxmodem_set_termio(vbm, &devicetio) == -1) + { + set_modem_error("Can't setup modem device settings"); + vboxmodem_close(vbm); + + return(-1); + } + + strcpy(lastmodemerrmsg, ""); + return(0); +} + +/*************************************************************************/ +/** vboxmodem_close(): Frees all resources from vboxmodem_open(). **/ +/*************************************************************************/ +/** => vbm Pointer to the initialized modem structure **/ +/*************************************************************************/ + +void vboxmodem_close(struct vboxmodem *vbm) +{ + if (vbm->fd != -1) close(vbm->fd); + + if (vbm->devicename ) free(vbm->devicename); + if (vbm->input ) free(vbm->input); + if (vbm->nocarriertxt) free(vbm->nocarriertxt); + + vbm->fd = -1; + vbm->devicename = NULL; + vbm->input = NULL; + vbm->nocarriertxt = NULL; +} + +/*************************************************************************/ +/** vboxmodem_error(): Returns a pointer to the last error message. **/ +/*************************************************************************/ +/** <= Pointer to the message **/ +/*************************************************************************/ + +unsigned char *vboxmodem_error(void) +{ + return(&lastmodemerrmsg[0]); +} + +/*************************************************************************/ +/** vboxmodem_raw_read(): Reads raw bytes from modem. **/ +/*************************************************************************/ +/** => vbm Pointer to the modem structure **/ +/** => line Pointer to the read buffer **/ +/** => len Length of the read buffer **/ +/** <= Number of bytes in the read buffer **/ +/*************************************************************************/ + +int vboxmodem_raw_read(struct vboxmodem *vbm, unsigned char *line, int len) +{ + int use = 0; + int pos = 0; + + if (len > VBOXMODEM_BUFFER_SIZE) len = VBOXMODEM_BUFFER_SIZE; + + if (vbm->inputlen >= len) + { + memcpy(line, &vbm->input[vbm->inputpos], len); + + vbm->inputlen -= len; + vbm->inputpos += len; + + return(len); + } + + if (vbm->inputlen > 0) + { + memcpy(line, &vbm->input[vbm->inputpos], vbm->inputlen); + } + + len -= vbm->inputlen; + use += vbm->inputlen; + + vbm->inputpos = 0; + vbm->inputlen = 0; + + if ((vbm->inputlen = read(vbm->fd, vbm->input, VBOXMODEM_BUFFER_SIZE)) < 0) + { + vbm->inputpos = 0; + vbm->inputlen = 0; + + return(use); + } + + for (pos = 0; pos < vbm->inputlen; pos++) + { + vboxmodem_check_nocarrier(vbm, vbm->input[pos]); + } + + if (vbm->inputlen < len) len = vbm->inputlen; + + memcpy(&line[use], &vbm->input[vbm->inputpos], len); + + vbm->inputlen -= len; + vbm->inputpos += len; + + return(use + len); +} + +/*************************************************************************/ +/** vboxmodem_raw_write(): Sends a buffer to the modem. **/ +/*************************************************************************/ +/** => vmb Pointer to modem structure **/ +/** => output Pointer to datas **/ +/** => len Number of datas to write **/ +/*************************************************************************/ + +size_t vboxmodem_raw_write(struct vboxmodem *vbm, unsigned char *output, int len) +{ + return(write(vbm->fd, output, len)); +} + +/*************************************************************************/ +/** vboxmodem_set_termio(): Sets the terminal io settings. **/ +/*************************************************************************/ +/** => vbm Pointer to modem structure **/ +/** => modemtio Pointer to a terminal io structure **/ +/*************************************************************************/ + +int vboxmodem_set_termio(struct vboxmodem *vbm, TIO *modemtio) +{ + if (tcsetattr(vbm->fd, TCSANOW, modemtio) >= 0) return(0); + + return(-1); +} + +/*************************************************************************/ +/** vboxmodem_get_termio(): Gets the terminal io settings. **/ +/*************************************************************************/ +/** => vbm Pointer to modem structure **/ +/** => modemtio Pointer to a terminal io structure **/ +/*************************************************************************/ + +int vboxmodem_get_termio(struct vboxmodem *vbm, TIO *modemtio) +{ + if (tcgetattr(vbm->fd, modemtio) >= 0) return(0); + + return(-1); +} + +/*************************************************************************/ +/** vboxmodem_sane_mode(): Sets sane mode. **/ +/*************************************************************************/ +/** => modemtio Pointer to a terminal io structure **/ +/*************************************************************************/ + +static void vboxmodem_sane_mode(TIO *modemtio, int local) +{ + modemtio->c_iflag = (BRKINT|IGNPAR|IXON|IXANY); + modemtio->c_oflag = (OPOST|TAB3); + modemtio->c_cflag &= ~(CSIZE|CSTOPB|PARENB|PARODD|CLOCAL); + modemtio->c_cflag |= (CS8|CREAD|HUPCL|(local ? CLOCAL : 0)); + modemtio->c_lflag = (ECHOK|ECHOE|ECHO|ISIG|ICANON); +} + +/*************************************************************************/ +/** vboxmodem_raw_mode(): Sets raw mode. **/ +/*************************************************************************/ +/** => modemtio Pointer to a terminal io structure **/ +/*************************************************************************/ + +static void vboxmodem_raw_mode(TIO *modemtio) +{ + modemtio->c_iflag &= (IXON|IXOFF|IXANY); + modemtio->c_oflag = 0; + modemtio->c_lflag = 0; + modemtio->c_cc[VMIN] = 1; + modemtio->c_cc[VTIME] = 0; +} + +/*************************************************************************/ +/** vboxmodem_speed(): Sets speed to 57600. **/ +/*************************************************************************/ +/** => modemtio Pointer to a terminal io structure **/ +/*************************************************************************/ + +static void vboxmodem_speed(TIO *modemtio) +{ + cfsetospeed(modemtio, B57600); + cfsetispeed(modemtio, B57600); +} + +/*************************************************************************/ +/** vboxmodem_flowcontrol(): Sets flow control to hardware. **/ +/*************************************************************************/ +/** => modemtio Pointer to a terminal io structure **/ +/*************************************************************************/ + +static void vboxmodem_flowcontrol(TIO *modemtio) +{ + modemtio->c_cflag &= ~(CRTSCTS); + modemtio->c_iflag &= ~(IXON|IXOFF|IXANY); + modemtio->c_cflag |= (CRTSCTS); +} + + +/*************************************************************************/ +/** vboxmodem_check_nocarrier(): Checks for carrier lost. **/ +/*************************************************************************/ +/** => Pointer to the modem structure **/ +/** => c Byte from modem input **/ +/*************************************************************************/ + +static void vboxmodem_check_nocarrier(struct vboxmodem *vbm, unsigned char c) +{ + if (c == vbm->nocarriertxt[vbm->nocarrierpos]) + { + vbm->nocarrierpos++; + + if (vbm->nocarrierpos >= strlen(vbm->nocarriertxt)) + { + vbm->nocarrier = 1; + vbm->nocarrierpos = 0; + } + } + else + { + vbm->nocarrierpos = 0; + + if (c == vbm->nocarriertxt[0]) vbm->nocarrierpos++; + } +} diff --git a/vbox3/vboxgetty/libvboxmodem.h b/vbox3/vboxgetty/libvboxmodem.h new file mode 100644 index 00000000..78449ec4 --- /dev/null +++ b/vbox3/vboxgetty/libvboxmodem.h @@ -0,0 +1,46 @@ +/* +** $Id$ +** +** Copyright 1997-1998 by Michael 'Ghandi' Herold +*/ + +#ifndef _VBOX_LIBMODEM_H +#define _VBOX_LIBMODEM_H 1 + +#include + +/** Defines **************************************************************/ + +#define VBOXMODEM_BUFFER_SIZE 255 /* Modem input buffer size */ + +/** Variables ************************************************************/ + +typedef struct termios TIO; + +struct vboxmodem +{ + int fd; + char *devicename; + unsigned char *input; + int inputpos; + int inputlen; + int nocarrier; + int nocarrierpos; + char *nocarriertxt; +}; + +/** Internal junk ********************************************************/ + +#define set_modem_error(A) strcpy(lastmodemerrmsg, A) + +/** Prototypes ***********************************************************/ + +extern int vboxmodem_open(struct vboxmodem *, unsigned char *); +extern void vboxmodem_close(struct vboxmodem *); +extern unsigned char *vboxmodem_error(void); +extern int vboxmodem_raw_read(struct vboxmodem *, unsigned char *, int); +extern size_t vboxmodem_raw_write(struct vboxmodem *, unsigned char *, int); +extern int vboxmodem_set_termio(struct vboxmodem *, TIO *); +extern int vboxmodem_get_termio(struct vboxmodem *, TIO *); + +#endif /* _VBOX_LIBMODEM_H */ diff --git a/vbox3/vboxgetty/log.c b/vbox3/vboxgetty/log.c new file mode 100644 index 00000000..3c03a3bd --- /dev/null +++ b/vbox3/vboxgetty/log.c @@ -0,0 +1,217 @@ +/* +** $Id$ +** +** Copyright 1997-1998 by Michael Herold +** +** $Log$ +** Revision 1.1 1998/06/10 13:31:52 michael +** Source added. +** +*/ + +#include +#include +#include +#include +#include +#include + +#include "voice.h" +#include "log.h" + +/** Variables ************************************************************/ + +static FILE *logtxtio = NULL; +static int loglevel = LOG_E|LOG_W|LOG_I; + +/** Structures ***********************************************************/ + +static struct logsequence logsequence[] = +{ + { ETX , "" }, { NL , "" }, { CR , "" }, + { DLE , "" }, { XON , "" }, { XOFF, "" }, + { DC4 , "" }, { CAN , "" }, { 0 , NULL } +}; + +/*************************************************************************/ +/** log_open(): Opens the log. **/ +/*************************************************************************/ +/** => name Name of the ttyI (appended to real logname) **/ +/** <= 0 on success or -1 on error **/ +/*************************************************************************/ + +int log_open(char *name) +{ + if ((logtxtio = fopen(name, "a"))) return(0); + + return(-1); +} + +/*************************************************************************/ +/** log_close(): Close the log. **/ +/*************************************************************************/ + +void log_close(void) +{ + if (logtxtio) fclose(logtxtio); + + logtxtio = NULL; +} + +/*************************************************************************/ +/** **/ +/*************************************************************************/ + +void log_set_debuglevel(int level) +{ + loglevel = level; +} + +/*************************************************************************/ +/** log_line(): Writes a line to the log including the current date & **/ +/** time and the log level. **/ +/*************************************************************************/ +/** => level Debuglevel **/ +/** => fmt Formatstring **/ +/** => ... Args **/ +/*************************************************************************/ + +void log_line(int level, char *fmt, ...) +{ + struct tm *timel; + time_t timec; + va_list arg; + char logsign; + char timeline[20]; + FILE *useio; + + useio = (logtxtio ? logtxtio : stderr); + + if ((loglevel & level) || (level == LOG_E)) + { + timec = time(NULL); + + if ((timel = localtime(&timec))) + { + if (strftime(timeline, 20, "%d-%b %H:%M:%S", timel) != 15) + { + strcpy(timeline, "??-??? ??:??:??"); + } + } + + switch (level) + { + case LOG_E: + logsign = 'E'; + break; + + case LOG_W: + logsign = 'W'; + break; + + case LOG_I: + logsign = 'I'; + break; + + case LOG_D: + logsign = 'D'; + break; + + case LOG_A: + logsign = 'A'; + break; + + default: + logsign = '?'; + break; + } + + fprintf(useio, "%s <%c> ", timeline, logsign); + + va_start(arg, fmt); + vfprintf(useio, fmt, arg); + va_end(arg); + + fflush(useio); + } +} + +/*************************************************************************/ +/** log_char(): Writes a char to the log. **/ +/*************************************************************************/ +/** => level Debuglevel **/ +/** => c Char to log **/ +/*************************************************************************/ + +void log_char(int level, char c) +{ + int i; + + if ((loglevel & level) || (level == LOG_E)) + { + if (!isprint(c)) + { + i = 0; + + while (logsequence[i].text) + { + if (logsequence[i].code == c) + { + log_text(level, "%s", logsequence[i].text); + + return; + } + + i++; + } + + log_text(level, "[0x%02X]", (unsigned char)c); + } + else log_text(level, "%c", c); + } +} + +/*************************************************************************/ +/** log_text(): Writes a line to the log. **/ +/*************************************************************************/ +/** => level Debuglevel **/ +/** => fmt Formatstring **/ +/** => ... Args **/ +/*************************************************************************/ + +void log_text(int level, char *fmt, ...) +{ + FILE *useio; + va_list arg; + + useio = (logtxtio ? logtxtio : stderr); + + if ((loglevel & level) || (level == LOG_E)) + { + va_start(arg, fmt); + vfprintf(useio, fmt, arg); + va_end(arg); + + fflush(useio); + } +} + +/*************************************************************************/ +/** log_code(): Writes a line with log_char() to the log. **/ +/*************************************************************************/ +/** => level Debuglevel **/ +/** => sequence Sequence of chars to log **/ +/*************************************************************************/ + +void log_code(int level, char *sequence) +{ + int i; + + if ((loglevel & level) || (level == LOG_E)) + { + for (i = 0; i < strlen(sequence); i++) + { + log_char(level, sequence[i]); + } + } +} diff --git a/vbox3/vboxgetty/log.h b/vbox3/vboxgetty/log.h new file mode 100644 index 00000000..f250e841 --- /dev/null +++ b/vbox3/vboxgetty/log.h @@ -0,0 +1,37 @@ +/* +** $Id$ +** +** Copyright 1997-1998 by Michael 'Ghandi' Herold +*/ + +#ifndef _VBOX_LOG_H +#define _VBOX_LOG_H 1 + +/** Defines **************************************************************/ + +#define LOG_E (0) /* Errors */ +#define LOG_W (1) /* Warnings */ +#define LOG_I (2) /* Informations */ +#define LOG_A (4) /* Action */ +#define LOG_D (128) /* Debug */ +#define LOG_X (255) /* Full debug */ + +/** Structures ***********************************************************/ + +struct logsequence +{ + char code; + char *text; +}; + +/** Prototypes ***********************************************************/ + +extern int log_open(char *); +extern void log_set_debuglevel(int); +extern void log_close(void); +extern void log_line(int, char *, ...); +extern void log_char(int, char); +extern void log_text(int, char *, ...); +extern void log_code(int, char *); + +#endif /* _VBOX_LOG_H */ diff --git a/vbox3/vboxgetty/modem.c b/vbox3/vboxgetty/modem.c new file mode 100644 index 00000000..c04bcf4d --- /dev/null +++ b/vbox3/vboxgetty/modem.c @@ -0,0 +1,550 @@ +/* +** $Id$ +** +** Copyright 1997-1998 by Michael Herold +** +** $Log$ +** Revision 1.2 1998/06/17 12:20:36 michael +** - Changes for automake/autoconf added. +** +** Revision 1.1 1998/06/10 13:31:53 michael +** Source added. +** +*/ + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "modem.h" +#include "libvboxmodem.h" + +static struct modemsetup modemsetup = +{ + 4, /* Echo timeout (sec) */ + 4, /* Command timeout (sec) */ + 6, /* Ring timeout (sec) */ + 1800, /* Alive timeout (sec) */ + 400 /* Toggle DTR (ms) */ +}; + +static unsigned char lastmodemresult[VBOXMODEM_BUFFER_SIZE + 1]; + +static int timeoutstatus = 0; + +static void modem_timeout_function(int); +static int modem_write(struct vboxmodem *, char *); +static int modem_get_echo(struct vboxmodem *, char *); +static int modem_get_rawsequence(struct vboxmodem *, char *, int); +static int modem_check_result(char *, char *); + +/*************************************************************************/ +/** modem_set_timeout(): Sets modem function timeout. **/ +/*************************************************************************/ +/** => timeout Timeout in seconds **/ +/*************************************************************************/ + +void modem_set_timeout(int timeout) +{ + if (timeout != 0) + { + timeoutstatus = 0; + + signal(SIGALRM, modem_timeout_function); + siginterrupt(SIGALRM, 1); + alarm(timeout); + } + else + { + signal(SIGALRM, SIG_IGN); + alarm(0); + } +} + +/*************************************************************************/ +/** modem_get_timeout(): Returns the timeout status. **/ +/*************************************************************************/ +/** <= 1 if timeout or 0 if not **/ +/*************************************************************************/ + +int modem_get_timeout(void) +{ + return(timeoutstatus); +} + +/*************************************************************************/ +/** modem_get_sequence(): Reads a specified sequence from the modem. **/ +/*************************************************************************/ +/** => seq Sequence to read **/ +/** <= 0 sequence read or -1 not read **/ +/*************************************************************************/ + +int modem_get_sequence(struct vboxmodem *vbm, char *seq) +{ + return(modem_get_rawsequence(vbm, seq, 0)); +} + +/*************************************************************************/ +/** modem_flush(): Flushs modem input/output. **/ +/*************************************************************************/ +/** => Pointer to modem structure **/ +/** => Flush timeout in seconds **/ +/*************************************************************************/ + +void modem_flush(struct vboxmodem *vbm, int timeout) +{ + TIO porttio; + TIO savetio; + long gotjunk = 0; + char onebyte = 0; + + log_line(LOG_D, "Flushing modem%s...\n", (timeout ? " (with timeout)" : "")); + + if (vboxmodem_get_termio(vbm, &porttio) == 0) + { + savetio = porttio; + + porttio.c_lflag &= ~ICANON; + porttio.c_cc[VMIN] = 0; + porttio.c_cc[VTIME] = timeout; + + if (vboxmodem_set_termio(vbm, &porttio) == 0) + { + while (vboxmodem_raw_read(vbm, &onebyte, 1) == 1) + { + if (gotjunk++ < 20) + { + log_line(LOG_D, "Junk: "); + log_char(LOG_D, onebyte); + log_text(LOG_D, "\n"); + } + } + + if (gotjunk > 20) + { + log_line(LOG_D, "Flush has junked %d byte(s)...\n", gotjunk); + } + + vboxmodem_set_termio(vbm, &savetio); + } + } + + tcflush(vbm->fd, TCIOFLUSH); + tcflush(vbm->fd, TCIOFLUSH); +} + +/*************************************************************************/ +/** modem_hangup(): Toggles the data terminal ready line to hangup the **/ +/** modem. **/ +/*************************************************************************/ +/** => vbm Pointer to modem structure **/ +/** <= 0 on success or -1 on error **/ +/*************************************************************************/ + +int modem_hangup(struct vboxmodem *vbm) +{ + TIO porttio; + TIO savetio; + + log_line(LOG_D, "Hangup modem (drop dtr %d ms)...\n", modemsetup.toggle_dtr_time); + + modem_flush(vbm, 1); + + if (vboxmodem_get_termio(vbm, &porttio) == -1) return(-1); + + savetio = porttio; + + cfsetospeed(&porttio, B0); + cfsetispeed(&porttio, B0); + + vboxmodem_set_termio(vbm, &porttio); + + usleep(modemsetup.toggle_dtr_time * 1000); + + return(vboxmodem_set_termio(vbm, &savetio)); +} + +/*************************************************************************/ +/** modem_command(): Sends a command to the modem and waits for one or **/ +/** more results. **/ +/*************************************************************************/ +/** => vbm Pointer to modem structure **/ +/** => command Command to send **/ +/** => result Needed answer(s) (seperater with '|') **/ +/** <= Number of the found answer, 0 nothing found, -1 on **/ +/** error **/ +/*************************************************************************/ + +int modem_command(struct vboxmodem *vbm, char *command, char *result) +{ + char line[VBOXMODEM_BUFFER_SIZE + 1]; + int back; + + lastmodemresult[0] = '\0'; + + if ((command) && (*command)) + { + modem_flush(vbm, 0); + + log_line(LOG_D, "Sending \"%s\"...\n", command); + + if (strcmp(command, "\r") != 0) + { + if ((modem_write(vbm, command) == -1) || (modem_write(vbm, "\r") == -1)) + { + log_line(LOG_E, "Can't send modem command.\n"); + + modem_flush(vbm, 1); + + return(-1); + } + + if (modem_get_echo(vbm, command) == -1) + { + log_line(LOG_E, "Can't read modem command echo.\n"); + + modem_flush(vbm, 1); + + return(-1); + } + } + else + { + if (vboxmodem_raw_write(vbm, command, strlen(command)) == -1) + { + log_line(LOG_E, "Can't send modem command.\n"); + + modem_flush(vbm, 1); + + return(-1); + } + } + } + + if ((result) && (*result)) + { + if (modem_read(vbm, line, modemsetup.commandtimeout) == -1) + { + if ((command) && (*command)) + { + log_line(LOG_E, "Can't read modem command result.\n"); + } + + modem_flush(vbm, 1); + + return(-1); + } + + strcpy(lastmodemresult, line); + + if (strcmp(result, "?") == 0) return(0); + + if ((back = modem_check_result(line, result)) < 1) + { + log_line(LOG_E, "Modem returns unneeded command \""); + log_code(LOG_E, line); + log_text(LOG_E, "\".\n"); + + modem_flush(vbm, 1); + + return(-1); + } + else return(back); + } + + return(0); +} + +/*************************************************************************/ +/** modem_read(): Reads a terminated string from the modem. **/ +/*************************************************************************/ +/** => vbm Pointer to modem structure **/ +/** => line Pointer to write buffer **/ +/** => readtimeout Timeout in seconds **/ +/*************************************************************************/ + +int modem_read(struct vboxmodem *vbm, char *line, int readtimeout) +{ + char c; + int r; + int timeout; + int linelen = 0; + int havetxt = 0; + + log_line(LOG_D, "Reading modem answer (%ds timeout)...\n", readtimeout); + + modem_set_timeout(readtimeout); + + while (((r = vboxmodem_raw_read(vbm, &c, 1)) == 1) && (linelen < (VBOXMODEM_BUFFER_SIZE - 1))) + { + if (c >= 32) havetxt = 1; + + if (havetxt) + { + if (c == '\n') break; + + if ((c != '\r') && (c != '\n')) + { + *line++ = c; + + linelen++; + } + } + + if (modem_get_timeout()) break; + } + + timeout = modem_get_timeout(); + + modem_set_timeout(0); + + *line = 0; + + if ((r != 1) || (timeout) || (linelen >= (VBOXMODEM_BUFFER_SIZE - 1))) + { + log_line(LOG_W, "Can't read from modem [%d]%s.\n", r, (timeout ? " (timeout)" : "")); + + return(-1); + } + + return(0); +} + + +/*************************************************************************/ +/** **/ +/*************************************************************************/ + +int modem_wait(struct vboxmodem *vbm) +{ + struct timeval timeout; + struct timeval *usetimeout; + + fd_set fd; + int back; + + log_line(LOG_D, "Waiting...\n"); + + FD_ZERO(&fd); + FD_SET(vbm->fd, &fd); + + if (modemsetup.alivetimeout > 0) + { + timeout.tv_sec = modemsetup.alivetimeout; + timeout.tv_usec = modemsetup.alivetimeout * 1000; + + usetimeout = &timeout; + } + else usetimeout = NULL; + + back = select(FD_SETSIZE, &fd, NULL, NULL, usetimeout); + + if (back <= 0) + { + if (back < 0) + { + log_line(LOG_E, "Select returns with error (%d)...\n", back); + } + else log_line(LOG_D, "Select returns with timeout...\n"); + + return(-1); + } + + return(0); +} + +void modem_set_nocarrier(struct vboxmodem *vbm, int carrier) +{ + vbm->nocarrier = carrier; +} + +int modem_get_nocarrier(struct vboxmodem *vbm) +{ + return(vbm->nocarrier); +} + + + + + + + + + + + + + + +/*************************************************************************/ +/** modem_timeout_function(): Function called from timeout signal hand- **/ +/** ler. **/ +/*************************************************************************/ +/** => s Signal number **/ +/*************************************************************************/ + +static void modem_timeout_function(int s) +{ + alarm(0); + signal(SIGALRM, SIG_IGN); + + log_line(LOG_D, "Modem timeout function called...\n"); + + timeoutstatus = 1; +} + +/*************************************************************************/ +/** modem_write(): Sends a null terminated string to the modem. **/ +/*************************************************************************/ +/** => vbm Pointer to modem structure **/ +/** => s Terminated string to write **/ +/*************************************************************************/ + +static int modem_write(struct vboxmodem *vbm, char *s) +{ + if (vboxmodem_raw_write(vbm, s, strlen(s)) == strlen(s)) return(0); + + return(-1); +} + + +/*************************************************************************/ +/** modem_get_echo(): Reads modem echo. **/ +/*************************************************************************/ +/** => vbm Pointer to modem structure **/ +/** => echo Command to get echo from **/ +/*************************************************************************/ + +static int modem_get_echo(struct vboxmodem *vbm, char *echo) +{ + return(modem_get_rawsequence(vbm, echo, 1)); +} + +/*************************************************************************/ +/** modem_get_rawsequence(): Reads a raw sequence from modem. This is **/ +/** a subroutine for modem_get_sequence() & **/ +/** modem_get_echo(). **/ +/*************************************************************************/ + +static int modem_get_rawsequence(struct vboxmodem *vbm, char *line, int echo) +{ + char c; + int i; + int timeout; + + timeout = (echo ? modemsetup.echotimeout : modemsetup.commandtimeout); + + log_line(LOG_D, "Reading modem %s (%ds timeout)...\n", (echo ? "echo" : "sequence"), timeout); + + modem_set_timeout(timeout); + + for (i = 0; i < strlen(line); i++) + { + if ((vboxmodem_raw_read(vbm, &c, 1) != 1) || (modem_get_timeout())) + { + modem_set_timeout(0); + + return(-1); + } + + if (line[i] != c) + { + modem_set_timeout(0); + + return(-1); + } + } + + if (echo) + { + if ((vboxmodem_raw_read(vbm, &c, 1) != 1) || (modem_get_timeout())) + { + modem_set_timeout(0); + + return(-1); + } + } + + modem_set_timeout(0); + + if (echo) + { + if (c != '\r') return(-1); + } + + return(0); +} + +/*************************************************************************/ +/** modem_check_result(): Checks for a string in the modem result. **/ +/*************************************************************************/ + +static int modem_check_result(char *have, char *need) +{ + char line[VBOXMODEM_BUFFER_SIZE + 1]; + char *word; + char *more; + int nr; + + log_line(LOG_D, "Waiting for \""); + log_code(LOG_D, need); + log_text(LOG_D, "\"... "); + + strncpy(line, need, VBOXMODEM_BUFFER_SIZE); + line[VBOXMODEM_BUFFER_SIZE] = '\0'; + + more = strchr(line, '|'); + word = strtok(line, "|"); + nr = 0; + + while (word) + { + nr++; + + if (strncmp(have, word, strlen(word)) == 0) + { + if (more) + { + log_text(LOG_D, "Got \""); + log_code(LOG_D, word); + log_text(LOG_D, "\" (%d).\n", nr); + } + else log_text(LOG_D, "Got it.\n"); + + return(nr); + } + + word = strtok(NULL, "|"); + } + + log_text(LOG_D, "Oops!\n"); + + return(0); +} + + + + + + + + + diff --git a/vbox3/vboxgetty/modem.h b/vbox3/vboxgetty/modem.h new file mode 100644 index 00000000..4fa8251f --- /dev/null +++ b/vbox3/vboxgetty/modem.h @@ -0,0 +1,50 @@ +/* +** $Id$ +** +** Copyright 1997-1998 by Michael 'Ghandi' Herold +*/ + +#ifndef _VBOX_MODEM_H +#define _VBOX_MODEM_H 1 + +#include "libvboxmodem.h" + +#define VBOXMODEM_STAT_INIT 0 +#define VBOXMODEM_STAT_WAIT 1 +#define VBOXMODEM_STAT_RING 2 +#define VBOXMODEM_STAT_TEST 3 +#define VBOXMODEM_STAT_EXIT 255 + + + + + +struct modemsetup +{ + int echotimeout; + int commandtimeout; + int ringtimeout; + int alivetimeout; + int toggle_dtr_time; + + + + +}; + + + + + +extern void modem_set_timeout(int); +extern int modem_get_timeout(void); +extern int modem_get_sequence(struct vboxmodem *, char *); +extern void modem_flush(struct vboxmodem *, int); +extern int modem_command(struct vboxmodem *, char *, char *); +extern int modem_hangup(struct vboxmodem *); +extern int modem_wait(struct vboxmodem *); +extern void modem_set_nocarrier(struct vboxmodem *, int); +extern int modem_get_nocarrier(struct vboxmodem *); +extern int modem_read(struct vboxmodem *, char *, int); + +#endif /* _VBOX_MODEM_H */ diff --git a/vbox3/vboxgetty/rc.c b/vbox3/vboxgetty/rc.c new file mode 100644 index 00000000..cfa37411 --- /dev/null +++ b/vbox3/vboxgetty/rc.c @@ -0,0 +1,176 @@ +/* +** $Id$ +** +** Copyright 1997-1998 by Michael Herold +** +** $Log$ +** Revision 1.1 1998/06/10 13:31:55 michael +** Source added. +** +*/ + +#include +#include +#include +#include + +#include "log.h" +#include "rc.h" + +/*************************************************************************/ +/** rc_read(): Reads a configuration into the structure. **/ +/*************************************************************************/ +/** => rc Configuration structure **/ +/** => rcname Name of the configuration to read **/ +/** => section Name of the section to jump to **/ +/** <= 0 success **/ +/** <= -1 unable to open **/ +/** <= -2 section not found **/ +/*************************************************************************/ + +int rc_read(struct vboxrc *rc, char *rcname, char *section) +{ + char rctmpln[VBOX_MAX_RCLINE_SIZE + 1]; + FILE *rctxtio; + int rcerror; + int rcsjump; + char *stop; + char *name; + char *args; + + log_line(LOG_D, "Parsing \"%s\"...\n", rcname); + + rcerror = 0; + rcsjump = 0; + + if ((rctxtio = fopen(rcname, "r"))) + { + while ((fgets(rctmpln, VBOX_MAX_RCLINE_SIZE, rctxtio)) && (rcerror == 0)) + { + rctmpln[strlen(rctmpln) - 1] = '\0'; + + if ((stop = rindex(rctmpln, '#'))) *stop = '\0'; + + if (rctmpln[0] == '\0') continue; + + if ((section) && (rcsjump == 0)) + { + + continue; + } + + name = strtok(rctmpln, "\t "); + args = strtok(NULL , "\t "); + + rc_set_entry(rc, name, args); + } + + fclose(rctxtio); + } + else rcerror = -1; + + if ((rcerror == 0) && (section) && (rcsjump == 0)) + { + log_line(LOG_E, "Section \"%s\" not found.\n", section); + + rcerror = -2; + } + + return(rcerror); +} + +/*************************************************************************/ +/** **/ +/*************************************************************************/ + +void rc_free(struct vboxrc *rc) +{ + int i = 0; + + while (rc[i].name) + { + if (rc[i].value) free(rc[i].value); + + rc[i].value = NULL; + + i++; + } +} + +unsigned char *rc_get_entry(struct vboxrc *rc, char *name) +{ + int i = 0; + + while (rc[i].name) + { + if (strcasecmp(rc[i].name, name) == 0) return(rc[i].value); + + i++; + } + + return(NULL); +} + +/*************************************************************************/ +/** **/ +/*************************************************************************/ + +unsigned char *rc_set_entry(struct vboxrc *rc, char *name, char *value) +{ + int i = 0; + unsigned char *v = NULL; + + log_line(LOG_D, "Setting \"%s\" to \"%s\"...\n", (name ? name : "???"), (value ? value : "???")); + + if ((!name) || (!value)) + { + if (!name ) log_line(LOG_W, "Configuration variable name not set (ignored).\n"); + if (!value) log_line(LOG_W, "Configuration argument not set (ignored).\n"); + + return(NULL); + } + + while (rc[i].name) + { + if (strcasecmp(rc[i].name, name) == 0) + { + v = strdup(value); + + if (v) + { + if (rc[i].value) free(rc[i].value); + + rc[i].value = v; + } + else log_line(LOG_E, "Can't set \"%s\"'s value.\n", name); + + return(v); + } + + i++; + } + + log_line(LOG_W, "Unknown entry \"%s\" ignored.\n", name); + + return(NULL); +} + +unsigned char *rc_set_empty(struct vboxrc *rc, char *name, char *value) +{ + int i = 0; + + while (rc[i].name) + { + if (strcasecmp(rc[i].name, name) == 0) + { + if (rc[i].value) return(rc[i].value); + + return(rc_set_entry(rc, name, value)); + } + + i++; + } + + return(NULL); +} + diff --git a/vbox3/vboxgetty/rc.h b/vbox3/vboxgetty/rc.h new file mode 100644 index 00000000..11829154 --- /dev/null +++ b/vbox3/vboxgetty/rc.h @@ -0,0 +1,25 @@ +/* +** $Id$ +** +** Copyright 1997-1998 by Michael 'Ghandi' Herold +*/ + +#ifndef _VBOX_RC_H +#define _VBOX_RC_H 1 + +#define VBOX_MAX_RCLINE_SIZE 255 + +struct vboxrc +{ + unsigned char *name; + unsigned char *value; +}; + +extern int rc_read(struct vboxrc *, char *, char *); +extern void rc_free(struct vboxrc *); +extern unsigned char *rc_get_entry(struct vboxrc *, char *); +extern unsigned char *rc_set_entry(struct vboxrc *, char *, char *); +extern unsigned char *rc_set_empty(struct vboxrc *, char *, char *); + + +#endif /* _VBOX_RC_H */ diff --git a/vbox3/vboxgetty/stringutils.c b/vbox3/vboxgetty/stringutils.c new file mode 100644 index 00000000..44230c02 --- /dev/null +++ b/vbox3/vboxgetty/stringutils.c @@ -0,0 +1,42 @@ + +#include + +#include "stringutils.h" + +/*************************************************************************/ +/** xstrncpy(): Copy one string to another (length limited). **/ +/*************************************************************************/ +/** => dest Destination **/ +/** => source Source **/ +/** => max Destination buffer length **/ +/*************************************************************************/ + +void xstrncpy(char *dest, char *source, int max) +{ + strncpy(dest, source, max); + + dest[max] = '\0'; +} + +/*************************************************************************/ +/** xstrtol(): Converts a string to a number. **/ +/*************************************************************************/ +/** => string String to convert **/ +/** => number Default number if string can not converted **/ +/** <= Number **/ +/*************************************************************************/ + +long xstrtol(char *string, long number) +{ + long back; + char *stop; + + if (string) + { + back = strtol(string, &stop, 10); + + if (*stop == '\0') return(back); + } + + return(number); +} diff --git a/vbox3/vboxgetty/stringutils.h b/vbox3/vboxgetty/stringutils.h new file mode 100644 index 00000000..35d9a310 --- /dev/null +++ b/vbox3/vboxgetty/stringutils.h @@ -0,0 +1,15 @@ +/* +** $Id$ +** +** Copyright 1997-1998 by Michael 'Ghandi' Herold +*/ + +#ifndef _VBOX_STRINGUTILS_H +#define _VBOX_STRINGUTILS_H 1 + +/** Prototypes ***********************************************************/ + +extern void xstrncpy(char *, char *, int); +extern long xstrtol(char *, long); + +#endif /* _VBOX_STRINGUTILS_H */ diff --git a/vbox3/vboxgetty/tclscript.c b/vbox3/vboxgetty/tclscript.c new file mode 100644 index 00000000..1530a223 --- /dev/null +++ b/vbox3/vboxgetty/tclscript.c @@ -0,0 +1,284 @@ +/* +** $Id$ +** +** Copyright 1997-1998 by Michael Herold +** +** $Log$ +** Revision 1.1 1998/06/10 13:31:56 michael +** Source added. +** +*/ + +#include +#include +#include + +#include "config.h" +#include "vboxgetty.h" +#include "log.h" +#include "modem.h" +#include "tclscript.h" + +static Tcl_Interp *interpreter = NULL; + + + + + +int vbox_block(VBOX_TCLFUNC_PROTO); +int vbox_log(VBOX_TCLFUNC_PROTO); +int vbox_modem_command(VBOX_TCLFUNC_PROTO); + + +static struct vbox_tcl_function vbox_tcl_functions[] = +{ + { "exit", vbox_block }, + { "vbox_log", vbox_log }, + { "vbox_modem_command", vbox_modem_command }, + { NULL, NULL } +}; + + +static int scr_init_functions(void); + + + + + + + + +int scr_create_interpreter(void) +{ + log_line(LOG_D, "Initializing tcl interpreter...\n"); + + if (TCL_MAJOR_VERSION >= 8) + { + if ((interpreter = Tcl_CreateInterp())) + { + if (scr_init_functions() == 0) return(0); + } + } + + return(-1); +} + +void scr_remove_interpreter(void) +{ + int rc; + + if (interpreter) + { + log_line(LOG_D, "Removing tcl interpreter...\n"); + + if ((rc = Tcl_InterpDeleted(interpreter)) == 0) + { + Tcl_DeleteInterp(interpreter); + } + else log_line(LOG_W, "Tcl interpreter can't be removed (returns %d).\n", rc); + } +} + +/*************************************************************************/ +/** scr_execute(): Executes a tcl script. **/ +/*************************************************************************/ +/** => name Name of the script to execute **/ +/** => user User name (if set, script is first searched in **/ +/** users spooldir) **/ +/** <= 0 on success or -1 on error **/ +/*************************************************************************/ + +int scr_execute(char *name, char *user) +{ + int canrun = 0; + + if (user) + { + + canrun = 0; + } + + if (!canrun) + { + printstring(temppathname, "%s/vboxgetty/%s", VBOX_LIBDIR, name); + + if (access(temppathname, F_OK|R_OK) == 0) canrun = 1; + } + + if (canrun) + { + log_line(LOG_A, "Running \"%s\"...\n", temppathname); + + if (Tcl_EvalFile(interpreter, temppathname) == TCL_OK) + { + log_line(LOG_D, "Tcl script returns without errors.\n"); + + return(0); + } + else log_line(LOG_E, "%s: %s [line %d]!\n", name, Tcl_GetStringResult(interpreter), interpreter->errorLine); + } + else log_line(LOG_E, "Tcl script \"%s\" not found.\n", name); + + return(-1); +} + +/*************************************************************************/ +/** scr_tcl_version(): Returns current tcl version number. **/ +/*************************************************************************/ +/** <= Tcl version string **/ +/*************************************************************************/ + +char *scr_tcl_version(void) +{ + return(TCL_VERSION); +} + +/*************************************************************************/ +/** scr_init_functions(): Adds the vbox functions to the interpreter. **/ +/*************************************************************************/ +/** <= 0 on success or -1 on error **/ +/*************************************************************************/ + +static int scr_init_functions(void) +{ + int i = 0; + + while (vbox_tcl_functions[i].name) + { + if (!Tcl_CreateObjCommand(interpreter, vbox_tcl_functions[i].name, vbox_tcl_functions[i].proc, NULL, NULL)) + { + log_line(LOG_E, "Can't add new tcl command \"%s\".\n", vbox_tcl_functions[i].name); + + return(-1); + } + else log_line(LOG_D, "New tcl command \"%s\" added.\n", vbox_tcl_functions[i].name); + + i++; + } + + return(0); +} + +/*************************************************************************/ +/** scr_init_variables(): Initialize global tcl variables. **/ +/*************************************************************************/ +/** => vars Pointer to a filled variable structure **/ +/** <= 0 on success or -1 on error **/ +/*************************************************************************/ + +int scr_init_variables(struct vbox_tcl_variable *vars) +{ + int i = 0; + + while (vars[i].name) + { + if (Tcl_VarEval(interpreter, "set ", vars[i].name, " \"", vars[i].args, "\"", NULL) != TCL_OK) + { + log_line(LOG_E, "Can't set tcl variable \"%s\".\n", vars[i].name); + + return(-1); + } + else log_line(LOG_D, "Tcl variable \"%s\" set to \"%s\".\n", vars[i].name, vars[i].args); + + i++; + } + + return(0); +} + + + + + + + + + + + + + + + + + +int vbox_block(VBOX_TCLFUNC) +{ + log_line(LOG_W, "Tcl command \"%s\" is blocked!\n", Tcl_GetStringFromObj(objv[0], NULL)); + + return(TCL_OK); +} + + + + + + + +int vbox_log(VBOX_TCLFUNC) +{ + char *levelv; + int levelc; + + if (objc == 3) + { + levelv = Tcl_GetStringFromObj(objv[1], NULL); + levelc = LOG_E; + + switch (levelv[0]) + { + case 'W': + levelc = LOG_W; + break; + + case 'I': + levelc = LOG_I; + break; + + case 'A': + levelc = LOG_A; + break; + + case 'D': + levelc = LOG_D; + break; + } + + log_line(levelc, "%s\n", Tcl_GetStringFromObj(objv[2], NULL)); + } + else log_line(LOG_E, "Bad vars %d\n", objc); + + return(TCL_OK); +} + +int vbox_modem_command(VBOX_TCLFUNC) +{ + int i; + + if (objc == 3) + { + i = modem_command(&vboxmodem, Tcl_GetStringFromObj(objv[1], NULL), Tcl_GetStringFromObj(objv[2], NULL)); + + printstring(temppathname, "%d", i); + + Tcl_SetResult(intp, temppathname, NULL); + } + else log_line(LOG_E, "Bad vars %d\n", objc); + + return(TCL_OK); +} + + + + + + + + + + + + + + + diff --git a/vbox3/vboxgetty/tclscript.h b/vbox3/vboxgetty/tclscript.h new file mode 100644 index 00000000..9a186a23 --- /dev/null +++ b/vbox3/vboxgetty/tclscript.h @@ -0,0 +1,39 @@ +/* +** $Id$ +** +** Copyright 1997-1998 by Michael 'Ghandi' Herold +*/ + +#ifndef _VBOX_TCLSCRIPT_H +#define _VBOX_TCLSCRIPT_H 1 + +#include + +struct vbox_tcl_function +{ + char *name; + Tcl_ObjCmdProc *proc; +}; + +struct vbox_tcl_variable +{ + char *name; + char *args; +}; + + +#define VBOX_TCLFUNC_PROTO ClientData, Tcl_Interp *, int, Tcl_Obj *CONST [] +#define VBOX_TCLFUNC ClientData data, Tcl_Interp *intp, int objc, Tcl_Obj *CONST objv[] + + +/** Prototypes ***********************************************************/ + +extern int scr_create_interpreter(void); +extern void scr_remove_interpreter(void); +extern int scr_execute(char *, char *); +extern int scr_init_variables(struct vbox_tcl_variable *); + + +extern char *scr_tcl_version(void); + +#endif /* _VBOX_TCLSCRIPT_H */ diff --git a/vbox3/vboxgetty/vboxgetty.c b/vbox3/vboxgetty/vboxgetty.c new file mode 100644 index 00000000..66fee731 --- /dev/null +++ b/vbox3/vboxgetty/vboxgetty.c @@ -0,0 +1,608 @@ +/* +** $Id$ +** +** Copyright 1997-1998 by Michael Herold +** +** $Log$ +** Revision 1.2 1998/06/17 12:20:37 michael +** - Changes for automake/autoconf added. +** +** Revision 1.1 1998/06/10 13:31:58 michael +** Source added. +** +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "log.h" +#include "tcl.h" +#include "modem.h" +#include "rc.h" +#include "voice.h" +#include "stringutils.h" +#include "tclscript.h" +#include "vboxgetty.h" + +/** Variables ************************************************************/ + +static char *progbasename; + +char temppathname[PATH_MAX + 1]; + +/** Structures ***********************************************************/ + +static struct vboxrc rc_getty_c[] = +{ + { "init" , NULL }, + { "initnumber" , NULL }, + { "badinitsexit" , NULL }, + { "initpause" , NULL }, + { "commandtimeout", NULL }, + { "echotimeout" , NULL }, + { "ringtimeout" , NULL }, + { "alivetimeout" , NULL }, + { NULL , NULL } +}; + +static struct option arguments[] = +{ + { "version" , no_argument , NULL, 'v' }, + { "help" , no_argument , NULL, 'h' }, + { "debug" , required_argument, NULL, 'x' }, + { "device" , required_argument, NULL, 'd' }, + { NULL , 0 , NULL, 0 } +}; + +struct vboxmodem vboxmodem; + +/** Prototypes ***********************************************************/ + +static int parse_getty_rc(unsigned char *); +static void show_usage(int, int); +static int process_incoming_call(void); +static int run_modem_init(void); +static int parse_user_rc(struct vboxincomingcall *); + + +/*************************************************************************/ +/** The magic main... **/ +/*************************************************************************/ + +void main(int argc, char **argv) +{ + char *isdnttyname; + char *stop; + int opts; + char *debugstr; + int debuglvl; + int i; + int modemstate; + int modeminits; + + progbasename = argv[0]; + + if ((stop = rindex(argv[0], '/'))) progbasename = ++stop; + + /* Parse command line arguments and set the selected (or default) */ + /* debuglevel. */ + + debugstr = NULL; + isdnttyname = NULL; + + while ((opts = getopt_long(argc, argv, "vhx:d:", arguments, (int *)0)) != EOF) + { + switch (opts) + { + case 'x': + debugstr = optarg; + break; + + case 'd': + isdnttyname = optarg; + break; + + case 'v': + show_usage(200, 0); + break; + + case 'h': + default: + show_usage(200, 1); + break; + } + } + + if (debugstr) + { + if (strcasecmp(debugstr, "FULL") != 0) + { + debuglvl = LOG_E; + + for (i = 0; i < strlen(debugstr); i++) + { + switch (debugstr[i]) + { + case 'W': + case 'w': + debuglvl |= LOG_W; + break; + + case 'I': + debuglvl |= LOG_I; + break; + + case 'A': + debuglvl |= LOG_A; + break; + + case 'D': + debuglvl |= LOG_D; + break; + } + } + } + else debuglvl = LOG_X; + + log_set_debuglevel(debuglvl); + } + + /* Remove all before the last '/' from the tty name. And check if */ + /* the device is accessable (not really needed since we need root */ + /* privilegs to start). */ + + if (isdnttyname) + { + if ((stop = rindex(isdnttyname, '/'))) isdnttyname = ++stop; + + printstring(temppathname, "/dev/%s", isdnttyname); + + if (access(temppathname, F_OK|R_OK|W_OK) != 0) + { + fprintf(stderr, "\n%s: error: \"%s\" doesn't exist or is not accessable!\n\n", progbasename, temppathname); + + quit_program(100); + } + } + else + { + fprintf(stderr, "\n%s: error: isdn tty name is required!\n", progbasename); + + show_usage(100, 1); + } + + /* Check if we start with root privilegs. The permissions will be */ + /* dropped later, but we need root privilegs to open tty's, logs */ + /* etc. */ + + if (getuid() != 0) + { + fprintf(stderr, "\n%s: error: need root privilegs to start!\n\n", progbasename); + + quit_program(100); + } + + /* Now its time to open the log. The name of the current tty will */ + /* be appended to the name. */ + + printstring(temppathname, "%s/vboxgetty-%s.log", VBOX_LOGDIR, isdnttyname); + + log_open(temppathname); + + /* Start and initialize the tcl-interpreter (version 8.0 or */ + /* higher is required). */ + + if (scr_create_interpreter() == -1) + { + log_line(LOG_E, "Can't create/initialize the tcl interpreter!\n"); + + quit_program(100); + } + + log_line(LOG_I, "Running vbox version %s (with tcl version %s).\n", VERSION, scr_tcl_version()); + + /* Read the vboxgetty runtime configuration. 1st the global */ + /* and 2nd the tty. */ + + if (parse_getty_rc(isdnttyname) == -1) + { + log_line(LOG_E, "Unable to read/parse configuration!\n"); + + quit_program(100); + } + + /* Open modem device and do the main loop (initialize, wait, */ + /* answer and alive check). */ + + printstring(temppathname, "/dev/%s", isdnttyname); + + log_line(LOG_D, "Opening modem device \"%s\" (57600, CTS/RTS)...\n", temppathname); + + if (vboxmodem_open(&vboxmodem, temppathname) == -1) + { + log_line(LOG_E, "Can't open/setup modem device (%s).\n", vboxmodem_error()); + + quit_program(100); + } + +signal(SIGINT , quit_program); +signal(SIGTERM, quit_program); + + modemstate = VBOXMODEM_STAT_INIT; + modeminits = 0; + + while (modemstate != VBOXMODEM_STAT_EXIT) + { + switch (modemstate) + { + case VBOXMODEM_STAT_INIT: + + if (run_modem_init() == -1) + { + if ((i = (int)xstrtol(rc_get_entry(rc_getty_c, "badinitsexit"), 10)) > 0) + { + modeminits++; + + if (modeminits >= i) + { + modemstate = VBOXMODEM_STAT_EXIT; + modeminits = 0; + + log_line(LOG_E, "Exit program while bad init limit are reached.\n"); + } + else log_line(LOG_W, "Bad initialization - Program will exist on %d trys!\n", (i - modeminits)); + } + } + else + { + modemstate = VBOXMODEM_STAT_WAIT; + modeminits = 0; + } + break; + + case VBOXMODEM_STAT_WAIT: + + modem_flush(&vboxmodem, 0); + + if (modem_wait(&vboxmodem) == 0) + { + modemstate = VBOXMODEM_STAT_RING; + modeminits = 0; + } + else modemstate = VBOXMODEM_STAT_TEST; + + break; + + case VBOXMODEM_STAT_TEST: + + log_line(LOG_D, "Checking if modem is still alive...\n"); + + if (modem_command(&vboxmodem, "AT", "OK") > 0) + { + modemstate = VBOXMODEM_STAT_WAIT; + modeminits = 0; + } + else modemstate = VBOXMODEM_STAT_INIT; + + break; + + case VBOXMODEM_STAT_RING: + + modem_set_nocarrier(&vboxmodem, 0); + process_incoming_call(); + modem_hangup(&vboxmodem); + + modemstate = VBOXMODEM_STAT_INIT; + + break; + + default: + + log_line(LOG_E, "Unknown modem status %d!\n", modemstate); + + modemstate = VBOXMODEM_STAT_INIT; + + break; + } + } + + quit_program(0); +} + +/*************************************************************************/ +/** quit_program(): Frees all used resources and exist. **/ +/*************************************************************************/ +/** => rc Exit return code (1-99 reserved for signals) **/ +/*************************************************************************/ + +void quit_program(int rc) +{ + modem_hangup(&vboxmodem); + vboxmodem_close(&vboxmodem); + + scr_remove_interpreter(); + + rc_free(rc_getty_c); + + log_close(); + + exit(rc); +} + +/*************************************************************************/ +/** show_usage(): Shows usage/version message. **/ +/*************************************************************************/ +/** => rc Exit return level (1-99 reserved for signals) **/ +/** => help 1 shows help message, 0 version string **/ +/*************************************************************************/ + +static void show_usage(int rc, int help) +{ + if (help) + { + fprintf(stdout, "\n"); + fprintf(stdout, "Usage: %s [OPTION] [OPTION] [...]\n", progbasename); + fprintf(stdout, "\n"); + fprintf(stdout, "--device TTY Name of the isdn tty to use (required).\n"); + fprintf(stdout, "--debug CODE Sets debug level (default \"EWI\").\n"); + fprintf(stdout, "--version Display version and exit.\n"); + fprintf(stdout, "--help Display this help and exit.\n"); + fprintf(stdout, "\n"); + } + else + { + fprintf(stdout, "%s version %s\n", progbasename, VERSION); + } + + exit(rc); +} + +/*************************************************************************/ +/** run_modem_init(): Starts the tcl script to initialize the modem. **/ +/*************************************************************************/ +/** <= 0 on success or -1 on error **/ +/*************************************************************************/ + +static int run_modem_init(void) +{ + struct vbox_tcl_variable vars[] = + { + { "vbxv_init" , rc_get_entry(rc_getty_c, "init" ) }, + { "vbxv_initnumber" , rc_get_entry(rc_getty_c, "initnumber") }, + { NULL , NULL } + }; + + log_line(LOG_A, "Initializing modem...\n"); + + if (scr_init_variables(vars) == 0) + { + if (scr_execute("initmodem.tcl", NULL) == 0) return(0); + } + + log_line(LOG_E, "Can't initialize modem!\n"); + + return(-1); +} + + + + + + + + + + + +static int parse_getty_rc(unsigned char *tty) +{ + char *name; + + log_line(LOG_A, "Reading configuration...\n"); + + name = "/usr/local/etc/vboxgetty.conf"; + + if (rc_read(rc_getty_c, name, NULL) < 0) + { + if (errno != ENOENT) + { + log_line(LOG_E, "Can't open \"%s\" (%s)!\n", name, strerror(errno)); + + return(-1); + } + } + + name = "/usr/local/etc/vboxgetty.conf.ttyI0"; + + if (rc_read(rc_getty_c, name, NULL) < 0) + { + if (errno != ENOENT) + { + log_line(LOG_E, "Can't open \"%s\" (%s)!\n", name, strerror(errno)); + + return(-1); + } + } + + log_line(LOG_D, "Filling unset configuration variables with defaults...\n"); + + if (!rc_set_empty(rc_getty_c, "init" , "ATZ&B512")) return(-1); + if (!rc_set_empty(rc_getty_c, "badinitsexit" , "10" )) return(-1); + if (!rc_set_empty(rc_getty_c, "initpause" , "2500" )) return(-1); + if (!rc_set_empty(rc_getty_c, "commandtimeout" , "4" )) return(-1); + if (!rc_set_empty(rc_getty_c, "echotimeout" , "4" )) return(-1); + if (!rc_set_empty(rc_getty_c, "ringtimeout" , "6" )) return(-1); + if (!rc_set_empty(rc_getty_c, "alivetimeout" , "1800" )) return(-1); + + if (!rc_get_entry(rc_getty_c, "initnumber")) + { + log_line(LOG_E, "Variable \"initnumber\" *must* be set!\n"); + + return(-1); + } + + return(0); +} + + +/*************************************************************************/ +/** **/ +/*************************************************************************/ + +static int process_incoming_call(void) +{ + struct vboxuser vboxuser; + + char line[VBOXMODEM_BUFFER_SIZE + 1]; + int haverings; + int waitrings; + int havesetup; + + haverings = 0; + waitrings = 0; + havesetup = 0; + + while (modem_read(&vboxmodem, line, (int)xstrtol(rc_get_entry(rc_getty_c, "ringtimeout"), 6)) == 0) + { + if ((strncmp(line, "CALLER NUMBER: ", 15) == 0) && (!havesetup)) + { + xstrncpy(vboxuser.incomingid, &line[15], VBOX_CALL_ID); + xstrncpy(vboxuser.localphone, "9317840513", VBOX_CALL_NUMBER); + + if (parse_user_rc(&vboxuser) == 0) + { + if ((vboxuser.uid == 0) || (vboxuser.gid == 0)) + { + log_line(LOG_W, "No user for ID %s found - call will be ignored!\n", vboxcall.callerid); + + + + + + + + + } + + havesetup = 1; + } + + continue; + } + + if (strcmp(line, "RING") == 0) + { + haverings++; + + if (havesetup) + log_line(LOG_A, "RING #%03d (%s)...\n", haverings, incomingid); + else + log_line(LOG_A, "RING #%03d...\n", haverings); + } + else + { + log_line(LOG_D, "Got junk line \""); + log_code(LOG_D, line); + log_text(LOG_D, "\"...\n"); + } + } + + return(-1); +} + +/*************************************************************************/ +/** **/ +/*************************************************************************/ + +static int parse_user_rc(struct vboxuser *vboxuser) +{ + char line[VBOX_RCLINE_SIZE + 1]; + FILE *rc; + char *stop; + int linenr; + + log_line(LOG_D, "Searching local user for ID %s...\n", vboxuser->incomingid); + + vboxuser->uid = 0; + vboxuser->gid = 0; + vboxuser->home[0] = 0 + vboxuser->umask = -1; + vboxuser->space = -1; + + printstring(temppathname, "%s/vboxgetty.user", VBOX_ETCDIR); + + if ((rc = fopen(temppathname, "r"))) + { + linenr = 0; + + while (fgets(line, VBOX_RCLINE_SIZE, rc)) + { + linenr++; + + line[strlen(line) - 1] = '\0'; + + if ((stop = rindex(line, '#'))) *stop = '\0'; + + while (strlen(line) > 0) + { + if ((line[strlen(line) - 1] != ' ') && (line[strlen(line) - 1] != '\t')) break; + + line[strlen(line) - 1] = '\0'; + } + + if (*line == '\0') continue; + + pattern = strtok(line, ":"); + name = strtok(NULL, ":"); + group = strtok(NULL, ":"); + mask = strtok(NULL, ":"); + space = strtok(NULL, ":"); + + if ((!pattern) || (!name) || (!group) || (!mask) || (!space)) + { + log_line(LOG_E, "Error in \"%s\" line %d.\n", temppathname, linenr); + + fclose(rc); + return(-1); + } + + + + + + + + + } + + fclose(rc); + } + else + { + log_line(LOG_W, "Can't open \"%s\".\n", temppathname); + + return(-1); + } + + return(0); +} + + + + + + + + + + + + + + diff --git a/vbox3/vboxgetty/vboxgetty.h b/vbox3/vboxgetty/vboxgetty.h new file mode 100644 index 00000000..49f52690 --- /dev/null +++ b/vbox3/vboxgetty/vboxgetty.h @@ -0,0 +1,51 @@ +/* +** $Id$ +** +** Copyright 1997-1998 by Michael 'Ghandi' Herold +*/ + +#ifndef _VBOXGETTY_H +#define _VBOXGETTY_H 1 + +#include +#include +#include +#include + +#define VBOX_DEFAULT_SPOOLDIR "/var/spool/vbox" + +#define VBOX_RCLINE_SIZE 255 + +#define VBOXUSER_CALLID 64 +#define VBOXUSER_NUMBER 64 + +extern char temppathname[PATH_MAX + 1]; + +extern struct vboxmodem vboxmodem; + +struct vboxuser +{ + uid_t uid; + gid_t gid; + int umask; + long space; + char incomingid[VBOXUSER_CALLID + 1]; + char localphone[VBOXUSER_NUMBER + 1]; + char home[PATH_MAX + 1]; +}; + + + + + + + + + + +extern void quit_program(int); + +#define printstring sprintf + + +#endif /* _VBOXGETTY_H */ diff --git a/vbox3/vboxgetty/voice.c b/vbox3/vboxgetty/voice.c new file mode 100644 index 00000000..5e959451 --- /dev/null +++ b/vbox3/vboxgetty/voice.c @@ -0,0 +1,219 @@ +/* +** $Id$ +** +** Copyright 1997-1998 by Michael Herold +** +** $Log$ +** Revision 1.1 1998/06/10 13:31:59 michael +** Source added. +** +*/ + +#include +#include +#include +#include +#include + +#include "log.h" +#include "vboxgetty.h" +#include "modem.h" +#include "voice.h" + +static int voicesave = -1; +static int voicehear = -1; +static int voicestat = VBOXVOICE_STAT_OK; + +static char voicename[1000]; + +int voice_init(void) +{ + log_line(LOG_D, "Setting voice compression to \"ulaw\"...\n"); + + if (modem_command(&vboxmodem, "AT+VSM=6+VLS=2", "OK") > 0) + { + log_line(LOG_D, "Starting full duplex audio mode...\n"); + + if (modem_command(&vboxmodem, "AT+VTX+VRX", "CONNECT") > 0) + { + /* start answer.tcl */ + + printstring(voicename, "/tmp/vbox-1.ulaw"); + + voice_hear(1); + voice_save(1); + + voice_wait(30); + + voice_save(0); + voice_hear(0); + + return(0); + } + } + + return(-1); +} + +/*************************************************************************/ +/** voice_wait(): Reads audio datas. **/ +/*************************************************************************/ +/** => timeout Timeout in seconds **/ +/*************************************************************************/ + +int voice_wait(int timeout) +{ + char line_i[1]; + char line_o[VBOXVOICE_BUFFER_SIZE + 1]; + int byte_i; + int byte_o; + int result; + int gotdle; + + voicestat = VBOXVOICE_STAT_OK; + gotdle = 0; + + if (voicesave == -1) + log_line(LOG_D, "Reading audio datas (%ds timeout)...\n", timeout); + else + log_line(LOG_D, "Recording \"%s\" (%ds timeout)...\n", voicename, timeout); + + modem_set_timeout(timeout); + + while (voicestat == VBOXVOICE_STAT_OK) + { + byte_i = 0; + byte_o = 0; + result = 0; + + while ((byte_o < VBOXVOICE_BUFFER_SIZE) && (voicestat == VBOXVOICE_STAT_OK)) + { + if ((result = vboxmodem_raw_read(&vboxmodem, line_i, 1)) == 1) + { + byte_i++; + + if (gotdle) + { + switch (*line_i) + { + case ETX: + voicestat |= VBOXVOICE_STAT_HANGUP; + break; + + default: + /*if (voice_check_touchtone(*line_i) == 0) voicestat |= VBOXVOICE_STAT_TOUCHTONE;*/ + break; + } + + gotdle = 0; + } + else + { + if (*line_i != DLE) + { + line_o[byte_o++] = *line_i; + } + else gotdle = 1; + } + } + else break; + } + + if (byte_o > 0) + { + if (voicesave != -1) write(voicesave, line_o, byte_o); + if (voicehear != -1) write(voicehear, line_o, byte_o); + } + + if ((result != 1) || (modem_get_timeout())) + { + if (!modem_get_timeout()) + { + log_line(LOG_W, "Can't read voice data: %s!\n", strerror(errno)); + + voicestat |= VBOXVOICE_STAT_TIMEOUT; + } + else voicestat |= VBOXVOICE_STAT_TIMEOUT; + } + } + + if (voicestat & VBOXVOICE_STAT_TOUCHTONE) + { + log_line(LOG_D, "Full touchtone sequence found!\n"); + } + + if ((voicestat & VBOXVOICE_STAT_HANGUP) || (vboxmodem.nocarrier)) + { + log_line(LOG_D, "Remote hangup - audio output & saving stopped.\n"); + + voice_save(0); + voice_hear(0); + + modem_command(&vboxmodem, "", "NO CARRIER"); + } + + + + + + + + + + + modem_set_timeout(0); + + return(0); +} + + + +/*************************************************************************/ +/** **/ +/*************************************************************************/ + +int voice_save(int save) +{ + if (save) + { + if (voicesave == -1) + { + voicesave = open(voicename, O_WRONLY|O_CREAT|O_APPEND); + } + + if (voicesave != -1) return(0); + } + else + { + if (voicesave != -1) close(voicesave); + + voicesave = -1; + + return(0); + } + + return(-1); +} + +int voice_hear(int hear) +{ + if (hear) + { + if (voicehear == -1) + { + voicehear = open("/dev/audio", O_WRONLY); + } + + if (voicehear != -1) return(0); + } + else + { + if (voicehear != -1) close(voicehear); + + voicehear = -1; + + return(0); + } + + return(-1); +} diff --git a/vbox3/vboxgetty/voice.h b/vbox3/vboxgetty/voice.h new file mode 100644 index 00000000..6f946951 --- /dev/null +++ b/vbox3/vboxgetty/voice.h @@ -0,0 +1,32 @@ +/* +** $Id$ +** +** Copyright 1997-1998 by Michael 'Ghandi' Herold +*/ + +#ifndef _VBOX_VOICE_H +#define _VBOX_VOICE_H 1 + +#define VBOXVOICE_BUFFER_SIZE 32 + +#define VBOXVOICE_STAT_OK 0 +#define VBOXVOICE_STAT_TIMEOUT 1 +#define VBOXVOICE_STAT_HANGUP 2 +#define VBOXVOICE_STAT_TOUCHTONE 4 + +#define ETX (0x03) +#define NL (0x0A) +#define CR (0x0D) +#define DLE (0x10) +#define XON (0x11) +#define XOFF (0x13) +#define DC4 (0x14) +#define CAN (0x18) + + +extern int voice_init(void); +extern int voice_save(int); +extern int voice_hear(int); +extern int voice_wait(int); + +#endif /* _VBOX_VOICE_H */