initial commit
initial commit

file:b/FILES (new)
--- /dev/null
+++ b/FILES
@@ -1,1 +1,7 @@
+README
+Makefile
+version.h
+mini_sendmail.c
+mini_sendmail.8
+FILES
 

file:b/Makefile (new)
--- /dev/null
+++ b/Makefile
@@ -1,1 +1,50 @@
+# Makefile for mini_sendmail
 
+# CONFIGURE: If you are using a SystemV-based operating system, such as
+# Solaris, you will need to uncomment this definition.
+#SYSV_LIBS =    -lnsl -lsocket
+
+BINDIR =	/usr/local/sbin
+MANDIR =	/usr/local/man
+CC =		gcc
+CFLAGS =	-O
+#CFLAGS =	-g
+LDFLAGS =	-s -static
+#LDFLAGS =	-g -static
+LDLIBS =	$(SYSV_LIBS)
+
+CC :=		$(DIET) $(CC)
+
+
+all:		mini_sendmail
+
+diet:
+	make DIET=diet mini_sendmail
+
+
+mini_sendmail:	mini_sendmail.o
+	$(CC) $(CFLAGS) $(LDFLAGS) mini_sendmail.o $(LDLIBS) -o mini_sendmail
+
+mini_sendmail.o:	mini_sendmail.c version.h
+	$(CC) $(CFLAGS) -c mini_sendmail.c
+
+
+install:	all
+	rm -f $(BINDIR)/mini_sendmail
+	cp mini_sendmail $(BINDIR)
+	rm -f $(MANDIR)/man8/mini_sendmail.8
+	cp mini_sendmail.8 $(MANDIR)/man8
+
+clean:
+	rm -f mini_sendmail *.o core core.* *.core
+
+tar:
+	@name=`sed -n -e '/#define VERSION/!d' -e 's,.*mini_sendmail/,mini_sendmail-,' -e 's, .*,,p' version.h` ; \
+	  rm -rf $$name ; \
+	  mkdir $$name ; \
+	  tar cf - `cat FILES` | ( cd $$name ; tar xfBp - ) ; \
+	  chmod 644 $$name/Makefile ; \
+	  tar cf $$name.tar $$name ; \
+	  rm -rf $$name ; \
+	  gzip $$name.tar
+

file:b/README (new)
--- /dev/null
+++ b/README
@@ -1,1 +1,54 @@
+     mini_sendmail - accept email on behalf of real sendmail
+                   version 1.3.6 of 29jun2005
 
+mini_sendmail reads its standard input up to an end-of-file and
+sends a copy of the message found there to all of the addresses
+listed.  The message is sent by connecting to a local SMTP server.
+This means mini_sendmail can be used to send email from inside a
+chroot(2) area.
+
+See the manual entry for more details.
+
+Files in this distribution:
+
+    README		this
+    Makefile		guess
+    mini_sendmail.c	source file
+    mini_sendmail.8	manual entry
+
+To build: If you're on a SysV-like machine (which includes old Linux systems
+but not new Linux systems), edit the Makefile and uncomment the SYSV_LIBS
+line.  Otherwise, just do a make.
+
+After it's built, you must test it to make sure your local sendmail
+daemon is (a) running and (b) accepting local mail for delivery
+elsewhere.  Here's what a successful test run might look like:
+
+    % echo 'Subject: test' | ./mini_sendmail -v jef@mail.acme.com
+    <<<< 220 gate.acme.com ESMTP Sendmail; Thu, 16 Dec 1999 17:17:37 -0800 (PST)
+    >>>> HELO localhost
+    <<<< 250 gate.acme.com Hello localhost [127.0.0.1], pleased to meet you
+    >>>> MAIL FROM:<jef@gate.acme.com>
+    <<<< 250 <jef@gate.acme.com>... Sender ok
+    >>>> RCPT TO:<jef@mail.acme.com>
+    <<<< 250 <jef@mail.acme.com>... Recipient ok
+    >>>> DATA
+    <<<< 354 Enter mail, end with "." on a line by itself
+    <<<< 250 RAA58877 Message accepted for delivery
+    >>>> QUIT
+    <<<< 221 gate.acme.com closing connection
+    % 
+
+And here's an unsuccessful run where there's no local sendmail
+daemon running:
+
+    % echo 'Subject: test' | ./mini_sendmail -v jef@mail.acme.com
+    ./mini_sendmail: connect: Connection refused
+    % 
+
+
+Feedback is welcome - send bug reports, enhancements, checks, money
+orders, etc. to the addresses below.
+
+    Jef Poskanzer  jef@mail.acme.com  http://www.acme.com/jef/
+

file:b/mini_sendmail.8 (new)
--- /dev/null
+++ b/mini_sendmail.8
@@ -1,1 +1,71 @@
+.TH mini_sendmail 8 "12 July 2001"
+.SH NAME
+mini_sendmail - accept email on behalf of real sendmail
+.SH SYNOPSIS
+.B mini_sendmail
+.RB [ -f<name> ]
+.RB [ -t ]
+.RB [ -s<server> ]
+.RB [ -p<port> ]
+.RB [ -T<timeout> ]
+.RB [ -v ]
+.I address ...
+.SH DESCRIPTION
+.PP
+With no flags,
+.I mini_sendmail
+reads its standard input up to an end-of-file
+and sends a copy of the message
+found there to all of the addresses listed.
+.PP
+The message is sent by connecting to a local SMTP server.
+This means
+.I mini_sendmail
+can be used to send email from inside a chroot(2) area.
+.TP
+.B -f
+Sets the name of the "from" person (i.e. the sender of the mail).
+.TP
+.B -t
+Read message for recipients.
+To:, Cc:, and Bcc: lines will be scanned for recipient addresses.
+The Bcc: line will be deleted before transmission.
+.TP
+.B -s
+Specifies the SMTP server to use.
+Without this it uses localhost.
+.TP
+.B -p
+Specifies the port to use.
+Without this it uses 25, the standard SMTP port.
+.TP
+.B -T
+Specifies timeout - defaults to one minute.
+.TP
+.B -v
+Verbose mode - shows the conversation with the SMTP server.
+.SH "SEE ALSO"
+sendmail(8)
+.SH AUTHOR

+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
 

file:b/mini_sendmail.c (new)
--- /dev/null
+++ b/mini_sendmail.c
@@ -1,1 +1,846 @@
-
+/* mini_sendmail - accept email on behalf of real sendmail
+**

+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+**    notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+**    notice, this list of conditions and the following disclaimer in the
+**    documentation and/or other materials provided with the distribution.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+** SUCH DAMAGE.
+*/
+
+
+/* These defines control some optional features of the program.  If you
+** don't want the features you can undef the symbols; some of them mean
+** a significant savings in executable size.
+*/
+#define DO_RECEIVED	/* whether to add a "Received:" header */
+#define DO_GETPWUID	/* whether to try a getpwuid() if getlogin() fails */
+#define DO_MINUS_SP	/* whether to implement the -s and -p flags */
+#define DO_DNS		/* whether to do a name lookup on -s, or just IP# */
+
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#ifdef DO_RECEIVED
+#include <time.h>
+#endif /* DO_RECEIVED */
+#ifdef DO_GETPWUID
+#include <pwd.h>
+#endif /* DO_GETPWUID */
+
+#include "version.h"
+
+
+/* Defines. */
+#define SMTP_PORT 25
+#define DEFAULT_TIMEOUT 60
+
+
+/* Globals. */
+static char* argv0;
+static char* fake_from;
+static int parse_message, verbose;
+#ifdef DO_MINUS_SP
+static char* server;
+static short port;
+#endif /* DO_MINUS_SP */
+static int timeout;
+static int sockfd1, sockfd2;
+static FILE* sockrfp;
+static FILE* sockwfp;
+static int got_a_recipient;
+
+
+/* Forwards. */
+static void usage( void );
+static char* slurp_message( void );
+#ifdef DO_RECEIVED
+static char* make_received( char* from, char* username, char* hostname );
+#endif /* DO_RECEIVED */
+static void parse_for_recipients( char* message );
+static void add_recipient( char* recipient, int len );
+static int open_client_socket( void );
+static int read_response( void );
+static void send_command( char* command );
+static void send_data( char* data );
+static void send_done( void );
+static void sigcatch( int sig );
+static void show_error( char* cause );
+
+
+int
+main( int argc, char** argv )
+    {
+    int argn;
+    char* message;
+#ifdef DO_RECEIVED
+    char* received;
+#endif /* DO_RECEIVED */
+    char* username;
+    char hostname[500];
+    char from[1000];
+    int status;
+    char buf[2000];
+
+    /* Parse args. */
+    argv0 = argv[0];
+    fake_from = (char*) 0;
+    parse_message = 0;
+#ifdef DO_MINUS_SP
+    server = "127.0.0.1";
+    port = SMTP_PORT;
+#endif /* DO_MINUS_SP */
+    verbose = 0;
+    timeout = DEFAULT_TIMEOUT;
+    argn = 1;
+    while ( argn < argc && argv[argn][0] == '-' )
+	{
+	if ( strncmp( argv[argn], "-f", 2 ) == 0 && argv[argn][2] != '\0' )
+	    fake_from = &(argv[argn][2]);
+	else if ( strcmp( argv[argn], "-t" ) == 0 )
+	    parse_message = 1;
+#ifdef DO_MINUS_SP
+	else if ( strncmp( argv[argn], "-s", 2 ) == 0 && argv[argn][2] != '\0' )
+	    server = &(argv[argn][2]);
+	else if ( strncmp( argv[argn], "-p", 2 ) == 0 && argv[argn][2] != '\0' )
+	    port = atoi( &(argv[argn][2]) );
+#endif /* DO_MINUS_SP */
+	else if ( strncmp( argv[argn], "-T", 2 ) == 0 && argv[argn][2] != '\0' )
+	    timeout = atoi( &(argv[argn][2]) );
+	else if ( strcmp( argv[argn], "-v" ) == 0 )
+	    verbose = 1;
+	else if ( strcmp( argv[argn], "-i" ) == 0 )
+	    ;	/* ignore */
+	else if ( strcmp( argv[argn], "-oi" ) == 0 )
+	    ;	/* ignore */
+	else if ( strcmp( argv[argn], "--" ) == 0 )
+	    ;	/* ignore */
+	else
+	    usage();
+	++argn;
+	}
+
+    username = getlogin();
+    if ( username == (char*) 0 )
+	{
+#ifdef DO_GETPWUID
+	struct passwd* pw = getpwuid( getuid() );
+	if ( pw == (struct passwd*) 0 )
+	    {
+	    (void) fprintf( stderr, "%s: can't determine username\n", argv0 );
+	    exit( 1 );
+	    }
+	username = pw->pw_name;
+#else /* DO_GETPWUID */
+	(void) fprintf( stderr, "%s: can't determine username\n", argv0 );
+	exit( 1 );
+#endif /* DO_GETPWUID */
+	}
+
+    if ( gethostname( hostname, sizeof(hostname) - 1 ) < 0 )
+	show_error( "gethostname" );
+
+    if ( fake_from == (char*) 0 )
+	(void) snprintf( from, sizeof(from), "%s@%s", username, hostname );
+    else
+	if ( strchr( fake_from, '@' ) == (char*) 0 )
+	    (void) snprintf( from, sizeof(from), "%s@%s", fake_from, hostname );
+	else
+	    (void) snprintf( from, sizeof(from), "%s", fake_from );
+
+    /* Strip off any angle brackets in the from address. */
+    while ( from[0] == '<' )
+	(void) strcpy( from, &from[1] );
+    while ( from[strlen(from)-1] == '>' )
+	from[strlen(from)-1] = '\0';
+
+    message = slurp_message();
+#ifdef DO_RECEIVED
+    received = make_received( from, username, hostname );
+#endif /* DO_RECEIVED */
+
+    (void) signal( SIGALRM, sigcatch );
+
+    (void) alarm( timeout );
+    sockfd1 = open_client_socket();
+
+    sockfd2 = dup( sockfd1 );
+    sockrfp = fdopen( sockfd1, "r" );
+    sockwfp = fdopen( sockfd2, "w" );
+
+    /* The full SMTP protocol is spelled out in RFC821, available at
+    ** http://www.faqs.org/rfcs/rfc821.html
+    ** The only non-obvious wrinkles:
+    **  - The commands are terminated with CRLF, not newline.
+    **  - Newlines in the data file get turned into CRLFs.
+    **  - Any data lines beginning with a period get an extra period prepended.
+    */
+
+    status = read_response();
+    if ( status != 220 )
+	{
+	(void) fprintf(
+	    stderr,  "%s: unexpected initial greeting %d\n", argv0, status );
+	exit( 1 );
+	}
+
+    (void) snprintf( buf, sizeof(buf), "HELO %s", hostname );
+    send_command( buf );
+    status = read_response();
+    if ( status != 250 )
+	{
+	(void) fprintf(
+	    stderr,  "%s: unexpected response %d to HELO command\n",
+	    argv0, status );
+	exit( 1 );
+	}
+
+    (void) snprintf( buf, sizeof(buf), "MAIL FROM:<%s>", from );
+    send_command( buf );
+    status = read_response();
+    if ( status != 250 )
+	{
+	(void) fprintf(
+	    stderr,  "%s: unexpected response %d to MAIL FROM command\n",
+	    argv0, status );
+	exit( 1 );
+	}
+
+    got_a_recipient = 0;
+    for ( ; argn < argc; ++argn )
+	add_recipient( argv[argn], strlen( argv[argn] ) );
+    if ( parse_message )
+	parse_for_recipients( message );
+    if ( ! got_a_recipient )
+	{
+	(void) fprintf( stderr,  "%s: no recipients found\n", argv0 );
+	exit( 1 );
+	}
+
+    send_command( "DATA" );
+    status = read_response();
+    if ( status != 354 )
+	{
+	(void) fprintf(
+	    stderr,  "%s: unexpected response %d to DATA command\n",
+	    argv0, status );
+	exit( 1 );
+	}
+
+#ifdef DO_RECEIVED
+    send_data( received );
+#endif /* DO_RECEIVED */
+    send_data( message );
+    send_done();
+    status = read_response();
+    if ( status != 250 )
+	{
+	(void) fprintf(
+	    stderr,  "%s: unexpected response %d to DATA\n", argv0, status );
+	exit( 1 );
+	}
+
+    send_command( "QUIT" );
+    status = read_response();
+    if ( status != 221 )
+	(void) fprintf(
+	    stderr,  "%s: unexpected response %d to QUIT command - ignored\n",
+	    argv0, status );
+
+    (void) close( sockfd1 );
+    (void) close( sockfd2 );
+
+    exit( 0 );
+    }
+
+
+static void
+usage( void )
+    {
+#ifdef DO_MINUS_SP
+#ifdef DO_DNS
+    char* spflag = "[-s<server>] [-p<port>] ";
+#else /* DO_DNS */
+    char* spflag = "[-s<server_ip>] [-p<port>] ";
+#endif /* DO_DNS */
+#else /* DO_MINUS_SP */
+    char* spflag = "";
+#endif /* DO_MINUS_SP */
+    (void) fprintf( stderr, "usage:  %s [-f<name>] [-t] %s[-T<timeout>] [-v] [address ...]\n", argv0, spflag );
+    exit( 1 );
+    }
+
+
+static char*
+slurp_message( void )
+    {
+    char* message;
+    int message_size, message_len;
+    int c;
+
+    message_size = 5000;
+    message = (char*) malloc( message_size );
+    if ( message == (char*) 0 )
+	{
+	(void) fprintf( stderr, "%s: out of memory\n", argv0 );
+	exit( 1 );
+	}
+    message_len = 0;
+
+    for (;;)
+	{
+	c = getchar();
+	if ( c == EOF )
+	    break;
+	if ( message_len + 1 >= message_size )
+	    {
+	    message_size *= 2;
+	    message = (char*) realloc( (void*) message, message_size );
+	    if ( message == (char*) 0 )
+		{
+		(void) fprintf( stderr, "%s: out of memory\n", argv0 );
+		exit( 1 );
+		}
+	    }
+	message[message_len++] = c;
+	}
+    message[message_len] = '\0';
+
+    return message;
+    }
+
+
+#ifdef DO_RECEIVED
+static char*
+make_received( char* from, char* username, char* hostname )
+    {
+    int received_size;
+    char* received;
+    time_t t;
+    struct tm* tmP;
+    char timestamp[100];
+
+    t = time( (time_t*) 0 );
+    tmP = localtime( &t );
+    (void) strftime( timestamp, sizeof(timestamp), "%a, %d %b %Y %T %Z", tmP );
+    received_size =
+	500 + strlen( from ) + strlen( hostname ) * 2 + strlen( VERSION ) +
+	strlen( timestamp ) + strlen( username );
+    received = (char*) malloc( received_size );
+    if ( received == (char*) 0 )
+	{
+	(void) fprintf( stderr, "%s: out of memory\n", argv0 );
+	exit( 1 );
+	}
+    (void) snprintf(
+	received, received_size,
+	"Received: (from %s)\n\tby %s (%s);\n\t%s\n\t(sender %s@%s)\n",
+	from, hostname, VERSION, timestamp, username, hostname );
+    return received;
+    }
+#endif /* DO_RECEIVED */
+
+
+static void
+parse_for_recipients( char* message )
+    {
+    /* A little finite-state machine that parses the message, looking
+    ** for To:, Cc:, and Bcc: recipients.
+    */
+    int state;
+#define ST_BOL		0
+#define ST_OTHERHEAD	1
+#define ST_T		2
+#define ST_C		3
+#define ST_B		4
+#define ST_BC		5
+#define ST_RECIPHEAD	6
+#define ST_RECIPS	7
+    char* cp;
+    char* bcc;
+    char* recip;
+
+    state = ST_BOL;
+    bcc = (char*) 0;
+    for ( cp = message; *cp != '\0'; ++cp )
+	{
+	switch ( state )
+	    {
+	    case ST_BOL:
+	    switch ( *cp )
+		{
+		case '\n':
+		return;
+		case 'T':
+		case 't':
+		state = ST_T;
+		break;
+		case 'C':
+		case 'c':
+		state = ST_C;
+		break;
+		case 'B':
+		case 'b':
+		state = ST_B;
+		bcc = cp;
+		break;
+		default:
+		state = ST_OTHERHEAD;
+		break;
+		}
+	    break;
+	    case ST_OTHERHEAD:
+	    switch ( *cp )
+		{
+		case '\n':
+		state = ST_BOL;
+		break;
+		}
+	    break;
+	    case ST_T:
+	    switch ( *cp )
+		{
+		case '\n':
+		state = ST_BOL;
+		break;
+		case 'O':
+		case 'o':
+		state = ST_RECIPHEAD;
+		break;
+		default:
+		state = ST_OTHERHEAD;
+		break;
+		}
+	    break;
+	    case ST_C:
+	    switch ( *cp )
+		{
+		case '\n':
+		state = ST_BOL;
+		break;
+		case 'C':
+		case 'c':
+		state = ST_RECIPHEAD;
+		break;
+		default:
+		state = ST_OTHERHEAD;
+		break;
+		}
+	    break;
+	    case ST_B:
+	    switch ( *cp )
+		{
+		case '\n':
+		state = ST_BOL;
+		bcc = (char*) 0;
+		break;
+		case 'C':
+		case 'c':
+		state = ST_BC;
+		break;
+		default:
+		state = ST_OTHERHEAD;
+		bcc = (char*) 0;
+		break;
+		}
+	    break;
+	    case ST_BC:
+	    switch ( *cp )
+		{
+		case '\n':
+		state = ST_BOL;
+		bcc = (char*) 0;
+		break;
+		case 'C':
+		case 'c':
+		state = ST_RECIPHEAD;
+		break;
+		default:
+		state = ST_OTHERHEAD;
+		bcc = (char*) 0;
+		break;
+		}
+	    break;
+	    case ST_RECIPHEAD:
+	    switch ( *cp )
+		{
+		case '\n':
+		state = ST_BOL;
+		bcc = (char*) 0;
+		break;
+		case ':':
+		state = ST_RECIPS;
+		recip = cp + 1;
+		break;
+		default:
+		state = ST_OTHERHEAD;
+		bcc = (char*) 0;
+		break;
+		}
+	    break;
+	    case ST_RECIPS:
+	    switch ( *cp )
+		{
+		case '\n':
+		add_recipient( recip, ( cp - recip ) );
+		state = ST_BOL;
+		if ( bcc != (char*) 0 )
+		    {
+		    /* Elide the Bcc: line, and reset cp. */
+		    (void) strcpy( bcc, cp + 1 );
+		    cp = bcc - 1;
+		    bcc = (char*) 0;
+		    }
+		break;
+		case ',':
+		add_recipient( recip, ( cp - recip ) );
+		recip = cp + 1;
+		break;
+		}
+	    break;
+	    }
+	}
+    }
+
+
+static void
+add_recipient( char* recipient, int len )
+    {
+    char buf[1000];
+    int status;
+
+    /* Skip leading whitespace. */
+    while ( len > 0 && ( *recipient == ' ' || *recipient == '\t' ) )
+	{
+	++recipient;
+	--len;
+	}
+
+    /* Strip off any angle brackets. */
+    while ( len > 0 && *recipient == '<' )
+	{
+	++recipient;
+	--len;
+	}
+    while ( len > 0 && recipient[len-1] == '>' )
+	--len;
+
+    (void) snprintf( buf, sizeof(buf), "RCPT TO:<%.*s>", len, recipient );
+    send_command( buf );
+    status = read_response();
+    if ( status != 250  && status != 251 )
+	{
+	(void) fprintf(
+	    stderr,  "%s: unexpected response %d to RCPT TO command\n",
+	    argv0, status );
+	exit( 1 );
+	}
+    got_a_recipient = 1;
+    }
+
+
+#if defined(AF_INET6) && defined(IN6_IS_ADDR_V4MAPPED)
+#define USE_IPV6
+#endif
+
+static int
+open_client_socket( void )
+    {
+#ifdef USE_IPV6
+    struct sockaddr_in6 sa;
+#else /* USE_IPV6 */
+    struct sockaddr_in sa;
+#endif /* USE_IPV6 */
+    int sa_len, sock_family, sock_type, sock_protocol;
+    int sockfd;
+
+    sock_type = SOCK_STREAM;
+    sock_protocol = 0;
+    sa_len = sizeof(sa);
+    (void) memset( (void*) &sa, 0, sa_len );
+
+#ifdef USE_IPV6
+
+    {
+#ifdef DO_MINUS_SP
+    struct sockaddr_in sa4;
+    struct addrinfo hints;
+    char portstr[10];
+    int gaierr;
+    struct addrinfo* ai;
+    struct addrinfo* ai2;
+    struct addrinfo* aiv4;
+    struct addrinfo* aiv6;
+#endif /* DO_MINUS_SP */
+
+    sock_family = PF_INET6;
+
+#ifdef DO_MINUS_SP
+    (void) memset( (void*) &sa4, 0, sizeof(sa4) );
+    if ( inet_pton( AF_INET, server, (void*) &sa4.sin_addr ) == 1 )
+	{
+	sock_family = PF_INET;
+	sa4.sin_port = htons( port );
+	sa_len = sizeof(sa4);
+	(void) memmove( &sa, &sa4, sa_len );
+	}
+    else if ( inet_pton( AF_INET6, server, (void*) &sa.sin6_addr ) != 1 )
+	{
+#ifdef DO_DNS
+	(void) memset( &hints, 0, sizeof(hints) );
+	hints.ai_family = PF_UNSPEC;
+	hints.ai_socktype = SOCK_STREAM;
+	(void) snprintf( portstr, sizeof(portstr), "%d", port );
+	if ( (gaierr = getaddrinfo( server, portstr, &hints, &ai )) != 0 )
+	    {
+	    (void) fprintf(
+		stderr, "%s: getaddrinfo %s - %s\n", argv0, server,
+		gai_strerror( gaierr ) );
+	    exit( 1 );
+	    }
+
+	/* Find the first IPv4 and IPv6 entries. */
+	aiv4 = (struct addrinfo*) 0;
+	aiv6 = (struct addrinfo*) 0;
+	for ( ai2 = ai; ai2 != (struct addrinfo*) 0; ai2 = ai2->ai_next )
+	    {
+	    switch ( ai2->ai_family )
+		{
+		case PF_INET:
+		if ( aiv4 == (struct addrinfo*) 0 )
+		    aiv4 = ai2;
+		break;
+		case PF_INET6:
+		if ( aiv6 == (struct addrinfo*) 0 )
+		    aiv6 = ai2;
+		break;
+		}
+	    }
+
+	/* If there's an IPv4 address, use that, otherwise try IPv6. */
+	if ( aiv4 != (struct addrinfo*) 0 )
+	    {
+	    if ( sizeof(sa) < aiv4->ai_addrlen )
+		{
+		(void) fprintf(
+		    stderr, "%s - sockaddr too small (%lu < %lu)\n",
+		    server, (unsigned long) sizeof(sa),
+		    (unsigned long) aiv4->ai_addrlen );
+		exit( 1 );
+		}
+	    sock_family = aiv4->ai_family;
+	    sock_type = aiv4->ai_socktype;
+	    sock_protocol = aiv4->ai_protocol;
+	    sa_len = aiv4->ai_addrlen;
+	    (void) memmove( &sa, aiv4->ai_addr, sa_len );
+	    goto ok;
+	    }
+	if ( aiv6 != (struct addrinfo*) 0 )
+	    {
+	    if ( sizeof(sa) < aiv6->ai_addrlen )
+		{
+		(void) fprintf(
+		    stderr, "%s - sockaddr too small (%lu < %lu)\n",
+		    server, (unsigned long) sizeof(sa),
+		    (unsigned long) aiv6->ai_addrlen );
+		exit( 1 );
+		}
+	    sock_family = aiv6->ai_family;
+	    sock_type = aiv6->ai_socktype;
+	    sock_protocol = aiv6->ai_protocol;
+	    sa_len = aiv6->ai_addrlen;
+	    (void) memmove( &sa, aiv6->ai_addr, sa_len );
+	    goto ok;
+	    }
+
+	(void) fprintf(
+	    stderr, "%s: no valid address found for host %s\n", argv0, server );
+	exit( 1 );
+
+	ok:
+	freeaddrinfo( ai );
+#else /* DO_DNS */
+        (void) fprintf(
+	    stderr, "%s: bad server IP address %s\n", argv0, server );
+	exit( 1 );
+#endif /* DO_DNS */
+	}
+#else /* DO_MINUS_SP */
+    sa.sin6_addr = in6addr_any;
+    sa.sin6_port = htons( SMTP_PORT );
+#endif /* DO_MINUS_SP */
+
+    sa.sin6_family = sock_family;
+
+    }
+
+#else /* USE_IPV6 */
+
+    {
+#ifdef DO_MINUS_SP
+    struct hostent *he;
+#else /* DO_MINUS_SP */
+    char local_addr[4] = { 127, 0, 0, 1 };
+#endif /* DO_MINUS_SP */
+
+    sock_family = PF_INET;
+
+#ifdef DO_MINUS_SP
+    sa.sin_addr.s_addr = inet_addr( server );
+    sa.sin_port = htons( port );
+    if ( (int32_t) sa.sin_addr.s_addr == -1 )
+	{
+#ifdef DO_DNS
+	he = gethostbyname( server );
+	if ( he == (struct hostent*) 0 )
+	    {
+	    (void) fprintf(
+		stderr, "%s: server name lookup of '%s' failed - %s\n",
+		argv0, server, hstrerror( h_errno ) );
+	    exit( 1 );
+	    }
+	sock_family = he->h_addrtype;
+	(void) memmove( &sa.sin_addr, he->h_addr, he->h_length );
+#else /* DO_DNS */
+	(void) fprintf(
+	    stderr, "%s: bad server IP address %s\n", argv0, server );
+	exit( 1 );
+#endif /* DO_DNS */
+	}
+#else /* DO_MINUS_SP */
+    (void) memmove( &sa.sin_addr, local_addr, sizeof(local_addr) );
+    sa.sin_port = htons( SMTP_PORT );
+#endif /* DO_MINUS_SP */
+
+    sa.sin_family = sock_family;
+    }
+
+#endif /* USE_IPV6 */
+
+    sockfd = socket( sock_family, sock_type, sock_protocol );
+    if ( sockfd < 0 )
+	show_error( "socket" );
+
+    if ( connect( sockfd, (struct sockaddr*) &sa, sa_len ) < 0 )
+	show_error( "connect" );
+
+    return sockfd;
+    }
+
+
+static int
+read_response( void )
+    {
+    char buf[10000];
+    char* cp;
+    int status;
+
+    for (;;)
+	{
+	(void) alarm( timeout );
+	if ( fgets( buf, sizeof(buf), sockrfp ) == (char*) 0 )
+	    {
+	    (void) fprintf( stderr, "%s: unexpected EOF\n", argv0 );
+	    exit( 1 );
+	    }
+	if ( verbose )
+	    (void) fprintf( stderr, "<<<< %s", buf );
+	for ( status = 0, cp = buf; *cp >= '0' && *cp <= '9'; ++cp )
+	    status = 10 * status + ( *cp - '0' );
+	if ( *cp == ' ' )
+	    break;
+	if ( *cp != '-' )
+	    {
+	    (void) fprintf(
+		stderr,  "%s: bogus reply syntax - '%s'\n", argv0, buf );
+	    exit( 1 );
+	    }
+	}
+    return status;
+    }
+
+
+static void
+send_command( char* command )
+    {
+    (void) alarm( timeout );
+    if ( verbose )
+	(void) fprintf( stderr, ">>>> %s\n", command );
+    (void) fprintf( sockwfp, "%s\r\n", command );
+    (void) fflush( sockwfp );
+    }
+
+
+static void
+send_data( char* data )
+    {
+    int bol;
+
+    for ( bol = 1; *data != '\0'; ++data )
+	{
+	if ( bol && *data == '.' )
+	    putc( '.', sockwfp );
+	bol = 0;
+	if ( *data == '\n' )
+	    {
+	    putc( '\r', sockwfp );
+	    bol = 1;
+	    }
+	putc( *data, sockwfp );
+	}
+    if ( ! bol )
+	(void) fputs( "\r\n", sockwfp );
+    }
+
+
+static void
+send_done( void )
+    {
+    (void) fputs( ".\r\n", sockwfp );
+    (void) fflush( sockwfp );
+    }
+
+
+static void
+sigcatch( int sig )
+    {
+    (void) fprintf( stderr, "%s: timed out\n", argv0 );
+    exit( 1 );
+    }
+
+
+static void
+show_error( char* cause )
+    {
+    char buf[5000];
+
+    (void) snprintf( buf, sizeof(buf), "%s: %s", argv0, cause );
+    perror( buf );
+    exit( 1 );
+    }
+

file:b/version.h (new)
--- /dev/null
+++ b/version.h
@@ -1,1 +1,9 @@
+/* version.h - version define for mini_sendmail */
 
+#ifndef _VERSION_H_
+#define _VERSION_H_
+
+#define VERSION "mini_sendmail/1.3.6 29jun2005"
+
+#endif /* _VERSION_H_ */
+

comments