home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.qualcomm.com
/
2014.06.ftp.qualcomm.com.tar
/
ftp.qualcomm.com
/
eudora
/
servers
/
unix
/
srialpop.shar
/
srialpop.c
< prev
Wrap
C/C++ Source or Header
|
1997-03-26
|
14KB
|
532 lines
/*
S R I A L P O P (POP over serial lines)
Author: Rudi van Houten <R.vanHouten@cc.ruu.nl>
Ac.Comp.Centr.Utrecht (Netherlands)
With thanks to:
Steve Dorner <sdorner@qualcomm.com>
Scott Hannahs <sth@slipknot.mit.edu>
Mogen Trab Damsgaard <trab@kubism.ku.dk>
Richard J. Johnson <johnsonr@Colorado.EDU>
see the file README for an introduction and hints for installation
========================== COPYRIGHT NOTICE =============================
This package srialpop is written by and copyright Rudi van Houten
<R.vanHouten@cc.ruu.nl>, it is tested and used now at ACCU (Ac.Comp.
Centr.Utrecht, the Netherlands) for several years.
The package consists of four files:
srialpop.c the C source of the program
Makefile to build and eventually install the package
README an old documentation describing the package
INSTALL a newer document with concise installation instructions
I grant everybody the right to use the package and eventually
adapt it to local requirements. Please document your changes in the
program source with comments explicitely stating that a modification
to the original package has been made. I don't want to be blamed for
your errors nor get the praise for your inventions.
Also everybody has the right to bundle this package with other software
(e.g. a POP client) on distribution media, but THEN THE UNCHANGED VERSION
MUST BE DISTRIBUTED, and no extra fee may be charged for the presence
of srialpop in the bundle. If there is a need to modify srialpop for
special purposes these modification should be made available as a separate
file (e.g. a diff file to be applied with Larry Wall's patch program).
I present this package as is, feeling it can be of use. But no
guarantees are given about its proper working or behaviour. It has
been used at ACCU for some years now without troubles, so I think it may
be bug free. But I cannot be held responsible for any damage or other
misery resulting from using srialpop.
===========================================================================
*/
static char sccsid[]= "@(#)srialpop.c 2.3";
/*
this is the time to wait (seconds) after a logout command before
actually breaking the connection
*/
#define LOGOUTGRACE 3
/*
define some symbols for the logging facility
*/
#define ONFILE 0
#define LOGBSD42 1
#define LOGBSD43 2
/*
define the include file for the termio/sgtty structs
*/
#define SGTTY 0
#define TERMIO 1
#define TERMIOS 2
#include <stdio.h>
#include "hdrs.h"
#include <fcntl.h>
#include <signal.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <string.h>
#if TERM_H==TERMIOS
# include <termios.h>
#elif TERM_H==TERMIO
# include <termio.h>
#else
# include <sgtty.h>
#endif
#ifdef __STDC__
# include <stdarg.h>
#else
# include <varargs.h>
#endif
#include <time.h>
#if LOGGING > ONFILE
# include <syslog.h>
#endif
#ifndef TIMEOUT
# define TIMEOUT 300
#endif
#ifdef LOGGING
# if LOGGING==ONFILE
# define LOG_NOTICE 0
# define LOG_INFO 1
# undef LOGLEVEL
# define LOGLEVEL LOG_INFO
# else
# if LOGGING==LOGBSD43
# ifndef LOGFACILITY
# define LOGFACILITY LOG_LOCAL0
# endif
# endif
# ifndef LOGLEVEL
# define LOGLEVEL LOG_INFO
# endif
# endif
#endif
#define CRLF "\r\n"
#define warning(msg) write(2,msg,strlen(msg))
#define iBuflen 512
static char sBuf[iBuflen];
static short iValidPort[]=
{105 /* PH server */
,106 /* password server */
,109 /* POP2 */
,110 /* POP3 */
#ifndef NO_SMTP
,25 /* SMTP */
#endif
};
#define iValidPortsCount sizeof(iValidPort)/sizeof(short)
#if TERM_H==TERMIOS
static struct termios sTermHold, sTermCurr;
#elif TERM_H==TERMIO
static struct termio sTermHold, sTermCurr;
#else
static struct sgttyb sTermHold, sTermCurr;
#endif
#if LOGGING==ONFILE
static char *tMonth[]=
{"Jan","Feb","Mar","Apr","May","Jun"
,"Jul","Aug","Sep","Oct","Nov","Dec"
};
#endif
#if TERM_H > SGTTY
# if defined(sgi) || defined(__sgi)
# define CRTSCTS CNEW_RTSCTS
# elif !defined(CRTSCTS) && defined(FLOWRTSCTS)
!! This machine seems unable to set rts/cts flowcontrol
!! disable/change that definition in the Makefile in DEFS=
# endif
#endif
extern int errno, sys_nerr;
extern char *sys_errlist[];
#ifdef __STDC__
static void errorexit(const char*, ... );
static void timetrap(int);
static void timtrap2(int);
# ifdef EXTRATTYFLAGS
static void extrattyflags(void);
# endif
# ifdef LOGGING
static void report(const int,const char*, ...);
# endif
void main(void);
#endif
#ifdef EXTRATTYFLAGS
static void extrattyflags()
{
/*
* This routine can be enabled by defining EXTRATTYFLAGS
* in the Makefile.
* Here code can be placed to add/clear extra flags and
* attributes in the tty discipline descriptions if you feel
* the need and don't want to change the main routine.
*/
return;
} /* void extrattyflags */
#endif
#ifdef LOGGING
# ifdef __STDC__
static void report(const int level,const char *sFormat, ...)
{
# else
static void report(va_alist) va_dcl
{
int level;
char *sFormat;
# endif
char sLogBuf[128];
va_list ap;
# if LOGGING==ONFILE
time_t iNow;
struct tm *sNow;
register FILE *logfile;
# endif
# ifdef __STDC__
va_start(ap,sFormat);
# else
va_start(ap);
level= va_arg(ap,int);
sFormat= va_arg(ap,char*);
# endif
vsprintf(sLogBuf,sFormat,ap);
va_end(ap);
# if LOGGING==ONFILE
iNow= time(NULL);
sNow= localtime(&iNow);
if ((logfile= fopen("srialpop.log","a+")) == NULL)
warning("Couldn't open logfile, notify system manager\r\n");
else
{
fprintf(logfile,"%2d %s %2d %2d:%2d:%2d [%d]%s: %s\n"
,sNow->tm_mday,tMonth[sNow->tm_mon],sNow->tm_year
,sNow->tm_hour,sNow->tm_min,sNow->tm_sec
,getpid(),level == LOGLEVEL ? "" : " NOTICE",sLogBuf
);
(void)fclose(logfile);
}
# else
(void)syslog(level,"%s",sLogBuf);
# endif
} /* void report() */
#endif
#ifdef __STDC__
static void errorexit(const char *sFormat, ...)
{
#else
static void errorexit(va_alist) va_dcl
{
char *sFormat;
#endif
char sMsgBuf[128];
va_list ap;
write(2,CRLF,2);
#ifdef __STDC__
va_start(ap,sFormat);
#else
va_start(ap);
sFormat= va_arg(ap,char*);
#endif
vsprintf(sMsgBuf,sFormat,ap);
va_end(ap);
warning(sMsgBuf);
write(2,CRLF,2);
#ifdef LOGGING
report(errno != 0 ? LOG_NOTICE : LOGLEVEL,sMsgBuf);
#endif
#if TERM_H==TERMIOS
tcsetattr(0,TCSANOW,&sTermHold);
#elif TERM_H==TERMIO
ioctl(0,TCSETAF,&sTermHold);
#else
ioctl(0,TIOCSETP,&sTermHold);
#endif
sleep(1); exit(1);
} /* errorexit */
static void timetrap(iSign)
int iSign;
{
errorexit("Timeout on %d seconds",TIMEOUT);
} /* timetrap */
static void timtrap2(iSign)
int iSign;
{
exit(1);
} /* timtrap2 */
void main()
{
int iSock, iPort, iChild;
register int i, l;
struct in_addr sInAddr;
union CombineSock
{
struct sockaddr_in sServer;
struct sockaddr addr;
} uServer;
struct hostent *psHost, *gethostbyname(), *gethostbyaddr();
char *psCommand, *psName, *psNumber;
#ifdef LOGGING
# if LOGGING==LOGBSD42
openlog("srialpop",LOG_PID);
# elif LOGGING==LOGBSD43
openlog("srialpop",LOG_PID,LOGFACILITY);
# endif
#endif
/* get stty structure sTermHold */
#if TERM_H==TERMIOS
(void)tcgetattr(0,&sTermHold);
#elif TERM_H==TERMIO
ioctl(0,TCGETA,&sTermHold);
#else
ioctl(0,TIOCGETP,&sTermHold);
#endif
memcpy(&sTermCurr,&sTermHold,sizeof(sTermCurr));
/* and here prepare the line characteristics */
#if TERM_H > SGTTY
/* don't translate CR or LF, neither ignore CR */
sTermCurr.c_iflag &= ~(ICRNL | INLCR | IGNCR);
# ifndef _POSIX_SOURCE
sTermCurr.c_iflag &= ~IXANY;
# endif
# ifdef FLOWXONXOFF
/* enable software flow control (XON/XOFF, ^S/^Q) */
sTermCurr.c_iflag |= (IXON | IXOFF);
# endif
/* no output post processing */
sTermCurr.c_oflag &= ~OPOST;
# ifdef FLOWRTSCTS
/* enable hardware flow control (CTS/RTS) */
sTermCurr.c_cflag |= CRTSCTS;
# endif
/* disable echo, erase/kill processing and special
* signal handling (INTR, SUP, QUIT */
sTermCurr.c_lflag &= ~(ECHO | ICANON | ISIG );
/* read will wait endlessly till a character is received,
* but a timeout is set with alarm */
sTermCurr.c_cc[VMIN] = 1;
sTermCurr.c_cc[VTIME] = 0;
#else
/* disable echo, CR translation, tab expanding */
sTermCurr.sg_flags &= ~(ECHO | CRMOD | XTABS);
/* set half-cooked mode */
sTermCurr.sg_flags |= CBREAK;
/* get rid of funny old AT&T defaults for erase and kill */
sTermCurr.sg_erase = 0xff; sTermCurr.sg_kill = 0x15;
# ifdef FLOWRTSCTS
!! hardware flow control not supported with sgtty.h
!! disable/change that definition in the Makefile in DEFS=
# endif
# ifdef FLOWXONXOFF
/* set software flow control (XON/XOFF, ^S/^Q) */
sTermCurr.sg_flags |= TANDEM;
# endif
#endif
#ifdef EXTRATTYFLAGS
extrattyflags();
#endif
/* set line characteristics to NOECHO, NOCRLF etc. */
#if TERM_H==TERMIOS
tcsetattr(0,TCSANOW,&sTermCurr);
#elif TERM_H==TERMIO
ioctl(0,TCSETAF,&sTermCurr);
#else
ioctl(0,TIOCSETP,&sTermCurr);
#endif
/* first set the timeout trap (primitive signal call) */
signal(SIGALRM,timetrap);
#ifdef LOGGING
report(LOGLEVEL,"srialpop starts processing");
#endif
/* this is the main loop, it reads the telnet or exit commandline */
for (;;)
{
write(1,"%",1); l= 0;
while(alarm(TIMEOUT)
,read(0,&sBuf[l],1) == 1 && sBuf[l] != '\n' && sBuf[l] != '\r'
)
{
alarm(0);
write(1,&sBuf[l],1);
if (++l >= iBuflen) errorexit("Too long commandline");
}
if (sBuf[l] == '\n' || sBuf[l] == '\r') sBuf[l]= '\0'; else sBuf[++l]= '\0';
if (l == 0) continue;
write(1,CRLF,2);
if (strcmp(sBuf,"logout") == 0
|| strcmp(sBuf,"exit") == 0
|| strcmp(sBuf,"quit") == 0
)
break; /* finished, logout now */
/* next loop splits the commandline in its constituents */
i= 0; psCommand= psName= psNumber= NULL;
while (i < l && psNumber == NULL)
{
while (isspace(sBuf[i])) i++;
if (i >= l) break;
if (psCommand == NULL) psCommand= &sBuf[i]; /* command found */
else
if (psName == NULL) psName= &sBuf[i]; /* argument 1 */
else psNumber= &sBuf[i]; /* argument 2 */
do { i++; } while (!isspace(sBuf[i]) && i < l);
sBuf[i++]= '\0'; /* terminator after last argument */
}
/* now we have a command (telnet) with two
arguments (1=host 2=portnumber) */
if (strcmp(psCommand,"telnet"))
errorexit("Sorry, don't know '%s'\n",psCommand);
/* telnet is the only known command */
if (psName == NULL || psNumber == NULL)
errorexit("Sorry, hostname or portnumber missing\n");
/* and both host and port are required */
if (l= strlen(psNumber))
{
for (i= 0; i < l; i++)
if (!isdigit(psNumber[i]))
errorexit("Portnumber (%s) not numeric\n",psNumber);
iPort= atoi(psNumber);
}
else iPort= 0;
#ifdef LOGGING
report(LOGLEVEL,"connect to host %s on port %d",psName,iPort);
#endif
/* check validity of portnumber */
for (i=0; iPort != iValidPort[i]; i++)
if (i == iValidPortsCount)
errorexit("Sorry, %d is not a valid port\n",iPort);
/*
(unsigned long)(-1) = 0xffffffff, returnvalue
from inet_addr() if illegal address passed through.
I assume then it is a domain name.
Thanks to Edwin Kremer (edwin@cs.ruu.nl) for the trick
*/
if ((sInAddr.s_addr= inet_addr(psName)) == 0xffffffff)
psHost= gethostbyname(psName);
else
psHost= gethostbyaddr((char*)&sInAddr,sizeof(struct in_addr),AF_INET);
if (psHost == 0)
errorexit("Cannot find server %s (host unknown)\n",psName);
/* create socket */
if ((iSock= socket(AF_INET,SOCK_STREAM,0)) < 0)
errorexit("Cannot open IP socket: %s"
, errno > 0 && errno < sys_nerr ? sys_errlist[errno] : ""
);
/* fill socket structure .....*/
uServer.sServer.sin_family= AF_INET;
memcpy(&(uServer.sServer.sin_addr),psHost->h_addr,psHost->h_length);
uServer.sServer.sin_port= htons(iPort);
/*........and connect */
if (connect(iSock,&(uServer.addr),sizeof(uServer.addr)) < 0)
errorexit("connecting stream socket: %s"
, errno > 0 && errno < sys_nerr ? sys_errlist[errno] : ""
);
/* now fork a child to copy stdin to socket */
iChild= fork();
if (iChild < 0)
errorexit("Cannot fork: %s"
, errno > 0 && errno < sys_nerr ? sys_errlist[errno] : ""
);
if (iChild == 0)
{ /* the child copies stdin to the socket */
close(1); close(2); /* now close stdout and stderr */
signal(SIGALRM,timtrap2); /* reset to even more primitve routine */
if (alarm(TIMEOUT), read(0,sBuf,1) == 1)
{
if (sBuf[0] != '\r' && sBuf[0] != '\n') write(iSock,sBuf,1);
while ((alarm(TIMEOUT), l= read(0,sBuf,iBuflen)) > 0)
write(iSock,sBuf,l);
alarm(0);
}
close(0); exit(0);
} /* if (iChild == 0) */
/* no else part, child does exit
the parent copies the socket to stdout
*/
while ((alarm(TIMEOUT), l= read(iSock,sBuf,iBuflen)) > 0) write(1,sBuf,l);
alarm(0);
close(iSock);
kill(iChild,SIGTERM); /* superfluous */
#ifdef LOGGING
report(LOGLEVEL,"close TCP connection on port %d",iPort);
#endif
} /* main loop */
#ifdef LOGGING
report(LOGLEVEL,"srialpop session ending normally");
#endif
/* reset line characteristics */
#if TERM_H==TERMIOS
tcsetattr(0,TCSANOW,&sTermHold);
#elif TERM_H==TERMIO
ioctl(0,TCSETAF,&sTermHold);
#else
ioctl(0,TIOCSETP,&sTermHold);
#endif
sleep(LOGOUTGRACE); /* wait to satisfy Mac's Hayes Modem Tool */
close(0); close(1); close(2);
#if LOGGING==LOGBSD42 || LOGGING==LOGBSD43
closelog();
#endif
exit(0);
} /* main */