1: # 2: 3: #include "rcv.h" 4: #include <sys/stat.h> 5: #include <errno.h> 6: 7: /* 8: * Mail -- a mail program 9: * 10: * File I/O. 11: */ 12: 13: static char *SccsId = "@(#)fio.c 2.15 6/17/83"; 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, "w")) == NULL) { 356: perror(editfile); 357: relsesigs(); 358: reset(0); 359: } 360: c = 0; 361: for (mp = &message[0]; mp < &message[msgCount]; mp++) { 362: if ((mp->m_flag & MDELETED) != 0) 363: continue; 364: c++; 365: if (send(mp, obuf, 0) < 0) { 366: perror(editfile); 367: relsesigs(); 368: reset(0); 369: } 370: } 371: gotcha = (c == 0 && ibuf == NULL); 372: if (ibuf != NULL) { 373: while ((c = getc(ibuf)) != EOF) 374: putc(c, obuf); 375: fclose(ibuf); 376: } 377: fflush(obuf); 378: if (ferror(obuf)) { 379: perror(editfile); 380: relsesigs(); 381: reset(0); 382: } 383: fclose(obuf); 384: if (gotcha) { 385: remove(editfile); 386: printf("removed\n"); 387: } 388: else 389: printf("complete\n"); 390: flush(); 391: 392: done: 393: relsesigs(); 394: } 395: 396: static int sigdepth = 0; /* depth of holdsigs() */ 397: /* 398: * Hold signals SIGHUP - SIGQUIT. 399: */ 400: holdsigs() 401: { 402: register int i; 403: 404: if (sigdepth++ == 0) 405: for (i = SIGHUP; i <= SIGQUIT; i++) 406: sighold(i); 407: } 408: 409: /* 410: * Release signals SIGHUP - SIGQUIT 411: */ 412: relsesigs() 413: { 414: register int i; 415: 416: if (--sigdepth == 0) 417: for (i = SIGHUP; i <= SIGQUIT; i++) 418: sigrelse(i); 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: }