[aadk-commits] qwell: uClinux/trunk r249 - in /uClinux/trunk/uClinux-dist: config/ user/ use...

aadk-commits at lists.digium.com aadk-commits at lists.digium.com
Fri Mar 16 16:30:29 MST 2007


Author: qwell
Date: Fri Mar 16 18:30:29 2007
New Revision: 249

URL: http://svn.digium.com/view/aadk?view=rev&rev=249
Log:
Remove smtp-client from default build.

Add ssmtp sources and add to default build.

Added:
    uClinux/trunk/uClinux-dist/user/ssmtp/
    uClinux/trunk/uClinux-dist/user/ssmtp/Makefile   (with props)
    uClinux/trunk/uClinux-dist/user/ssmtp/arpadate.c   (with props)
    uClinux/trunk/uClinux-dist/user/ssmtp/base64.c   (with props)
    uClinux/trunk/uClinux-dist/user/ssmtp/ssmtp.c   (with props)
    uClinux/trunk/uClinux-dist/user/ssmtp/ssmtp.conf   (with props)
    uClinux/trunk/uClinux-dist/user/ssmtp/ssmtp.h   (with props)
Modified:
    uClinux/trunk/uClinux-dist/config/.config
    uClinux/trunk/uClinux-dist/config/Configure.help
    uClinux/trunk/uClinux-dist/config/config.in
    uClinux/trunk/uClinux-dist/user/Makefile
    uClinux/trunk/uClinux-dist/vendors/Digium/S800I/Makefile
    uClinux/trunk/uClinux-dist/vendors/Digium/S800I/config.linux-2.6.x
    uClinux/trunk/uClinux-dist/vendors/Digium/S800I/config.vendor-2.6.x
    uClinux/trunk/uClinux-dist/vendors/Digium/S800I/scripts/save_config

Modified: uClinux/trunk/uClinux-dist/config/.config
URL: http://svn.digium.com/view/aadk/uClinux/trunk/uClinux-dist/config/.config?view=diff&rev=249&r1=248&r2=249
==============================================================================
--- uClinux/trunk/uClinux-dist/config/.config (original)
+++ uClinux/trunk/uClinux-dist/config/.config Fri Mar 16 18:30:29 2007
@@ -201,7 +201,7 @@
 # CONFIG_USER_LINUXIGD_LINUXIGD is not set
 # CONFIG_USER_LOATTACH_LOATTACH is not set
 # CONFIG_USER_LRPSTAT_LRPSTAT is not set
-CONFIG_USER_SMTP_SMTPCLIENT=y
+# CONFIG_USER_SMTP_SMTPCLIENT is not set
 # CONFIG_USER_MAIL_MAIL_IP is not set
 # CONFIG_USER_MINI_HTTPD_MINI_HTTPD is not set
 # CONFIG_USER_MSNTP_MSNTP is not set
@@ -238,6 +238,7 @@
 # CONFIG_USER_SPEEDTOUCH_MODEM_RUN is not set
 # CONFIG_USER_STUNNEL_STUNNEL is not set
 # CONFIG_USER_SSLWRAP_SSLWRAP is not set
+CONFIG_USER_SMTP_SSMTP=y
 # CONFIG_USER_SQUID_SQUID is not set
 # CONFIG_USER_SSH_SSH is not set
 # CONFIG_USER_SSH_SSHD is not set

Modified: uClinux/trunk/uClinux-dist/config/Configure.help
URL: http://svn.digium.com/view/aadk/uClinux/trunk/uClinux-dist/config/Configure.help?view=diff&rev=249&r1=248&r2=249
==============================================================================
--- uClinux/trunk/uClinux-dist/config/Configure.help (original)
+++ uClinux/trunk/uClinux-dist/config/Configure.help Fri Mar 16 18:30:29 2007
@@ -1452,6 +1452,9 @@
 CONFIG_USER_SMTP_SMTPCLIENT
   Client which allows mail to be sent to other hosts that support SMTP
 
+CONFIG_USER_SMTP_SSMTP
+  Sendmail compatible client which allows mail to be sent to other hosts that support SMTP
+
 CONFIG_USER_SNMPD_SNMPD
   SNMP daemon
   Approx. binary size: 20k with no modules

Modified: uClinux/trunk/uClinux-dist/config/config.in
URL: http://svn.digium.com/view/aadk/uClinux/trunk/uClinux-dist/config/config.in?view=diff&rev=249&r1=248&r2=249
==============================================================================
--- uClinux/trunk/uClinux-dist/config/config.in (original)
+++ uClinux/trunk/uClinux-dist/config/config.in Fri Mar 16 18:30:29 2007
@@ -553,6 +553,7 @@
 bool 'speedtouch modem_run'	CONFIG_USER_SPEEDTOUCH_MODEM_RUN
 bool 'stunnel'			CONFIG_USER_STUNNEL_STUNNEL
 bool 'sslwrap'			CONFIG_USER_SSLWRAP_SSLWRAP
+bool 'ssmtp' 			CONFIG_USER_SMTP_SSMTP
 bool 'squid'			CONFIG_USER_SQUID_SQUID
 
 bool 'ssh'			CONFIG_USER_SSH_SSH

Modified: uClinux/trunk/uClinux-dist/user/Makefile
URL: http://svn.digium.com/view/aadk/uClinux/trunk/uClinux-dist/user/Makefile?view=diff&rev=249&r1=248&r2=249
==============================================================================
--- uClinux/trunk/uClinux-dist/user/Makefile (original)
+++ uClinux/trunk/uClinux-dist/user/Makefile Fri Mar 16 18:30:29 2007
@@ -308,6 +308,7 @@
 dir_$(CONFIG_USER_SNMPD_SNMPD)              += snmpd
 dir_$(CONFIG_USER_SNORT_SNORT)              += snort
 dir_$(CONFIG_USER_SPEEDTOUCH_MODEM_RUN)     += speedtouch/src
+dir_$(CONFIG_USER_SMTP_SSMTP)               += ssmtp
 dir_$(CONFIG_USER_STUNNEL_STUNNEL)          += stunnel
 dir_$(CONFIG_USER_SSLWRAP_SSLWRAP)          += sslwrap
 dir_$(CONFIG_USER_SQUID_SQUID)              += squid

Added: uClinux/trunk/uClinux-dist/user/ssmtp/Makefile
URL: http://svn.digium.com/view/aadk/uClinux/trunk/uClinux-dist/user/ssmtp/Makefile?view=auto&rev=249
==============================================================================
--- uClinux/trunk/uClinux-dist/user/ssmtp/Makefile (added)
+++ uClinux/trunk/uClinux-dist/user/ssmtp/Makefile Fri Mar 16 18:30:29 2007
@@ -1,0 +1,55 @@
+# Generated automatically from Makefile.in by configure.
+
+
+srcdir= .
+prefix=/
+exec_prefix=${prefix}
+libexecdir=${exec_prefix}/libexec
+bindir=$(prefix)/sbin
+mandir=$(prefix)/man/man8
+
+LN_S=ln -s
+
+etcdir=${prefix}/etc
+SSMTPCONFDIR=$(etcdir)/ssmtp
+# (End of relocation section)
+
+# Configuration files
+CONFIGURATION_FILE=$(SSMTPCONFDIR)/ssmtp.conf
+REVALIASES_FILE=$(SSMTPCONFDIR)/revaliases
+
+INSTALLED_CONFIGURATION_FILE=$(CONFIGURATION_FILE)
+INSTALLED_REVALIASES_FILE=$(REVALIASES_FILE)
+
+# Programs
+GEN_CONFIG=$(srcdir)/generate_config
+
+SRCS=ssmtp.c arpadate.c base64.c 
+
+OBJS=$(SRCS:.c=.o)
+
+INSTALL=/usr/bin/install -c
+
+EXTRADEFS=\
+-DSSMTPCONFDIR=\"$(SSMTPCONFDIR)\" \
+-DCONFIGURATION_FILE=\"$(CONFIGURATION_FILE)\" \
+-DREVALIASES_FILE=\"$(REVALIASES_FILE)\" \
+
+
+CFLAGS+=-Wall -DLOGFILE -DSTDC_HEADERS=1 -DHAVE_LIMITS_H=1 -DHAVE_STRINGS_H=1 -DHAVE_UNISTD_H=1 -DHAVE_LIBNSL=1 -DRETSIGTYPE=void -DHAVE_VPRINTF=1 -DHAVE_GETHOSTNAME=1 -DHAVE_SOCKET=1 -DHAVE_STRDUP=1 -DHAVE_STRSTR=1 -DREWRITE_DOMAIN=1  $(EXTRADEFS) -g -O2
+
+.PHONY: all
+all: ssmtp
+
+# Binaries:
+ssmtp: $(OBJS)
+	$(CC) $(LDFLAGS) -o ssmtp $(OBJS) -lnsl 
+
+romfs:
+	$(ROMFSINST) /bin/ssmtp
+	$(ROMFSINST) /etc/ssmtp/ssmtp.conf
+
+.PHONY: clean
+clean:
+	$(RM) ssmtp *.o md5auth/*.o core
+

Propchange: uClinux/trunk/uClinux-dist/user/ssmtp/Makefile
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: uClinux/trunk/uClinux-dist/user/ssmtp/Makefile
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: uClinux/trunk/uClinux-dist/user/ssmtp/arpadate.c
URL: http://svn.digium.com/view/aadk/uClinux/trunk/uClinux-dist/user/ssmtp/arpadate.c?view=auto&rev=249
==============================================================================
--- uClinux/trunk/uClinux-dist/user/ssmtp/arpadate.c (added)
+++ uClinux/trunk/uClinux-dist/user/ssmtp/arpadate.c Fri Mar 16 18:30:29 2007
@@ -1,0 +1,89 @@
+/*
+ *  arpadate.c - get_arpadate() is a function returning the date in the
+ *               ARPANET format (see RFC822 and RFC1123)
+ *  Copyright (C) 1998 Hugo Haas
+ *  
+ *  Inspired by smail source code by Ronald S. Karr and Landon Curt Noll
+ *
+ *  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 FITNESS 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.
+ */
+
+#define ARPADATE_LENGTH	32
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+void 
+get_arpadate (char *d_string)
+{
+  struct tm *date;
+#ifdef USE_OLD_ARPADATE
+  static char *week_day[] =
+  {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
+  static char *month[] =
+  {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
+   "Aug", "Sep", "Oct", "Nov", "Dec"};
+  static char timezone[3];
+
+  time_t current;
+  int offset, gmt_yday, gmt_hour, gmt_min;
+
+  /* Get current time */
+  (void) time (&current);
+
+  /* Get GMT and then local dates */
+  date = gmtime ((const time_t *) &current);
+  gmt_yday = date->tm_yday;
+  gmt_hour = date->tm_hour;
+  gmt_min = date->tm_min;
+  date = localtime ((const time_t *) &current);
+
+  /* Calculates offset */
+
+  offset = (date->tm_hour - gmt_hour) * 60 + (date->tm_min - gmt_min);
+  /* Be careful, there can be problems if the day has changed between the
+     evaluation of local and gmt's one */
+  if (date->tm_yday != gmt_yday)
+    {
+      if (date->tm_yday == (gmt_yday + 1))
+	offset += 1440;
+      else if (date->tm_yday == (gmt_yday - 1))
+	offset -= 1440;
+      else
+	offset += (date->tm_yday > gmt_yday) ? -1440 : 1440;
+    }
+
+  if (offset >= 0)
+    sprintf (timezone, "+%02d%02d", offset / 60, offset % 60);
+  else
+    sprintf (timezone, "-%02d%02d", -offset / 60, -offset % 60);
+
+  sprintf (d_string, "%s, %d %s %04d %02d:%02d:%02d %s",
+	   week_day[date->tm_wday],
+	   date->tm_mday, month[date->tm_mon], date->tm_year + 1900,
+	   date->tm_hour, date->tm_min, date->tm_sec, timezone);
+#else
+	time_t now;
+
+	/* RFC822 format string borrowed from GNU shellutils date.c */
+	const char *format = "%a, %d %b %Y %H:%M:%S %z";
+
+	now = time(NULL);
+
+	date = localtime((const time_t *)&now);
+	(void)strftime(d_string, ARPADATE_LENGTH, format, date);
+#endif
+}

Propchange: uClinux/trunk/uClinux-dist/user/ssmtp/arpadate.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: uClinux/trunk/uClinux-dist/user/ssmtp/arpadate.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: uClinux/trunk/uClinux-dist/user/ssmtp/base64.c
URL: http://svn.digium.com/view/aadk/uClinux/trunk/uClinux-dist/user/ssmtp/base64.c?view=auto&rev=249
==============================================================================
--- uClinux/trunk/uClinux-dist/user/ssmtp/base64.c (added)
+++ uClinux/trunk/uClinux-dist/user/ssmtp/base64.c Fri Mar 16 18:30:29 2007
@@ -1,0 +1,103 @@
+/*
+ * base64.c -- base-64 conversion routines.
+ *
+ * For license terms, see the file COPYING in this directory.
+ *
+ * This base 64 encoding is defined in RFC2045 section 6.8,
+ * "Base64 Content-Transfer-Encoding", but lines must not be broken in the
+ * scheme used here.
+ */
+
+/*
+ * This code borrowed from fetchmail sources by
+ * Eric S. Raymond <esr at snark.thyrsus.com>.
+ */
+#include <ctype.h>
+
+
+static const char base64digits[] =
+   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+#define BAD	-1
+static const char base64val[] = {
+    BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD,
+    BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD,
+    BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD, 62, BAD,BAD,BAD, 63,
+     52, 53, 54, 55,  56, 57, 58, 59,  60, 61,BAD,BAD, BAD,BAD,BAD,BAD,
+    BAD,  0,  1,  2,   3,  4,  5,  6,   7,  8,  9, 10,  11, 12, 13, 14,
+     15, 16, 17, 18,  19, 20, 21, 22,  23, 24, 25,BAD, BAD,BAD,BAD,BAD,
+    BAD, 26, 27, 28,  29, 30, 31, 32,  33, 34, 35, 36,  37, 38, 39, 40,
+     41, 42, 43, 44,  45, 46, 47, 48,  49, 50, 51,BAD, BAD,BAD,BAD,BAD
+};
+#define DECODE64(c)  (isascii(c) ? base64val[c] : BAD)
+
+void to64frombits(unsigned char *out, const unsigned char *in, int inlen)
+/* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */
+{
+    for (; inlen >= 3; inlen -= 3)
+    {
+	*out++ = base64digits[in[0] >> 2];
+	*out++ = base64digits[((in[0] << 4) & 0x30) | (in[1] >> 4)];
+	*out++ = base64digits[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
+	*out++ = base64digits[in[2] & 0x3f];
+	in += 3;
+    }
+    if (inlen > 0)
+    {
+	unsigned char fragment;
+    
+	*out++ = base64digits[in[0] >> 2];
+	fragment = (in[0] << 4) & 0x30;
+	if (inlen > 1)
+	    fragment |= in[1] >> 4;
+	*out++ = base64digits[fragment];
+	*out++ = (inlen < 2) ? '=' : base64digits[(in[1] << 2) & 0x3c];
+	*out++ = '=';
+    }
+    *out = '\0';
+}
+
+int from64tobits(char *out, const char *in)
+/* base 64 to raw bytes in quasi-big-endian order, returning count of bytes */
+{
+    int len = 0;
+    register unsigned char digit1, digit2, digit3, digit4;
+
+    if (in[0] == '+' && in[1] == ' ')
+	in += 2;
+    if (*in == '\r')
+	return(0);
+
+    do {
+	digit1 = in[0];
+	if (DECODE64(digit1) == BAD)
+	    return(-1);
+	digit2 = in[1];
+	if (DECODE64(digit2) == BAD)
+	    return(-1);
+	digit3 = in[2];
+	if (digit3 != '=' && DECODE64(digit3) == BAD)
+	    return(-1); 
+	digit4 = in[3];
+	if (digit4 != '=' && DECODE64(digit4) == BAD)
+	    return(-1);
+	in += 4;
+	*out++ = (DECODE64(digit1) << 2) | (DECODE64(digit2) >> 4);
+	++len;
+	if (digit3 != '=')
+	{
+	    *out++ = ((DECODE64(digit2) << 4) & 0xf0) | (DECODE64(digit3) >> 2);
+	    ++len;
+	    if (digit4 != '=')
+	    {
+		*out++ = ((DECODE64(digit3) << 6) & 0xc0) | DECODE64(digit4);
+		++len;
+	    }
+	}
+    } while 
+	(*in && *in != '\r' && digit4 != '=');
+
+    return (len);
+}
+
+/* base64.c ends here */

Propchange: uClinux/trunk/uClinux-dist/user/ssmtp/base64.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: uClinux/trunk/uClinux-dist/user/ssmtp/base64.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: uClinux/trunk/uClinux-dist/user/ssmtp/ssmtp.c
URL: http://svn.digium.com/view/aadk/uClinux/trunk/uClinux-dist/user/ssmtp/ssmtp.c?view=auto&rev=249
==============================================================================
--- uClinux/trunk/uClinux-dist/user/ssmtp/ssmtp.c (added)
+++ uClinux/trunk/uClinux-dist/user/ssmtp/ssmtp.c Fri Mar 16 18:30:29 2007
@@ -1,0 +1,1876 @@
+/*
+
+ $Id: ssmtp.c,v 2.60 2003/08/17 14:17:57 matt Exp $
+
+ sSMTP -- send messages via SMTP to a mailhub for local delivery or forwarding.
+ This program is used in place of /usr/sbin/sendmail, called by "mail" (et all).
+ sSMTP does a selected subset of sendmail's standard tasks (including exactly
+ one rewriting task), and explains if you ask it to do something it can't. It
+ then sends the mail to the mailhub via an SMTP connection. Believe it or not,
+ this is nothing but a filter
+
+ See COPYRIGHT for the license
+
+*/
+#define VERSION "2.60.4"
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/param.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <string.h>
+#include <ctype.h>
+#include <netdb.h>
+#ifdef HAVE_SSL
+#include <openssl/crypto.h>
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#endif
+#ifdef MD5AUTH
+#include "md5auth/hmac_md5.h"
+#endif
+#include "ssmtp.h"
+
+
+bool_t have_date = False;
+bool_t have_from = False;
+#ifdef HASTO_OPTION
+bool_t have_to = False;
+#endif
+bool_t minus_t = False;
+bool_t minus_v = False;
+bool_t override_from = False;
+bool_t rewrite_domain = False;
+bool_t use_tls = False;			/* Use SSL to transfer mail to HUB */
+bool_t use_starttls = False;		/* SSL only after STARTTLS (RFC2487) */
+bool_t use_cert = False;		/* Use a certificate to transfer SSL mail */
+
+#define ARPADATE_LENGTH 32		/* Current date in RFC format */
+char arpadate[ARPADATE_LENGTH];
+char *auth_user = (char)NULL;
+char *auth_pass = (char)NULL;
+char *auth_method = (char)NULL;		/* Mechanism for SMTP authentication */
+char *mail_domain = (char)NULL;
+char *from = (char)NULL;		/* Use this as the From: address */
+char hostname[MAXHOSTNAMELEN] = "localhost";
+char *mailhost = "mailhub";
+char *minus_f = (char)NULL;
+char *minus_F = (char)NULL;
+char *gecos;
+char *prog = (char)NULL;
+char *root = NULL;
+char *tls_cert = "/etc/ssl/certs/ssmtp.pem";	/* Default Certificate */
+char *uad = (char)NULL;
+
+headers_t headers, *ht;
+
+#ifdef DEBUG
+int log_level = 1;
+#else
+int log_level = 0;
+#endif
+int port = 25;
+#ifdef INET6
+int p_family = PF_UNSPEC;		/* Protocol family used in SMTP connection */
+#endif
+
+jmp_buf TimeoutJmpBuf;			/* Timeout waiting for input from network */
+
+rcpt_t rcpt_list, *rt;
+
+#ifdef HAVE_SSL
+SSL *ssl;
+#endif
+
+#ifdef MD5AUTH
+static char hextab[]="0123456789abcdef";
+#endif
+
+
+/*
+log_event() -- Write event to syslog (or log file if defined)
+*/
+void log_event(int priority, char *format, ...)
+{
+	char buf[(BUF_SZ + 1)];
+	va_list ap;
+
+	va_start(ap, format);
+	(void)vsnprintf(buf, BUF_SZ, format, ap);
+	va_end(ap);
+
+#ifdef LOGFILE
+	FILE *fp;
+
+	if((fp = fopen("/tmp/ssmtp.log", "a")) != (FILE *)NULL) {
+		(void)fprintf(fp, "%s\n", buf);
+		(void)fclose(fp);
+	}
+	else {
+		(void)fprintf(stderr, "Can't write to /tmp/ssmtp.log\n");
+	}
+#endif
+
+#if HAVE_SYSLOG_H
+#if OLDSYSLOG
+	openlog("sSMTP", LOG_PID);
+#else
+	openlog("sSMTP", LOG_PID, LOG_MAIL);
+#endif
+	syslog(priority, "%s", buf);
+	closelog();
+#endif
+}
+
+void smtp_write(int fd, char *format, ...);
+int smtp_read(int fd, char *response);
+int smtp_read_all(int fd, char *response);
+int smtp_okay(int fd, char *response);
+
+/*
+dead_letter() -- Save stdin to ~/dead.letter if possible
+*/
+void dead_letter(void)
+{
+	char path[(MAXPATHLEN + 1)], buf[(BUF_SZ + 1)];
+	struct passwd *pw;
+	uid_t uid;
+	FILE *fp;
+
+	uid = getuid();
+	pw = getpwuid(uid);
+
+	if(isatty(fileno(stdin))) {
+		if(log_level > 0) {
+			log_event(LOG_ERR,
+				"stdin is a TTY - not saving to %s/dead.letter, pw->pw_dir");
+		}
+		return;
+	}
+
+	if(pw == (struct passwd *)NULL) {
+		/* Far to early to save things */
+		if(log_level > 0) {
+			log_event(LOG_ERR, "No sender failing horribly!");
+		}
+		return;
+	}
+
+	if(snprintf(path, BUF_SZ, "%s/dead.letter", pw->pw_dir) == -1) {
+		/* Can't use die() here since dead_letter() is called from die() */
+		exit(1);
+	}
+
+	if((fp = fopen(path, "a")) == (FILE *)NULL) {
+		/* Perhaps the person doesn't have a homedir... */
+		if(log_level > 0) {
+			log_event(LOG_ERR, "Can't open %s failing horribly!", path);
+		}
+		return;
+	}
+
+	/* We start on a new line with a blank line separating messages */
+	(void)fprintf(fp, "\n\n");
+
+	while(fgets(buf, sizeof(buf), stdin)) {
+		(void)fputs(buf, fp);
+	}
+
+	if(fclose(fp) == -1) {
+		if(log_level > 0) {
+			log_event(LOG_ERR,
+				"Can't close %s/dead.letter, possibly truncated", pw->pw_dir);
+		}
+	}
+}
+
+/*
+die() -- Write error message, dead.letter and exit
+*/
+void die(char *format, ...)
+{
+	char buf[(BUF_SZ + 1)];
+	va_list ap;
+
+	va_start(ap, format);
+	(void)vsnprintf(buf, BUF_SZ, format, ap);
+	va_end(ap);
+
+	(void)fprintf(stderr, "%s: %s\n", prog, buf);
+	log_event(LOG_ERR, "%s", buf);
+
+	/* Send message to dead.letter */
+	(void)dead_letter();
+
+	exit(1);
+}
+
+/*
+basename() -- Return last element of path
+*/
+char *basename(char *str)
+{
+	char buf[MAXPATHLEN +1], *p;
+
+	if((p = strrchr(str, '/'))) {
+		if(strncpy(buf, ++p, MAXPATHLEN) == (char *)NULL) {
+			die("basename() -- strncpy() failed");
+		}
+	}
+	else {
+		if(strncpy(buf, str, MAXPATHLEN) == (char *)NULL) {
+			die("basename() -- strncpy() failed");
+		}
+	}
+	buf[MAXPATHLEN] = (char)NULL;
+
+	return(strdup(buf));
+}
+
+/*
+strip_pre_ws() -- Return pointer to first non-whitespace character
+*/
+char *strip_pre_ws(char *str)
+{
+	char *p;
+
+	p = str;
+	while(*p && isspace(*p)) p++;
+
+	return(p);
+}
+
+/*
+strip_post_ws() -- Return pointer to last non-whitespace character
+*/
+char *strip_post_ws(char *str)
+{
+	char *p;
+
+	p = (str + strlen(str));
+	while(isspace(*--p)) {
+		*p = (char)NULL;
+	}
+
+	return(p);
+}
+
+/*
+addr_parse() -- Parse <user at domain.com> from full email address
+*/
+char *addr_parse(char *str)
+{
+	char *p, *q;
+
+#if 0
+	(void)fprintf(stderr, "*** addr_parse(): str = [%s]\n", str);
+#endif
+
+	/* Simple case with email address enclosed in <> */
+	if((p = strdup(str)) == (char *)NULL) {
+		die("addr_parse(): strdup()");
+	}
+
+	if((q = strchr(p, '<'))) {
+		q++;
+
+		if((p = strchr(q, '>'))) {
+			*p = (char)NULL;
+		}
+
+#if 0
+		(void)fprintf(stderr, "*** addr_parse(): q = [%s]\n", q);
+#endif
+
+		return(q);
+	}
+
+	q = strip_pre_ws(p);
+	if(*q == '(') {
+		while((*q++ != ')'));
+	}
+	p = strip_pre_ws(q);
+
+#if 0
+	(void)fprintf(stderr, "*** addr_parse(): p = [%s]\n", p);
+#endif
+
+	q = strip_post_ws(p);
+	if(*q == ')') {
+		while((*--q != '('));
+		*q = (char)NULL;
+	}
+	(void)strip_post_ws(p);
+
+#if 0
+	(void)fprintf(stderr, "*** addr_parse(): p = [%s]\n", p);
+#endif
+
+	return(p);
+}
+
+/*
+append_domain() -- Fix up address with @domain.com
+*/
+char *append_domain(char *str)
+{
+	char buf[(BUF_SZ + 1)];
+
+	if(strchr(str, '@') == (char *)NULL) {
+		if(snprintf(buf, BUF_SZ, "%s@%s", str,
+#ifdef REWRITE_DOMAIN
+			rewrite_domain == True ? mail_domain : hostname
+#else
+			hostname
+#endif
+														) == -1) {
+				die("append_domain() -- snprintf() failed");
+		}
+		return(strdup(buf));
+	}
+
+	return(strdup(str));
+}
+
+/*
+standardise() -- Trim off '\n's and double leading dots
+*/
+void standardise(char *str)
+{
+	size_t sl;
+	char *p;
+
+	if((p = strchr(str, '\n'))) {
+		*p = (char)NULL;
+	}
+
+	/* Any line beginning with a dot has an additional dot inserted;
+	not just a line consisting solely of a dot. Thus we have to slide
+	the buffer down one */
+	sl = strlen(str);
+
+	if(*str == '.') {
+		if((sl + 2) > BUF_SZ) {
+			die("standardise() -- Buffer overflow");
+		}
+		(void)memmove((str + 1), str, (sl + 1));	/* Copy trailing \0 */
+
+		*str = '.';
+	}
+}
+
+/*
+revaliases() -- Parse the reverse alias file
+	Fix globals to use any entry for sender
+*/
+void revaliases(struct passwd *pw)
+{
+	char buf[(BUF_SZ + 1)], *p;
+	FILE *fp;
+
+	/* Try to open the reverse aliases file */
+	if((fp = fopen(REVALIASES_FILE, "r"))) {
+		/* Search if a reverse alias is defined for the sender */
+		while(fgets(buf, sizeof(buf), fp)) {
+			/* Make comments invisible */
+			if((p = strchr(buf, '#'))) {
+				*p = (char)NULL;
+			}
+
+			/* Ignore malformed lines and comments */
+			if(strchr(buf, ':') == (char *)NULL) {
+				continue;
+			}
+
+			/* Parse the alias */
+			if(((p = strtok(buf, ":"))) && !strcmp(p, pw->pw_name)) {
+				if((p = strtok(NULL, ": \t\r\n"))) {
+					if((uad = strdup(p)) == (char *)NULL) {
+						die("revaliases() -- strdup() failed");
+					}
+				}
+
+				if((p = strtok(NULL, " \t\r\n:"))) {
+					if((mailhost = strdup(p)) == (char *)NULL) {
+						die("revaliases() -- strdup() failed");
+					}
+
+					if((p = strtok(NULL, " \t\r\n:"))) {
+						port = atoi(p);
+					}
+
+					if(log_level > 0) {
+						log_event(LOG_INFO, "Set MailHub=\"%s\"\n", mailhost);
+						log_event(LOG_INFO,
+							"via SMTP Port Number=\"%d\"\n", port);
+					}
+				}
+			}
+		}
+
+		fclose(fp);
+	}
+}
+
+/* 
+from_strip() -- Transforms "Name <login at host>" into "login at host" or "login at host (Real name)"
+*/
+char *from_strip(char *str)
+{
+	char *p;
+
+#if 0
+	(void)fprintf(stderr, "*** from_strip(): str = [%s]\n", str);
+#endif
+
+	if(strncmp("From:", str, 5) == 0) {
+		str += 5;
+	}
+
+	/* Remove the real name if necessary - just send the address */
+	if((p = addr_parse(str)) == (char *)NULL) {
+		die("from_strip() -- addr_parse() failed");
+	}
+#if 0
+	(void)fprintf(stderr, "*** from_strip(): p = [%s]\n", p);
+#endif
+
+	return(strdup(p));
+}
+
+/*
+from_format() -- Generate standard From: line
+*/
+char *from_format(char *str, bool_t override_from)
+{
+	char buf[(BUF_SZ + 1)];
+
+	if(override_from) {
+		if(minus_f) {
+			str = append_domain(minus_f);
+		}
+
+		if(minus_F) {
+			if(snprintf(buf,
+				BUF_SZ, "\"%s\" <%s>", minus_F, str) == -1) {
+				die("from_format() -- snprintf() failed");
+			}
+		}
+		else if(gecos) {
+			if(snprintf(buf, BUF_SZ, "\"%s\" <%s>", gecos, str) == -1) {
+				die("from_format() -- snprintf() failed");
+			}
+		}
+		else {
+			if(snprintf(buf, BUF_SZ, "%s", str) == -1) {
+				die("from_format() -- snprintf() failed");
+			}
+		}
+	}
+	else {
+		if(gecos) {
+			if(snprintf(buf, BUF_SZ, "\"%s\" <%s>", gecos, str) == -1) {
+				die("from_format() -- snprintf() failed");
+			}
+		}
+	}
+
+#if 0
+	(void)fprintf(stderr, "*** from_format(): buf = [%s]\n", buf);
+#endif
+
+	return(strdup(buf));
+}
+
+/*
+rcpt_save() -- Store entry into RCPT list
+*/
+void rcpt_save(char *str)
+{
+	char *p;
+
+# if 1
+	/* Horrible botch for group stuff */
+	p = str;
+	while(*p) p++;
+
+	if(*--p == ';') {
+		return;
+	}
+#endif
+
+#if 0
+	(void)fprintf(stderr, "*** rcpt_save(): str = [%s]\n", str);
+#endif
+
+	/* Ignore missing usernames */
+	if(*str == (char)NULL) {
+		return;
+	}
+
+	if((rt->string = strdup(str)) == (char *)NULL) {
+		die("rcpt_save() -- strdup() failed");
+	}
+
+	rt->next = (rcpt_t *)malloc(sizeof(rcpt_t));
+	if(rt->next == (rcpt_t *)NULL) {
+		die("rcpt_save() -- malloc() failed");
+	}
+	rt = rt->next;
+
+	rt->next = (rcpt_t *)NULL;
+}
+
+/*
+rcpt_parse() -- Break To|Cc|Bcc into individual addresses
+*/
+void rcpt_parse(char *str)
+{
+	bool_t in_quotes = False, got_addr = False;
+	char *p, *q, *r;
+
+#if 0
+	(void)fprintf(stderr, "*** rcpt_parse(): str = [%s]\n", str);
+#endif
+
+	if((p = strdup(str)) == (char *)NULL) {
+		die("rcpt_parse(): strdup() failed");
+	}
+	q = p;
+
+	/* Replace <CR>, <LF> and <TAB> */
+	while(*q) {
+		switch(*q) {
+			case '\t':
+			case '\n':
+			case '\r':
+					*q = ' ';
+		}
+		q++;
+	}
+	q = p;
+
+#if 0
+	(void)fprintf(stderr, "*** rcpt_parse(): q = [%s]\n", q);
+#endif
+
+	r = q;
+	while(*q) {
+		if(*q == '"') {
+			in_quotes = (in_quotes ? False : True);
+		}
+
+		/* End of string? */
+		if(*(q + 1) == (char)NULL) {
+			got_addr = True;
+		}
+
+		/* End of address? */
+		if((*q == ',') && (in_quotes == False)) {
+			got_addr = True;
+
+			*q = (char)NULL;
+		}
+
+		if(got_addr) {
+			while(*r && isspace(*r)) r++;
+
+			rcpt_save(addr_parse(r));
+			r = (q + 1);
+#if 0
+			(void)fprintf(stderr, "*** rcpt_parse(): r = [%s]\n", r);
+#endif
+			got_addr = False;
+		}
+		q++;
+	}
+	free(p);
+}
+
+#ifdef MD5AUTH
+int crammd5(char *challengeb64, char *username, char *password, char *responseb64)
+{
+	int i;
+	unsigned char digest[MD5_DIGEST_LEN];
+	unsigned char digascii[MD5_DIGEST_LEN * 2];
+	unsigned char challenge[(BUF_SZ + 1)];
+	unsigned char response[(BUF_SZ + 1)];
+	unsigned char secret[(MD5_BLOCK_LEN + 1)]; 
+
+	memset (secret,0,sizeof(secret));
+	memset (challenge,0,sizeof(challenge));
+	strncpy (secret, password, sizeof(secret));	
+	if (!challengeb64 || strlen(challengeb64) > sizeof(challenge) * 3 / 4)
+		return 0;
+	from64tobits(challenge, challengeb64);
+
+	hmac_md5(challenge, strlen(challenge), secret, strlen(secret), digest);
+
+	for (i = 0; i < MD5_DIGEST_LEN; i++) {
+		digascii[2 * i] = hextab[digest[i] >> 4];
+		digascii[2 * i + 1] = hextab[(digest[i] & 0x0F)];
+	}
+	digascii[MD5_DIGEST_LEN * 2] = '\0';
+
+	if (sizeof(response) <= strlen(username) + sizeof(digascii))
+		return 0;
+	
+	strncpy (response, username, sizeof(response) - sizeof(digascii) - 2);
+	strcat (response, " ");
+	strcat (response, digascii);
+	to64frombits(responseb64, response, strlen(response));
+
+	return 1;
+}
+#endif
+
+/*
+rcpt_remap() -- Alias systems-level users to the person who
+	reads their mail. This is variously the owner of a workstation,
+	the sysadmin of a group of stations and the postmaster otherwise.
+	We don't just mail stuff off to root on the mailhub :-)
+*/
+char *rcpt_remap(char *str)
+{
+	struct passwd *pw;
+	if((root==NULL) || strlen(root)==0 || strchr(str, '@') ||
+		((pw = getpwnam(str)) == NULL) || (pw->pw_uid > MAXSYSUID)) {
+		return(append_domain(str));	/* It's not a local systems-level user */
+	}
+	else {
+		return(append_domain(root));
+	}
+}
+
+/*
+header_save() -- Store entry into header list
+*/
+void header_save(char *str)
+{
+	char *p;
+
+#if 0
+	(void)fprintf(stderr, "header_save(): str = [%s]\n", str);
+#endif
+
+	if((p = strdup(str)) == (char *)NULL) {
+		die("header_save() -- strdup() failed");
+	}
+	ht->string = p;
+
+	if(strncasecmp(ht->string, "From:", 5) == 0) {
+#if 1
+		/* Hack check for NULL From: line */
+		if(*(p + 6) == (char)NULL) {
+			return;
+		}
+#endif
+
+#ifdef REWRITE_DOMAIN
+		if(override_from == True) {
+			uad = from_strip(ht->string);
+		}
+		else {
+			return;
+		}
+#endif
+		have_from = True;
+	}
+#ifdef HASTO_OPTION
+	else if(strncasecmp(ht->string, "To:" ,3) == 0) {
+		have_to = True;
+	}
+#endif
+	else if(strncasecmp(ht->string, "Date:", 5) == 0) {
+		have_date = True;
+	}
+
+	if(minus_t) {
+		/* Need to figure out recipients from the e-mail */
+		if(strncasecmp(ht->string, "To:", 3) == 0) {
+			p = (ht->string + 3);
+			rcpt_parse(p);
+		}
+		else if(strncasecmp(ht->string, "Bcc:", 4) == 0) {
+			p = (ht->string + 4);
+			rcpt_parse(p);
+		}
+		else if(strncasecmp(ht->string, "CC:", 3) == 0) {
+			p = (ht->string + 3);
+			rcpt_parse(p);
+		}
+	}
+
+#if 0
+	(void)fprintf(stderr, "header_save(): ht->string = [%s]\n", ht->string);
+#endif
+
+	ht->next = (headers_t *)malloc(sizeof(headers_t));
+	if(ht->next == (headers_t *)NULL) {
+		die("header_save() -- malloc() failed");
+	}
+	ht = ht->next;
+
+	ht->next = (headers_t *)NULL;
+}
+
+/*
+header_parse() -- Break headers into seperate entries
+*/
+void header_parse(FILE *stream)
+{
+	size_t size = BUF_SZ, len = 0;
+	char *p = (char *)NULL, *q;
+	bool_t in_header = True;
+	char l = (char)NULL;
+	int c;
+
+	while(in_header && ((c = fgetc(stream)) != EOF)) {
+		/* Must have space for up to two more characters, since we
+			may need to insert a '\r' */
+		if((p == (char *)NULL) || (len >= (size - 1))) {
+			size += BUF_SZ;
+
+			p = (char *)realloc(p, (size * sizeof(char)));
+			if(p == (char *)NULL) {
+				die("header_parse() -- realloc() failed");
+			}
+			q = (p + len);
+		}
+		len++;
+
+		if(l == '\n') {
+			switch(c) {
+				case ' ':
+				case '\t':
+						/* Must insert '\r' before '\n's embedded in header
+						   fields otherwise qmail won't accept our mail
+						   because a bare '\n' violates some RFC */
+						
+						*(q - 1) = '\r';	/* Replace previous \n with \r */
+						*q++ = '\n';		/* Insert \n */
+						len++;
+						
+						break;
+
+				case '\n':
+						in_header = False;
+
+				default:
+						*q = (char)NULL;
+						if((q = strrchr(p, '\n'))) {
+							*q = (char)NULL;
+						}
+						header_save(p);
+
+						q = p;
+						len = 0;
+			}
+		}
+		*q++ = c;
+
+		l = c;
+	}
+	(void)free(p);
+}
+
+/*
+read_config() -- Open and parse config file and extract values of variables
+*/
+bool_t read_config()
+{
+	char buf[(BUF_SZ + 1)], *p, *q, *r;
+	FILE *fp;
+
+	if((fp = fopen(CONFIGURATION_FILE, "r")) == NULL) {
+		return(False);
+	}
+
+	while(fgets(buf, sizeof(buf), fp)) {
+		/* Make comments invisible */
+		if((p = strchr(buf, '#'))) {
+			*p = (char)NULL;
+		}
+
+		/* Ignore malformed lines and comments */
+		if(strchr(buf, '=') == (char *)NULL) continue;
+
+		/* Parse out keywords */
+		if(((p = strtok(buf, "= \t\n")) != (char *)NULL)
+			&& ((q = strtok(NULL, "= \t\n:")) != (char *)NULL)) {
+			if(strcasecmp(p, "Root") == 0) {
+				if((root = strdup(q)) == (char *)NULL) {
+					die("parse_config() -- strdup() failed");
+				}
+
+				if(log_level > 0) {
+					log_event(LOG_INFO, "Set Root=\"%s\"\n", root);
+				}
+			}
+			else if(strcasecmp(p, "MailHub") == 0) {
+				if((mailhost = strdup(q)) == (char *)NULL) {
+					die("parse_config() -- strdup() failed");
+				}
+
+				if((r = strtok(NULL, "= \t\n:")) != NULL) {
+					port = atoi(r);
+				}
+
+				if(log_level > 0) {
+					log_event(LOG_INFO, "Set MailHub=\"%s\"\n", mailhost);
+					log_event(LOG_INFO, "Set RemotePort=\"%d\"\n", port);
+				}
+			}
+			else if(strcasecmp(p, "HostName") == 0) {
+				if(strncpy(hostname, q, MAXHOSTNAMELEN) == NULL) {
+					die("parse_config() -- strncpy() failed");
+				}
+
+				if(log_level > 0) {
+					log_event(LOG_INFO, "Set HostName=\"%s\"\n", hostname);
+				}
+			}
+#ifdef REWRITE_DOMAIN
+			else if(strcasecmp(p, "RewriteDomain") == 0) {
+				if((p = strrchr(q, '@'))) {
+					mail_domain = strdup(++p);
+
+					log_event(LOG_ERR,
+						"Set RewriteDomain=\"%s\" is invalid\n", q);
+					log_event(LOG_ERR,
+						"Set RewriteDomain=\"%s\" used\n", mail_domain);
+				}
+				else {
+					mail_domain = strdup(q);
+				}
+
+				if(mail_domain == (char *)NULL) {
+					die("parse_config() -- strdup() failed");
+				}
+				rewrite_domain = True;
+
+				if(log_level > 0) {
+					log_event(LOG_INFO,
+						"Set RewriteDomain=\"%s\"\n", mail_domain);
+				}
+			}
+#endif
+			else if(strcasecmp(p, "FromLineOverride") == 0) {
+				if(strcasecmp(q, "YES") == 0) {
+					override_from = True;
+				}
+				else {
+					override_from = False;
+				}
+
+				if(log_level > 0) {
+					log_event(LOG_INFO,
+						"Set FromLineOverride=\"%s\"\n",
+						override_from ? "True" : "False");
+				}
+			}
+			else if(strcasecmp(p, "RemotePort") == 0) {
+				port = atoi(q);
+
+				if(log_level > 0) {
+					log_event(LOG_INFO, "Set RemotePort=\"%d\"\n", port);
+				}
+			}
+#ifdef HAVE_SSL
+			else if(strcasecmp(p, "UseTLS") == 0) {
+				if(strcasecmp(q, "YES") == 0) {
+					use_tls = True;
+				}
+				else {
+					use_tls = False;
+					use_starttls = False;
+				}
+
+				if(log_level > 0) { 
+					log_event(LOG_INFO,
+						"Set UseTLS=\"%s\"\n", use_tls ? "True" : "False");
+				}
+			}
+			else if(strcasecmp(p, "UseSTARTTLS") == 0) {
+				if(strcasecmp(q, "YES") == 0) {
+					use_starttls = True;
+					use_tls = True;
+				}
+				else {
+					use_starttls = False;
+				}
+
+				if(log_level > 0) { 
+					log_event(LOG_INFO,
+						"Set UseSTARTTLS=\"%s\"\n", use_tls ? "True" : "False");
+				}
+			}
+			else if(strcasecmp(p, "UseTLSCert") == 0) {
+				if(strcasecmp(q, "YES") == 0) {
+					use_cert = True;
+				}
+				else {
+					use_cert = False;
+				}
+
+				if(log_level > 0) {
+					log_event(LOG_INFO,
+						"Set UseTLSCert=\"%s\"\n",
+						use_cert ? "True" : "False");
+				}
+			}
+			else if(strcasecmp(p, "TLSCert") == 0) {
+				if((tls_cert = strdup(q)) == (char *)NULL) {
+					die("parse_config() -- strdup() failed");
+				}
+
+				if(log_level > 0) {
+					log_event(LOG_INFO, "Set TLSCert=\"%s\"\n", tls_cert);
+				}
+			}
+#endif
+			/* Command-line overrides these */
+			else if(strcasecmp(p, "AuthUser") == 0 && !auth_user) {
+				if((auth_user = strdup(q)) == (char *)NULL) {
+					die("parse_config() -- strdup() failed");
+				}
+
+				if(log_level > 0) {
+					log_event(LOG_INFO, "Set AuthUser=\"%s\"\n", auth_user);
+				}
+			}
+			else if(strcasecmp(p, "AuthPass") == 0 && !auth_pass) {
+				if((auth_pass = strdup(q)) == (char *)NULL) {
+					die("parse_config() -- strdup() failed");
+				}
+
+				if(log_level > 0) {
+					log_event(LOG_INFO, "Set AuthPass=\"%s\"\n", auth_pass);
+				}
+			}
+			else if(strcasecmp(p, "AuthMethod") == 0 && !auth_method) {
+				if((auth_method = strdup(q)) == (char *)NULL) {
+					die("parse_config() -- strdup() failed");
+				}
+
+				if(log_level > 0) {
+					log_event(LOG_INFO, "Set AuthMethod=\"%s\"\n", auth_method);
+				}
+			}
+			else {
+				log_event(LOG_INFO, "Unable to set %s=\"%s\"\n", p, q);
+			}
+		}
+	}
+	(void)fclose(fp);
+
+	return(True);
+}
+
+/*
+smtp_open() -- Open connection to a remote SMTP listener
+*/
+int smtp_open(char *host, int port)
+{
+#ifdef INET6
+	struct addrinfo hints, *ai0, *ai;
+	char servname[NI_MAXSERV];
+	int s;
+#else
+	struct sockaddr_in name;
+	struct hostent *hent;
+	int s, namelen;
+#endif
+
+#ifdef HAVE_SSL
+	int err;
+	char buf[(BUF_SZ + 1)];
+
+	/* Init SSL stuff */
+	SSL_CTX *ctx;
+	SSL_METHOD *meth;
+	X509 *server_cert;
+
+	SSL_load_error_strings();
+	SSLeay_add_ssl_algorithms();
+	meth=SSLv23_client_method();
+	ctx = SSL_CTX_new(meth);
+	if(!ctx) {
+		log_event(LOG_ERR, "No SSL support initiated\n");
+		return(-1);
+	}
+
+	if(use_cert == True) { 
+		if(SSL_CTX_use_certificate_chain_file(ctx, tls_cert) <= 0) {
+			perror("Use certfile");
+			return(-1);
+		}
+
+		if(SSL_CTX_use_PrivateKey_file(ctx, tls_cert, SSL_FILETYPE_PEM) <= 0) {
+			perror("Use PrivateKey");
+			return(-1);
+		}
+
+		if(!SSL_CTX_check_private_key(ctx)) {
+			log_event(LOG_ERR, "Private key does not match the certificate public key\n");
+			return(-1);
+		}
+	}
+#endif
+
+#ifdef INET6
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = p_family;
+	hints.ai_socktype = SOCK_STREAM;
+	snprintf(servname, sizeof(servname), "%d", port);
+
+	/* Check we can reach the host */
+	if (getaddrinfo(host, servname, &hints, &ai0)) {
+		log_event(LOG_ERR, "Unable to locate %s", host);
+		return(-1);
+	}
+
+	for (ai = ai0; ai; ai = ai->ai_next) {
+		/* Create a socket for the connection */
+		s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+		if (s < 0) {
+			continue;
+		}
+
+		if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
+			s = -1;
+			continue;
+		}
+		break;
+	}
+
+	if(s < 0) {
+		log_event (LOG_ERR,
+			"Unable to connect to \"%s\" port %d.\n", host, port);
+
+		return(-1);
+	}
+#else
+	/* Check we can reach the host */
+	if((hent = gethostbyname(host)) == (struct hostent *)NULL) {
+		log_event(LOG_ERR, "Unable to locate %s", host);
+		return(-1);
+	}
+
+	if(hent->h_length > sizeof(hent->h_addr)) {
+		log_event(LOG_ERR, "Buffer overflow in gethostbyname()");
+		return(-1);
+	}
+
+	/* Create a socket for the connection */
+	if((s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
+		log_event(LOG_ERR, "Unable to create a socket");
+		return(-1);
+	}
+
+	/* This SHOULD already be in Network Byte Order from gethostbyname() */
+	name.sin_addr.s_addr = ((struct in_addr *)(hent->h_addr))->s_addr;
+	name.sin_family = hent->h_addrtype;
+	name.sin_port = htons(port);
+
+	namelen = sizeof(struct sockaddr_in);
+	if(connect(s, (struct sockaddr *)&name, namelen) < 0) {
+		log_event(LOG_ERR, "Unable to connect to %s:%d", host, port);
+		return(-1);
+	}
+#endif
+
+#ifdef HAVE_SSL
+	if(use_tls == True) {
+		log_event(LOG_INFO, "Creating SSL connection to host");
+
+		if (use_starttls == True)
+		{
+			use_tls=False; /* need to write plain text for a while */
+
+			if (smtp_okay(s, buf))
+			{
+				smtp_write(s, "EHLO %s", hostname);
+				if (smtp_okay(s, buf)) {
+					smtp_write(s, "STARTTLS"); /* assume STARTTLS regardless */
+					if (!smtp_okay(s, buf)) {
+						log_event(LOG_ERR, "STARTTLS not working");
+						return(-1);
+					}
+				}
+				else
+				{
+					log_event(LOG_ERR, "Invalid response: %s (%s)", buf, hostname);
+				}
+			}
+			else
+			{
+				log_event(LOG_ERR, "Invalid response SMTP Server (STARTTLS)");
+				return(-1);
+			}
+			use_tls=True; /* now continue as normal for SSL */
+		}
+
+		ssl = SSL_new(ctx);
+		if(!ssl) {
+			log_event(LOG_ERR, "SSL not working");
+			return(-1);
+		}
+		SSL_set_fd(ssl, s);
+
+		err = SSL_connect(ssl);
+		if(err < 0) { 
+			perror("SSL_connect");
+			return(-1);
+		}
+
+		if(log_level > 0 || 1) {
+			log_event(LOG_INFO, "SSL connection using %s",
+				SSL_get_cipher(ssl));
+		}
+
+		server_cert = SSL_get_peer_certificate(ssl);
+		if(!server_cert) {
+			return(-1);
+		}
+		X509_free(server_cert);
+
+		/* TODO: Check server cert if changed! */
+	}
+#endif
+
+	return(s);
+}
+
+/*
+fd_getc() -- Read a character from an fd
+*/
+ssize_t fd_getc(int fd, void *c)
+{
+#ifdef HAVE_SSL
+	if(use_tls == True) { 
+		return(SSL_read(ssl, c, 1));
+	}
+#endif
+	return(read(fd, c, 1));
+}
+
+/*
+fd_gets() -- Get characters from a fd instead of an fp
+*/
+char *fd_gets(char *buf, int size, int fd)
+{
+	int i = 0;
+	char c;
+
+	while((i < size) && (fd_getc(fd, &c) == 1)) {
+		if(c == '\r');	/* Strip <CR> */
+		else if(c == '\n') {
+			break;
+		}
+		else {
+			buf[i++] = c;
+		}
+	}
+	buf[i] = (char)NULL;
+
+	return(buf);
+}
+
+/*
+smtp_read() -- Get a line and return the initial digit
+*/

[... 1174 lines stripped ...]


More information about the aadk-commits mailing list