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>