|
|
1.1 root 1: #ident "@(#)fio.c 1.3 'attmail mail(1) command'"
2: #ident "@(#)mailx:fio.c 1.13.1.2"
3: /* Copyright (c) 1984 AT&T */
4: /* All Rights Reserved */
5:
6: /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
7: /* The copyright notice above does not evidence any */
8: /* actual or intended publication of such source code. */
9:
10: #ident "@(#)mailx:fio.c 1.13.1.1"
11:
12: #include "rcv.h"
13:
14: /*
15: * mailx -- a modified version of a University of California at Berkeley
16: * mail program
17: *
18: * File I/O.
19: */
20:
21: static int getln();
22:
23: /*
24: * Set up the input pointers while copying the mail file into
25: * /tmp.
26: */
27:
28: void
29: setptr(ibuf)
30: FILE *ibuf;
31: {
32: int n, newline = 1;
33: int ToldUser = FALSE;
34: int ctf = FALSE; /* header continuation flag */
35: long clen = 0;
36: long explicit_clen = 0;
37: int hdr = 0;
38: register char *cp;
39: register int l;
40: register long s;
41: off_t offset;
42: char linebuf[LINESIZE];
43: int inhead, newmail, Odot;
44: short flag;
45:
46: if ( !space ) {
47: msgCount = 0;
48: offset = 0;
49: space = 32;
50: newmail = 0;
51: message = (struct message *)calloc(space, sizeof(struct message));
52: if ( message == NULL ) {
53: fprintf(stderr,"calloc: insufficient memory for %d messages\n",space);
54: exit(1);
55: /* NOTREACHED */
56: }
57: dot = message;
58: } else {
59: newmail = 1;
60: offset = fsize(otf);
61: }
62: s = 0L;
63: l = 0;
64: flag = MUSED|MNEW;
65:
66: while ((n = getln(linebuf, sizeof linebuf, ibuf)) > 0) {
67: if (!newline) {
68: goto putout;
69: } else if ((hdr = isheader (linebuf, &ctf)) == FALSE) {
70: ctf = FALSE; /* next line can't be cont. */
71: }
72:
73: /*
74: bug msgCount should be checked
75: also, ignore anything that looks like a header line
76: after the header is finished!!! -- adb
77: */
78: switch (hdr) {
79: case H_FROM:
80:
81: if ( (msgCount > 0) && (!newmail) ){
82: message[msgCount-1].m_size = s;
83: message[msgCount-1].m_clen =
84: (explicit_clen <= 0 || clen < explicit_clen) ?
85: clen : explicit_clen;
86: /* if ( message[msgCount-1].m_text == TRUE ) { */
87: message[msgCount-1].m_lines = l;
88: /* } else { */
89: /* message[msgCount-1].m_lines = -99; */
90: /* } */
91: message[msgCount-1].m_flag = flag;
92: flag = MUSED|MNEW;
93: }
94: if ( msgCount >= space ) {
95:
96: /* Limit the speed at which the allocated space grows */
97:
98: if ( space < 512 )
99: space = space*2;
100: else
101: space += 512;
102: errno = 0;
103: Odot = dot - &(message[0]);
104: message = (struct message *)realloc(message,space*(sizeof( struct message)));
105: if ( message == NULL ) {
106: perror("realloc failed");
107: fprintf(stderr,"realloc: insufficient memory for %d messages\n",space);
108: exit(1);
109: }
110: dot = &message[Odot];
111: }
112: message[msgCount].m_block = blockof(offset);
113: message[msgCount].m_offset = offsetofaddr(offset);
114: message[msgCount].m_text = TRUE;
115: newmail = 0;
116: msgCount++;
117: flag = MUSED|MNEW;
118: inhead = 1;
119: s = 0L;
120: explicit_clen = clen = 0L;
121: l = 0;
122: ToldUser = FALSE;
123: break;
124: case H_CLEN:
125: if (!inhead) {
126: break;
127: }
128: explicit_clen = atol (strpbrk (linebuf, ":")+1);
129: break;
130:
131: case H_STATUS:
132: if (inhead && ishfield(linebuf, "status")) {
133: cp = hcontents(linebuf);
134: if (strchr(cp, 'R'))
135: flag |= MREAD;
136: if (strchr(cp, 'O'))
137: flag &= ~MNEW;
138: }
139: break;
140: default:
141: break;
142: }
143: if( !inhead && hdr) hdr = 0;
144: putout:
145: offset += n;
146: s += (long)n;
147: if( !hdr ) {
148: if( inhead ) {
149: inhead = 0;
150: if( n == 1 && linebuf[0] == '\n')
151: clen = -1L; /* cheat: avoid leading blank */
152: }
153: clen += (long)n;
154: }
155: if (msgCount && message[msgCount-1].m_text == TRUE) {
156: message[msgCount-1].m_text = istext(linebuf,(long)n);
157: }
158: if (fwrite(linebuf,1,n,otf) != n) {
159: fclose(ibuf);
160: fflush(otf);
161: } else {
162: l++;
163: }
164: if (ferror(otf)) {
165: perror("/tmp");
166: exit(1);
167: }
168: if (msgCount == 0) {
169: fclose(ibuf);
170: fflush(otf);
171:
172: }
173: newline = (linebuf[n-1] == '\n');
174:
175: /* distribution mailx had unreachable code here -- ignore */
176: }
177:
178: /*
179: last plus 1
180: */
181:
182: if (n == 0) {
183: fflush(otf);
184: if ( msgCount ) {
185: message[msgCount-1].m_size = s;
186: message[msgCount-1].m_clen = clen;
187: /* if ( message[msgCount-1].m_text == TRUE ) { */
188: message[msgCount-1].m_lines = l;
189: /* } else { */
190: /* message[msgCount-1].m_lines = -99; */
191: /* } */
192: message[msgCount-1].m_flag = flag;
193: }
194: flag = MUSED|MNEW;
195: fclose(ibuf);
196: fflush(otf);
197: return;
198: }
199: }
200:
201: /* HMF: Code from fio.c. (getln) */
202:
203: static int
204: getln(line, max, f)
205: char *line;
206: int max;
207: FILE *f;
208: {
209: int i,ch;
210: for (i=0; i < max-1 && (ch=getc(f)) != EOF;)
211: if ((line[i++] = (char)ch) == '\n') break;
212: line[i] = '\0';
213: return(i);
214: }
215:
216: /*
217: * Drop the passed line onto the passed output buffer.
218: * If a write error occurs, return -1, else the count of
219: * characters written, including the newline.
220: */
221:
222: putline(obuf, linebuf)
223: FILE *obuf;
224: char *linebuf;
225: {
226: register int c;
227:
228: c = strlen(linebuf);
229: fputs(linebuf, obuf);
230: putc('\n', obuf);
231: if (ferror(obuf))
232: return(-1);
233: return(c+1);
234: }
235:
236: /*
237: * Read up a line from the specified input into the line
238: * buffer. Return the number of characters read. Do not
239: * include the newline at the end.
240: */
241:
242: readline(ibuf, linebuf)
243: FILE *ibuf;
244: char *linebuf;
245: {
246: register char *cp;
247: register int c;
248:
249: do {
250: clearerr(ibuf);
251: c = getc(ibuf);
252: for (cp = linebuf; c != '\n' && c != EOF; c = getc(ibuf)) {
253: /*
254: if (c == 0) {
255: fprintf(stderr, "mailx: NUL changed to @\n");
256: c = '@';
257: }
258: */
259: if (cp - linebuf < LINESIZE-2)
260: *cp++ = (char)c;
261: }
262: } while (ferror(ibuf) && ibuf == stdin);
263: *cp = 0;
264: if (c == EOF && cp == linebuf)
265: return(0);
266: return(cp - linebuf + 1);
267: }
268:
269: /*
270: * Return a file buffer all ready to read up the
271: * passed message pointer.
272: */
273:
274: FILE *
275: setinput(mp)
276: register struct message *mp;
277: {
278: off_t off;
279:
280: fflush(otf);
281: off = mp->m_block;
282: off <<= 9;
283: off += mp->m_offset;
284: if (fseek(itf, off, 0) < 0) {
285: perror("fseek");
286: panic("temporary file seek");
287: }
288: return(itf);
289: }
290:
291:
292: /*
293: * Delete a file, but only if the file is a plain file.
294: */
295:
296: removefile(name)
297: char name[];
298: {
299: struct stat statb;
300:
301: if (stat(name, &statb) < 0)
302: return(-1);
303: if ((statb.st_mode & S_IFMT) != S_IFREG) {
304: errno = EISDIR;
305: return(-1);
306: }
307: return(unlink(name));
308: }
309:
310: /*
311: * Terminate an editing session by attempting to write out the user's
312: * file from the temporary. Save any new stuff appended to the file.
313: */
314: int
315: edstop()
316: {
317: register int gotcha, c;
318: register struct message *mp;
319: FILE *obuf, *ibuf, *tbuf = 0, *readstat;
320: FILE *lockopen(); /* adb */
321: struct stat statb;
322: char tempname[30], *id;
323:
324: if (readonly)
325: return(0);
326: holdsigs();
327: if (Tflag != NOSTR) {
328: if ((readstat = fopen(Tflag, "w")) == NULL)
329: Tflag = NOSTR;
330: }
331: for (mp = &message[0], gotcha = 0; mp < &message[msgCount]; mp++) {
332: if (mp->m_flag & MNEW) {
333: mp->m_flag &= ~MNEW;
334: mp->m_flag |= MSTATUS;
335: }
336: if (mp->m_flag & (MODIFY|MDELETED|MSTATUS))
337: gotcha++;
338: if (Tflag != NOSTR && (mp->m_flag & (MREAD|MDELETED)) != 0) {
339: if ((id = hfield("article-id", mp, addone)) != NOSTR)
340: fprintf(readstat, "%s\n", id);
341: }
342: }
343: if (Tflag != NOSTR)
344: fclose(readstat);
345: if (!gotcha || Tflag != NOSTR)
346: goto done;
347: if ((ibuf = lockopen(editfile, "r+w", 0666, -1, -1)) == NULL) { /* adb */
348: perror(editfile);
349: relsesigs();
350: longjmp(srbuf, 1);
351: }
352: /* lock(ibuf, "r+", 1); adb */
353: if (fstat(fileno(ibuf), &statb) >= 0 && statb.st_size > mailsize) {
354: strcpy(tempname, "/tmp/mboxXXXXXX");
355: mktemp(tempname);
356: if ((obuf = fopen(tempname, "w")) == NULL) {
357: perror(tempname);
358: lockclose(ibuf); /* adb */
359: relsesigs();
360: longjmp(srbuf, 1);
361: }
362: fseek(ibuf, mailsize, 0);
363: while ((c = getc(ibuf)) != EOF)
364: putc(c, obuf);
365: fclose(obuf);
366: if ((tbuf = fopen(tempname, "r")) == NULL) {
367: perror(tempname);
368: lockclose(ibuf); /* adb */
369: removefile(tempname);
370: relsesigs();
371: longjmp(srbuf, 1);
372: }
373: removefile(tempname);
374: }
375: printf("\"%s\" ", editfile);
376: flush();
377: if ((obuf = fopen(editfile, "w")) == NULL) {
378: perror(editfile);
379: lockclose(ibuf); /* adb */
380: if (tbuf)
381: fclose(tbuf);
382: relsesigs();
383: longjmp(srbuf, 1);
384: }
385: c = 0;
386: for (mp = &message[0]; mp < &message[msgCount]; mp++) {
387: if ((mp->m_flag & MDELETED) != 0)
388: continue;
389: c++;
390: if (send(mp, obuf, 0) < 0) {
391: perror(editfile);
392: lockclose(ibuf); /* adb */
393: fclose(obuf);
394: if (tbuf)
395: fclose(tbuf);
396: relsesigs();
397: longjmp(srbuf, 1);
398: }
399: }
400: gotcha = (c == 0 && ibuf == NULL);
401: if (tbuf != NULL) {
402: while ((c = getc(tbuf)) != EOF)
403: putc(c, obuf);
404: fclose(tbuf);
405: }
406: fflush(obuf);
407: if (ferror(obuf)) {
408: perror(editfile);
409: lockclose(ibuf); /* adb */
410: fclose(obuf);
411: relsesigs();
412: longjmp(srbuf, 1);
413: }
414: if (gotcha) {
415: removefile(editfile);
416: printf("removed\n");
417: }
418: else
419: printf("complete\n");
420: lockclose(ibuf); /* adb */
421: fclose(obuf);
422: flush();
423:
424: done:
425: relsesigs();
426: return(1);
427: }
428:
429: /*
430: * Hold signals SIGHUP - SIGQUIT.
431: */
432: void
433: holdsigs()
434: {
435: sighold(SIGHUP);
436: sighold(SIGINT);
437: sighold(SIGQUIT);
438: }
439:
440: /*
441: * Release signals SIGHUP - SIGQUIT
442: */
443: void
444: relsesigs()
445: {
446: sigrelse(SIGHUP);
447: sigrelse(SIGINT);
448: sigrelse(SIGQUIT);
449: }
450:
451: /*
452: * Empty the output buffer.
453: * (now a no-op; why was it here?)
454: */
455: void
456: clrbuf(buf)
457: register FILE *buf;
458: {
459: /***
460: buf = stdout;
461: buf->_ptr = buf->_base;
462: buf->_cnt = BUFSIZ;
463: ***/ (void) buf;
464: }
465:
466:
467: /*
468: * Flush the standard output.
469: */
470:
471: void
472: flush()
473: {
474: fflush(stdout);
475: fflush(stderr);
476: }
477:
478: /*
479: * Determine the size of the file possessed by
480: * the passed buffer.
481: */
482:
483: off_t
484: fsize(iob)
485: FILE *iob;
486: {
487: register int f;
488: struct stat sbuf;
489:
490: f = fileno(iob);
491: if (fstat(f, &sbuf) < 0)
492: return(0);
493: return(sbuf.st_size);
494: }
495:
496: /*
497: * Take a file name, possibly with shell meta characters
498: * in it and expand it by using "sh -c echo filename"
499: * Return the file name as a dynamic string.
500: */
501:
502: char *
503: expand(name)
504: char name[];
505: {
506: char xname[BUFSIZ];
507: char cmdbuf[BUFSIZ];
508: register pid_t pid;
509: register int l;
510: register char *cp;
511: int s, pivec[2];
512: struct stat sbuf;
513: char *Shell;
514:
515: if (debug) fprintf(stderr, "expand(%s)=", name);
516: if (name[0] == '+') {
517: cp = expand(++name);
518: if (*cp != '/' && getfold(cmdbuf) >= 0) {
519: sprintf(xname, "%s/%s", cmdbuf, cp);
520: cp = savestr(xname);
521: }
522: if (debug) fprintf(stderr, "%s\n", cp);
523: return cp;
524: }
525: if (!anyof(name, "~{[*?$`'\"\\")) {
526: if (debug) fprintf(stderr, "%s\n", name);
527: return(name);
528: }
529: if (pipe(pivec) < 0) {
530: perror("pipe");
531: return(name);
532: }
533: sprintf(cmdbuf, "echo %s", name);
534: if ((pid = fork()) == 0) {
535: sigchild();
536: close(pivec[0]);
537: close(1);
538: dup(pivec[1]);
539: close(pivec[1]);
540: close(2);
541: if ((Shell = value("SHELL")) == NOSTR || *Shell=='\0')
542: Shell = SHELL;
543: execlp(Shell, Shell, "-c", cmdbuf, (char *)0);
544: _exit(1);
545: }
546: if (pid == (pid_t)-1) {
547: perror("fork");
548: close(pivec[0]);
549: close(pivec[1]);
550: return(NOSTR);
551: }
552: close(pivec[1]);
553: l = read(pivec[0], xname, BUFSIZ);
554: close(pivec[0]);
555: while (wait(&s) != pid);
556: ;
557: s &= 0377;
558: if (s != 0 && s != SIGPIPE) {
559: fprintf(stderr, "\"Echo\" failed\n");
560: goto err;
561: }
562: if (l < 0) {
563: perror("read");
564: goto err;
565: }
566: if (l == 0) {
567: fprintf(stderr, "\"%s\": No match\n", name);
568: goto err;
569: }
570: if (l == BUFSIZ) {
571: fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
572: goto err;
573: }
574: xname[l] = 0;
575: for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
576: ;
577: *++cp = '\0';
578: if (any(' ', xname) && stat(xname, &sbuf) < 0) {
579: fprintf(stderr, "\"%s\": Ambiguous\n", name);
580: goto err;
581: }
582: if (debug) fprintf(stderr, "%s\n", xname);
583: return(savestr(xname));
584:
585: err:
586: printf("\n");
587: return(NOSTR);
588: }
589:
590: /*
591: * Determine the current folder directory name.
592: */
593: getfold(name)
594: char *name;
595: {
596: char *folder;
597:
598: if ((folder = value("folder")) == NOSTR) {
599: strcpy(name, homedir);
600: return(0);
601: }
602: if ((folder = expand(folder)) == NOSTR)
603: return(-1);
604: if (*folder == '/')
605: strcpy(name, folder);
606: else
607: sprintf(name, "%s/%s", homedir, folder);
608: return(0);
609: }
610:
611: /*
612: * A nicer version of Fdopen, which allows us to fclose
613: * without losing the open file.
614: */
615:
616: FILE *
617: Fdopen(fildes, mode)
618: char *mode;
619: {
620: register int f;
621:
622: f = dup(fildes);
623: if (f < 0) {
624: perror("dup");
625: return(NULL);
626: }
627: return(fdopen(f, mode));
628: }
629:
630: /*
631: * return the filename associated with "s". This function always
632: * returns a non-null string (no error checking is done on the receiving end)
633: */
634: char *
635: Getf(s)
636: register char *s;
637: {
638: register char *cp;
639: static char defbuf[PATHSIZE];
640:
641: if (((cp = value(s)) != 0) && *cp) {
642: return expand(cp);
643: } else if (strcmp(s, "MBOX")==0) {
644: strcpy(defbuf, Getf("HOME"));
645: strcat(defbuf, "/");
646: strcat(defbuf, "mbox");
647: return(defbuf);
648: } else if (strcmp(s, "DEAD")==0) {
649: strcpy(defbuf, Getf("HOME"));
650: strcat(defbuf, "/");
651: strcat(defbuf, "dead.letter");
652: return(defbuf);
653: } else if (strcmp(s, "MAILRC")==0) {
654: strcpy(defbuf, Getf("HOME"));
655: strcat(defbuf, "/");
656: strcat(defbuf, ".mailrc");
657: return(defbuf);
658: } else if (strcmp(s, "HOME")==0) {
659: /* no recursion allowed! */
660: return(".");
661: }
662: return("DEAD"); /* "cannot happen" */
663: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.