File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mini_sendmail / mini_sendmail.c
Revision 1.1.1.1.2.2: download - view: text, annotated - select for diffs - revision graph
Tue Oct 18 13:48:41 2016 UTC (7 years, 8 months ago) by misho
Branches: v1_3_6p0
CVS tags: v1_3_9p0
Diff to: branchpoint 1.1.1.1: preferred, unified
v1_3_9p0

    1: /* mini_sendmail - accept email on behalf of real sendmail
    2: **
    3: ** Copyright © 1999,2015 by Jef Poskanzer <jef@mail.acme.com>.
    4: ** All rights reserved.
    5: **
    6: ** Redistribution and use in source and binary forms, with or without
    7: ** modification, are permitted provided that the following conditions
    8: ** are met:
    9: ** 1. Redistributions of source code must retain the above copyright
   10: **    notice, this list of conditions and the following disclaimer.
   11: ** 2. Redistributions in binary form must reproduce the above copyright
   12: **    notice, this list of conditions and the following disclaimer in the
   13: **    documentation and/or other materials provided with the distribution.
   14: **
   15: ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16: ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17: ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18: ** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19: ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20: ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21: ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22: ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23: ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24: ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25: ** SUCH DAMAGE.
   26: */
   27: 
   28: 
   29: /* These defines control some optional features of the program.  If you
   30: ** don't want the features you can undef the symbols; some of them mean
   31: ** a significant savings in executable size.
   32: */
   33: #define DO_RECEIVED	/* whether to add a "Received:" header */
   34: #define DO_GETPWUID	/* whether to try a getpwuid() if getlogin() fails */
   35: #define DO_MINUS_SP	/* whether to implement the -s and -p flags */
   36: #define DO_DNS		/* whether to do a name lookup on -s, or just IP# */
   37: 
   38: 
   39: #include <unistd.h>
   40: #include <stdlib.h>
   41: #include <stdio.h>
   42: #include <signal.h>
   43: #include <string.h>
   44: #include <sys/types.h>
   45: #include <sys/socket.h>
   46: #include <netinet/in.h>
   47: #include <arpa/inet.h>
   48: #include <netdb.h>
   49: 
   50: #ifdef DO_RECEIVED
   51: #include <time.h>
   52: #endif /* DO_RECEIVED */
   53: #ifdef DO_GETPWUID
   54: #include <pwd.h>
   55: #endif /* DO_GETPWUID */
   56: 
   57: #include "version.h"
   58: 
   59: 
   60: /* Defines. */
   61: #define SMTP_PORT 25
   62: #define DEFAULT_TIMEOUT 60
   63: 
   64: 
   65: /* Globals. */
   66: static char* argv0;
   67: static char* fake_from;
   68: static int parse_message, verbose;
   69: #ifdef DO_MINUS_SP
   70: static char* server;
   71: static short port;
   72: #endif /* DO_MINUS_SP */
   73: static int timeout;
   74: static int sockfd1, sockfd2;
   75: static FILE* sockrfp;
   76: static FILE* sockwfp;
   77: static int got_a_recipient;
   78: 
   79: 
   80: /* Forwards. */
   81: static void usage( void );
   82: static char* slurp_message( void );
   83: #ifdef DO_RECEIVED
   84: static char* make_received( char* from, char* username, char* hostname );
   85: #endif /* DO_RECEIVED */
   86: static void parse_for_recipients( char* message );
   87: static void add_recipient( char* recipient, int len );
   88: static int open_client_socket( void );
   89: static int read_response( void );
   90: static void send_command( char* command );
   91: static void send_data( char* data );
   92: static void send_done( void );
   93: static void sigcatch( int sig );
   94: static void show_error( char* cause );
   95: 
   96: 
   97: /* Do overlapping strcpy safely, by using memmove. */
   98: #define ol_strcpy(dst,src) memmove(dst,src,strlen(src)+1)
   99: 
  100: 
  101: int
  102: main( int argc, char** argv )
  103:     {
  104:     int argn;
  105:     char* message;
  106: #ifdef DO_RECEIVED
  107:     char* received;
  108: #endif /* DO_RECEIVED */
  109:     char* username;
  110:     char hostname[500];
  111:     char from[1000];
  112:     int status;
  113:     char buf[2000];
  114: 
  115:     /* Parse args. */
  116:     argv0 = argv[0];
  117:     fake_from = (char*) 0;
  118:     parse_message = 0;
  119: #ifdef DO_MINUS_SP
  120:     server = "127.0.0.1";
  121:     port = SMTP_PORT;
  122: #endif /* DO_MINUS_SP */
  123:     verbose = 0;
  124:     timeout = DEFAULT_TIMEOUT;
  125:     argn = 1;
  126:     while ( argn < argc && argv[argn][0] == '-' )
  127: 	{
  128: 	if ( strncmp( argv[argn], "-f", 2 ) == 0 && argv[argn][2] != '\0' )
  129: 	    fake_from = &(argv[argn][2]);
  130: 	else if ( strcmp( argv[argn], "-t" ) == 0 )
  131: 	    parse_message = 1;
  132: #ifdef DO_MINUS_SP
  133: 	else if ( strncmp( argv[argn], "-s", 2 ) == 0 && argv[argn][2] != '\0' )
  134: 	    server = &(argv[argn][2]);
  135: 	else if ( strncmp( argv[argn], "-p", 2 ) == 0 && argv[argn][2] != '\0' )
  136: 	    port = atoi( &(argv[argn][2]) );
  137: #endif /* DO_MINUS_SP */
  138: 	else if ( strncmp( argv[argn], "-T", 2 ) == 0 && argv[argn][2] != '\0' )
  139: 	    timeout = atoi( &(argv[argn][2]) );
  140: 	else if ( strcmp( argv[argn], "-v" ) == 0 )
  141: 	    verbose = 1;
  142: 	else if ( strcmp( argv[argn], "-i" ) == 0 )
  143: 	    ;	/* ignore */
  144: 	else if ( strcmp( argv[argn], "-oi" ) == 0 )
  145: 	    ;	/* ignore */
  146: 	else if ( strcmp( argv[argn], "--" ) == 0 )
  147: 	    ;	/* ignore */
  148: 	else
  149: 	    usage();
  150: 	++argn;
  151: 	}
  152: 
  153:     username = getlogin();
  154:     if ( username == (char*) 0 )
  155: 	{
  156: #ifdef DO_GETPWUID
  157: 	struct passwd* pw = getpwuid( getuid() );
  158: 	if ( pw == (struct passwd*) 0 )
  159: 	    {
  160: 	    (void) fprintf( stderr, "%s: can't determine username\n", argv0 );
  161: 	    exit( 1 );
  162: 	    }
  163: 	username = pw->pw_name;
  164: #else /* DO_GETPWUID */
  165: 	(void) fprintf( stderr, "%s: can't determine username\n", argv0 );
  166: 	exit( 1 );
  167: #endif /* DO_GETPWUID */
  168: 	}
  169: 
  170:     if ( gethostname( hostname, sizeof(hostname) - 1 ) < 0 )
  171: 	show_error( "gethostname" );
  172: 
  173:     if ( fake_from == (char*) 0 )
  174: 	(void) snprintf( from, sizeof(from), "%s@%s", username, hostname );
  175:     else
  176: 	if ( strchr( fake_from, '@' ) == (char*) 0 )
  177: 	    (void) snprintf( from, sizeof(from), "%s@%s", fake_from, hostname );
  178: 	else
  179: 	    (void) snprintf( from, sizeof(from), "%s", fake_from );
  180: 
  181:     /* Strip off any angle brackets in the from address. */
  182:     while ( from[0] == '<' )
  183: 	(void) ol_strcpy( from, &from[1] );
  184:     while ( from[strlen(from)-1] == '>' )
  185: 	from[strlen(from)-1] = '\0';
  186: 
  187:     message = slurp_message();
  188: #ifdef DO_RECEIVED
  189:     received = make_received( from, username, hostname );
  190: #endif /* DO_RECEIVED */
  191: 
  192:     (void) signal( SIGALRM, sigcatch );
  193: 
  194:     (void) alarm( timeout );
  195:     sockfd1 = open_client_socket();
  196: 
  197:     sockfd2 = dup( sockfd1 );
  198:     sockrfp = fdopen( sockfd1, "r" );
  199:     sockwfp = fdopen( sockfd2, "w" );
  200: 
  201:     /* The full SMTP protocol is spelled out in RFC821, available at
  202:     ** http://www.faqs.org/rfcs/rfc821.html
  203:     ** The only non-obvious wrinkles:
  204:     **  - The commands are terminated with CRLF, not newline.
  205:     **  - Newlines in the data file get turned into CRLFs.
  206:     **  - Any data lines beginning with a period get an extra period prepended.
  207:     */
  208: 
  209:     status = read_response();
  210:     if ( status != 220 )
  211: 	{
  212: 	(void) fprintf(
  213: 	    stderr,  "%s: unexpected initial greeting %d\n", argv0, status );
  214: 	exit( 1 );
  215: 	}
  216: 
  217:     (void) snprintf( buf, sizeof(buf), "HELO %s", hostname );
  218:     send_command( buf );
  219:     status = read_response();
  220:     if ( status != 250 )
  221: 	{
  222: 	(void) fprintf(
  223: 	    stderr,  "%s: unexpected response %d to HELO command\n",
  224: 	    argv0, status );
  225: 	exit( 1 );
  226: 	}
  227: 
  228:     (void) snprintf( buf, sizeof(buf), "MAIL FROM:<%s>", from );
  229:     send_command( buf );
  230:     status = read_response();
  231:     if ( status != 250 )
  232: 	{
  233: 	(void) fprintf(
  234: 	    stderr,  "%s: unexpected response %d to MAIL FROM command\n",
  235: 	    argv0, status );
  236: 	exit( 1 );
  237: 	}
  238: 
  239:     got_a_recipient = 0;
  240:     for ( ; argn < argc; ++argn )
  241: 	add_recipient( argv[argn], strlen( argv[argn] ) );
  242:     if ( parse_message )
  243: 	parse_for_recipients( message );
  244:     if ( ! got_a_recipient )
  245: 	{
  246: 	(void) fprintf( stderr,  "%s: no recipients found\n", argv0 );
  247: 	exit( 1 );
  248: 	}
  249: 
  250:     send_command( "DATA" );
  251:     status = read_response();
  252:     if ( status != 354 )
  253: 	{
  254: 	(void) fprintf(
  255: 	    stderr,  "%s: unexpected response %d to DATA command\n",
  256: 	    argv0, status );
  257: 	exit( 1 );
  258: 	}
  259: 
  260: #ifdef DO_RECEIVED
  261:     send_data( received );
  262: #endif /* DO_RECEIVED */
  263:     send_data( message );
  264:     send_done();
  265:     status = read_response();
  266:     if ( status != 250 )
  267: 	{
  268: 	(void) fprintf(
  269: 	    stderr,  "%s: unexpected response %d to DATA\n", argv0, status );
  270: 	exit( 1 );
  271: 	}
  272: 
  273:     send_command( "QUIT" );
  274:     status = read_response();
  275:     if ( status != 221 )
  276: 	(void) fprintf(
  277: 	    stderr,  "%s: unexpected response %d to QUIT command - ignored\n",
  278: 	    argv0, status );
  279: 
  280:     (void) close( sockfd1 );
  281:     (void) close( sockfd2 );
  282: 
  283:     exit( 0 );
  284:     }
  285: 
  286: 
  287: static void
  288: usage( void )
  289:     {
  290: #ifdef DO_MINUS_SP
  291: #ifdef DO_DNS
  292:     char* spflag = "[-s<server>] [-p<port>] ";
  293: #else /* DO_DNS */
  294:     char* spflag = "[-s<server_ip>] [-p<port>] ";
  295: #endif /* DO_DNS */
  296: #else /* DO_MINUS_SP */
  297:     char* spflag = "";
  298: #endif /* DO_MINUS_SP */
  299:     (void) fprintf( stderr, "usage:  %s [-f<name>] [-t] %s[-T<timeout>] [-v] [address ...]\n", argv0, spflag );
  300:     exit( 1 );
  301:     }
  302: 
  303: 
  304: static char*
  305: slurp_message( void )
  306:     {
  307:     char* message;
  308:     int message_size, message_len;
  309:     int c;
  310: 
  311:     message_size = 5000;
  312:     message = (char*) malloc( message_size );
  313:     if ( message == (char*) 0 )
  314: 	{
  315: 	(void) fprintf( stderr, "%s: out of memory\n", argv0 );
  316: 	exit( 1 );
  317: 	}
  318:     message_len = 0;
  319: 
  320:     for (;;)
  321: 	{
  322: 	c = getchar();
  323: 	if ( c == EOF )
  324: 	    break;
  325: 	if ( message_len + 1 >= message_size )
  326: 	    {
  327: 	    message_size *= 2;
  328: 	    message = (char*) realloc( (void*) message, message_size );
  329: 	    if ( message == (char*) 0 )
  330: 		{
  331: 		(void) fprintf( stderr, "%s: out of memory\n", argv0 );
  332: 		exit( 1 );
  333: 		}
  334: 	    }
  335: 	message[message_len++] = c;
  336: 	}
  337:     message[message_len] = '\0';
  338: 
  339:     return message;
  340:     }
  341: 
  342: 
  343: #ifdef DO_RECEIVED
  344: static char*
  345: make_received( char* from, char* username, char* hostname )
  346:     {
  347:     int received_size;
  348:     char* received;
  349:     time_t t;
  350:     struct tm* tmP;
  351:     char timestamp[100];
  352: 
  353:     t = time( (time_t*) 0 );
  354:     tmP = localtime( &t );
  355:     (void) strftime( timestamp, sizeof(timestamp), "%a, %d %b %Y %T %Z", tmP );
  356:     received_size =
  357: 	500 + strlen( from ) + strlen( hostname ) * 2 + strlen( MINI_SENDMAIL_VERSION ) +
  358: 	strlen( timestamp ) + strlen( username );
  359:     received = (char*) malloc( received_size );
  360:     if ( received == (char*) 0 )
  361: 	{
  362: 	(void) fprintf( stderr, "%s: out of memory\n", argv0 );
  363: 	exit( 1 );
  364: 	}
  365:     (void) snprintf(
  366: 	received, received_size,
  367: 	"Received: (from %s)\n\tby %s (%s);\n\t%s\n\t(sender %s@%s)\n",
  368: 	from, hostname, MINI_SENDMAIL_VERSION, timestamp, username, hostname );
  369:     return received;
  370:     }
  371: #endif /* DO_RECEIVED */
  372: 
  373: 
  374: static void
  375: parse_for_recipients( char* message )
  376:     {
  377:     /* A little finite-state machine that parses the message, looking
  378:     ** for To:, Cc:, and Bcc: recipients.
  379:     */
  380:     int state;
  381: #define ST_BOL		0
  382: #define ST_OTHERHEAD	1
  383: #define ST_T		2
  384: #define ST_C		3
  385: #define ST_B		4
  386: #define ST_BC		5
  387: #define ST_RECIPHEAD	6
  388: #define ST_RECIPS	7
  389:     char* cp;
  390:     char* bcc;
  391:     char* recip = (char*) 0;
  392: 
  393:     state = ST_BOL;
  394:     bcc = (char*) 0;
  395:     for ( cp = message; *cp != '\0'; ++cp )
  396: 	{
  397: 	switch ( state )
  398: 	    {
  399: 	    case ST_BOL:
  400: 	    switch ( *cp )
  401: 		{
  402: 		case '\n':
  403: 		return;
  404: 		case 'T':
  405: 		case 't':
  406: 		state = ST_T;
  407: 		break;
  408: 		case 'C':
  409: 		case 'c':
  410: 		state = ST_C;
  411: 		break;
  412: 		case 'B':
  413: 		case 'b':
  414: 		state = ST_B;
  415: 		bcc = cp;
  416: 		break;
  417: 		default:
  418: 		state = ST_OTHERHEAD;
  419: 		break;
  420: 		}
  421: 	    break;
  422: 	    case ST_OTHERHEAD:
  423: 	    switch ( *cp )
  424: 		{
  425: 		case '\n':
  426: 		state = ST_BOL;
  427: 		break;
  428: 		}
  429: 	    break;
  430: 	    case ST_T:
  431: 	    switch ( *cp )
  432: 		{
  433: 		case '\n':
  434: 		state = ST_BOL;
  435: 		break;
  436: 		case 'O':
  437: 		case 'o':
  438: 		state = ST_RECIPHEAD;
  439: 		break;
  440: 		default:
  441: 		state = ST_OTHERHEAD;
  442: 		break;
  443: 		}
  444: 	    break;
  445: 	    case ST_C:
  446: 	    switch ( *cp )
  447: 		{
  448: 		case '\n':
  449: 		state = ST_BOL;
  450: 		break;
  451: 		case 'C':
  452: 		case 'c':
  453: 		state = ST_RECIPHEAD;
  454: 		break;
  455: 		default:
  456: 		state = ST_OTHERHEAD;
  457: 		break;
  458: 		}
  459: 	    break;
  460: 	    case ST_B:
  461: 	    switch ( *cp )
  462: 		{
  463: 		case '\n':
  464: 		state = ST_BOL;
  465: 		bcc = (char*) 0;
  466: 		break;
  467: 		case 'C':
  468: 		case 'c':
  469: 		state = ST_BC;
  470: 		break;
  471: 		default:
  472: 		state = ST_OTHERHEAD;
  473: 		bcc = (char*) 0;
  474: 		break;
  475: 		}
  476: 	    break;
  477: 	    case ST_BC:
  478: 	    switch ( *cp )
  479: 		{
  480: 		case '\n':
  481: 		state = ST_BOL;
  482: 		bcc = (char*) 0;
  483: 		break;
  484: 		case 'C':
  485: 		case 'c':
  486: 		state = ST_RECIPHEAD;
  487: 		break;
  488: 		default:
  489: 		state = ST_OTHERHEAD;
  490: 		bcc = (char*) 0;
  491: 		break;
  492: 		}
  493: 	    break;
  494: 	    case ST_RECIPHEAD:
  495: 	    switch ( *cp )
  496: 		{
  497: 		case '\n':
  498: 		state = ST_BOL;
  499: 		bcc = (char*) 0;
  500: 		break;
  501: 		case ':':
  502: 		state = ST_RECIPS;
  503: 		recip = cp + 1;
  504: 		break;
  505: 		default:
  506: 		state = ST_OTHERHEAD;
  507: 		bcc = (char*) 0;
  508: 		break;
  509: 		}
  510: 	    break;
  511: 	    case ST_RECIPS:
  512: 	    switch ( *cp )
  513: 		{
  514: 		case '\n':
  515: 		add_recipient( recip, ( cp - recip ) );
  516: 		state = ST_BOL;
  517: 		if ( bcc != (char*) 0 )
  518: 		    {
  519: 		    /* Elide the Bcc: line, and reset cp. */
  520: 		    (void) ol_strcpy( bcc, cp + 1 );
  521: 		    cp = bcc - 1;
  522: 		    bcc = (char*) 0;
  523: 		    }
  524: 		break;
  525: 		case ',':
  526: 		add_recipient( recip, ( cp - recip ) );
  527: 		recip = cp + 1;
  528: 		break;
  529: 		}
  530: 	    break;
  531: 	    }
  532: 	}
  533:     }
  534: 
  535: 
  536: static void
  537: add_recipient( char* recipient, int len )
  538:     {
  539:     char buf[1000];
  540:     int status;
  541: 
  542:     /* Skip leading whitespace. */
  543:     while ( len > 0 && ( *recipient == ' ' || *recipient == '\t' ) )
  544: 	{
  545: 	++recipient;
  546: 	--len;
  547: 	}
  548: 
  549:     /* Strip off any angle brackets. */
  550: /*
  551:     while ( len > 0 && *recipient == '<' )
  552: 	{
  553: 	++recipient;
  554: 	--len;
  555: 	}
  556:     while ( len > 0 && recipient[len-1] == '>' )
  557: 	--len;
  558: 
  559:     (void) snprintf( buf, sizeof(buf), "RCPT TO:<%.*s>", len, recipient );
  560: */
  561:     if (len > 0 && recipient[len-1] == '>' )
  562:     {
  563:         /* "<name@domain>" or: "Full Name <name@domain>" */
  564:         while (len > 0 && *recipient != '<' )
  565:             {
  566:             ++recipient;
  567:             --len;
  568:             }
  569:         (void) snprintf( buf, sizeof(buf), "RCPT TO:%.*s", len, recipient );
  570:     }
  571:     else
  572:     {
  573:         /* name@domain */
  574:         (void) snprintf( buf, sizeof(buf), "RCPT TO:<%.*s>", len, recipient );
  575:     }
  576: 
  577:     send_command( buf );
  578:     status = read_response();
  579:     if ( status != 250  && status != 251 )
  580: 	{
  581: 	(void) fprintf(
  582: 	    stderr,  "%s: unexpected response %d to RCPT TO command\n",
  583: 	    argv0, status );
  584: 	exit( 1 );
  585: 	}
  586:     got_a_recipient = 1;
  587:     }
  588: 
  589: 
  590: #if defined(AF_INET6) && defined(IN6_IS_ADDR_V4MAPPED)
  591: #define USE_IPV6
  592: #endif
  593: 
  594: static int
  595: open_client_socket( void )
  596:     {
  597: #ifdef USE_IPV6
  598:     struct sockaddr_in6 sa_in;
  599: #else /* USE_IPV6 */
  600:     struct sockaddr_in sa_in;
  601: #endif /* USE_IPV6 */
  602:     int sa_len, sock_family, sock_type, sock_protocol;
  603:     int sockfd;
  604: 
  605:     sock_type = SOCK_STREAM;
  606:     sock_protocol = 0;
  607:     sa_len = sizeof(sa_in);
  608:     (void) memset( (void*) &sa_in, 0, sa_len );
  609: 
  610: #ifdef USE_IPV6
  611: 
  612:     {
  613: #ifdef DO_MINUS_SP
  614:     struct sockaddr_in sa_in4;
  615:     struct addrinfo hints;
  616:     char portstr[10];
  617:     int gaierr;
  618:     struct addrinfo* ai;
  619:     struct addrinfo* ai2;
  620:     struct addrinfo* aiv4;
  621:     struct addrinfo* aiv6;
  622: #endif /* DO_MINUS_SP */
  623: 
  624:     sock_family = PF_INET6;
  625: 
  626: #ifdef DO_MINUS_SP
  627:     (void) memset( (void*) &sa_in4, 0, sizeof(sa_in4) );
  628:     if ( inet_pton( AF_INET, server, (void*) &sa_in4.sin_addr ) == 1 )
  629: 	{
  630: 	sock_family = PF_INET;
  631: 	sa_in4.sin_port = htons( port );
  632: 	sa_len = sizeof(sa_in4);
  633: 	(void) memmove( &sa_in, &sa_in4, sa_len );
  634: 	}
  635:     else if ( inet_pton( AF_INET6, server, (void*) &sa_in.sin6_addr ) != 1 )
  636: 	{
  637: #ifdef DO_DNS
  638: 	(void) memset( &hints, 0, sizeof(hints) );
  639: 	hints.ai_family = PF_UNSPEC;
  640: 	hints.ai_socktype = SOCK_STREAM;
  641: 	(void) snprintf( portstr, sizeof(portstr), "%d", port );
  642: 	if ( (gaierr = getaddrinfo( server, portstr, &hints, &ai )) != 0 )
  643: 	    {
  644: 	    (void) fprintf(
  645: 		stderr, "%s: getaddrinfo %s - %s\n", argv0, server,
  646: 		gai_strerror( gaierr ) );
  647: 	    exit( 1 );
  648: 	    }
  649: 
  650: 	/* Find the first IPv4 and IPv6 entries. */
  651: 	aiv4 = (struct addrinfo*) 0;
  652: 	aiv6 = (struct addrinfo*) 0;
  653: 	for ( ai2 = ai; ai2 != (struct addrinfo*) 0; ai2 = ai2->ai_next )
  654: 	    {
  655: 	    switch ( ai2->ai_family )
  656: 		{
  657: 		case PF_INET:
  658: 		if ( aiv4 == (struct addrinfo*) 0 )
  659: 		    aiv4 = ai2;
  660: 		break;
  661: 		case PF_INET6:
  662: 		if ( aiv6 == (struct addrinfo*) 0 )
  663: 		    aiv6 = ai2;
  664: 		break;
  665: 		}
  666: 	    }
  667: 
  668: 	/* If there's an IPv4 address, use that, otherwise try IPv6. */
  669: 	if ( aiv4 != (struct addrinfo*) 0 )
  670: 	    {
  671: 	    if ( sizeof(sa_in) < aiv4->ai_addrlen )
  672: 		{
  673: 		(void) fprintf(
  674: 		    stderr, "%s - sockaddr too small (%lu < %lu)\n",
  675: 		    server, (unsigned long) sizeof(sa_in),
  676: 		    (unsigned long) aiv4->ai_addrlen );
  677: 		exit( 1 );
  678: 		}
  679: 	    sock_family = aiv4->ai_family;
  680: 	    sock_type = aiv4->ai_socktype;
  681: 	    sock_protocol = aiv4->ai_protocol;
  682: 	    sa_len = aiv4->ai_addrlen;
  683: 	    (void) memmove( &sa_in, aiv4->ai_addr, sa_len );
  684: 	    goto ok;
  685: 	    }
  686: 	if ( aiv6 != (struct addrinfo*) 0 )
  687: 	    {
  688: 	    if ( sizeof(sa_in) < aiv6->ai_addrlen )
  689: 		{
  690: 		(void) fprintf(
  691: 		    stderr, "%s - sockaddr too small (%lu < %lu)\n",
  692: 		    server, (unsigned long) sizeof(sa_in),
  693: 		    (unsigned long) aiv6->ai_addrlen );
  694: 		exit( 1 );
  695: 		}
  696: 	    sock_family = aiv6->ai_family;
  697: 	    sock_type = aiv6->ai_socktype;
  698: 	    sock_protocol = aiv6->ai_protocol;
  699: 	    sa_len = aiv6->ai_addrlen;
  700: 	    (void) memmove( &sa_in, aiv6->ai_addr, sa_len );
  701: 	    goto ok;
  702: 	    }
  703: 
  704: 	(void) fprintf(
  705: 	    stderr, "%s: no valid address found for host %s\n", argv0, server );
  706: 	exit( 1 );
  707: 
  708: 	ok:
  709: 	freeaddrinfo( ai );
  710: #else /* DO_DNS */
  711:         (void) fprintf(
  712: 	    stderr, "%s: bad server IP address %s\n", argv0, server );
  713: 	exit( 1 );
  714: #endif /* DO_DNS */
  715: 	}
  716: #else /* DO_MINUS_SP */
  717:     sa_in.sin6_addr = in6addr_any;
  718:     sa_in.sin6_port = htons( SMTP_PORT );
  719: #endif /* DO_MINUS_SP */
  720: 
  721:     sa_in.sin6_family = sock_family;
  722: 
  723:     }
  724: 
  725: #else /* USE_IPV6 */
  726: 
  727:     {
  728: #ifdef DO_MINUS_SP
  729:     struct hostent *he;
  730: #else /* DO_MINUS_SP */
  731:     char local_addr[4] = { 127, 0, 0, 1 };
  732: #endif /* DO_MINUS_SP */
  733: 
  734:     sock_family = PF_INET;
  735: 
  736: #ifdef DO_MINUS_SP
  737:     sa_in.sin_addr.s_addr = inet_addr( server );
  738:     sa_in.sin_port = htons( port );
  739:     if ( (int32_t) sa_in.sin_addr.s_addr == -1 )
  740: 	{
  741: #ifdef DO_DNS
  742: 	he = gethostbyname( server );
  743: 	if ( he == (struct hostent*) 0 )
  744: 	    {
  745: 	    (void) fprintf(
  746: 		stderr, "%s: server name lookup of '%s' failed - %s\n",
  747: 		argv0, server, hstrerror( h_errno ) );
  748: 	    exit( 1 );
  749: 	    }
  750: 	sock_family = he->h_addrtype;
  751: 	(void) memmove( &sa_in.sin_addr, he->h_addr, he->h_length );
  752: #else /* DO_DNS */
  753: 	(void) fprintf(
  754: 	    stderr, "%s: bad server IP address %s\n", argv0, server );
  755: 	exit( 1 );
  756: #endif /* DO_DNS */
  757: 	}
  758: #else /* DO_MINUS_SP */
  759:     (void) memmove( &sa_in.sin_addr, local_addr, sizeof(local_addr) );
  760:     sa_in.sin_port = htons( SMTP_PORT );
  761: #endif /* DO_MINUS_SP */
  762: 
  763:     sa_in.sin_family = sock_family;
  764:     }
  765: 
  766: #endif /* USE_IPV6 */
  767: 
  768:     sockfd = socket( sock_family, sock_type, sock_protocol );
  769:     if ( sockfd < 0 )
  770: 	show_error( "socket" );
  771: 
  772:     if ( connect( sockfd, (struct sockaddr*) &sa_in, sa_len ) < 0 )
  773: 	show_error( "connect" );
  774: 
  775:     return sockfd;
  776:     }
  777: 
  778: 
  779: static int
  780: read_response( void )
  781:     {
  782:     char buf[10000];
  783:     char* cp;
  784:     int status;
  785: 
  786:     for (;;)
  787: 	{
  788: 	(void) alarm( timeout );
  789: 	if ( fgets( buf, sizeof(buf), sockrfp ) == (char*) 0 )
  790: 	    {
  791: 	    (void) fprintf( stderr, "%s: unexpected EOF\n", argv0 );
  792: 	    exit( 1 );
  793: 	    }
  794: 	if ( verbose )
  795: 	    (void) fprintf( stderr, "<<<< %s", buf );
  796: 	for ( status = 0, cp = buf; *cp >= '0' && *cp <= '9'; ++cp )
  797: 	    status = 10 * status + ( *cp - '0' );
  798: 	if ( *cp == ' ' )
  799: 	    break;
  800: 	if ( *cp != '-' )
  801: 	    {
  802: 	    (void) fprintf(
  803: 		stderr,  "%s: bogus reply syntax - '%s'\n", argv0, buf );
  804: 	    exit( 1 );
  805: 	    }
  806: 	}
  807:     return status;
  808:     }
  809: 
  810: 
  811: static void
  812: send_command( char* command )
  813:     {
  814:     (void) alarm( timeout );
  815:     if ( verbose )
  816: 	(void) fprintf( stderr, ">>>> %s\n", command );
  817:     (void) fprintf( sockwfp, "%s\r\n", command );
  818:     (void) fflush( sockwfp );
  819:     }
  820: 
  821: 
  822: static void
  823: send_data( char* data )
  824:     {
  825:     int bol;
  826: 
  827:     for ( bol = 1; *data != '\0'; ++data )
  828: 	{
  829: 	if ( bol && *data == '.' )
  830: 	    putc( '.', sockwfp );
  831: 	bol = 0;
  832: 	if ( *data == '\n' )
  833: 	    {
  834: 	    putc( '\r', sockwfp );
  835: 	    bol = 1;
  836: 	    }
  837: 	putc( *data, sockwfp );
  838: 	}
  839:     if ( ! bol )
  840: 	(void) fputs( "\r\n", sockwfp );
  841:     }
  842: 
  843: 
  844: static void
  845: send_done( void )
  846:     {
  847:     (void) fputs( ".\r\n", sockwfp );
  848:     (void) fflush( sockwfp );
  849:     }
  850: 
  851: 
  852: static void
  853: sigcatch( int sig )
  854:     {
  855:     (void) fprintf( stderr, "%s: timed out\n", argv0 );
  856:     exit( 1 );
  857:     }
  858: 
  859: 
  860: static void
  861: show_error( char* cause )
  862:     {
  863:     char buf[5000];
  864: 
  865:     (void) snprintf( buf, sizeof(buf), "%s: %s", argv0, cause );
  866:     perror( buf );
  867:     exit( 1 );
  868:     }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>