from shannon
[unix-history] / usr / src / usr.bin / mail / fio.c
CommitLineData
77a2ce8a
KS
1#
2
3#include "rcv.h"
4#include <sys/stat.h>
5#include <errno.h>
6
7/*
8 * Mail -- a mail program
9 *
10 * File I/O.
11 */
12
0154300b 13static char *SccsId = "@(#)fio.c 2.12 %G%";
77a2ce8a
KS
14
15/*
16 * Set up the input pointers while copying the mail file into
17 * /tmp.
18 */
19
20setptr(ibuf)
21 FILE *ibuf;
22{
9008b544 23 register int c;
9b888765 24 register char *cp, *cp2;
0154300b
CS
25 register int count, l;
26 long s;
77a2ce8a
KS
27 off_t offset;
28 char linebuf[LINESIZE];
9b888765
KS
29 char wbuf[LINESIZE];
30 int maybe, mestmp, flag, inhead;
77a2ce8a
KS
31 struct message this;
32 extern char tempSet[];
33
34 if ((mestmp = opentemp(tempSet)) < 0)
35 exit(1);
36 msgCount = 0;
37 offset = 0;
0154300b 38 s = 0L;
77a2ce8a
KS
39 l = 0;
40 maybe = 1;
9b888765 41 flag = MUSED|MNEW;
77a2ce8a 42 for (;;) {
9008b544
KS
43 cp = linebuf;
44 c = getc(ibuf);
45 while (c != EOF && c != '\n') {
53b2e4eb 46 if (cp - linebuf >= LINESIZE - 1) {
9008b544
KS
47 ungetc(c, ibuf);
48 *cp = 0;
49 break;
50 }
51 *cp++ = c;
52 c = getc(ibuf);
53 }
54 *cp = 0;
55 if (cp == linebuf && c == EOF) {
77a2ce8a 56 this.m_flag = flag;
9b888765 57 flag = MUSED|MNEW;
77a2ce8a
KS
58 this.m_offset = offsetof(offset);
59 this.m_block = blockof(offset);
60 this.m_size = s;
61 this.m_lines = l;
62 if (append(&this, mestmp)) {
63 perror(tempSet);
64 exit(1);
65 }
66 fclose(ibuf);
67 makemessage(mestmp);
68 close(mestmp);
69 return;
70 }
9008b544
KS
71 count = cp - linebuf + 1;
72 for (cp = linebuf; *cp;)
73 putc(*cp++, otf);
74 putc('\n', otf);
75 if (ferror(otf)) {
77a2ce8a
KS
76 perror("/tmp");
77 exit(1);
78 }
9b888765 79 if (maybe && linebuf[0] == 'F' && ishead(linebuf)) {
77a2ce8a
KS
80 msgCount++;
81 this.m_flag = flag;
9b888765 82 flag = MUSED|MNEW;
29c01f3c 83 inhead = 1;
77a2ce8a
KS
84 this.m_block = blockof(offset);
85 this.m_offset = offsetof(offset);
86 this.m_size = s;
87 this.m_lines = l;
0154300b 88 s = 0L;
77a2ce8a
KS
89 l = 0;
90 if (append(&this, mestmp)) {
91 perror(tempSet);
92 exit(1);
93 }
94 }
9b888765
KS
95 if (linebuf[0] == 0)
96 inhead = 0;
97 if (inhead && index(linebuf, ':')) {
98 cp = linebuf;
99 cp2 = wbuf;
100 while (isalpha(*cp))
101 *cp2++ = *cp++;
102 *cp2 = 0;
103 if (icequal(wbuf, "status")) {
104 cp = index(linebuf, ':');
105 if (index(cp, 'R'))
106 flag |= MREAD;
107 if (index(cp, 'O'))
108 flag &= ~MNEW;
109 inhead = 0;
110 }
111 }
77a2ce8a 112 offset += count;
0154300b 113 s += (long) count;
77a2ce8a
KS
114 l++;
115 maybe = 0;
116 if (linebuf[0] == 0)
117 maybe = 1;
118 }
119}
120
121/*
122 * Drop the passed line onto the passed output buffer.
123 * If a write error occurs, return -1, else the count of
124 * characters written, including the newline.
125 */
126
127putline(obuf, linebuf)
128 FILE *obuf;
129 char *linebuf;
130{
131 register int c;
132
133 c = strlen(linebuf);
134 fputs(linebuf, obuf);
135 putc('\n', obuf);
136 if (ferror(obuf))
137 return(-1);
138 return(c+1);
139}
140
de9a3738
KS
141/*
142 * Quickly read a line from the specified input into the line
143 * buffer; return characters read.
144 */
145
146freadline(ibuf, linebuf)
147 register FILE *ibuf;
148 register char *linebuf;
149{
150 register int c;
151 register char *cp;
152
153 c = getc(ibuf);
154 cp = linebuf;
155 while (c != '\n' && c != EOF) {
156 if (c == 0) {
157 c = getc(ibuf);
158 continue;
159 }
160 if (cp - linebuf >= BUFSIZ-1) {
161 *cp = 0;
162 return(cp - linebuf + 1);
163 }
164 *cp++ = c;
165 c = getc(ibuf);
166 }
167 if (c == EOF && cp == linebuf)
168 return(0);
169 *cp = 0;
170 return(cp - linebuf + 1);
171}
172
77a2ce8a
KS
173/*
174 * Read up a line from the specified input into the line
175 * buffer. Return the number of characters read. Do not
176 * include the newline at the end.
177 */
178
179readline(ibuf, linebuf)
180 FILE *ibuf;
181 char *linebuf;
182{
183 register char *cp;
184 register int c;
185
186 do {
187 clearerr(ibuf);
188 c = getc(ibuf);
189 for (cp = linebuf; c != '\n' && c != EOF; c = getc(ibuf)) {
190 if (c == 0)
191 continue;
192 if (cp - linebuf < LINESIZE-2)
193 *cp++ = c;
194 }
195 } while (ferror(ibuf) && ibuf == stdin);
196 *cp = 0;
197 if (c == EOF && cp == linebuf)
198 return(0);
199 return(cp - linebuf + 1);
200}
201
202/*
203 * Return a file buffer all ready to read up the
204 * passed message pointer.
205 */
206
207FILE *
208setinput(mp)
209 register struct message *mp;
210{
211 off_t off;
212
213 fflush(otf);
214 off = mp->m_block;
215 off <<= 9;
216 off += mp->m_offset;
217 if (fseek(itf, off, 0) < 0) {
218 perror("fseek");
219 panic("temporary file seek");
220 }
221 return(itf);
222}
223
224/*
225 * Take the data out of the passed ghost file and toss it into
226 * a dynamically allocated message structure.
227 */
228
229makemessage(f)
230{
231 register struct message *m;
232 register char *mp;
233 register count;
234
235 mp = calloc((unsigned) (msgCount + 1), sizeof *m);
236 if (mp == NOSTR) {
237 printf("Insufficient memory for %d messages\n", msgCount);
238 exit(1);
239 }
838681f8
KS
240 if (message != (struct message *) 0)
241 cfree((char *) message);
77a2ce8a
KS
242 message = (struct message *) mp;
243 dot = message;
244 lseek(f, 0L, 0);
245 while (count = read(f, mp, BUFSIZ))
246 mp += count;
247 for (m = &message[0]; m < &message[msgCount]; m++) {
248 m->m_size = (m+1)->m_size;
249 m->m_lines = (m+1)->m_lines;
9b888765 250 m->m_flag = (m+1)->m_flag;
77a2ce8a 251 }
0154300b 252 message[msgCount].m_size = 0L;
77a2ce8a
KS
253 message[msgCount].m_lines = 0;
254}
255
256/*
257 * Append the passed message descriptor onto the temp file.
258 * If the write fails, return 1, else 0
259 */
260
261append(mp, f)
262 struct message *mp;
263{
264 if (write(f, (char *) mp, sizeof *mp) != sizeof *mp)
265 return(1);
266 return(0);
267}
268
269/*
270 * Delete a file, but only if the file is a plain file.
271 */
272
273remove(name)
274 char name[];
275{
276 struct stat statb;
277 extern int errno;
278
279 if (stat(name, &statb) < 0)
280 return(-1);
281 if ((statb.st_mode & S_IFMT) != S_IFREG) {
282 errno = EISDIR;
283 return(-1);
284 }
285 return(unlink(name));
286}
287
288/*
289 * Terminate an editing session by attempting to write out the user's
5ab0568d 290 * file from the temporary. Save any new stuff appended to the file.
77a2ce8a 291 */
77a2ce8a
KS
292edstop()
293{
294 register int gotcha, c;
295 register struct message *mp;
8b5a06af 296 FILE *obuf, *ibuf, *readstat;
5ab0568d 297 struct stat statb;
8b5a06af 298 char tempname[30], *id;
b3d49ad3 299 int (*sigs[3])();
77a2ce8a 300
838681f8
KS
301 if (readonly)
302 return;
985c722d 303 holdsigs();
8b5a06af
KS
304 if (Tflag != NOSTR) {
305 if ((readstat = fopen(Tflag, "w")) == NULL)
306 Tflag = NOSTR;
307 }
953c713a
KS
308 for (mp = &message[0], gotcha = 0; mp < &message[msgCount]; mp++) {
309 if (mp->m_flag & MNEW) {
310 mp->m_flag &= ~MNEW;
311 mp->m_flag |= MSTATUS;
312 }
8b5a06af 313 if (mp->m_flag & (MODIFY|MDELETED|MSTATUS))
77a2ce8a 314 gotcha++;
8b5a06af
KS
315 if (Tflag != NOSTR && (mp->m_flag & (MREAD|MDELETED)) != 0) {
316 if ((id = hfield("article-id", mp)) != NOSTR)
317 fprintf(readstat, "%s\n", id);
77a2ce8a 318 }
953c713a 319 }
8b5a06af
KS
320 if (Tflag != NOSTR)
321 fclose(readstat);
d85bd93d 322 if (!gotcha || Tflag != NOSTR)
b3d49ad3 323 goto done;
5ab0568d
KS
324 ibuf = NULL;
325 if (stat(editfile, &statb) >= 0 && statb.st_size > mailsize) {
326 strcpy(tempname, "/tmp/mboxXXXXXX");
327 mktemp(tempname);
328 if ((obuf = fopen(tempname, "w")) == NULL) {
329 perror(tempname);
985c722d 330 relsesigs();
5ab0568d
KS
331 reset(0);
332 }
333 if ((ibuf = fopen(editfile, "r")) == NULL) {
334 perror(editfile);
335 fclose(obuf);
336 remove(tempname);
985c722d 337 relsesigs();
5ab0568d
KS
338 reset(0);
339 }
0c3a2f40 340 fseek(ibuf, mailsize, 0);
5ab0568d
KS
341 while ((c = getc(ibuf)) != EOF)
342 putc(c, obuf);
343 fclose(ibuf);
344 fclose(obuf);
345 if ((ibuf = fopen(tempname, "r")) == NULL) {
346 perror(tempname);
347 remove(tempname);
985c722d 348 relsesigs();
5ab0568d
KS
349 reset(0);
350 }
351 remove(tempname);
352 }
77a2ce8a
KS
353 printf("\"%s\" ", editfile);
354 flush();
355 if ((obuf = fopen(editfile, "w")) == NULL) {
356 perror(editfile);
985c722d 357 relsesigs();
77a2ce8a
KS
358 reset(0);
359 }
360 c = 0;
361 for (mp = &message[0]; mp < &message[msgCount]; mp++) {
362 if ((mp->m_flag & MDELETED) != 0)
363 continue;
364 c++;
c718ab56 365 if (send(mp, obuf, 0) < 0) {
77a2ce8a 366 perror(editfile);
985c722d 367 relsesigs();
77a2ce8a
KS
368 reset(0);
369 }
370 }
5ab0568d
KS
371 gotcha = (c == 0 && ibuf == NULL);
372 if (ibuf != NULL) {
373 while ((c = getc(ibuf)) != EOF)
374 putc(c, obuf);
375 fclose(ibuf);
376 }
77a2ce8a
KS
377 fflush(obuf);
378 if (ferror(obuf)) {
379 perror(editfile);
985c722d 380 relsesigs();
77a2ce8a
KS
381 reset(0);
382 }
5ab0568d
KS
383 fclose(obuf);
384 if (gotcha) {
77a2ce8a
KS
385 remove(editfile);
386 printf("removed\n");
387 }
388 else
389 printf("complete\n");
390 flush();
b3d49ad3
KS
391
392done:
985c722d 393 relsesigs();
b3d49ad3
KS
394}
395
396/*
985c722d 397 * Hold signals SIGHUP - SIGQUIT.
b3d49ad3 398 */
985c722d 399holdsigs()
b3d49ad3
KS
400{
401 register int i;
402
403 for (i = SIGHUP; i <= SIGQUIT; i++)
eb47257a
CS
404 /*
405 * This cannot be changed to ``sighold(i)'' because
406 * of a bug in the jobs library. Sighold does not
407 * record that one is using the new signal mechanisms
408 * so an eventual sigrelse() will fail.
409 */
410 sigset(i, SIG_HOLD);
b3d49ad3
KS
411}
412
413/*
985c722d 414 * Release signals SIGHUP - SIGQUIT
b3d49ad3 415 */
985c722d 416relsesigs()
b3d49ad3
KS
417{
418 register int i;
985c722d 419
b3d49ad3 420 for (i = SIGHUP; i <= SIGQUIT; i++)
985c722d 421 sigrelse(i);
77a2ce8a
KS
422}
423
424/*
425 * Empty the output buffer.
426 */
427
428clrbuf(buf)
429 register FILE *buf;
430{
431
432 buf = stdout;
433 buf->_ptr = buf->_base;
434 buf->_cnt = BUFSIZ;
435}
436
437/*
438 * Open a temp file by creating, closing, unlinking, and
439 * reopening. Return the open file descriptor.
440 */
441
442opentemp(file)
443 char file[];
444{
445 register int f;
446
447 if ((f = creat(file, 0600)) < 0) {
448 perror(file);
449 return(-1);
450 }
451 close(f);
452 if ((f = open(file, 2)) < 0) {
453 perror(file);
454 remove(file);
455 return(-1);
456 }
457 remove(file);
458 return(f);
459}
460
461/*
462 * Flush the standard output.
463 */
464
465flush()
466{
467 fflush(stdout);
468 fflush(stderr);
469}
470
471/*
472 * Determine the size of the file possessed by
473 * the passed buffer.
474 */
475
476off_t
477fsize(iob)
478 FILE *iob;
479{
480 register int f;
481 struct stat sbuf;
482
483 f = fileno(iob);
484 if (fstat(f, &sbuf) < 0)
485 return(0);
486 return(sbuf.st_size);
487}
488
489/*
490 * Take a file name, possibly with shell meta characters
491 * in it and expand it by using "sh -c echo filename"
492 * Return the file name as a dynamic string.
493 */
494
495char *
496expand(name)
497 char name[];
498{
499 char xname[BUFSIZ];
500 char cmdbuf[BUFSIZ];
501 register int pid, l, rc;
502 register char *cp, *Shell;
503 int s, pivec[2], (*sigint)();
504 struct stat sbuf;
505
df3c4fbd
KS
506 if (name[0] == '+' && getfold(cmdbuf) >= 0) {
507 sprintf(xname, "%s/%s", cmdbuf, name + 1);
38a42545
KS
508 return(expand(savestr(xname)));
509 }
77a2ce8a
KS
510 if (!anyof(name, "~{[*?$`'\"\\"))
511 return(name);
77a2ce8a
KS
512 if (pipe(pivec) < 0) {
513 perror("pipe");
77a2ce8a
KS
514 return(name);
515 }
516 sprintf(cmdbuf, "echo %s", name);
517 if ((pid = vfork()) == 0) {
9ff57b47 518 sigchild();
77a2ce8a
KS
519 Shell = value("SHELL");
520 if (Shell == NOSTR)
521 Shell = SHELL;
522 close(pivec[0]);
523 close(1);
524 dup(pivec[1]);
525 close(pivec[1]);
526 close(2);
527 execl(Shell, Shell, "-c", cmdbuf, 0);
528 _exit(1);
529 }
530 if (pid == -1) {
531 perror("fork");
532 close(pivec[0]);
533 close(pivec[1]);
534 return(NOSTR);
535 }
536 close(pivec[1]);
537 l = read(pivec[0], xname, BUFSIZ);
538 close(pivec[0]);
539 while (wait(&s) != pid);
540 ;
541 s &= 0377;
542 if (s != 0 && s != SIGPIPE) {
543 fprintf(stderr, "\"Echo\" failed\n");
544 goto err;
545 }
546 if (l < 0) {
547 perror("read");
548 goto err;
549 }
550 if (l == 0) {
551 fprintf(stderr, "\"%s\": No match\n", name);
552 goto err;
553 }
554 if (l == BUFSIZ) {
555 fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
556 goto err;
557 }
558 xname[l] = 0;
559 for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
560 ;
561 *++cp = '\0';
562 if (any(' ', xname) && stat(xname, &sbuf) < 0) {
563 fprintf(stderr, "\"%s\": Ambiguous\n", name);
564 goto err;
565 }
77a2ce8a
KS
566 return(savestr(xname));
567
568err:
77a2ce8a
KS
569 return(NOSTR);
570}
571
df3c4fbd
KS
572/*
573 * Determine the current folder directory name.
574 */
575getfold(name)
576 char *name;
577{
578 char *folder;
579
580 if ((folder = value("folder")) == NOSTR)
581 return(-1);
582 if (*folder == '/')
583 strcpy(name, folder);
584 else
585 sprintf(name, "%s/%s", homedir, folder);
586 return(0);
587}
588
77a2ce8a
KS
589/*
590 * A nicer version of Fdopen, which allows us to fclose
591 * without losing the open file.
592 */
593
594FILE *
595Fdopen(fildes, mode)
596 char *mode;
597{
598 register int f;
599 FILE *fdopen();
600
601 f = dup(fildes);
602 if (f < 0) {
603 perror("dup");
604 return(NULL);
605 }
606 return(fdopen(f, mode));
607}