Mercurial > hg > xemacs-beta
annotate lib-src/fakemail.c @ 5750:66d2f63df75f
Correct some spelling and formatting in behavior.el.
Mentioned in tracker issue 826, the third thing mentioned there (the file
name at the bottom of the file) had already been fixed.
lisp/ChangeLog addition:
2013-08-05 Aidan Kehoe <kehoea@parhasard.net>
* behavior.el:
(override-behavior):
Correct some spelling and formatting here, thank you Steven
Mitchell in tracker issue 826.
author | Aidan Kehoe <kehoea@parhasard.net> |
---|---|
date | Mon, 05 Aug 2013 10:05:32 +0100 |
parents | a9094f28f9a9 |
children |
rev | line source |
---|---|
428 | 1 /* sendmail-like interface to /bin/mail for system V, |
2 Copyright (C) 1985, 1994 Free Software Foundation, Inc. | |
3 | |
613 | 4 This file is part of XEmacs. |
428 | 5 |
5406
061f4f90f874
Convert lib-src/ to GPLv3.
Mike Sperber <sperber@deinprogramm.de>
parents:
4932
diff
changeset
|
6 XEmacs is free software: you can redistribute it and/or modify it |
061f4f90f874
Convert lib-src/ to GPLv3.
Mike Sperber <sperber@deinprogramm.de>
parents:
4932
diff
changeset
|
7 under the terms of the GNU General Public License as published by the |
061f4f90f874
Convert lib-src/ to GPLv3.
Mike Sperber <sperber@deinprogramm.de>
parents:
4932
diff
changeset
|
8 Free Software Foundation, either version 3 of the License, or (at your |
061f4f90f874
Convert lib-src/ to GPLv3.
Mike Sperber <sperber@deinprogramm.de>
parents:
4932
diff
changeset
|
9 option) any later version. |
428 | 10 |
5406
061f4f90f874
Convert lib-src/ to GPLv3.
Mike Sperber <sperber@deinprogramm.de>
parents:
4932
diff
changeset
|
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT |
061f4f90f874
Convert lib-src/ to GPLv3.
Mike Sperber <sperber@deinprogramm.de>
parents:
4932
diff
changeset
|
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
061f4f90f874
Convert lib-src/ to GPLv3.
Mike Sperber <sperber@deinprogramm.de>
parents:
4932
diff
changeset
|
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
061f4f90f874
Convert lib-src/ to GPLv3.
Mike Sperber <sperber@deinprogramm.de>
parents:
4932
diff
changeset
|
14 for more details. |
428 | 15 |
16 You should have received a copy of the GNU General Public License | |
5406
061f4f90f874
Convert lib-src/ to GPLv3.
Mike Sperber <sperber@deinprogramm.de>
parents:
4932
diff
changeset
|
17 along with XEmacs. If not, see <http://www.gnu.org/licenses/>. */ |
428 | 18 |
19 /* Synched up with: FSF 19.28. */ | |
20 | |
21 #define NO_SHORTNAMES | |
438 | 22 #include <config.h> |
428 | 23 |
24 #if defined (BSD) && !defined (BSD4_1) && !defined (USE_FAKEMAIL) | |
25 /* This program is not used in BSD, so just avoid loader complaints. */ | |
26 int | |
27 main (int argc, char *argv[]) | |
28 { | |
29 return 0; | |
30 } | |
31 #elif defined (LINUX) | |
32 #include <stdio.h> | |
33 #include <stdlib.h> | |
34 int | |
2509 | 35 main (int argc, char *argv[]) |
428 | 36 { |
37 /* Linux /bin/mail, if it exists, is NOT the Unix v7 mail that | |
38 fakemail depends on! This causes garbled mail. Better to | |
39 output an error message. */ | |
40 fprintf (stderr, "Sorry, fakemail does not work on Linux.\n"); | |
41 fprintf (stderr, "Make sure you have the sendmail program, and\n"); | |
42 fprintf (stderr, "set the Lisp variable `sendmail-program' to point\n"); | |
43 fprintf (stderr, "to the path of the sendmail binary.\n"); | |
44 return 1; | |
45 } | |
46 #else /* not BSD 4.2 (or newer) */ | |
47 | |
48 /* These are defined in config in some versions. */ | |
49 | |
50 #ifdef static | |
51 #undef static | |
52 #endif | |
53 | |
54 #ifdef read | |
55 #undef read | |
56 #undef write | |
57 #undef open | |
58 #undef close | |
59 #endif | |
60 | |
61 #include <stdio.h> | |
62 #if __STDC__ || defined(STDC_HEADERS) | |
63 #include <stdlib.h> | |
64 #include <unistd.h> | |
65 #endif | |
66 #include <string.h> | |
67 #include <ctype.h> | |
68 #include <time.h> | |
69 #include <pwd.h> | |
70 | |
71 /* Type definitions */ | |
72 | |
73 #define boolean int | |
74 #define true 1 | |
75 #define false 0 | |
76 | |
77 /* Various lists */ | |
78 | |
79 struct line_record | |
80 { | |
81 char *string; | |
82 struct line_record *continuation; | |
83 }; | |
84 typedef struct line_record *line_list; | |
85 | |
86 struct header_record | |
87 { | |
88 line_list text; | |
89 struct header_record *next; | |
90 struct header_record *previous; | |
91 }; | |
92 typedef struct header_record *header; | |
93 | |
94 struct stream_record | |
95 { | |
96 FILE *handle; | |
97 int (*action)(FILE *); | |
98 struct stream_record *rest_streams; | |
99 }; | |
100 typedef struct stream_record *stream_list; | |
101 | |
102 /* A `struct linebuffer' is a structure which holds a line of text. | |
103 * `readline' reads a line from a stream into a linebuffer | |
104 * and works regardless of the length of the line. | |
105 */ | |
106 | |
107 struct linebuffer | |
108 { | |
440 | 109 size_t size; |
428 | 110 char *buffer; |
111 }; | |
112 | |
113 struct linebuffer lb; | |
114 | |
115 #define new_list() \ | |
116 ((line_list) xmalloc (sizeof (struct line_record))) | |
117 #define new_header() \ | |
118 ((header) xmalloc (sizeof (struct header_record))) | |
119 #define new_stream() \ | |
120 ((stream_list) xmalloc (sizeof (struct stream_record))) | |
121 #define alloc_string(nchars) \ | |
122 ((char *) xmalloc ((nchars) + 1)) | |
123 | |
124 /* Global declarations */ | |
125 | |
126 #define BUFLEN 1024 | |
127 #define KEYWORD_SIZE 256 | |
128 #define FROM_PREFIX "From" | |
129 #define MY_NAME "fakemail" | |
130 #define NIL ((line_list) NULL) | |
131 #define INITIAL_LINE_SIZE 200 | |
132 #define MAIL_PROGRAM_NAME "/bin/mail" | |
133 | |
442 | 134 static const char *my_name; |
428 | 135 static char *the_date; |
136 static char *the_user; | |
137 static line_list file_preface; | |
138 static stream_list the_streams; | |
139 static boolean no_problems = true; | |
140 | |
141 #if !__STDC__ && !defined(STDC_HEADERS) | |
142 extern FILE *popen (); | |
143 extern int fclose (), pclose (); | |
144 extern char *malloc (), *realloc (); | |
145 #endif | |
146 | |
5341 | 147 #if defined(__FreeBSD__) |
148 #include <osreldate.h> | |
149 #endif | |
150 | |
2687 | 151 #if defined(__FreeBSD_version) && __FreeBSD_version >= 400000 |
152 #define CURRENT_USER | |
153 #endif | |
154 | |
428 | 155 #ifdef CURRENT_USER |
156 extern struct passwd *getpwuid (); | |
2687 | 157 #if defined(__FreeBSD_version) && __FreeBSD_version >= 400000 |
158 extern uid_t geteuid (); | |
159 #else | |
160 extern unsigned short geteuid (); | |
161 #endif | |
428 | 162 static struct passwd *my_entry; |
163 #define cuserid(s) \ | |
434 | 164 (my_entry = getpwuid ((int) geteuid ()), \ |
428 | 165 my_entry->pw_name) |
166 #endif | |
167 | |
168 /* Utilities */ | |
169 | |
170 /* Print error message. `s1' is printf control string, `s2' is arg for it. */ | |
171 | |
172 static void | |
442 | 173 error (const char *s1, const char *s2) |
428 | 174 { |
175 printf ("%s: ", my_name); | |
176 printf (s1, s2); | |
177 printf ("\n"); | |
178 no_problems = false; | |
179 } | |
180 | |
181 /* Print error message and exit. */ | |
182 | |
183 static void | |
442 | 184 fatal (const char *s1, const char *s2) |
428 | 185 { |
186 error (s1, s2); | |
187 exit (1); | |
188 } | |
189 | |
190 /* Like malloc but get fatal error if memory is exhausted. */ | |
191 | |
440 | 192 static void * |
428 | 193 xmalloc (size_t size) |
194 { | |
440 | 195 void *result = malloc (size); |
196 if (result == NULL) | |
428 | 197 fatal ("virtual memory exhausted", (char *) 0); |
198 return result; | |
199 } | |
200 | |
440 | 201 static void * |
202 xrealloc (void *ptr, size_t size) | |
428 | 203 { |
440 | 204 void *result = realloc (ptr, size); |
205 if (result == NULL) | |
428 | 206 fatal ("virtual memory exhausted", (char *) 0); |
207 return result; | |
208 } | |
209 | |
210 /* Initialize a linebuffer for use */ | |
211 | |
212 static void | |
213 init_linebuffer (struct linebuffer *linebuffer) | |
214 { | |
215 linebuffer->size = INITIAL_LINE_SIZE; | |
440 | 216 linebuffer->buffer = (char *) xmalloc (INITIAL_LINE_SIZE); |
428 | 217 } |
218 | |
219 /* Read a line of text from `stream' into `linebuffer'. | |
220 * Return the length of the line. | |
221 */ | |
222 | |
223 static long | |
224 readline (struct linebuffer *linebuffer, FILE *stream) | |
225 { | |
226 char *buffer = linebuffer->buffer; | |
227 char *p = linebuffer->buffer; | |
228 char *end = p + linebuffer->size; | |
229 | |
230 while (true) | |
231 { | |
232 int c = getc (stream); | |
233 if (p == end) | |
234 { | |
235 linebuffer->size *= 2; | |
440 | 236 buffer = (char *) xrealloc (buffer, linebuffer->size); |
428 | 237 p = buffer + (p - linebuffer->buffer); |
238 end = buffer + linebuffer->size; | |
239 linebuffer->buffer = buffer; | |
240 } | |
241 if (c < 0 || c == '\n') | |
242 { | |
243 *p = 0; | |
244 break; | |
245 } | |
246 *p++ = c; | |
247 } | |
248 | |
249 return p - buffer; | |
250 } | |
251 | |
252 static char * | |
253 get_keyword (register char *field, char **rest) | |
254 { | |
255 static char keyword[KEYWORD_SIZE]; | |
256 register char *ptr; | |
257 register char c; | |
258 | |
259 ptr = &keyword[0]; | |
260 c = *field++; | |
261 if ((isspace ((int) (unsigned char) c)) || (c == ':')) | |
262 return (char *) NULL; | |
263 *ptr++ = ((islower ((int) (unsigned char) c)) ? | |
264 (toupper ((int) (unsigned char) c)) : c); | |
265 while (((c = *field++) != ':') && | |
266 (!(isspace ((int) (unsigned char) c)))) | |
267 *ptr++ = ((islower ((int) (unsigned char) c)) ? | |
268 (toupper ((int) (unsigned char) c)) : c); | |
269 *ptr++ = '\0'; | |
270 while (isspace ((int) (unsigned char) c)) c = *field++; | |
271 if (c != ':') return (char *) NULL; | |
272 *rest = field; | |
273 return &keyword[0]; | |
274 } | |
275 | |
276 static boolean | |
277 has_keyword (char *field) | |
278 { | |
279 char *ignored; | |
440 | 280 return (get_keyword (field, &ignored) != (char *) NULL); |
428 | 281 } |
282 | |
283 static char * | |
284 add_field (line_list the_list, register char *field, register char *where) | |
285 { | |
286 register char c; | |
287 while (true) | |
288 { | |
289 *where++ = ' '; | |
290 while ((c = *field++) != '\0') | |
291 { | |
292 if (c == '(') | |
293 { | |
294 while (*field && *field != ')') ++field; | |
295 if (! (*field++)) break; /* no closer */ | |
296 if (! (*field)) break; /* closerNULL */ | |
297 c = *field; | |
298 } | |
299 *where++ = ((c == ','||c=='>'||c=='<') ? ' ' : c); | |
300 } | |
301 if (the_list == NIL) break; | |
302 field = the_list->string; | |
303 the_list = the_list->continuation; | |
304 } | |
305 return where; | |
306 } | |
307 | |
308 static line_list | |
309 make_file_preface (void) | |
310 { | |
311 char *the_string, *temp; | |
442 | 312 time_t idiotic_interface; |
428 | 313 long prefix_length; |
314 long user_length; | |
315 long date_length; | |
316 line_list result; | |
317 | |
318 prefix_length = strlen (FROM_PREFIX); | |
319 time (&idiotic_interface); | |
320 the_date = ctime (&idiotic_interface); | |
321 /* the_date has an unwanted newline at the end */ | |
322 date_length = strlen (the_date) - 1; | |
442 | 323 if (the_date[date_length] == '\n') |
324 the_date[date_length] = '\0'; | |
325 #ifdef WIN32_NATIVE | |
428 | 326 temp = "(null)"; |
327 #else | |
328 temp = cuserid ((char *) NULL); | |
329 #endif | |
330 user_length = strlen (temp); | |
331 the_user = alloc_string ((size_t) (user_length + 1)); | |
332 strcpy (the_user, temp); | |
333 the_string = alloc_string ((size_t) (3 + prefix_length + | |
334 user_length + | |
335 date_length)); | |
336 temp = the_string; | |
337 strcpy (temp, FROM_PREFIX); | |
338 temp = &temp[prefix_length]; | |
339 *temp++ = ' '; | |
340 strcpy (temp, the_user); | |
341 temp = &temp[user_length]; | |
342 *temp++ = ' '; | |
343 strcpy (temp, the_date); | |
344 result = new_list (); | |
345 result->string = the_string; | |
346 result->continuation = ((line_list) NULL); | |
347 return result; | |
348 } | |
349 | |
350 static void | |
351 write_line_list (register line_list the_list, FILE *the_stream) | |
352 { | |
353 for ( ; | |
354 the_list != ((line_list) NULL) ; | |
355 the_list = the_list->continuation) | |
356 { | |
357 fputs (the_list->string, the_stream); | |
358 putc ('\n', the_stream); | |
359 } | |
360 return; | |
361 } | |
362 | |
363 static int | |
364 close_the_streams (void) | |
365 { | |
366 register stream_list rem; | |
367 for (rem = the_streams; | |
368 rem != ((stream_list) NULL); | |
369 rem = rem->rest_streams) | |
370 no_problems = (no_problems && | |
371 ((*rem->action) (rem->handle) == 0)); | |
372 the_streams = ((stream_list) NULL); | |
373 return (no_problems ? 0 : 1); | |
374 } | |
375 | |
376 static void | |
377 add_a_stream (FILE *the_stream, int (*closing_action)(FILE *)) | |
378 { | |
379 stream_list old = the_streams; | |
380 the_streams = new_stream (); | |
381 the_streams->handle = the_stream; | |
382 the_streams->action = closing_action; | |
383 the_streams->rest_streams = old; | |
384 return; | |
385 } | |
386 | |
387 static int | |
388 my_fclose (FILE *the_file) | |
389 { | |
390 putc ('\n', the_file); | |
391 fflush (the_file); | |
392 return fclose (the_file); | |
393 } | |
394 | |
395 static boolean | |
396 open_a_file (char *name) | |
397 { | |
398 FILE *the_stream = fopen (name, "a"); | |
399 if (the_stream != ((FILE *) NULL)) | |
400 { | |
401 add_a_stream (the_stream, my_fclose); | |
440 | 402 if (the_user == (char *) NULL) |
428 | 403 file_preface = make_file_preface (); |
404 write_line_list (file_preface, the_stream); | |
405 return true; | |
406 } | |
407 return false; | |
408 } | |
409 | |
410 static void | |
411 put_string (char *s) | |
412 { | |
413 register stream_list rem; | |
414 for (rem = the_streams; | |
415 rem != ((stream_list) NULL); | |
416 rem = rem->rest_streams) | |
417 fputs (s, rem->handle); | |
418 return; | |
419 } | |
420 | |
421 static void | |
442 | 422 put_line (const char *string) |
428 | 423 { |
424 register stream_list rem; | |
425 for (rem = the_streams; | |
426 rem != ((stream_list) NULL); | |
427 rem = rem->rest_streams) | |
428 { | |
442 | 429 const char *s = string; |
428 | 430 int column = 0; |
431 | |
432 /* Divide STRING into lines. */ | |
433 while (*s != 0) | |
434 { | |
442 | 435 const char *breakpos; |
428 | 436 |
437 /* Find the last char that fits. */ | |
438 for (breakpos = s; *breakpos && column < 78; ++breakpos) | |
439 { | |
440 if (*breakpos == '\t') | |
441 column += 8; | |
442 else | |
443 column++; | |
444 } | |
445 /* If we didn't reach end of line, break the line. */ | |
446 if (*breakpos) | |
447 { | |
448 /* Back up to just after the last comma that fits. */ | |
449 while (breakpos != s && breakpos[-1] != ',') --breakpos; | |
450 | |
451 if (breakpos == s) | |
452 { | |
453 /* If no comma fits, move past the first address anyway. */ | |
454 while (*breakpos != 0 && *breakpos != ',') ++breakpos; | |
455 if (*breakpos != 0) | |
456 /* Include the comma after it. */ | |
457 ++breakpos; | |
458 } | |
459 } | |
460 /* Output that much, then break the line. */ | |
461 fwrite (s, 1, breakpos - s, rem->handle); | |
462 column = 8; | |
463 | |
464 /* Skip whitespace and prepare to print more addresses. */ | |
465 s = breakpos; | |
466 while (*s == ' ' || *s == '\t') ++s; | |
467 if (*s != 0) | |
468 fputs ("\n\t", rem->handle); | |
469 } | |
470 putc ('\n', rem->handle); | |
471 } | |
472 return; | |
473 } | |
474 | |
475 #define mail_error error | |
476 | |
477 static void | |
478 setup_files (register line_list the_list, register char *field) | |
479 { | |
480 register char *start; | |
481 register char c; | |
482 while (true) | |
483 { | |
484 while (((c = *field) != '\0') && | |
485 ((c == ' ') || | |
486 (c == '\t') || | |
487 (c == ','))) | |
488 field += 1; | |
489 if (c != '\0') | |
490 { | |
491 start = field; | |
492 while (((c = *field) != '\0') && | |
493 (c != ' ') && | |
494 (c != '\t') && | |
495 (c != ',')) | |
496 field += 1; | |
497 *field = '\0'; | |
498 if (!open_a_file (start)) | |
499 mail_error ("Could not open file %s", start); | |
500 *field = c; | |
501 if (c != '\0') continue; | |
502 } | |
503 if (the_list == ((line_list) NULL)) return; | |
504 field = the_list->string; | |
505 the_list = the_list->continuation; | |
506 } | |
507 } | |
508 | |
509 static int | |
510 args_size (header the_header) | |
511 { | |
512 register header old = the_header; | |
513 register line_list rem; | |
514 register int size = 0; | |
515 do | |
516 { | |
4932 | 517 char *field = NULL; |
428 | 518 register char *keyword = get_keyword (the_header->text->string, &field); |
519 if ((strcmp (keyword, "TO") == 0) || | |
520 (strcmp (keyword, "CC") == 0) || | |
521 (strcmp (keyword, "BCC") == 0)) | |
522 { | |
523 size += 1 + strlen (field); | |
524 for (rem = the_header->text->continuation; | |
525 rem != NIL; | |
526 rem = rem->continuation) | |
527 size += 1 + strlen (rem->string); | |
528 } | |
529 the_header = the_header->next; | |
530 } while (the_header != old); | |
531 return size; | |
532 } | |
533 | |
534 static void | |
535 parse_header (header the_header, register char *where) | |
536 { | |
537 register header old = the_header; | |
538 do | |
539 { | |
4932 | 540 char *field = NULL; |
428 | 541 register char *keyword = get_keyword (the_header->text->string, &field); |
542 if (strcmp (keyword, "TO") == 0) | |
543 where = add_field (the_header->text->continuation, field, where); | |
544 else if (strcmp (keyword, "CC") == 0) | |
545 where = add_field (the_header->text->continuation, field, where); | |
546 else if (strcmp (keyword, "BCC") == 0) | |
547 { | |
548 where = add_field (the_header->text->continuation, field, where); | |
549 the_header->previous->next = the_header->next; | |
550 the_header->next->previous = the_header->previous; | |
551 } | |
552 else if (strcmp (keyword, "FCC") == 0) | |
553 setup_files (the_header->text->continuation, field); | |
554 the_header = the_header->next; | |
555 } while (the_header != old); | |
556 *where = '\0'; | |
557 return; | |
558 } | |
559 | |
560 static header | |
561 read_header (void) | |
562 { | |
563 register header the_header = ((header) NULL); | |
564 register line_list *next_line = ((line_list *) NULL); | |
565 | |
566 init_linebuffer (&lb); | |
567 | |
568 do | |
569 { | |
570 long length; | |
571 register char *line; | |
572 | |
573 readline (&lb, stdin); | |
574 line = lb.buffer; | |
575 length = strlen (line); | |
576 if (length == 0) break; | |
577 | |
578 if (has_keyword (line)) | |
579 { | |
580 register header old = the_header; | |
581 the_header = new_header (); | |
582 if (old == ((header) NULL)) | |
583 { | |
584 the_header->next = the_header; | |
585 the_header->previous = the_header; | |
586 } | |
587 else | |
588 { | |
589 the_header->previous = old; | |
590 the_header->next = old->next; | |
591 old->next = the_header; | |
592 } | |
593 next_line = &(the_header->text); | |
594 } | |
595 | |
596 if (next_line == ((line_list *) NULL)) | |
597 { | |
598 /* Not a valid header */ | |
599 exit (1); | |
600 } | |
601 *next_line = new_list (); | |
602 (*next_line)->string = alloc_string ((size_t) length); | |
603 strcpy (((*next_line)->string), line); | |
604 next_line = &((*next_line)->continuation); | |
605 *next_line = NIL; | |
606 | |
607 } while (true); | |
608 | |
609 return the_header->next; | |
610 } | |
611 | |
612 static void | |
613 write_header (header the_header) | |
614 { | |
615 register header old = the_header; | |
616 do | |
617 { | |
618 register line_list the_list; | |
619 for (the_list = the_header->text; | |
620 the_list != NIL; | |
621 the_list = the_list->continuation) | |
622 put_line (the_list->string); | |
623 the_header = the_header->next; | |
624 } while (the_header != old); | |
625 put_line (""); | |
626 return; | |
627 } | |
628 | |
629 int | |
630 main (int argc, char *argv[]) | |
631 { | |
632 char *command_line; | |
633 header the_header; | |
634 long name_length; | |
4759
aa5ed11f473b
Remove support for obsolete systems. See xemacs-patches message with ID
Jerry James <james@xemacs.org>
parents:
2687
diff
changeset
|
635 const char *mail_program_name; |
428 | 636 char buf[BUFLEN + 1]; |
637 register int size; | |
638 FILE *the_pipe; | |
639 | |
640 mail_program_name = getenv ("FAKEMAILER"); | |
641 if (!(mail_program_name && *mail_program_name)) | |
4759
aa5ed11f473b
Remove support for obsolete systems. See xemacs-patches message with ID
Jerry James <james@xemacs.org>
parents:
2687
diff
changeset
|
642 mail_program_name = MAIL_PROGRAM_NAME; |
428 | 643 name_length = strlen (mail_program_name); |
644 | |
645 my_name = MY_NAME; | |
646 the_streams = ((stream_list) NULL); | |
440 | 647 the_date = (char *) NULL; |
648 the_user = (char *) NULL; | |
428 | 649 |
650 the_header = read_header (); | |
651 command_line = alloc_string ((size_t) (name_length + | |
652 args_size (the_header))); | |
653 strcpy (command_line, mail_program_name); | |
654 parse_header (the_header, &command_line[name_length]); | |
655 | |
656 the_pipe = popen (command_line, "w"); | |
657 if (the_pipe == ((FILE *) NULL)) | |
440 | 658 fatal ("cannot open pipe to real mailer", (char *) NULL); |
428 | 659 |
660 add_a_stream (the_pipe, pclose); | |
661 | |
662 write_header (the_header); | |
663 | |
664 /* Dump the message itself */ | |
665 | |
666 while (!feof (stdin)) | |
667 { | |
668 size = fread (buf, 1, BUFLEN, stdin); | |
669 buf[size] = '\0'; | |
670 put_string (buf); | |
671 } | |
672 | |
673 return close_the_streams (); | |
674 } | |
675 | |
676 #endif /* not BSD 4.2 (or newer) */ |