|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1980 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted provided ! 6: * that: (1) source distributions retain this entire copyright notice and ! 7: * comment, and (2) distributions including binaries display the following ! 8: * acknowledgement: ``This product includes software developed by the ! 9: * University of California, Berkeley and its contributors'' in the ! 10: * documentation or other materials provided with the distribution and in ! 11: * all advertising materials mentioning features or use of this software. ! 12: * Neither the name of the University nor the names of its contributors may ! 13: * be used to endorse or promote products derived from this software without ! 14: * specific prior written permission. ! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 18: */ ! 19: ! 20: #ifndef lint ! 21: static char sccsid[] = "@(#)fio.c 5.23 (Berkeley) 6/25/90"; ! 22: #endif /* not lint */ ! 23: ! 24: #include "rcv.h" ! 25: #include <sys/stat.h> ! 26: #include <sys/file.h> ! 27: #include <sys/wait.h> ! 28: #include <errno.h> ! 29: ! 30: /* ! 31: * Mail -- a mail program ! 32: * ! 33: * File I/O. ! 34: */ ! 35: ! 36: /* ! 37: * Set up the input pointers while copying the mail file into ! 38: * /tmp. ! 39: */ ! 40: setptr(ibuf) ! 41: register FILE *ibuf; ! 42: { ! 43: register c; ! 44: register char *cp, *cp2; ! 45: register count; ! 46: char linebuf[LINESIZE]; ! 47: int maybe, inhead; ! 48: FILE *mestmp; ! 49: off_t offset; ! 50: struct message this; ! 51: extern char tempSet[]; ! 52: ! 53: if ((c = opentemp(tempSet)) < 0) ! 54: exit(1); ! 55: if ((mestmp = Fdopen(c, "r+")) == NULL) ! 56: panic("Can't open temporary"); ! 57: msgCount = 0; ! 58: maybe = 1; ! 59: inhead = 0; ! 60: offset = 0; ! 61: this.m_flag = MUSED|MNEW; ! 62: this.m_size = 0; ! 63: this.m_lines = 0; ! 64: this.m_block = 0; ! 65: this.m_offset = 0; ! 66: for (;;) { ! 67: if (fgets(linebuf, LINESIZE, ibuf) == NULL) { ! 68: if (append(&this, mestmp)) { ! 69: perror(tempSet); ! 70: exit(1); ! 71: } ! 72: makemessage(mestmp); ! 73: return; ! 74: } ! 75: count = strlen(linebuf); ! 76: (void) fwrite(linebuf, sizeof *linebuf, count, otf); ! 77: if (ferror(otf)) { ! 78: perror("/tmp"); ! 79: exit(1); ! 80: } ! 81: linebuf[count - 1] = 0; ! 82: if (maybe && linebuf[0] == 'F' && ishead(linebuf)) { ! 83: msgCount++; ! 84: if (append(&this, mestmp)) { ! 85: perror(tempSet); ! 86: exit(1); ! 87: } ! 88: this.m_flag = MUSED|MNEW; ! 89: this.m_size = 0; ! 90: this.m_lines = 0; ! 91: this.m_block = blockof(offset); ! 92: this.m_offset = offsetof(offset); ! 93: inhead = 1; ! 94: } else if (linebuf[0] == 0) { ! 95: inhead = 0; ! 96: } else if (inhead) { ! 97: for (cp = linebuf, cp2 = "status";; cp++) { ! 98: if ((c = *cp2++) == 0) { ! 99: while (isspace(*cp++)) ! 100: ; ! 101: if (cp[-1] != ':') ! 102: break; ! 103: while (c = *cp++) ! 104: if (c == 'R') ! 105: this.m_flag |= MREAD; ! 106: else if (c == 'O') ! 107: this.m_flag &= ~MNEW; ! 108: inhead = 0; ! 109: break; ! 110: } ! 111: if (*cp != c && *cp != toupper(c)) ! 112: break; ! 113: } ! 114: } ! 115: offset += count; ! 116: this.m_size += count; ! 117: this.m_lines++; ! 118: maybe = linebuf[0] == 0; ! 119: } ! 120: } ! 121: ! 122: /* ! 123: * Drop the passed line onto the passed output buffer. ! 124: * If a write error occurs, return -1, else the count of ! 125: * characters written, including the newline. ! 126: */ ! 127: putline(obuf, linebuf) ! 128: FILE *obuf; ! 129: char *linebuf; ! 130: { ! 131: register int c; ! 132: ! 133: c = strlen(linebuf); ! 134: (void) fwrite(linebuf, sizeof *linebuf, c, obuf); ! 135: (void) putc('\n', obuf); ! 136: if (ferror(obuf)) ! 137: return (-1); ! 138: return (c + 1); ! 139: } ! 140: ! 141: /* ! 142: * Read up a line from the specified input into the line ! 143: * buffer. Return the number of characters read. Do not ! 144: * include the newline at the end. ! 145: */ ! 146: readline(ibuf, linebuf, linesize) ! 147: FILE *ibuf; ! 148: char *linebuf; ! 149: { ! 150: register int n; ! 151: ! 152: clearerr(ibuf); ! 153: if (fgets(linebuf, linesize, ibuf) == NULL) ! 154: return -1; ! 155: n = strlen(linebuf); ! 156: if (n > 0 && linebuf[n - 1] == '\n') ! 157: linebuf[--n] = '\0'; ! 158: return n; ! 159: } ! 160: ! 161: /* ! 162: * Return a file buffer all ready to read up the ! 163: * passed message pointer. ! 164: */ ! 165: FILE * ! 166: setinput(mp) ! 167: register struct message *mp; ! 168: { ! 169: ! 170: fflush(otf); ! 171: if (fseek(itf, positionof(mp->m_block, mp->m_offset), 0) < 0) { ! 172: perror("fseek"); ! 173: panic("temporary file seek"); ! 174: } ! 175: return (itf); ! 176: } ! 177: ! 178: /* ! 179: * Take the data out of the passed ghost file and toss it into ! 180: * a dynamically allocated message structure. ! 181: */ ! 182: makemessage(f) ! 183: FILE *f; ! 184: { ! 185: register size = (msgCount + 1) * sizeof (struct message); ! 186: off_t lseek(); ! 187: ! 188: if (message != 0) ! 189: free((char *) message); ! 190: if ((message = (struct message *) malloc((unsigned) size)) == 0) ! 191: panic("Insufficient memory for %d messages", msgCount); ! 192: dot = message; ! 193: size -= sizeof (struct message); ! 194: fflush(f); ! 195: (void) lseek(fileno(f), (long) sizeof *message, 0); ! 196: if (read(fileno(f), (char *) message, size) != size) ! 197: panic("Message temporary file corrupted"); ! 198: message[msgCount].m_size = 0; ! 199: message[msgCount].m_lines = 0; ! 200: Fclose(f); ! 201: } ! 202: ! 203: /* ! 204: * Append the passed message descriptor onto the temp file. ! 205: * If the write fails, return 1, else 0 ! 206: */ ! 207: append(mp, f) ! 208: struct message *mp; ! 209: FILE *f; ! 210: { ! 211: return fwrite((char *) mp, sizeof *mp, 1, f) != 1; ! 212: } ! 213: ! 214: /* ! 215: * Delete a file, but only if the file is a plain file. ! 216: */ ! 217: remove(name) ! 218: char name[]; ! 219: { ! 220: struct stat statb; ! 221: extern int errno; ! 222: ! 223: if (stat(name, &statb) < 0) ! 224: return(-1); ! 225: if ((statb.st_mode & S_IFMT) != S_IFREG) { ! 226: errno = EISDIR; ! 227: return(-1); ! 228: } ! 229: return unlink(name); ! 230: } ! 231: ! 232: static int sigdepth; /* depth of holdsigs() */ ! 233: static int omask; ! 234: /* ! 235: * Hold signals SIGHUP, SIGINT, and SIGQUIT. ! 236: */ ! 237: holdsigs() ! 238: { ! 239: ! 240: if (sigdepth++ == 0) ! 241: omask = sigblock(sigmask(SIGHUP)|sigmask(SIGINT)|sigmask(SIGQUIT)); ! 242: } ! 243: ! 244: /* ! 245: * Release signals SIGHUP, SIGINT, and SIGQUIT. ! 246: */ ! 247: relsesigs() ! 248: { ! 249: ! 250: if (--sigdepth == 0) ! 251: sigsetmask(omask); ! 252: } ! 253: ! 254: /* ! 255: * Open a temp file by creating and unlinking. ! 256: * Return the open file descriptor. ! 257: */ ! 258: opentemp(file) ! 259: char file[]; ! 260: { ! 261: int f; ! 262: ! 263: if ((f = open(file, O_CREAT|O_EXCL|O_RDWR, 0600)) < 0) ! 264: perror(file); ! 265: remove(file); ! 266: return (f); ! 267: } ! 268: ! 269: /* ! 270: * Determine the size of the file possessed by ! 271: * the passed buffer. ! 272: */ ! 273: off_t ! 274: fsize(iob) ! 275: FILE *iob; ! 276: { ! 277: struct stat sbuf; ! 278: ! 279: if (fstat(fileno(iob), &sbuf) < 0) ! 280: return 0; ! 281: return sbuf.st_size; ! 282: } ! 283: ! 284: /* ! 285: * Evaluate the string given as a new mailbox name. ! 286: * Supported meta characters: ! 287: * % for my system mail box ! 288: * %user for user's system mail box ! 289: * # for previous file ! 290: * & invoker's mbox file ! 291: * +file file in folder directory ! 292: * any shell meta character ! 293: * Return the file name as a dynamic string. ! 294: */ ! 295: char * ! 296: expand(name) ! 297: register char *name; ! 298: { ! 299: char xname[PATHSIZE]; ! 300: char cmdbuf[PATHSIZE]; /* also used for file names */ ! 301: register int pid, l; ! 302: register char *cp, *shell; ! 303: int pivec[2]; ! 304: struct stat sbuf; ! 305: extern union wait wait_status; ! 306: ! 307: /* ! 308: * The order of evaluation is "%" and "#" expand into constants. ! 309: * "&" can expand into "+". "+" can expand into shell meta characters. ! 310: * Shell meta characters expand into constants. ! 311: * This way, we make no recursive expansion. ! 312: */ ! 313: switch (*name) { ! 314: case '%': ! 315: findmail(name[1] ? name + 1 : myname, xname); ! 316: return savestr(xname); ! 317: case '#': ! 318: if (name[1] != 0) ! 319: break; ! 320: if (prevfile[0] == 0) { ! 321: printf("No previous file\n"); ! 322: return NOSTR; ! 323: } ! 324: return savestr(prevfile); ! 325: case '&': ! 326: if (name[1] == 0 && (name = value("MBOX")) == NOSTR) ! 327: name = "~/mbox"; ! 328: /* fall through */ ! 329: } ! 330: if (name[0] == '+' && getfold(cmdbuf) >= 0) { ! 331: sprintf(xname, "%s/%s", cmdbuf, name + 1); ! 332: name = savestr(xname); ! 333: } ! 334: /* catch the most common shell meta character */ ! 335: if (name[0] == '~' && (name[1] == '/' || name[1] == '\0')) { ! 336: sprintf(xname, "%s%s", homedir, name + 1); ! 337: name = savestr(xname); ! 338: } ! 339: if (!anyof(name, "~{[*?$`'\"\\")) ! 340: return name; ! 341: if (pipe(pivec) < 0) { ! 342: perror("pipe"); ! 343: return name; ! 344: } ! 345: sprintf(cmdbuf, "echo %s", name); ! 346: if ((shell = value("SHELL")) == NOSTR) ! 347: shell = _PATH_CSHELL; ! 348: pid = start_command(shell, 0, -1, pivec[1], "-c", cmdbuf, NOSTR); ! 349: if (pid < 0) { ! 350: close(pivec[0]); ! 351: close(pivec[1]); ! 352: return NOSTR; ! 353: } ! 354: close(pivec[1]); ! 355: l = read(pivec[0], xname, BUFSIZ); ! 356: close(pivec[0]); ! 357: if (wait_child(pid) < 0 && wait_status.w_termsig != SIGPIPE) { ! 358: fprintf(stderr, "\"%s\": Expansion failed.\n", name); ! 359: return NOSTR; ! 360: } ! 361: if (l < 0) { ! 362: perror("read"); ! 363: return NOSTR; ! 364: } ! 365: if (l == 0) { ! 366: fprintf(stderr, "\"%s\": No match.\n", name); ! 367: return NOSTR; ! 368: } ! 369: if (l == BUFSIZ) { ! 370: fprintf(stderr, "\"%s\": Expansion buffer overflow.\n", name); ! 371: return NOSTR; ! 372: } ! 373: xname[l] = 0; ! 374: for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--) ! 375: ; ! 376: cp[1] = '\0'; ! 377: if (index(xname, ' ') && stat(xname, &sbuf) < 0) { ! 378: fprintf(stderr, "\"%s\": Ambiguous.\n", name); ! 379: return NOSTR; ! 380: } ! 381: return savestr(xname); ! 382: } ! 383: ! 384: /* ! 385: * Determine the current folder directory name. ! 386: */ ! 387: getfold(name) ! 388: char *name; ! 389: { ! 390: char *folder; ! 391: ! 392: if ((folder = value("folder")) == NOSTR) ! 393: return (-1); ! 394: if (*folder == '/') ! 395: strcpy(name, folder); ! 396: else ! 397: sprintf(name, "%s/%s", homedir, folder); ! 398: return (0); ! 399: } ! 400: ! 401: /* ! 402: * Return the name of the dead.letter file. ! 403: */ ! 404: char * ! 405: getdeadletter() ! 406: { ! 407: register char *cp; ! 408: ! 409: if ((cp = value("DEAD")) == NOSTR || (cp = expand(cp)) == NOSTR) ! 410: cp = expand("~/dead.letter"); ! 411: else if (*cp != '/') { ! 412: char buf[PATHSIZE]; ! 413: ! 414: (void) sprintf(buf, "~/%s", cp); ! 415: cp = expand(buf); ! 416: } ! 417: return cp; ! 418: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.