|
|
1.1 root 1: #ifndef lint
2: static char sccsid[] = "@(#)fio.c 2.16 (Berkeley) 8/11/83";
3: #endif
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:
15: /*
16: * Set up the input pointers while copying the mail file into
17: * /tmp.
18: */
19:
20: setptr(ibuf)
21: FILE *ibuf;
22: {
23: register int c;
24: register char *cp, *cp2;
25: register int count, l;
26: long s;
27: off_t offset;
28: char linebuf[LINESIZE];
29: char wbuf[LINESIZE];
30: int maybe, mestmp, flag, inhead;
31: struct message this;
32: extern char tempSet[];
33:
34: if ((mestmp = opentemp(tempSet)) < 0)
35: exit(1);
36: msgCount = 0;
37: offset = 0;
38: s = 0L;
39: l = 0;
40: maybe = 1;
41: flag = MUSED|MNEW;
42: for (;;) {
43: cp = linebuf;
44: c = getc(ibuf);
45: while (c != EOF && c != '\n') {
46: if (cp - linebuf >= LINESIZE - 1) {
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) {
56: this.m_flag = flag;
57: flag = MUSED|MNEW;
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: }
71: count = cp - linebuf + 1;
72: for (cp = linebuf; *cp;)
73: putc(*cp++, otf);
74: putc('\n', otf);
75: if (ferror(otf)) {
76: perror("/tmp");
77: exit(1);
78: }
79: if (maybe && linebuf[0] == 'F' && ishead(linebuf)) {
80: msgCount++;
81: this.m_flag = flag;
82: flag = MUSED|MNEW;
83: inhead = 1;
84: this.m_block = blockof(offset);
85: this.m_offset = offsetof(offset);
86: this.m_size = s;
87: this.m_lines = l;
88: s = 0L;
89: l = 0;
90: if (append(&this, mestmp)) {
91: perror(tempSet);
92: exit(1);
93: }
94: }
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: }
112: offset += count;
113: s += (long) count;
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:
127: putline(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:
141: /*
142: * Quickly read a line from the specified input into the line
143: * buffer; return characters read.
144: */
145:
146: freadline(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:
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:
179: readline(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:
207: FILE *
208: setinput(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:
229: makemessage(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: }
240: if (message != (struct message *) 0)
241: cfree((char *) message);
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;
250: m->m_flag = (m+1)->m_flag;
251: }
252: message[msgCount].m_size = 0L;
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:
261: append(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:
273: remove(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
290: * file from the temporary. Save any new stuff appended to the file.
291: */
292: edstop()
293: {
294: register int gotcha, c;
295: register struct message *mp;
296: FILE *obuf, *ibuf, *readstat;
297: struct stat statb;
298: char tempname[30], *id;
299: int (*sigs[3])();
300:
301: if (readonly)
302: return;
303: holdsigs();
304: if (Tflag != NOSTR) {
305: if ((readstat = fopen(Tflag, "w")) == NULL)
306: Tflag = NOSTR;
307: }
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: }
313: if (mp->m_flag & (MODIFY|MDELETED|MSTATUS))
314: gotcha++;
315: if (Tflag != NOSTR && (mp->m_flag & (MREAD|MDELETED)) != 0) {
316: if ((id = hfield("article-id", mp)) != NOSTR)
317: fprintf(readstat, "%s\n", id);
318: }
319: }
320: if (Tflag != NOSTR)
321: fclose(readstat);
322: if (!gotcha || Tflag != NOSTR)
323: goto done;
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);
330: relsesigs();
331: reset(0);
332: }
333: if ((ibuf = fopen(editfile, "r")) == NULL) {
334: perror(editfile);
335: fclose(obuf);
336: remove(tempname);
337: relsesigs();
338: reset(0);
339: }
340: fseek(ibuf, mailsize, 0);
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);
348: relsesigs();
349: reset(0);
350: }
351: remove(tempname);
352: }
353: printf("\"%s\" ", editfile);
354: flush();
355: if ((obuf = fopen(editfile, "r+")) == NULL) {
356: perror(editfile);
357: relsesigs();
358: reset(0);
359: }
360: trunc(obuf);
361: c = 0;
362: for (mp = &message[0]; mp < &message[msgCount]; mp++) {
363: if ((mp->m_flag & MDELETED) != 0)
364: continue;
365: c++;
366: if (send(mp, obuf, 0) < 0) {
367: perror(editfile);
368: relsesigs();
369: reset(0);
370: }
371: }
372: gotcha = (c == 0 && ibuf == NULL);
373: if (ibuf != NULL) {
374: while ((c = getc(ibuf)) != EOF)
375: putc(c, obuf);
376: fclose(ibuf);
377: }
378: fflush(obuf);
379: if (ferror(obuf)) {
380: perror(editfile);
381: relsesigs();
382: reset(0);
383: }
384: fclose(obuf);
385: if (gotcha) {
386: remove(editfile);
387: printf("removed\n");
388: }
389: else
390: printf("complete\n");
391: flush();
392:
393: done:
394: relsesigs();
395: }
396:
397: static int sigdepth = 0; /* depth of holdsigs() */
398: static int sigmask = 0;
399: /*
400: * Hold signals SIGHUP - SIGQUIT.
401: */
402: holdsigs()
403: {
404: register int i;
405:
406: if (sigdepth++ == 0)
407: sigmask = sigblock(mask(SIGHUP)|mask(SIGINT)|mask(SIGQUIT));
408: }
409:
410: /*
411: * Release signals SIGHUP - SIGQUIT
412: */
413: relsesigs()
414: {
415: register int i;
416:
417: if (--sigdepth == 0)
418: sigsetmask(sigmask);
419: }
420:
421: /*
422: * Empty the output buffer.
423: */
424:
425: clrbuf(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:
439: opentemp(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:
462: flush()
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:
473: off_t
474: fsize(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:
492: char *
493: expand(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:
503: if (name[0] == '+' && getfold(cmdbuf) >= 0) {
504: sprintf(xname, "%s/%s", cmdbuf, name + 1);
505: return(expand(savestr(xname)));
506: }
507: if (!anyof(name, "~{[*?$`'\"\\"))
508: return(name);
509: if (pipe(pivec) < 0) {
510: perror("pipe");
511: return(name);
512: }
513: sprintf(cmdbuf, "echo %s", name);
514: if ((pid = vfork()) == 0) {
515: sigchild();
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: }
563: return(savestr(xname));
564:
565: err:
566: return(NOSTR);
567: }
568:
569: /*
570: * Determine the current folder directory name.
571: */
572: getfold(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:
586: /*
587: * A nicer version of Fdopen, which allows us to fclose
588: * without losing the open file.
589: */
590:
591: FILE *
592: Fdopen(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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.