standardize sccs keyword lines
[unix-history] / usr / src / usr.bin / mail / fio.c
CommitLineData
2ae9f53f
SL
1#ifndef lint
2static char sccsid[] = "@(#)fio.c 2.16 (Berkeley) %G%";
3#endif
77a2ce8a
KS
4
5#include "rcv.h"
6#include <sys/stat.h>
7#include <errno.h>
8
9/*
10 * Mail -- a mail program
11 *
12 * File I/O.
13 */
14
77a2ce8a
KS
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();
b17445e6 355 if ((obuf = fopen(editfile, "r+")) == NULL) {
77a2ce8a 356 perror(editfile);
985c722d 357 relsesigs();
77a2ce8a
KS
358 reset(0);
359 }
b17445e6 360 trunc(obuf);
77a2ce8a
KS
361 c = 0;
362 for (mp = &message[0]; mp < &message[msgCount]; mp++) {
363 if ((mp->m_flag & MDELETED) != 0)
364 continue;
365 c++;
c718ab56 366 if (send(mp, obuf, 0) < 0) {
77a2ce8a 367 perror(editfile);
985c722d 368 relsesigs();
77a2ce8a
KS
369 reset(0);
370 }
371 }
5ab0568d
KS
372 gotcha = (c == 0 && ibuf == NULL);
373 if (ibuf != NULL) {
374 while ((c = getc(ibuf)) != EOF)
375 putc(c, obuf);
376 fclose(ibuf);
377 }
77a2ce8a
KS
378 fflush(obuf);
379 if (ferror(obuf)) {
380 perror(editfile);
985c722d 381 relsesigs();
77a2ce8a
KS
382 reset(0);
383 }
5ab0568d
KS
384 fclose(obuf);
385 if (gotcha) {
77a2ce8a
KS
386 remove(editfile);
387 printf("removed\n");
388 }
389 else
390 printf("complete\n");
391 flush();
b3d49ad3
KS
392
393done:
985c722d 394 relsesigs();
b3d49ad3
KS
395}
396
f5df67b9 397static int sigdepth = 0; /* depth of holdsigs() */
4bc721c3 398static int sigmask = 0;
b3d49ad3 399/*
985c722d 400 * Hold signals SIGHUP - SIGQUIT.
b3d49ad3 401 */
985c722d 402holdsigs()
b3d49ad3
KS
403{
404 register int i;
405
f5df67b9 406 if (sigdepth++ == 0)
4bc721c3 407 sigmask = sigblock(mask(SIGHUP)|mask(SIGINT)|mask(SIGQUIT));
b3d49ad3
KS
408}
409
410/*
985c722d 411 * Release signals SIGHUP - SIGQUIT
b3d49ad3 412 */
985c722d 413relsesigs()
b3d49ad3
KS
414{
415 register int i;
985c722d 416
f5df67b9 417 if (--sigdepth == 0)
4bc721c3 418 sigsetmask(sigmask);
77a2ce8a
KS
419}
420
421/*
422 * Empty the output buffer.
423 */
424
425clrbuf(buf)
426 register FILE *buf;
427{
428
429 buf = stdout;
430 buf->_ptr = buf->_base;
431 buf->_cnt = BUFSIZ;
432}
433
434/*
435 * Open a temp file by creating, closing, unlinking, and
436 * reopening. Return the open file descriptor.
437 */
438
439opentemp(file)
440 char file[];
441{
442 register int f;
443
444 if ((f = creat(file, 0600)) < 0) {
445 perror(file);
446 return(-1);
447 }
448 close(f);
449 if ((f = open(file, 2)) < 0) {
450 perror(file);
451 remove(file);
452 return(-1);
453 }
454 remove(file);
455 return(f);
456}
457
458/*
459 * Flush the standard output.
460 */
461
462flush()
463{
464 fflush(stdout);
465 fflush(stderr);
466}
467
468/*
469 * Determine the size of the file possessed by
470 * the passed buffer.
471 */
472
473off_t
474fsize(iob)
475 FILE *iob;
476{
477 register int f;
478 struct stat sbuf;
479
480 f = fileno(iob);
481 if (fstat(f, &sbuf) < 0)
482 return(0);
483 return(sbuf.st_size);
484}
485
486/*
487 * Take a file name, possibly with shell meta characters
488 * in it and expand it by using "sh -c echo filename"
489 * Return the file name as a dynamic string.
490 */
491
492char *
493expand(name)
494 char name[];
495{
496 char xname[BUFSIZ];
497 char cmdbuf[BUFSIZ];
498 register int pid, l, rc;
499 register char *cp, *Shell;
500 int s, pivec[2], (*sigint)();
501 struct stat sbuf;
502
df3c4fbd
KS
503 if (name[0] == '+' && getfold(cmdbuf) >= 0) {
504 sprintf(xname, "%s/%s", cmdbuf, name + 1);
38a42545
KS
505 return(expand(savestr(xname)));
506 }
77a2ce8a
KS
507 if (!anyof(name, "~{[*?$`'\"\\"))
508 return(name);
77a2ce8a
KS
509 if (pipe(pivec) < 0) {
510 perror("pipe");
77a2ce8a
KS
511 return(name);
512 }
513 sprintf(cmdbuf, "echo %s", name);
514 if ((pid = vfork()) == 0) {
9ff57b47 515 sigchild();
77a2ce8a
KS
516 Shell = value("SHELL");
517 if (Shell == NOSTR)
518 Shell = SHELL;
519 close(pivec[0]);
520 close(1);
521 dup(pivec[1]);
522 close(pivec[1]);
523 close(2);
524 execl(Shell, Shell, "-c", cmdbuf, 0);
525 _exit(1);
526 }
527 if (pid == -1) {
528 perror("fork");
529 close(pivec[0]);
530 close(pivec[1]);
531 return(NOSTR);
532 }
533 close(pivec[1]);
534 l = read(pivec[0], xname, BUFSIZ);
535 close(pivec[0]);
536 while (wait(&s) != pid);
537 ;
538 s &= 0377;
539 if (s != 0 && s != SIGPIPE) {
540 fprintf(stderr, "\"Echo\" failed\n");
541 goto err;
542 }
543 if (l < 0) {
544 perror("read");
545 goto err;
546 }
547 if (l == 0) {
548 fprintf(stderr, "\"%s\": No match\n", name);
549 goto err;
550 }
551 if (l == BUFSIZ) {
552 fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
553 goto err;
554 }
555 xname[l] = 0;
556 for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
557 ;
558 *++cp = '\0';
559 if (any(' ', xname) && stat(xname, &sbuf) < 0) {
560 fprintf(stderr, "\"%s\": Ambiguous\n", name);
561 goto err;
562 }
77a2ce8a
KS
563 return(savestr(xname));
564
565err:
77a2ce8a
KS
566 return(NOSTR);
567}
568
df3c4fbd
KS
569/*
570 * Determine the current folder directory name.
571 */
572getfold(name)
573 char *name;
574{
575 char *folder;
576
577 if ((folder = value("folder")) == NOSTR)
578 return(-1);
579 if (*folder == '/')
580 strcpy(name, folder);
581 else
582 sprintf(name, "%s/%s", homedir, folder);
583 return(0);
584}
585
77a2ce8a
KS
586/*
587 * A nicer version of Fdopen, which allows us to fclose
588 * without losing the open file.
589 */
590
591FILE *
592Fdopen(fildes, mode)
593 char *mode;
594{
595 register int f;
596 FILE *fdopen();
597
598 f = dup(fildes);
599 if (f < 0) {
600 perror("dup");
601 return(NULL);
602 }
603 return(fdopen(f, mode));
604}