Annotation of embedaddon/mini_sendmail/mini_sendmail.c, revision 1.1.1.1.2.1

1.1       misho       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:     while ( len > 0 && *recipient == '<' )
                    546:        {
                    547:        ++recipient;
                    548:        --len;
                    549:        }
                    550:     while ( len > 0 && recipient[len-1] == '>' )
                    551:        --len;
                    552: 
                    553:     (void) snprintf( buf, sizeof(buf), "RCPT TO:<%.*s>", len, recipient );
                    554:     send_command( buf );
                    555:     status = read_response();
                    556:     if ( status != 250  && status != 251 )
                    557:        {
                    558:        (void) fprintf(
                    559:            stderr,  "%s: unexpected response %d to RCPT TO command\n",
                    560:            argv0, status );
                    561:        exit( 1 );
                    562:        }
                    563:     got_a_recipient = 1;
                    564:     }
                    565: 
                    566: 
                    567: #if defined(AF_INET6) && defined(IN6_IS_ADDR_V4MAPPED)
                    568: #define USE_IPV6
                    569: #endif
                    570: 
                    571: static int
                    572: open_client_socket( void )
                    573:     {
                    574: #ifdef USE_IPV6
                    575:     struct sockaddr_in6 sa;
                    576: #else /* USE_IPV6 */
                    577:     struct sockaddr_in sa;
                    578: #endif /* USE_IPV6 */
                    579:     int sa_len, sock_family, sock_type, sock_protocol;
                    580:     int sockfd;
                    581: 
                    582:     sock_type = SOCK_STREAM;
                    583:     sock_protocol = 0;
                    584:     sa_len = sizeof(sa);
                    585:     (void) memset( (void*) &sa, 0, sa_len );
                    586: 
                    587: #ifdef USE_IPV6
                    588: 
                    589:     {
                    590: #ifdef DO_MINUS_SP
                    591:     struct sockaddr_in sa4;
                    592:     struct addrinfo hints;
                    593:     char portstr[10];
                    594:     int gaierr;
                    595:     struct addrinfo* ai;
                    596:     struct addrinfo* ai2;
                    597:     struct addrinfo* aiv4;
                    598:     struct addrinfo* aiv6;
                    599: #endif /* DO_MINUS_SP */
                    600: 
                    601:     sock_family = PF_INET6;
                    602: 
                    603: #ifdef DO_MINUS_SP
                    604:     (void) memset( (void*) &sa4, 0, sizeof(sa4) );
                    605:     if ( inet_pton( AF_INET, server, (void*) &sa4.sin_addr ) == 1 )
                    606:        {
                    607:        sock_family = PF_INET;
                    608:        sa4.sin_port = htons( port );
                    609:        sa_len = sizeof(sa4);
                    610:        (void) memmove( &sa, &sa4, sa_len );
                    611:        }
                    612:     else if ( inet_pton( AF_INET6, server, (void*) &sa.sin6_addr ) != 1 )
                    613:        {
                    614: #ifdef DO_DNS
                    615:        (void) memset( &hints, 0, sizeof(hints) );
                    616:        hints.ai_family = PF_UNSPEC;
                    617:        hints.ai_socktype = SOCK_STREAM;
                    618:        (void) snprintf( portstr, sizeof(portstr), "%d", port );
                    619:        if ( (gaierr = getaddrinfo( server, portstr, &hints, &ai )) != 0 )
                    620:            {
                    621:            (void) fprintf(
                    622:                stderr, "%s: getaddrinfo %s - %s\n", argv0, server,
                    623:                gai_strerror( gaierr ) );
                    624:            exit( 1 );
                    625:            }
                    626: 
                    627:        /* Find the first IPv4 and IPv6 entries. */
                    628:        aiv4 = (struct addrinfo*) 0;
                    629:        aiv6 = (struct addrinfo*) 0;
                    630:        for ( ai2 = ai; ai2 != (struct addrinfo*) 0; ai2 = ai2->ai_next )
                    631:            {
                    632:            switch ( ai2->ai_family )
                    633:                {
                    634:                case PF_INET:
                    635:                if ( aiv4 == (struct addrinfo*) 0 )
                    636:                    aiv4 = ai2;
                    637:                break;
                    638:                case PF_INET6:
                    639:                if ( aiv6 == (struct addrinfo*) 0 )
                    640:                    aiv6 = ai2;
                    641:                break;
                    642:                }
                    643:            }
                    644: 
                    645:        /* If there's an IPv4 address, use that, otherwise try IPv6. */
                    646:        if ( aiv4 != (struct addrinfo*) 0 )
                    647:            {
                    648:            if ( sizeof(sa) < aiv4->ai_addrlen )
                    649:                {
                    650:                (void) fprintf(
                    651:                    stderr, "%s - sockaddr too small (%lu < %lu)\n",
                    652:                    server, (unsigned long) sizeof(sa),
                    653:                    (unsigned long) aiv4->ai_addrlen );
                    654:                exit( 1 );
                    655:                }
                    656:            sock_family = aiv4->ai_family;
                    657:            sock_type = aiv4->ai_socktype;
                    658:            sock_protocol = aiv4->ai_protocol;
                    659:            sa_len = aiv4->ai_addrlen;
                    660:            (void) memmove( &sa, aiv4->ai_addr, sa_len );
                    661:            goto ok;
                    662:            }
                    663:        if ( aiv6 != (struct addrinfo*) 0 )
                    664:            {
                    665:            if ( sizeof(sa) < aiv6->ai_addrlen )
                    666:                {
                    667:                (void) fprintf(
                    668:                    stderr, "%s - sockaddr too small (%lu < %lu)\n",
                    669:                    server, (unsigned long) sizeof(sa),
                    670:                    (unsigned long) aiv6->ai_addrlen );
                    671:                exit( 1 );
                    672:                }
                    673:            sock_family = aiv6->ai_family;
                    674:            sock_type = aiv6->ai_socktype;
                    675:            sock_protocol = aiv6->ai_protocol;
                    676:            sa_len = aiv6->ai_addrlen;
                    677:            (void) memmove( &sa, aiv6->ai_addr, sa_len );
                    678:            goto ok;
                    679:            }
                    680: 
                    681:        (void) fprintf(
                    682:            stderr, "%s: no valid address found for host %s\n", argv0, server );
                    683:        exit( 1 );
                    684: 
                    685:        ok:
                    686:        freeaddrinfo( ai );
                    687: #else /* DO_DNS */
                    688:         (void) fprintf(
                    689:            stderr, "%s: bad server IP address %s\n", argv0, server );
                    690:        exit( 1 );
                    691: #endif /* DO_DNS */
                    692:        }
                    693: #else /* DO_MINUS_SP */
                    694:     sa.sin6_addr = in6addr_any;
                    695:     sa.sin6_port = htons( SMTP_PORT );
                    696: #endif /* DO_MINUS_SP */
                    697: 
                    698:     sa.sin6_family = sock_family;
                    699: 
                    700:     }
                    701: 
                    702: #else /* USE_IPV6 */
                    703: 
                    704:     {
                    705: #ifdef DO_MINUS_SP
                    706:     struct hostent *he;
                    707: #else /* DO_MINUS_SP */
                    708:     char local_addr[4] = { 127, 0, 0, 1 };
                    709: #endif /* DO_MINUS_SP */
                    710: 
                    711:     sock_family = PF_INET;
                    712: 
                    713: #ifdef DO_MINUS_SP
                    714:     sa.sin_addr.s_addr = inet_addr( server );
                    715:     sa.sin_port = htons( port );
                    716:     if ( (int32_t) sa.sin_addr.s_addr == -1 )
                    717:        {
                    718: #ifdef DO_DNS
                    719:        he = gethostbyname( server );
                    720:        if ( he == (struct hostent*) 0 )
                    721:            {
                    722:            (void) fprintf(
                    723:                stderr, "%s: server name lookup of '%s' failed - %s\n",
                    724:                argv0, server, hstrerror( h_errno ) );
                    725:            exit( 1 );
                    726:            }
                    727:        sock_family = he->h_addrtype;
                    728:        (void) memmove( &sa.sin_addr, he->h_addr, he->h_length );
                    729: #else /* DO_DNS */
                    730:        (void) fprintf(
                    731:            stderr, "%s: bad server IP address %s\n", argv0, server );
                    732:        exit( 1 );
                    733: #endif /* DO_DNS */
                    734:        }
                    735: #else /* DO_MINUS_SP */
                    736:     (void) memmove( &sa.sin_addr, local_addr, sizeof(local_addr) );
                    737:     sa.sin_port = htons( SMTP_PORT );
                    738: #endif /* DO_MINUS_SP */
                    739: 
                    740:     sa.sin_family = sock_family;
                    741:     }
                    742: 
                    743: #endif /* USE_IPV6 */
                    744: 
                    745:     sockfd = socket( sock_family, sock_type, sock_protocol );
                    746:     if ( sockfd < 0 )
                    747:        show_error( "socket" );
                    748: 
                    749:     if ( connect( sockfd, (struct sockaddr*) &sa, sa_len ) < 0 )
                    750:        show_error( "connect" );
                    751: 
                    752:     return sockfd;
                    753:     }
                    754: 
                    755: 
                    756: static int
                    757: read_response( void )
                    758:     {
                    759:     char buf[10000];
                    760:     char* cp;
                    761:     int status;
                    762: 
                    763:     for (;;)
                    764:        {
                    765:        (void) alarm( timeout );
                    766:        if ( fgets( buf, sizeof(buf), sockrfp ) == (char*) 0 )
                    767:            {
                    768:            (void) fprintf( stderr, "%s: unexpected EOF\n", argv0 );
                    769:            exit( 1 );
                    770:            }
                    771:        if ( verbose )
                    772:            (void) fprintf( stderr, "<<<< %s", buf );
                    773:        for ( status = 0, cp = buf; *cp >= '0' && *cp <= '9'; ++cp )
                    774:            status = 10 * status + ( *cp - '0' );
                    775:        if ( *cp == ' ' )
                    776:            break;
                    777:        if ( *cp != '-' )
                    778:            {
                    779:            (void) fprintf(
                    780:                stderr,  "%s: bogus reply syntax - '%s'\n", argv0, buf );
                    781:            exit( 1 );
                    782:            }
                    783:        }
                    784:     return status;
                    785:     }
                    786: 
                    787: 
                    788: static void
                    789: send_command( char* command )
                    790:     {
                    791:     (void) alarm( timeout );
                    792:     if ( verbose )
                    793:        (void) fprintf( stderr, ">>>> %s\n", command );
                    794:     (void) fprintf( sockwfp, "%s\r\n", command );
                    795:     (void) fflush( sockwfp );
                    796:     }
                    797: 
                    798: 
                    799: static void
                    800: send_data( char* data )
                    801:     {
                    802:     int bol;
                    803: 
                    804:     for ( bol = 1; *data != '\0'; ++data )
                    805:        {
                    806:        if ( bol && *data == '.' )
                    807:            putc( '.', sockwfp );
                    808:        bol = 0;
                    809:        if ( *data == '\n' )
                    810:            {
                    811:            putc( '\r', sockwfp );
                    812:            bol = 1;
                    813:            }
                    814:        putc( *data, sockwfp );
                    815:        }
                    816:     if ( ! bol )
                    817:        (void) fputs( "\r\n", sockwfp );
                    818:     }
                    819: 
                    820: 
                    821: static void
                    822: send_done( void )
                    823:     {
                    824:     (void) fputs( ".\r\n", sockwfp );
                    825:     (void) fflush( sockwfp );
                    826:     }
                    827: 
                    828: 
                    829: static void
                    830: sigcatch( int sig )
                    831:     {
                    832:     (void) fprintf( stderr, "%s: timed out\n", argv0 );
                    833:     exit( 1 );
                    834:     }
                    835: 
                    836: 
                    837: static void
                    838: show_error( char* cause )
                    839:     {
                    840:     char buf[5000];
                    841: 
                    842:     (void) snprintf( buf, sizeof(buf), "%s: %s", argv0, cause );
                    843:     perror( buf );
                    844:     exit( 1 );
                    845:     }

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