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