File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mini_sendmail / mini_sendmail.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 16:52:55 2012 UTC (12 years, 3 months ago) by misho
Branches: mini_sendmail, MAIN
CVS tags: v1_3_6p0, v1_3_6, HEAD
mini_sendmail

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

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