Annotation of src/usr.bin/mail/fio.c, Revision 1.6
1.6 ! millert 1: /* $OpenBSD: fio.c,v 1.5 1997/05/30 08:51:39 deraadt Exp $ */
! 2: /* $NetBSD: fio.c,v 1.8 1997/07/07 22:57:55 phil Exp $ */
1.2 deraadt 3:
1.1 deraadt 4: /*
5: * Copyright (c) 1980, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: */
36:
37: #ifndef lint
1.2 deraadt 38: #if 0
1.6 ! millert 39: static char sccsid[] = "@(#)fio.c 8.2 (Berkeley) 4/20/95";
1.2 deraadt 40: #else
1.6 ! millert 41: static char rcsid[] = "$OpenBSD: fio.c,v 1.5 1997/05/30 08:51:39 deraadt Exp $";
1.2 deraadt 42: #endif
1.1 deraadt 43: #endif /* not lint */
44:
45: #include "rcv.h"
46: #include <sys/file.h>
47: #include <sys/wait.h>
48:
49: #include <unistd.h>
50: #include <paths.h>
51: #include <errno.h>
52: #include "extern.h"
53:
54: /*
55: * Mail -- a mail program
56: *
57: * File I/O.
58: */
59:
60: /*
61: * Set up the input pointers while copying the mail file into /tmp.
62: */
63: void
1.6 ! millert 64: setptr(ibuf, offset)
1.1 deraadt 65: register FILE *ibuf;
1.6 ! millert 66: off_t offset;
1.1 deraadt 67: {
68: extern char *tmpdir;
69: register int c, count;
70: register char *cp, *cp2;
71: struct message this;
72: FILE *mestmp;
73: int maybe, inhead;
1.5 deraadt 74: char linebuf[LINESIZE], pathbuf[PATHSIZE];
1.6 ! millert 75: int omsgCount;
1.1 deraadt 76:
77: /* Get temporary file. */
1.6 ! millert 78: (void)snprintf(pathbuf, sizeof(pathbuf), "%s/mail.XXXXXXXXXX", tmpdir);
! 79: if ((c = mkstemp(pathbuf)) == -1 || (mestmp = Fdopen(c, "r+")) == NULL)
! 80: err(1, "can't open %s", pathbuf);
1.5 deraadt 81: (void)unlink(pathbuf);
1.1 deraadt 82:
1.6 ! millert 83: if (offset == 0) {
! 84: msgCount = 0;
! 85: } else {
! 86: /* Seek into the file to get to the new messages */
! 87: (void) fseek(ibuf, offset, 0);
! 88: /*
! 89: * We need to make "offset" a pointer to the end of
! 90: * the temp file that has the copy of the mail file.
! 91: * If any messages have been edited, this will be
! 92: * different from the offset into the mail file.
! 93: */
! 94: (void) fseek(otf, 0L, SEEK_END);
! 95: offset = ftell(otf);
! 96: }
! 97: omsgCount = msgCount;
1.1 deraadt 98: maybe = 1;
99: inhead = 0;
100: this.m_flag = MUSED|MNEW;
101: this.m_size = 0;
102: this.m_lines = 0;
103: this.m_block = 0;
104: this.m_offset = 0;
105: for (;;) {
1.6 ! millert 106: if (fgets(linebuf, sizeof(linebuf), ibuf) == NULL) {
! 107: if (append(&this, mestmp))
! 108: err(1, "temporary file");
! 109: makemessage(mestmp, omsgCount);
1.1 deraadt 110: return;
111: }
112: count = strlen(linebuf);
1.6 ! millert 113: (void) fwrite(linebuf, sizeof(*linebuf), count, otf);
! 114: if (ferror(otf))
! 115: err(1, "/tmp");
! 116: linebuf[count - 1] = '\0';
1.1 deraadt 117: if (maybe && linebuf[0] == 'F' && ishead(linebuf)) {
118: msgCount++;
1.6 ! millert 119: if (append(&this, mestmp))
! 120: err(1, "temporary file");
1.1 deraadt 121: this.m_flag = MUSED|MNEW;
122: this.m_size = 0;
123: this.m_lines = 0;
124: this.m_block = blockof(offset);
125: this.m_offset = offsetof(offset);
126: inhead = 1;
127: } else if (linebuf[0] == 0) {
128: inhead = 0;
129: } else if (inhead) {
130: for (cp = linebuf, cp2 = "status";; cp++) {
131: if ((c = *cp2++) == 0) {
132: while (isspace(*cp++))
133: ;
134: if (cp[-1] != ':')
135: break;
1.2 deraadt 136: while ((c = *cp++) != '\0')
1.1 deraadt 137: if (c == 'R')
138: this.m_flag |= MREAD;
139: else if (c == 'O')
140: this.m_flag &= ~MNEW;
141: inhead = 0;
142: break;
143: }
144: if (*cp != c && *cp != toupper(c))
145: break;
146: }
147: }
148: offset += count;
149: this.m_size += count;
150: this.m_lines++;
151: maybe = linebuf[0] == 0;
152: }
153: }
154:
155: /*
156: * Drop the passed line onto the passed output buffer.
157: * If a write error occurs, return -1, else the count of
1.6 ! millert 158: * characters written, including the newline if requested.
1.1 deraadt 159: */
160: int
1.6 ! millert 161: putline(obuf, linebuf, outlf)
1.1 deraadt 162: FILE *obuf;
163: char *linebuf;
1.6 ! millert 164: int outlf;
1.1 deraadt 165: {
166: register int c;
167:
168: c = strlen(linebuf);
1.6 ! millert 169: (void) fwrite(linebuf, sizeof(*linebuf), c, obuf);
! 170: if (outlf) {
! 171: (void) putc('\n', obuf);
! 172: c++;
! 173: }
1.1 deraadt 174: if (ferror(obuf))
1.6 ! millert 175: return(-1);
! 176: return(c);
1.1 deraadt 177: }
178:
179: /*
180: * Read up a line from the specified input into the line
181: * buffer. Return the number of characters read. Do not
182: * include the newline at the end.
183: */
184: int
185: readline(ibuf, linebuf, linesize)
186: FILE *ibuf;
187: char *linebuf;
188: int linesize;
189: {
190: register int n;
191:
192: clearerr(ibuf);
193: if (fgets(linebuf, linesize, ibuf) == NULL)
1.6 ! millert 194: return(-1);
! 195:
1.1 deraadt 196: n = strlen(linebuf);
197: if (n > 0 && linebuf[n - 1] == '\n')
198: linebuf[--n] = '\0';
1.6 ! millert 199: return(n);
1.1 deraadt 200: }
201:
202: /*
203: * Return a file buffer all ready to read up the
204: * passed message pointer.
205: */
206: FILE *
207: setinput(mp)
208: register struct message *mp;
209: {
210:
211: fflush(otf);
212: if (fseek(itf, (long)positionof(mp->m_block, mp->m_offset), 0) < 0) {
1.6 ! millert 213: warn("fseek");
1.1 deraadt 214: panic("temporary file seek");
215: }
1.6 ! millert 216: return(itf);
1.1 deraadt 217: }
218:
219: /*
220: * Take the data out of the passed ghost file and toss it into
221: * a dynamically allocated message structure.
222: */
223: void
1.6 ! millert 224: makemessage(f, omsgCount)
1.1 deraadt 225: FILE *f;
1.6 ! millert 226: int omsgCount;
1.1 deraadt 227: {
1.6 ! millert 228: register size = (msgCount + 1) * sizeof(struct message);
1.1 deraadt 229:
1.6 ! millert 230: if (omsgCount) {
! 231: message = (struct message *)realloc(message, (unsigned) size);
! 232: if (message == 0)
! 233: panic("Insufficient memory for %d messages\n", msgCount);
! 234: } else {
! 235: if (message != 0)
! 236: free((char *) message);
! 237: if ((message = (struct message *) malloc((unsigned) size)) == 0)
! 238: panic("Insufficient memory for %d messages", msgCount);
! 239: dot = message;
! 240: }
! 241: size -= (omsgCount + 1) * sizeof(struct message);
1.1 deraadt 242: fflush(f);
1.6 ! millert 243: (void) lseek(fileno(f), (off_t)sizeof(*message), 0);
! 244: if (read(fileno(f), (void *) &message[omsgCount], size) != size)
1.1 deraadt 245: panic("Message temporary file corrupted");
246: message[msgCount].m_size = 0;
247: message[msgCount].m_lines = 0;
1.6 ! millert 248: (void)Fclose(f);
1.1 deraadt 249: }
250:
251: /*
252: * Append the passed message descriptor onto the temp file.
253: * If the write fails, return 1, else 0
254: */
255: int
256: append(mp, f)
257: struct message *mp;
258: FILE *f;
259: {
1.6 ! millert 260: return(fwrite((char *) mp, sizeof(*mp), 1, f) != 1);
1.1 deraadt 261: }
262:
263: /*
264: * Delete a file, but only if the file is a plain file.
265: */
266: int
267: rm(name)
268: char *name;
269: {
270: struct stat sb;
271:
272: if (stat(name, &sb) < 0)
273: return(-1);
274: if (!S_ISREG(sb.st_mode)) {
275: errno = EISDIR;
276: return(-1);
277: }
278: return(unlink(name));
279: }
280:
281: static int sigdepth; /* depth of holdsigs() */
1.2 deraadt 282: static sigset_t nset, oset;
1.1 deraadt 283: /*
284: * Hold signals SIGHUP, SIGINT, and SIGQUIT.
285: */
286: void
287: holdsigs()
288: {
289:
1.2 deraadt 290: if (sigdepth++ == 0) {
291: sigemptyset(&nset);
292: sigaddset(&nset, SIGHUP);
293: sigaddset(&nset, SIGINT);
294: sigaddset(&nset, SIGQUIT);
295: sigprocmask(SIG_BLOCK, &nset, &oset);
296: }
1.1 deraadt 297: }
298:
299: /*
300: * Release signals SIGHUP, SIGINT, and SIGQUIT.
301: */
302: void
303: relsesigs()
304: {
305:
306: if (--sigdepth == 0)
1.2 deraadt 307: sigprocmask(SIG_SETMASK, &oset, NULL);
1.1 deraadt 308: }
309:
310: /*
311: * Determine the size of the file possessed by
312: * the passed buffer.
313: */
314: off_t
315: fsize(iob)
316: FILE *iob;
317: {
318: struct stat sbuf;
319:
320: if (fstat(fileno(iob), &sbuf) < 0)
1.6 ! millert 321: return(0);
! 322: return(sbuf.st_size);
1.1 deraadt 323: }
324:
325: /*
326: * Evaluate the string given as a new mailbox name.
327: * Supported meta characters:
328: * % for my system mail box
329: * %user for user's system mail box
330: * # for previous file
331: * & invoker's mbox file
332: * +file file in folder directory
333: * any shell meta character
334: * Return the file name as a dynamic string.
335: */
336: char *
337: expand(name)
338: register char *name;
339: {
340: char xname[PATHSIZE];
341: char cmdbuf[PATHSIZE]; /* also used for file names */
342: register int pid, l;
343: register char *cp, *shell;
344: int pivec[2];
345: struct stat sbuf;
346: extern union wait wait_status;
347:
348: /*
349: * The order of evaluation is "%" and "#" expand into constants.
350: * "&" can expand into "+". "+" can expand into shell meta characters.
351: * Shell meta characters expand into constants.
352: * This way, we make no recursive expansion.
353: */
354: switch (*name) {
355: case '%':
1.6 ! millert 356: findmail(name[1] ? name + 1 : myname, xname, sizeof(xname));
! 357: return(savestr(xname));
1.1 deraadt 358: case '#':
359: if (name[1] != 0)
360: break;
361: if (prevfile[0] == 0) {
1.6 ! millert 362: puts("No previous file");
! 363: return(NOSTR);
1.1 deraadt 364: }
1.6 ! millert 365: return(savestr(prevfile));
1.1 deraadt 366: case '&':
367: if (name[1] == 0 && (name = value("MBOX")) == NOSTR)
368: name = "~/mbox";
369: /* fall through */
370: }
1.6 ! millert 371: if (name[0] == '+' && getfold(cmdbuf, sizeof(cmdbuf)) >= 0) {
! 372: snprintf(xname, sizeof(xname), "%s/%s", cmdbuf, name + 1);
1.1 deraadt 373: name = savestr(xname);
374: }
375: /* catch the most common shell meta character */
376: if (name[0] == '~' && (name[1] == '/' || name[1] == '\0')) {
1.6 ! millert 377: snprintf(xname, sizeof(xname), "%s%s", homedir, name + 1);
1.1 deraadt 378: name = savestr(xname);
379: }
380: if (!anyof(name, "~{[*?$`'\"\\"))
1.6 ! millert 381: return(name);
1.1 deraadt 382: if (pipe(pivec) < 0) {
1.6 ! millert 383: warn("pipe");
! 384: return(name);
1.1 deraadt 385: }
1.6 ! millert 386: snprintf(cmdbuf, sizeof(cmdbuf), "echo %s", name);
1.1 deraadt 387: if ((shell = value("SHELL")) == NOSTR)
388: shell = _PATH_CSHELL;
389: pid = start_command(shell, 0, -1, pivec[1], "-c", cmdbuf, NOSTR);
390: if (pid < 0) {
1.6 ! millert 391: (void)close(pivec[0]);
! 392: (void)close(pivec[1]);
! 393: return(NOSTR);
! 394: }
! 395: (void)close(pivec[1]);
! 396: l = read(pivec[0], xname, PATHSIZE);
! 397: (void)close(pivec[0]);
1.1 deraadt 398: if (wait_child(pid) < 0 && wait_status.w_termsig != SIGPIPE) {
399: fprintf(stderr, "\"%s\": Expansion failed.\n", name);
1.6 ! millert 400: return(NOSTR);
1.1 deraadt 401: }
402: if (l < 0) {
1.6 ! millert 403: warn("read");
! 404: return(NOSTR);
1.1 deraadt 405: }
406: if (l == 0) {
407: fprintf(stderr, "\"%s\": No match.\n", name);
1.6 ! millert 408: return(NOSTR);
1.1 deraadt 409: }
1.6 ! millert 410: if (l == PATHSIZE) {
1.1 deraadt 411: fprintf(stderr, "\"%s\": Expansion buffer overflow.\n", name);
1.6 ! millert 412: return(NOSTR);
1.1 deraadt 413: }
1.6 ! millert 414: xname[l] = '\0';
1.1 deraadt 415: for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
416: ;
417: cp[1] = '\0';
1.3 millert 418: if (strchr(xname, ' ') && stat(xname, &sbuf) < 0) {
1.1 deraadt 419: fprintf(stderr, "\"%s\": Ambiguous.\n", name);
1.6 ! millert 420: return(NOSTR);
1.1 deraadt 421: }
1.6 ! millert 422: return(savestr(xname));
1.1 deraadt 423: }
424:
425: /*
426: * Determine the current folder directory name.
427: */
428: int
1.5 deraadt 429: getfold(name, namelen)
1.1 deraadt 430: char *name;
1.5 deraadt 431: int namelen;
1.1 deraadt 432: {
433: char *folder;
434:
435: if ((folder = value("folder")) == NOSTR)
1.6 ! millert 436: return(-1);
1.5 deraadt 437: if (*folder == '/') {
438: strncpy(name, folder, namelen-1);
439: name[namelen-1] = '\0';
440: } else
441: snprintf(name, namelen, "%s/%s", homedir, folder);
1.6 ! millert 442: return(0);
1.1 deraadt 443: }
444:
445: /*
446: * Return the name of the dead.letter file.
447: */
448: char *
449: getdeadletter()
450: {
451: register char *cp;
452:
453: if ((cp = value("DEAD")) == NOSTR || (cp = expand(cp)) == NOSTR)
454: cp = expand("~/dead.letter");
455: else if (*cp != '/') {
456: char buf[PATHSIZE];
457:
1.6 ! millert 458: (void) snprintf(buf, sizeof(buf), "~/%s", cp);
1.1 deraadt 459: cp = expand(buf);
460: }
1.6 ! millert 461: return(cp);
1.1 deraadt 462: }