Commit | Line | Data |
---|---|---|
761330fe | 1 | /* |
ad787160 C |
2 | * Copyright (c) 1980, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
0c5f72fb | 4 | * |
ad787160 C |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
13 | * 3. All advertising materials mentioning features or use of this software | |
14 | * must display the following acknowledgement: | |
15 | * This product includes software developed by the University of | |
16 | * California, Berkeley and its contributors. | |
17 | * 4. Neither the name of the University nor the names of its contributors | |
18 | * may be used to endorse or promote products derived from this software | |
19 | * without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
761330fe DF |
32 | */ |
33 | ||
acfc7e9b | 34 | #ifndef lint |
ad787160 | 35 | static char sccsid[] = "@(#)send.c 8.1 (Berkeley) 6/6/93"; |
acfc7e9b | 36 | #endif /* not lint */ |
3184019b KS |
37 | |
38 | #include "rcv.h" | |
a0d23834 | 39 | #include "extern.h" |
3184019b KS |
40 | |
41 | /* | |
42 | * Mail -- a mail program | |
43 | * | |
44 | * Mail to others. | |
45 | */ | |
46 | ||
3184019b KS |
47 | /* |
48 | * Send message described by the passed pointer to the | |
2de8fc95 EW |
49 | * passed output buffer. Return -1 on error. |
50 | * Adjust the status: field if need be. | |
51 | * If doign is given, suppress ignored header fields. | |
52 | * prefix is a string to prepend to each output line. | |
3184019b | 53 | */ |
a0d23834 | 54 | int |
2de8fc95 | 55 | send(mp, obuf, doign, prefix) |
828615a1 | 56 | register struct message *mp; |
3184019b | 57 | FILE *obuf; |
887efe38 | 58 | struct ignoretab *doign; |
2de8fc95 | 59 | char *prefix; |
3184019b | 60 | { |
828615a1 EW |
61 | long count; |
62 | register FILE *ibuf; | |
63 | char line[LINESIZE]; | |
2de8fc95 | 64 | int ishead, infld, ignoring, dostat, firstline; |
828615a1 EW |
65 | register char *cp, *cp2; |
66 | register int c; | |
67 | int length; | |
ebbb3173 | 68 | int prefixlen; |
828615a1 | 69 | |
ebbb3173 EW |
70 | /* |
71 | * Compute the prefix string, without trailing whitespace | |
72 | */ | |
902a3466 EW |
73 | if (prefix != NOSTR) { |
74 | cp2 = 0; | |
75 | for (cp = prefix; *cp; cp++) | |
76 | if (*cp != ' ' && *cp != '\t') | |
77 | cp2 = cp; | |
78 | prefixlen = cp2 == 0 ? 0 : cp2 - prefix + 1; | |
79 | } | |
3184019b | 80 | ibuf = setinput(mp); |
828615a1 | 81 | count = mp->m_size; |
b870137d | 82 | ishead = 1; |
887efe38 | 83 | dostat = doign == 0 || !isign("status", doign); |
a6b3a6c5 | 84 | infld = 0; |
2de8fc95 | 85 | firstline = 1; |
828615a1 EW |
86 | /* |
87 | * Process headers first | |
88 | */ | |
89 | while (count > 0 && ishead) { | |
90 | if (fgets(line, LINESIZE, ibuf) == NULL) | |
91 | break; | |
92 | count -= length = strlen(line); | |
2de8fc95 | 93 | if (firstline) { |
b870137d KS |
94 | /* |
95 | * First line is the From line, so no headers | |
96 | * there to worry about | |
97 | */ | |
2de8fc95 EW |
98 | firstline = 0; |
99 | ignoring = doign == ignoreall; | |
828615a1 | 100 | } else if (line[0] == '\n') { |
b870137d KS |
101 | /* |
102 | * If line is blank, we've reached end of | |
103 | * headers, so force out status: field | |
104 | * and note that we are no longer in header | |
105 | * fields | |
106 | */ | |
828615a1 | 107 | if (dostat) { |
2de8fc95 | 108 | statusput(mp, obuf, prefix); |
828615a1 | 109 | dostat = 0; |
57079810 | 110 | } |
828615a1 | 111 | ishead = 0; |
2de8fc95 | 112 | ignoring = doign == ignoreall; |
828615a1 | 113 | } else if (infld && (line[0] == ' ' || line[0] == '\t')) { |
b870137d | 114 | /* |
df5134c8 BB |
115 | * If this line is a continuation (via space or tab) |
116 | * of a previous header field, just echo it | |
117 | * (unless the field should be ignored). | |
828615a1 | 118 | * In other words, nothing to do. |
b870137d | 119 | */ |
828615a1 | 120 | } else { |
b870137d | 121 | /* |
828615a1 | 122 | * Pick up the header field if we have one. |
b870137d | 123 | */ |
828615a1 EW |
124 | for (cp = line; (c = *cp++) && c != ':' && !isspace(c);) |
125 | ; | |
126 | cp2 = --cp; | |
127 | while (isspace(*cp++)) | |
128 | ; | |
129 | if (cp[-1] != ':') { | |
130 | /* | |
131 | * Not a header line, force out status: | |
132 | * This happens in uucp style mail where | |
133 | * there are no headers at all. | |
134 | */ | |
b870137d | 135 | if (dostat) { |
2de8fc95 | 136 | statusput(mp, obuf, prefix); |
b870137d KS |
137 | dostat = 0; |
138 | } | |
2de8fc95 EW |
139 | if (doign != ignoreall) |
140 | /* add blank line */ | |
141 | (void) putc('\n', obuf); | |
a6b3a6c5 | 142 | ishead = 0; |
828615a1 EW |
143 | ignoring = 0; |
144 | } else { | |
145 | /* | |
146 | * If it is an ignored field and | |
147 | * we care about such things, skip it. | |
148 | */ | |
149 | *cp2 = 0; /* temporarily null terminate */ | |
887efe38 | 150 | if (doign && isign(line, doign)) |
828615a1 EW |
151 | ignoring = 1; |
152 | else if ((line[0] == 's' || line[0] == 'S') && | |
470c33f3 | 153 | strcasecmp(line, "status") == 0) { |
828615a1 EW |
154 | /* |
155 | * If the field is "status," go compute | |
156 | * and print the real Status: field | |
157 | */ | |
158 | if (dostat) { | |
2de8fc95 | 159 | statusput(mp, obuf, prefix); |
828615a1 EW |
160 | dostat = 0; |
161 | } | |
162 | ignoring = 1; | |
163 | } else { | |
164 | ignoring = 0; | |
165 | *cp2 = c; /* restore */ | |
2d7a1b5d | 166 | } |
828615a1 | 167 | infld = 1; |
2d7a1b5d | 168 | } |
57079810 | 169 | } |
828615a1 | 170 | if (!ignoring) { |
ebbb3173 EW |
171 | /* |
172 | * Strip trailing whitespace from prefix | |
173 | * if line is blank. | |
174 | */ | |
175 | if (prefix != NOSTR) | |
176 | if (length > 1) | |
177 | fputs(prefix, obuf); | |
178 | else | |
179 | (void) fwrite(prefix, sizeof *prefix, | |
180 | prefixlen, obuf); | |
751b30cd | 181 | (void) fwrite(line, sizeof *line, length, obuf); |
828615a1 EW |
182 | if (ferror(obuf)) |
183 | return -1; | |
828615a1 | 184 | } |
3184019b | 185 | } |
828615a1 EW |
186 | /* |
187 | * Copy out message body | |
188 | */ | |
2de8fc95 EW |
189 | if (doign == ignoreall) |
190 | count--; /* skip final blank line */ | |
191 | if (prefix != NOSTR) | |
192 | while (count > 0) { | |
193 | if (fgets(line, LINESIZE, ibuf) == NULL) { | |
194 | c = 0; | |
195 | break; | |
196 | } | |
197 | count -= c = strlen(line); | |
ebbb3173 EW |
198 | /* |
199 | * Strip trailing whitespace from prefix | |
200 | * if line is blank. | |
201 | */ | |
2de8fc95 EW |
202 | if (c > 1) |
203 | fputs(prefix, obuf); | |
ebbb3173 EW |
204 | else |
205 | (void) fwrite(prefix, sizeof *prefix, | |
206 | prefixlen, obuf); | |
2de8fc95 EW |
207 | (void) fwrite(line, sizeof *line, c, obuf); |
208 | if (ferror(obuf)) | |
209 | return -1; | |
210 | } | |
211 | else | |
212 | while (count > 0) { | |
213 | c = count < LINESIZE ? count : LINESIZE; | |
214 | if ((c = fread(line, sizeof *line, c, ibuf)) <= 0) | |
215 | break; | |
216 | count -= c; | |
217 | if (fwrite(line, sizeof *line, c, obuf) != c) | |
218 | return -1; | |
219 | } | |
220 | if (doign == ignoreall && c > 0 && line[c - 1] != '\n') | |
221 | /* no final blank line */ | |
222 | if ((c = getc(ibuf)) != EOF && putc(c, obuf) == EOF) | |
828615a1 | 223 | return -1; |
2de8fc95 | 224 | return 0; |
a6b3a6c5 KS |
225 | } |
226 | ||
57079810 KS |
227 | /* |
228 | * Output a reasonable looking status field. | |
229 | */ | |
a0d23834 | 230 | void |
2de8fc95 | 231 | statusput(mp, obuf, prefix) |
57079810 | 232 | register struct message *mp; |
828615a1 | 233 | FILE *obuf; |
2de8fc95 | 234 | char *prefix; |
57079810 KS |
235 | { |
236 | char statout[3]; | |
828615a1 | 237 | register char *cp = statout; |
57079810 | 238 | |
57079810 | 239 | if (mp->m_flag & MREAD) |
828615a1 | 240 | *cp++ = 'R'; |
57079810 | 241 | if ((mp->m_flag & MNEW) == 0) |
828615a1 EW |
242 | *cp++ = 'O'; |
243 | *cp = 0; | |
244 | if (statout[0]) | |
2de8fc95 EW |
245 | fprintf(obuf, "%sStatus: %s\n", |
246 | prefix == NOSTR ? "" : prefix, statout); | |
57079810 KS |
247 | } |
248 | ||
3184019b KS |
249 | /* |
250 | * Interface between the argument list and the mail1 routine | |
251 | * which does all the dirty work. | |
252 | */ | |
a0d23834 | 253 | int |
3d6f01e5 | 254 | mail(to, cc, bcc, smopts, subject) |
790344bc | 255 | struct name *to, *cc, *bcc, *smopts; |
3d6f01e5 | 256 | char *subject; |
3184019b | 257 | { |
3184019b KS |
258 | struct header head; |
259 | ||
3d6f01e5 EW |
260 | head.h_to = to; |
261 | head.h_subject = subject; | |
262 | head.h_cc = cc; | |
263 | head.h_bcc = bcc; | |
264 | head.h_smopts = smopts; | |
322c8626 | 265 | mail1(&head, 0); |
3184019b KS |
266 | return(0); |
267 | } | |
268 | ||
269 | ||
270 | /* | |
271 | * Send mail to a bunch of user names. The interface is through | |
272 | * the mail routine below. | |
273 | */ | |
a0d23834 | 274 | int |
3184019b KS |
275 | sendmail(str) |
276 | char *str; | |
277 | { | |
3184019b KS |
278 | struct header head; |
279 | ||
3d6f01e5 | 280 | head.h_to = extract(str, GTO); |
3184019b | 281 | head.h_subject = NOSTR; |
3d6f01e5 EW |
282 | head.h_cc = NIL; |
283 | head.h_bcc = NIL; | |
284 | head.h_smopts = NIL; | |
322c8626 | 285 | mail1(&head, 0); |
3184019b KS |
286 | return(0); |
287 | } | |
288 | ||
289 | /* | |
290 | * Mail a message on standard input to the people indicated | |
291 | * in the passed header. (Internal interface). | |
292 | */ | |
a0d23834 | 293 | void |
3d6f01e5 | 294 | mail1(hp, printheaders) |
3184019b | 295 | struct header *hp; |
a0d23834 | 296 | int printheaders; |
3184019b | 297 | { |
322c8626 EW |
298 | char *cp; |
299 | int pid; | |
300 | char **namelist; | |
301 | struct name *to; | |
302 | FILE *mtf; | |
3184019b KS |
303 | |
304 | /* | |
305 | * Collect user's mail from standard input. | |
306 | * Get the result as mtf. | |
307 | */ | |
3d6f01e5 | 308 | if ((mtf = collect(hp, printheaders)) == NULL) |
322c8626 | 309 | return; |
686f6134 EW |
310 | if (value("interactive") != NOSTR) |
311 | if (value("askcc") != NOSTR) | |
312 | grabh(hp, GCC); | |
313 | else { | |
314 | printf("EOT\n"); | |
315 | (void) fflush(stdout); | |
316 | } | |
322c8626 EW |
317 | if (fsize(mtf) == 0) |
318 | if (hp->h_subject == NOSTR) | |
319 | printf("No message, no subject; hope that's ok\n"); | |
320 | else | |
321 | printf("Null message body; hope that's ok\n"); | |
3184019b KS |
322 | /* |
323 | * Now, take the user names from the combined | |
324 | * to and cc lists and do all the alias | |
325 | * processing. | |
326 | */ | |
3184019b | 327 | senderr = 0; |
3d6f01e5 | 328 | to = usermap(cat(hp->h_bcc, cat(hp->h_to, hp->h_cc))); |
3184019b KS |
329 | if (to == NIL) { |
330 | printf("No recipients specified\n"); | |
322c8626 | 331 | senderr++; |
3184019b | 332 | } |
3184019b KS |
333 | /* |
334 | * Look through the recipient list for names with /'s | |
335 | * in them which we write to as files directly. | |
336 | */ | |
3184019b | 337 | to = outof(to, mtf, hp); |
62e28b79 EW |
338 | if (senderr) |
339 | savedeadletter(mtf); | |
3184019b | 340 | to = elide(to); |
322c8626 EW |
341 | if (count(to) == 0) |
342 | goto out; | |
343 | fixhead(hp, to); | |
344 | if ((mtf = infix(hp, mtf)) == NULL) { | |
345 | fprintf(stderr, ". . . message lost, sorry.\n"); | |
346 | return; | |
3184019b | 347 | } |
3d6f01e5 | 348 | namelist = unpack(cat(hp->h_smopts, to)); |
3184019b | 349 | if (debug) { |
322c8626 EW |
350 | char **t; |
351 | ||
3d6f01e5 | 352 | printf("Sendmail arguments:"); |
3184019b KS |
353 | for (t = namelist; *t != NOSTR; t++) |
354 | printf(" \"%s\"", *t); | |
355 | printf("\n"); | |
322c8626 | 356 | goto out; |
3184019b KS |
357 | } |
358 | if ((cp = value("record")) != NOSTR) | |
751b30cd | 359 | (void) savemail(expand(cp), mtf); |
3184019b | 360 | /* |
322c8626 EW |
361 | * Fork, set up the temporary mail file as standard |
362 | * input for "mail", and exec with the user list we generated | |
363 | * far above. | |
3184019b | 364 | */ |
3184019b KS |
365 | pid = fork(); |
366 | if (pid == -1) { | |
367 | perror("fork"); | |
62e28b79 | 368 | savedeadletter(mtf); |
3184019b KS |
369 | goto out; |
370 | } | |
371 | if (pid == 0) { | |
322c8626 EW |
372 | prepare_child(sigmask(SIGHUP)|sigmask(SIGINT)|sigmask(SIGQUIT)| |
373 | sigmask(SIGTSTP)|sigmask(SIGTTIN)|sigmask(SIGTTOU), | |
374 | fileno(mtf), -1); | |
375 | if ((cp = value("sendmail")) != NOSTR) | |
376 | cp = expand(cp); | |
377 | else | |
435e8dff | 378 | cp = _PATH_SENDMAIL; |
322c8626 EW |
379 | execv(cp, namelist); |
380 | perror(cp); | |
7de887e1 | 381 | _exit(1); |
3184019b | 382 | } |
322c8626 EW |
383 | if (value("verbose") != NOSTR) |
384 | (void) wait_child(pid); | |
385 | else | |
386 | free_child(pid); | |
3184019b | 387 | out: |
07b0d286 | 388 | (void) Fclose(mtf); |
3184019b KS |
389 | } |
390 | ||
391 | /* | |
392 | * Fix the header by glopping all of the expanded names from | |
393 | * the distribution list into the appropriate fields. | |
3184019b | 394 | */ |
a0d23834 | 395 | void |
3184019b KS |
396 | fixhead(hp, tolist) |
397 | struct header *hp; | |
398 | struct name *tolist; | |
399 | { | |
3184019b KS |
400 | register struct name *np; |
401 | ||
3d6f01e5 EW |
402 | hp->h_to = NIL; |
403 | hp->h_cc = NIL; | |
404 | hp->h_bcc = NIL; | |
405 | for (np = tolist; np != NIL; np = np->n_flink) | |
406 | if ((np->n_type & GMASK) == GTO) | |
407 | hp->h_to = | |
408 | cat(hp->h_to, nalloc(np->n_name, np->n_type)); | |
409 | else if ((np->n_type & GMASK) == GCC) | |
410 | hp->h_cc = | |
411 | cat(hp->h_cc, nalloc(np->n_name, np->n_type)); | |
412 | else if ((np->n_type & GMASK) == GBCC) | |
413 | hp->h_bcc = | |
414 | cat(hp->h_bcc, nalloc(np->n_name, np->n_type)); | |
3184019b KS |
415 | } |
416 | ||
417 | /* | |
418 | * Prepend a header in front of the collected stuff | |
419 | * and return the new file. | |
420 | */ | |
3184019b KS |
421 | FILE * |
422 | infix(hp, fi) | |
423 | struct header *hp; | |
424 | FILE *fi; | |
425 | { | |
426 | extern char tempMail[]; | |
427 | register FILE *nfo, *nfi; | |
428 | register int c; | |
429 | ||
07b0d286 | 430 | if ((nfo = Fopen(tempMail, "w")) == NULL) { |
3184019b KS |
431 | perror(tempMail); |
432 | return(fi); | |
433 | } | |
07b0d286 | 434 | if ((nfi = Fopen(tempMail, "r")) == NULL) { |
3184019b | 435 | perror(tempMail); |
07b0d286 | 436 | (void) Fclose(nfo); |
3184019b KS |
437 | return(fi); |
438 | } | |
a7585c01 | 439 | (void) rm(tempMail); |
3d6f01e5 | 440 | (void) puthead(hp, nfo, GTO|GSUBJECT|GCC|GBCC|GNL|GCOMMA); |
3184019b KS |
441 | c = getc(fi); |
442 | while (c != EOF) { | |
751b30cd | 443 | (void) putc(c, nfo); |
3184019b KS |
444 | c = getc(fi); |
445 | } | |
446 | if (ferror(fi)) { | |
447 | perror("read"); | |
322c8626 | 448 | rewind(fi); |
3184019b KS |
449 | return(fi); |
450 | } | |
751b30cd | 451 | (void) fflush(nfo); |
3184019b KS |
452 | if (ferror(nfo)) { |
453 | perror(tempMail); | |
07b0d286 EW |
454 | (void) Fclose(nfo); |
455 | (void) Fclose(nfi); | |
322c8626 | 456 | rewind(fi); |
3184019b KS |
457 | return(fi); |
458 | } | |
07b0d286 EW |
459 | (void) Fclose(nfo); |
460 | (void) Fclose(fi); | |
3184019b KS |
461 | rewind(nfi); |
462 | return(nfi); | |
463 | } | |
464 | ||
465 | /* | |
466 | * Dump the to, subject, cc header on the | |
467 | * passed file buffer. | |
468 | */ | |
a0d23834 | 469 | int |
3184019b KS |
470 | puthead(hp, fo, w) |
471 | struct header *hp; | |
472 | FILE *fo; | |
a0d23834 | 473 | int w; |
3184019b KS |
474 | { |
475 | register int gotcha; | |
476 | ||
477 | gotcha = 0; | |
3d6f01e5 | 478 | if (hp->h_to != NIL && w & GTO) |
322c8626 | 479 | fmt("To:", hp->h_to, fo, w&GCOMMA), gotcha++; |
3184019b KS |
480 | if (hp->h_subject != NOSTR && w & GSUBJECT) |
481 | fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++; | |
3d6f01e5 | 482 | if (hp->h_cc != NIL && w & GCC) |
322c8626 | 483 | fmt("Cc:", hp->h_cc, fo, w&GCOMMA), gotcha++; |
3d6f01e5 | 484 | if (hp->h_bcc != NIL && w & GBCC) |
322c8626 | 485 | fmt("Bcc:", hp->h_bcc, fo, w&GCOMMA), gotcha++; |
3184019b | 486 | if (gotcha && w & GNL) |
751b30cd | 487 | (void) putc('\n', fo); |
3184019b KS |
488 | return(0); |
489 | } | |
490 | ||
491 | /* | |
322c8626 | 492 | * Format the given header line to not exceed 72 characters. |
3184019b | 493 | */ |
a0d23834 | 494 | void |
3d6f01e5 EW |
495 | fmt(str, np, fo, comma) |
496 | char *str; | |
497 | register struct name *np; | |
498 | FILE *fo; | |
499 | int comma; | |
3184019b | 500 | { |
3d6f01e5 | 501 | register col, len; |
a1f76dd3 | 502 | |
3d6f01e5 | 503 | comma = comma ? 1 : 0; |
a1f76dd3 CL |
504 | col = strlen(str); |
505 | if (col) | |
3d6f01e5 | 506 | fputs(str, fo); |
322c8626 | 507 | for (; np != NIL; np = np->n_flink) { |
3d6f01e5 EW |
508 | if (np->n_flink == NIL) |
509 | comma = 0; | |
510 | len = strlen(np->n_name); | |
322c8626 EW |
511 | col++; /* for the space */ |
512 | if (col + len + comma > 72 && col > 4) { | |
3d6f01e5 EW |
513 | fputs("\n ", fo); |
514 | col = 4; | |
322c8626 | 515 | } else |
3d6f01e5 | 516 | putc(' ', fo); |
322c8626 EW |
517 | fputs(np->n_name, fo); |
518 | if (comma) | |
519 | putc(',', fo); | |
520 | col += len + comma; | |
3184019b | 521 | } |
3d6f01e5 | 522 | putc('\n', fo); |
3184019b KS |
523 | } |
524 | ||
525 | /* | |
526 | * Save the outgoing mail on the passed file. | |
527 | */ | |
528 | ||
828615a1 | 529 | /*ARGSUSED*/ |
a0d23834 | 530 | int |
828615a1 | 531 | savemail(name, fi) |
3184019b | 532 | char name[]; |
828615a1 | 533 | register FILE *fi; |
3184019b KS |
534 | { |
535 | register FILE *fo; | |
828615a1 EW |
536 | char buf[BUFSIZ]; |
537 | register i; | |
538 | time_t now, time(); | |
828615a1 | 539 | char *ctime(); |
3184019b | 540 | |
07b0d286 | 541 | if ((fo = Fopen(name, "a")) == NULL) { |
3184019b | 542 | perror(name); |
828615a1 | 543 | return (-1); |
3184019b | 544 | } |
751b30cd | 545 | (void) time(&now); |
2f025913 | 546 | fprintf(fo, "From %s %s", myname, ctime(&now)); |
828615a1 | 547 | while ((i = fread(buf, 1, sizeof buf, fi)) > 0) |
751b30cd EW |
548 | (void) fwrite(buf, 1, i, fo); |
549 | (void) putc('\n', fo); | |
550 | (void) fflush(fo); | |
3184019b KS |
551 | if (ferror(fo)) |
552 | perror(name); | |
07b0d286 | 553 | (void) Fclose(fo); |
322c8626 | 554 | rewind(fi); |
828615a1 | 555 | return (0); |
3184019b | 556 | } |