/*
**
** Copyright (C) 1993 Swedish University Network (SUNET)
**
**
** This program is developed by UDAC, Uppsala University by commission
** of the Swedish University Network (SUNET).
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITTNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**
**
** Martin.Wendel@its.uu.se
** Torbjorn.Wictorin@its.uu.se
**
** ITS
** P.O. Box 887
** S-751 08 Uppsala
** Sweden
**
*/
#include "emil.h"
#ifdef SMTP
#define RTYPE(r) ((r) / 100)
#define RCLASS(r) (((r) / 10) % 10)
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#ifdef NAMED_BIND
#ifdef HAVE_RES_SEARCH
#include <arpa/nameser.h>
#include <resolv.h>
#endif
#endif
#define SMTPBUF 1024
#define smtpout out_fd
#ifndef INADDR_NONE
# define INADDR_NONE 0xffffffff
#endif
#ifndef SMTPHOSTNAME
#define SMTPHOSTNAME "nohost.nodomain"
#endif
FILE *smtpin;
extern FILE *out_fd;
static char outbuf[SMTPBUF], inbuf[SMTPBUF];
#endif
#ifdef NAMED_BIND
#ifdef HAVE_RES_SEARCH
extern int h_errno;
#endif
#endif
void
make_connection(char *ahost, FILE **in, FILE **out, int usemx)
{
#ifdef SMTP
register struct hostent *h = (struct hostent *)NULL;
struct sockaddr_in server;
int sock = 0;
int sockt = 0;
int i;
char *p, *t;
char *host;
#ifdef USE_MX
#ifdef HAVE_RES_SEARCH
struct mxlist *list;
#endif
#endif
t = NULL;
#ifdef NAMED_BIND
#ifdef HAVE_RES_SEARCH
_res.options &= (~RES_DNSRCH & 0xffff);
list = NULL;
#endif
#endif
host = ahost;
errno = h_errno = 0;
if (*host == '[')
{
unsigned long i = INADDR_NONE;
p = host + 1;
if ((t = index(host, ']')) != NULL)
{
*t = '\0';
i = inet_addr(p);
*t = ']';
}
if (t == NULL || i == INADDR_NONE)
{
/* Invalid server spec */
fprintf(stderr, "Emil: Unknown host %s\n", host);
exit(EX_NOHOST);
}
server.sin_addr.s_addr = i;
}
lookup:
errno = 0;
if (t == NULL)
{
#ifdef USE_MX
#ifdef HAVE_RES_SEARCH
if (usemx)
/* Look for MX */
{
list = (struct mxlist *)get_mx(host);
usemx = 0;
}
if (list != NULL)
{
host = list->host;
list = list->next;
}
#endif
#endif
if ((h = (struct hostent *)gethostbyname(host)) == NULL)
{
#ifdef USE_MX
#ifdef HAVE_RES_SEARCH
if (list != NULL)
goto lookup;
#endif
#endif
if (errno == ETIMEDOUT || h_errno == TRY_AGAIN)
exit (EX_TEMPFAIL);
if (errno == ECONNREFUSED)
exit(EX_TEMPFAIL);
/* Failed */
fprintf(stderr, "Emil: Host lookup failed.\n");
fprintf(stderr, "Emil: Unknown host %s\n", host);
exit(EX_NOHOST);
}
else
bcopy((char *)h->h_addr, (char *)&server.sin_addr, h->h_length);
}
i = 0;
again:
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
fprintf(stderr, "Emil: Unable to create socket\n");
exit(EX_TEMPFAIL);
}
server.sin_family = AF_INET;
server.sin_port = htons(25);
errno = 0;
if (connect(sock,(struct sockaddr *)&server, sizeof server) < 0)
{
close(sock);
#ifdef NAMED_BIND
#ifdef HAVE_RES_SEARCH
if (h && h->h_addr_list[i])
{
bcopy(h->h_addr_list[i++],
(char *)&server.sin_addr, h->h_length);
goto again;
}
if (list != NULL)
goto lookup;
#endif
#endif
switch(errno) {
case EISCONN:
case ETIMEDOUT:
case EINPROGRESS:
case EALREADY:
case EADDRINUSE:
case EHOSTDOWN:
case ENETDOWN:
case ENETRESET:
case ENOBUFS:
case ECONNREFUSED:
case ECONNRESET:
case EHOSTUNREACH:
case ENETUNREACH:
case EPERM:
exit (EX_TEMPFAIL);
default:
{
fprintf(stderr, "Emil: Unable to connect to %s\n", host);
exit(EX_TEMPFAIL);
}
}
}
*out = fdopen(sock, "a");
if ((sockt = dup(sock)) == -1)
{
fprintf(stderr, "Emil dup(socket) failed.\n");
exit(EX_OSERR);
}
*in = fdopen(sockt, "r");
if (smtpout == NULL || smtpin == NULL)
{
close(sock);
fprintf(stderr, "Emil: smtp open failed.\n");
exit(EX_TEMPFAIL);
}
}
void
smtp_open(char *host)
{
int r;
#if defined(HAVE_RES_SEARCH) && defined(USE_MX)
make_connection(host, &smtpin, &smtpout, 1);
#else
make_connection(host, &smtpin, &smtpout, 0);
#endif
if ((r = smtp_get()) < 0 || RTYPE(r) != 2)
{
fprintf(stderr, "Emil: %s greeted us with %d\n", host, r);
exit(EX_TEMPFAIL);
}
if (hostname == NULL)
hostname = NEWSTR(SMTPHOSTNAME);
sprintf(outbuf, "HELO %s\r\n", hostname);
if (fputs(outbuf, smtpout) == EOF)
{
fprintf(stderr, "Emil: smtp error on write\n");
exit(EX_TEMPFAIL);
}
fflush(smtpout);
#ifdef DEBUG
if (edebug)
fprintf(stderr, "SMTP write: %s", outbuf);
#endif
if ((r = smtp_get()) < 0 || RTYPE(r) != 2)
{
fprintf(stderr, "Emil: %s said %d\n", host, r);
exit(EX_TEMPFAIL);
}
sprintf(outbuf, "MAIL FROM: <%s>\r\n", sender);
if (fputs(outbuf, smtpout) == EOF)
{
fprintf(stderr, "Emil: smtp error on write\n");
exit(EX_TEMPFAIL);
}
fflush(smtpout);
#ifdef DEBUG
if (edebug)
fprintf(stderr, "SMTP write: %s", outbuf);
#endif
r = smtp_get();
if (r != 250)
{
fprintf(stderr, "Emil: sender %s not accepted by %s", sender, host);
exit(EX_NOUSER);
}
sprintf(outbuf, "RCPT TO: <%s>\r\n", recipient);
if (fputs(outbuf, smtpout) == EOF)
{
fprintf(stderr, "Emil: smtp error on write\n");
exit(EX_TEMPFAIL);
}
fflush(smtpout);
#ifdef DEBUG
if (edebug)
fprintf(stderr, "SMTP write: %s", outbuf);
#endif
r = smtp_get();
if (r != 250)
{
fprintf(stderr, "Emil: recipient %s not accepted by %s\n", recipient, host);
exit(EX_NOUSER);
}
sprintf(outbuf, "DATA\r\n");
if (fputs(outbuf, smtpout) == EOF)
{
fprintf(stderr, "Emil: smtp error on write\n");
exit(EX_TEMPFAIL);
}
fflush(smtpout);
#ifdef DEBUG
if (edebug)
fprintf(stderr, "SMTP write: DATA\r\n");
#endif
r = smtp_get();
if (r != 250 && r != 354)
{
fprintf(stderr, "Emil: data transfer to %s failed\n", host);
exit(EX_NOUSER);
}
#endif
}
void
smtp_close(char *host)
{
int r;
sprintf(outbuf, "\r\n.\r\n");
fputs(outbuf, smtpout);
fflush(smtpout);
#ifdef DEBUG
if (edebug)
fprintf(stderr, "SMTP write: .\r\n");
#endif
r = smtp_get();
if (r != 250)
{
fprintf(stderr, "Emil: %s said %d after data transer completed\n", host, r);
exit(EX_TEMPFAIL);
}
sprintf(outbuf, "QUIT\r\n");
#ifdef DEBUG
if (edebug)
fprintf(stderr, "SMTP write: QUIT\r\n");
#endif
fputs(outbuf, smtpout);
fflush(smtpout);
r = smtp_get();
}
int
smtp_get()
{
int i;
for(;;)
{
if ((fgets(inbuf, SMTPBUF, smtpin)) == NULL)
{
fprintf(stderr, "Emil SMTP: Error on read.\n");
exit(EX_TEMPFAIL);
}
#ifdef DEBUG
if (edebug)
fprintf(stderr, "SMTP read:%s:", inbuf);
#endif
if (inbuf[0] == '4' || inbuf[0] == '5')
{
/* Serious error */
exit(EX_NOUSER);
}
i = atoi(inbuf);
if (inbuf[3] == '-')
continue;
if (i < 100)
continue;
return(i);
}
}
syntax highlighted by Code2HTML, v. 0.9.1