This is tcpsmtp.c in view mode; [Download] [Up]
/* @(#)src/transports/tcpsmtp.c 1.2 24 Oct 1990 05:26:02 */ /* * 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(); /* * 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); } /* * 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; } /* * 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); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.