|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T r
Length: 8571 (0x217b)
Types: TextFile
Names: »remote.c«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
└─⟦f91e15335⟧ »EurOpenD3/news/nntp/nntplink2.0.0.tar.Z«
└─⟦2c70c5e6b⟧
└─⟦this⟧ »remote.c«
/*
** remote communication routines for NNTP/SMTP style communication.
**
** sendcmd - return TRUE on error.
**
** readreply - return reply code or FAIL for error;
** modifies buffer passed to it.
**
** converse - sendcmd() & readreply();
** return reply code or FAIL for error;
** modifies buffer passed to it.
**
** hello - establish connection with remote;
** check greeting code.
**
** goodbye - give QUIT command, and shut down connection.
**
** sfgets - safe fgets(); does fgets with TIMEOUT.
** (N.B.: possibly unportable stdio macro ref in here)
**
** sendfile - send a file with SMTP dot escaping and
** \n -> \r\n conversion.
**
** Erik E. Fair <fair@ucbarpa.berkeley.edu>
*/
#include "conf.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
#include <setjmp.h>
#include <signal.h>
#ifdef dgux
#define _IOERR _IO_ERR
#endif
#ifdef SYSLOG
#include <syslog.h>
#endif
#include "get_tcp_conn.h"
#include "nntp.h"
static jmp_buf SFGstack;
FILE *rmt_rd;
FILE *rmt_wr;
char *sfgets();
extern int errno;
extern char Debug;
extern char *errmsg();
extern char *strcpy();
extern void log();
/*
** send cmd to remote, terminated with a CRLF.
*/
sendcmd(cmd)
char *cmd;
{
if (cmd == (char *)NULL)
return(TRUE); /* error */
dprintf(stderr, ">>> %s\n", cmd); /* DEBUG */
(void) fprintf(rmt_wr, "%s\r\n", cmd);
(void) fflush(rmt_wr);
return(ferror(rmt_wr));
}
/*
** read a reply line from the remote server and return the code number
** as an integer, and the message in a buffer supplied by the caller.
** Returns FAIL if something went wrong.
*/
readreply(buf, size)
register char *buf;
int size;
{
register char *cp;
register int len;
if (buf == (char *)NULL || size <= 0)
return(FAIL);
/*
** make sure it's invalid, unless we say otherwise
*/
buf[0] = '\0';
/*
** read one line from the remote
*/
if (sfgets(buf, size, rmt_rd) == NULL)
return(FAIL); /* error reading from remote */
/*
** Make sure that what the remote sent us had a CRLF at the end
** of the line, and then null it out.
*/
if ((len = strlen(buf)) > 2 && *(cp = &buf[len - 2]) == '\r' &&
*(cp + 1) == '\n')
{
*cp = '\0';
} else
return(FAIL); /* error reading from remote */
dprintf(stderr, "%s\n", buf); /* DEBUG */
/*
** Skip any non-digits leading the response code
** and then convert the code from ascii to integer for
** return from this routine.
*/
cp = buf;
while(*cp != '\0' && isascii(*cp) && !isdigit(*cp))
cp++; /* skip anything leading */
if (*cp == '\0' || !isascii(*cp))
return(FAIL); /* error reading from remote */
return(atoi(cp));
}
/*
** send a command to the remote, and wait for a response
** returns the response code, and the message in the buffer
*/
converse(buf, size)
char *buf;
int size;
{
register int resp;
if (sendcmd(buf))
return(FAIL); /* Ooops! Something went wrong in xmit */
/*
** Skip the silly 100 series messages, since they're not the
** final response we can expect
*/
while((resp = readreply(buf, size)) >= 100 && resp < 200)
continue;
return(resp);
}
/*
** Contact the remote server and set up the two global FILE pointers
** to that descriptor.
**
** I can see the day when this routine will have 8 args: one for
** hostname, and one for each of the seven ISO Reference Model layers
** for networking. A curse upon those involved with the ISO protocol
** effort: may they be forced to use the network that they will create,
** as opposed to something that works (like the Internet).
*/
hello(host, transport)
char *host;
int transport;
{ char *service;
char *rmode = "r";
char *wmode = "w";
char *e_fdopen = "fdopen(%d, \"%s\"): %s";
int socket0, socket1; /* to me (bad pun) */
char buf[BUFSIZ];
retry:
switch(transport) {
case T_IP_TCP:
service = "nntp";
socket0 = get_tcp_conn(host, service);
break;
case T_DECNET:
#ifdef DECNET
(void) signal(SIGPIPE, SIG_IGN);
service = "NNTP";
socket0 = dnet_conn(host, service, 0, 0, 0, 0, 0);
if (socket0 < 0) {
switch(errno) {
case EADDRNOTAVAIL:
socket0 = NOHOST;
break;
case ESRCH:
socket0 = NOSERVICE;
break;
}
}
break;
#else
log(L_WARNING, "no DECNET support compiled in");
return(FAIL);
#endif
case T_FD:
service = "with a smile";
socket0 = atoi(host);
break;
}
if (socket0 < 0) {
switch(socket0) {
case NOHOST:
sprintf(buf, "%s host unknown", host);
log(L_WARNING, buf);
sleep(60);
goto retry;
case NOSERVICE:
sprintf(buf, "%s service unknown: %s", host, service);
log(L_WARNING, buf);
return(FAIL);
case FAIL:
sprintf(buf, "%s hello: %s", host, errmsg(errno));
log(L_NOTICE, buf);
return(FAIL);
}
}
if ((socket1 = dup(socket0)) < 0) {
sprintf(buf, "dup(%d): %s", socket0, errmsg(errno));
log(L_WARNING, buf);
(void) close(socket0);
return(FAIL);
}
if ((rmt_rd = fdopen(socket0, rmode)) == (FILE *)NULL) {
sprintf(buf, e_fdopen, socket0, rmode);
log(L_WARNING, buf);
(void) close(socket0);
(void) close(socket1);
return(FAIL);
}
if ((rmt_wr = fdopen(socket1, wmode)) == (FILE *)NULL) {
sprintf(buf, e_fdopen, socket1, wmode);
log(L_WARNING, buf);
(void) fclose(rmt_rd);
rmt_rd = (FILE *)NULL;
(void) close(socket1);
return(FAIL);
}
switch(readreply(buf, sizeof(buf))) {
case OK_CANPOST:
case OK_NOPOST:
if (ferror(rmt_rd)) {
goodbye(DONT_WAIT);
return(FAIL);
}
break;
default:
if (buf[0] != '\0') {
char err[BUFSIZ];
sprintf(err, "%s greeted us with %s", host, buf);
log(L_NOTICE, err);
}
goodbye(DONT_WAIT);
return(FAIL);
}
return(NULL);
}
/*
** Say goodbye to the nice remote server.
**
** We trap SIGPIPE because the socket might already be gone.
*/
goodbye(wait_for_reply)
int wait_for_reply;
{
#ifdef sun
register ifunp pstate = (int (*)())signal(SIGPIPE, SIG_IGN);
#else
register ifunp pstate = signal(SIGPIPE, SIG_IGN);
#endif sun
if (rmt_rd == NULL)
return;
if (sendcmd("QUIT"))
wait_for_reply = FALSE; /* override, something's wrong. */
/*
** I don't care what they say to me; this is just being polite.
*/
if (wait_for_reply) {
char buf[BUFSIZ];
(void) readreply(buf, sizeof(buf));
}
(void) fclose(rmt_rd);
rmt_rd = (FILE *)NULL;
(void) fclose(rmt_wr);
rmt_wr = (FILE *)NULL;
if (pstate != (ifunp)(-1));
(void) signal(SIGPIPE, pstate);
}
static
to_sfgets()
{
longjmp(SFGstack, 1);
}
/*
** `Safe' fgets, ala sendmail. This fgets will timeout after some
** period of time, on the assumption that if the remote did not
** return, they're gone.
** WARNING: contains a possibly unportable reference to stdio
** error macros.
*/
char *
sfgets(buf, size, fp)
char *buf;
int size;
FILE *fp;
{
register char *ret;
int esave;
if (buf == (char *)NULL || size <= 0 || fp == (FILE *)NULL)
return((char *)NULL);
if (setjmp(SFGstack)) {
(void) alarm(0); /* reset alarm clock */
(void) signal(SIGALRM, SIG_DFL);
#ifdef apollo
fp->_flag |= _SIERR;
#else
fp->_flag |= _IOERR; /* set stdio error */
#endif
#ifndef ETIMEDOUT
errno = EPIPE; /* USG doesn't have ETIMEDOUT */
#else
errno = ETIMEDOUT; /* connection timed out */
#endif
return((char *)NULL); /* bad read, remote time out */
}
(void) signal(SIGALRM, to_sfgets);
(void) alarm(TIMEOUT);
ret = fgets(buf, size, fp);
esave = errno;
(void) alarm(0); /* reset alarm clock */
(void) signal(SIGALRM, SIG_DFL); /* reset SIGALRM */
errno = esave;
return(ret);
}
/*
** send the contents of an open file descriptor to the remote,
** with appropriate RFC822 filtering (e.g. CRLF line termination,
** and dot escaping). Return FALSE if something went wrong.
*/
sendfile(fp)
FILE *fp;
{
register int c;
register FILE *remote = rmt_wr;
register int nl = TRUE; /* assume we start on a new line */
/*
** I'm using putc() instead of fputc();
** why do a subroutine call when you don't have to?
** Besides, this ought to give the C preprocessor a work-out.
*/
#define PUTC(c) if (putc(c, remote) == EOF) return(FALSE)
if (fp == (FILE *)NULL)
return(FALSE);
/*
** the second test makes no sense to me,
** but System V apparently needed it...
*/
while((c = fgetc(fp)) != EOF && !feof(fp)) {
switch(c) {
case '\n':
PUTC('\r'); /* \n -> \r\n */
PUTC(c);
nl = TRUE; /* for dot escaping */
break;
case '.':
if (nl) {
PUTC(c); /* add a dot */
nl = FALSE;
}
PUTC(c);
break;
default:
PUTC(c);
nl = FALSE;
break;
}
}
if (!nl) {
PUTC('\r');
PUTC('\n');
}
return( !(sendcmd(".") || ferror(fp)) );
}