Annotation of embedaddon/mini_sendmail/mini_sendmail.c, revision 1.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: /*
        !           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>