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>