|
|
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 t
Length: 9652 (0x25b4)
Types: TextFile
Names: »tcpsmtp.c«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
└─⟦2fafebccf⟧ »EurOpenD3/mail/smail3.1.19.tar.Z«
└─⟦bcd2bc73f⟧
└─⟦this⟧ »src/transports/tcpsmtp.c«
/* @(#)tcpsmtp.c 1.5 4/2/89 22:14:00 */
/*
* Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll
*
* See the file COPYING, distributed with smail, for restriction
* and warranty information.
*/
/*
* tcpsmtp.c:
* Send mail using the SMTP protocol.
*/
#include <stdio.h>
#include <signal.h>
#include <ctype.h>
#include <setjmp.h>
#include "defs.h"
#ifdef CMC
# include <sys/CMC/longnames.h>
# include <sys/CMC/netdb.h>
# include <sys/CMC/types.h>
# include <sys/CMC/socket.h>
# include <sys/CMC/in.h>
#else /* not CMC */
# include <netdb.h>
# include <sys/types.h>
# ifdef UNIX_CPC
# include <h/types42.h>
# include <h/socket.h>
# else /* not UNIX_CPC */
# include <sys/socket.h>
# endif /* not UNIX_CPC */
# include <netinet/in.h>
#endif /* not CMC */
#include "../smail.h"
#include "../dys.h"
#include "../addr.h"
#include "../transport.h"
#include "../spool.h"
#include "../exitcodes.h"
#include "../smailconf.h"
#include "../parse.h"
#include "tcpsmtp.h"
#include "smtplib.h"
#ifndef DEPEND
# include "../extern.h"
# include "../error.h"
# include "../debug.h"
#endif
/* functions local to this file */
static char *set_short_timeout();
static char *set_long_timeout();
static char *set_timeout();
static int tcpsmtp_connect();
static struct error *connect_failure();
\f
/*
* tpd_tcpsmtp - transport to remote machine using SMTP on top of TCP/IP.
*/
void
tpd_tcpsmtp(addr, succeed, defer, fail)
struct addr *addr; /* recipient addresses for transport */
struct addr **succeed; /* successful deliveries */
struct addr **defer; /* defer until a later queue run */
struct addr **fail; /* failed deliveries */
{
struct transport *tp = addr->transport;
struct tcpsmtp_private *priv;
int s; /* socket */
int s2; /* dup of s */
char *error_text; /* error message */
struct error *error; /* error structure */
struct smtp smtpbuf; /* SMTP description buffer */
int success;
char *service;
priv = (struct tcpsmtp_private *)tp->private;
DEBUG2(DBG_DRIVER_LO, "transport %s: connect to host %s ...",
addr->transport->name, addr->next_host);
service = expand_string(priv->service, addr, (char *)0, (char *)0);
if (service == NULL) {
error_text = xprintf("failed to expand service, %s", priv->service);
insert_addr_list(addr, defer,connect_failure(tp, error_text));
return;
}
s = tcpsmtp_connect(addr->next_host, service, &error_text);
if (s >= 0) {
s2 = dup(s);
if (s2 < 0) {
(void) close(s);
s = -1;
}
}
if (s < 0) {
insert_addr_list(addr, defer, connect_failure(tp, error_text));
return;
}
smtpbuf.in = fdopen(s, "r");
smtpbuf.out = fdopen(s2, "w");
smtpbuf.short_timeout = priv->short_timeout;
smtpbuf.long_timeout = priv->long_timeout;
smtpbuf.nl = "\r\n";
tp->flags |= PUT_CRLF;
smtpbuf.tp = tp;
DEBUG(DBG_DRIVER_LO, "connected\n");
switch (smtp_startup(&smtpbuf, &error)) {
case SMTP_FAIL:
insert_addr_list(addr, fail, error);
(void) fclose(smtpbuf.in);
(void) fclose(smtpbuf.out);
return;
case SMTP_AGAIN:
insert_addr_list(addr, defer, error);
(void) fclose(smtpbuf.in);
(void) fclose(smtpbuf.out);
return;
}
if (dont_deliver) {
insert_addr_list(addr, succeed, (struct error *)NULL);
smtp_shutdown(&smtpbuf);
} else {
success = smtp_send(&smtpbuf, addr, succeed, defer, fail);
if (success == SUCCEED) {
smtp_shutdown(&smtpbuf);
}
}
/* all done */
(void) fclose(smtpbuf.in);
(void) fclose(smtpbuf.out);
return;
}
/*
* tpd_smtp - obsolescent name for tpd_tcpsmtp driver
*
* This routine exists for backward compatibility with Smail alpha
* releases prior to version 3.1.12.
*/
void
tpd_smtp(addr, succeed, defer, fail)
struct addr *addr; /* recipient addresses for transport */
struct addr **succeed; /* successful deliveries */
struct addr **defer; /* defer until a later queue run */
struct addr **fail; /* failed deliveries */
{
tpd_tcpsmtp(addr, succeed, defer, fail);
}
\f
/*
* tpb_tcpsmtp - read the configuration file attributes
*/
char *
tpb_tcpsmtp(tp, attrs)
struct transport *tp; /* transport entry being defined */
struct attribute *attrs; /* list of per-driver attributes */
{
char *error;
static struct attr_table tcpsmtp_attributes[] = {
{ "short_timeout", t_proc, NULL, (tup *)set_short_timeout, 0 },
{ "long_timeout", t_proc, NULL, (tup *)set_long_timeout, 0 },
{ "service", t_string, NULL, NULL, OFFSET(tcpsmtp_private, service) },
};
static struct attr_table *end_tcpsmtp_attributes =
ENDTABLE(tcpsmtp_attributes);
static struct tcpsmtp_private tcpsmtp_template = {
5 * 60, /* short timeout, 5 minutes */
2 * 60 * 60, /* long timeout, 2 hours */
"smtp", /* use the "smtp" service */
};
struct tcpsmtp_private *priv; /* new tcpsmtp_private structure */
/* copy the template private data */
priv = (struct tcpsmtp_private *)xmalloc(sizeof(*priv));
(void) memcpy((char *)priv, (char *)&tcpsmtp_template, sizeof(*priv));
tp->private = (char *)priv;
/* fill in the attributes of the private data */
error = fill_attributes((char *)priv,
attrs,
&tp->flags,
tcpsmtp_attributes,
end_tcpsmtp_attributes);
if (error) {
return error;
}
return NULL;
}
/*
* tpb_smtp - obsolescent name for tcpsmtp driver
*
* This routine exists for backward compatibility with Smail alpha
* releases prior to version 3.1.12.
*/
char *
tpb_smtp(tp, attrs)
struct transport *tp; /* transport entry being defined */
struct attribute *attrs; /* list of per-driver attributes */
{
return tpb_tcpsmtp(tp, attrs);
}
static char *
set_short_timeout(struct_p, attr)
char *struct_p; /* passed private structure */
struct attribute *attr; /* parsed attribute */
{
struct tcpsmtp_private *priv = (struct tcpsmtp_private *)struct_p;
return set_timeout(&priv->short_timeout, attr);
}
static char *
set_long_timeout(struct_p, attr)
char *struct_p; /* passed private structure */
struct attribute *attr; /* parsed attribute */
{
struct tcpsmtp_private *priv = (struct tcpsmtp_private *)struct_p;
return set_timeout(&priv->long_timeout, attr);
}
static char *
set_timeout(timeout, attr)
unsigned *timeout; /* set this timeout variable */
struct attribute *attr; /* parsed attribute */
{
long l;
if (attr->value == on) {
return xprintf("%s: boolean form for non-boolean attribute",
attr->name);
}
l = ivaltol(attr->value);
if (l < 0) {
return xprintf("%s: %s: malformed interval",
attr->name, attr->value);
}
*timeout = (unsigned)l;
if (*timeout != l) {
return xprintf("%s: %s: interval too large", attr->name, attr->value);
}
return NULL;
}
\f
/*
* tcpsmtp_connect - return a socket connected to the remote host
*
* if the remote host is of the form [192.2.12.3] then use an explicit
* inet address.
*/
static int
tcpsmtp_connect(remote_host, service, error)
char *remote_host;
char *service;
char **error;
{
static int port = 0; /* port to connect to */
struct servent *smtp_service; /* service entry */
struct hostent *hostentp; /* addr for remote host */
struct sockaddr_in sin; /* inet socket address */
static char *save_error = NULL; /* keep handle to free error msgs */
int s; /* socket */
char *error_text;
if (isdigit(*service)) {
error_text = NULL;
port = c_atol(service, &error_text);
if (error_text) {
*error = xprintf("invalid port: %s", service, error_text);
return -1;
}
} else if (port == NULL) {
smtp_service = getservbyname(service, "tcp");
if (smtp_service == NULL) {
*error = xprintf("service name %s not found", service);
return -1;
}
port = smtp_service->s_port;
}
bzero((char *)&sin, sizeof(sin));
if (remote_host[0] == '[') {
/* INET addr literal address */
char *p = index(remote_host, ']');
unsigned long inet_number;
if (p == NULL || p[1] != '\0') {
*error = "Invalid host address";
return -1;
} else {
*p = '\0';
inet_number = inet_addr(remote_host + 1);
*p = ']';
}
sin.sin_addr.s_addr = inet_number;
sin.sin_family = AF_INET;
} else {
hostentp = gethostbyname(remote_host);
if (hostentp == NULL) {
*error = "Unknown hostname";
return -1;
}
bcopy(hostentp->h_addr, (char *)&sin.sin_addr, hostentp->h_length);
sin.sin_family = hostentp->h_addrtype;
}
sin.sin_port = port;
s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0) {
if (save_error) {
xfree(save_error);
}
*error = save_error = xprintf("socket: %s", strerrno());
return -1;
}
if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
if (save_error) {
xfree(save_error);
}
*error = save_error = xprintf("connect: %s", strerrno());
(void) close(s);
return -1;
}
return s;
}
static struct error *
connect_failure(tp, connect_error_text)
struct transport *tp;
char *connect_error_text;
{
char *error_text;
/*
* ERR_148 - smtp connection failure
*
* DESCRIPTION
* We failed to connect to the smtp service of the remote
* host. The reason is stored in `error'.
*
* ACTIONS
* The input addresses are deferred.
*
* RESOLUTION
* Hopefully we will connect on a retry.
*/
error_text = xprintf("transport %s: %s", tp->name, connect_error_text);
DEBUG1(DBG_DRIVER_LO, "%s\n", error_text);
return note_error(ERR_148, error_text);
}