1: /* 2: * Copyright (c) 1980 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: */ 6: 7: #ifndef lint 8: static char *sccsid = "@(#)cmd2.c 5.3 (Berkeley) 9/10/85"; 9: #endif not lint 10: 11: #include "rcv.h" 12: #include <sys/stat.h> 13: 14: /* 15: * Mail -- a mail program 16: * 17: * More user commands. 18: */ 19: 20: /* 21: * If any arguments were given, go to the next applicable argument 22: * following dot, otherwise, go to the next applicable message. 23: * If given as first command with no arguments, print first message. 24: */ 25: 26: next(msgvec) 27: int *msgvec; 28: { 29: register struct message *mp; 30: register int *ip, *ip2; 31: int list[2], mdot; 32: 33: if (*msgvec != NULL) { 34: 35: /* 36: * If some messages were supplied, find the 37: * first applicable one following dot using 38: * wrap around. 39: */ 40: 41: mdot = dot - &message[0] + 1; 42: 43: /* 44: * Find the first message in the supplied 45: * message list which follows dot. 46: */ 47: 48: for (ip = msgvec; *ip != NULL; ip++) 49: if (*ip > mdot) 50: break; 51: if (*ip == NULL) 52: ip = msgvec; 53: ip2 = ip; 54: do { 55: mp = &message[*ip2 - 1]; 56: if ((mp->m_flag & MDELETED) == 0) { 57: dot = mp; 58: goto hitit; 59: } 60: if (*ip2 != NULL) 61: ip2++; 62: if (*ip2 == NULL) 63: ip2 = msgvec; 64: } while (ip2 != ip); 65: printf("No messages applicable\n"); 66: return(1); 67: } 68: 69: /* 70: * If this is the first command, select message 1. 71: * Note that this must exist for us to get here at all. 72: */ 73: 74: if (!sawcom) 75: goto hitit; 76: 77: /* 78: * Just find the next good message after dot, no 79: * wraparound. 80: */ 81: 82: for (mp = dot+1; mp < &message[msgCount]; mp++) 83: if ((mp->m_flag & (MDELETED|MSAVED)) == 0) 84: break; 85: if (mp >= &message[msgCount]) { 86: printf("At EOF\n"); 87: return(0); 88: } 89: dot = mp; 90: hitit: 91: /* 92: * Print dot. 93: */ 94: 95: list[0] = dot - &message[0] + 1; 96: list[1] = NULL; 97: return(type(list)); 98: } 99: 100: /* 101: * Save a message in a file. Mark the message as saved 102: * so we can discard when the user quits. 103: */ 104: save(str) 105: char str[]; 106: { 107: 108: return(save1(str, 1)); 109: } 110: 111: /* 112: * Copy a message to a file without affected its saved-ness 113: */ 114: copycmd(str) 115: char str[]; 116: { 117: 118: return(save1(str, 0)); 119: } 120: 121: /* 122: * Save/copy the indicated messages at the end of the passed file name. 123: * If mark is true, mark the message "saved." 124: */ 125: save1(str, mark) 126: char str[]; 127: { 128: register int *ip, mesg; 129: register struct message *mp; 130: char *file, *disp, *cmd; 131: int f, *msgvec, lc, t; 132: long cc; 133: FILE *obuf; 134: struct stat statb; 135: 136: cmd = mark ? "save" : "copy"; 137: msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec); 138: if ((file = snarf(str, &f)) == NOSTR) 139: return(1); 140: if (!f) { 141: *msgvec = first(0, MMNORM); 142: if (*msgvec == NULL) { 143: printf("No messages to %s.\n", cmd); 144: return(1); 145: } 146: msgvec[1] = NULL; 147: } 148: if (f && getmsglist(str, msgvec, 0) < 0) 149: return(1); 150: if ((file = expand(file)) == NOSTR) 151: return(1); 152: printf("\"%s\" ", file); 153: fflush(stdout); 154: if (stat(file, &statb) >= 0) 155: disp = "[Appended]"; 156: else 157: disp = "[New file]"; 158: if ((obuf = fopen(file, "a")) == NULL) { 159: perror(NOSTR); 160: return(1); 161: } 162: cc = 0L; 163: lc = 0; 164: for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 165: mesg = *ip; 166: touch(mesg); 167: mp = &message[mesg-1]; 168: if ((t = send(mp, obuf, 0)) < 0) { 169: perror(file); 170: fclose(obuf); 171: return(1); 172: } 173: lc += t; 174: cc += mp->m_size; 175: if (mark) 176: mp->m_flag |= MSAVED; 177: } 178: fflush(obuf); 179: if (ferror(obuf)) 180: perror(file); 181: fclose(obuf); 182: printf("%s %d/%ld\n", disp, lc, cc); 183: return(0); 184: } 185: 186: /* 187: * Write the indicated messages at the end of the passed 188: * file name, minus header and trailing blank line. 189: */ 190: 191: swrite(str) 192: char str[]; 193: { 194: register int *ip, mesg; 195: register struct message *mp; 196: register char *file, *disp; 197: char linebuf[BUFSIZ]; 198: int f, *msgvec, lc, cc, t; 199: FILE *obuf, *mesf; 200: struct stat statb; 201: 202: msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec); 203: if ((file = snarf(str, &f)) == NOSTR) 204: return(1); 205: if ((file = expand(file)) == NOSTR) 206: return(1); 207: if (!f) { 208: *msgvec = first(0, MMNORM); 209: if (*msgvec == NULL) { 210: printf("No messages to write.\n"); 211: return(1); 212: } 213: msgvec[1] = NULL; 214: } 215: if (f && getmsglist(str, msgvec, 0) < 0) 216: return(1); 217: printf("\"%s\" ", file); 218: fflush(stdout); 219: if (stat(file, &statb) >= 0) 220: disp = "[Appended]"; 221: else 222: disp = "[New file]"; 223: if ((obuf = fopen(file, "a")) == NULL) { 224: perror(NOSTR); 225: return(1); 226: } 227: cc = lc = 0; 228: for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 229: mesg = *ip; 230: touch(mesg); 231: mp = &message[mesg-1]; 232: mesf = setinput(mp); 233: t = mp->m_lines - 1; 234: while (t-- > 0) { 235: readline(mesf, linebuf); 236: if (blankline(linebuf)) 237: break; 238: } 239: while (t-- > 0) { 240: fgets(linebuf, BUFSIZ, mesf); 241: fputs(linebuf, obuf); 242: cc += strlen(linebuf); 243: } 244: lc += mp->m_lines - 2; 245: mp->m_flag |= MSAVED; 246: } 247: fflush(obuf); 248: if (ferror(obuf)) 249: perror(file); 250: fclose(obuf); 251: printf("%s %d/%d\n", disp, lc, cc); 252: return(0); 253: } 254: 255: /* 256: * Snarf the file from the end of the command line and 257: * return a pointer to it. If there is no file attached, 258: * just return NOSTR. Put a null in front of the file 259: * name so that the message list processing won't see it, 260: * unless the file name is the only thing on the line, in 261: * which case, return 0 in the reference flag variable. 262: */ 263: 264: char * 265: snarf(linebuf, flag) 266: char linebuf[]; 267: int *flag; 268: { 269: register char *cp; 270: 271: *flag = 1; 272: cp = strlen(linebuf) + linebuf - 1; 273: 274: /* 275: * Strip away trailing blanks. 276: */ 277: 278: while (*cp == ' ' && cp > linebuf) 279: cp--; 280: *++cp = 0; 281: 282: /* 283: * Now search for the beginning of the file name. 284: */ 285: 286: while (cp > linebuf && !any(*cp, "\t ")) 287: cp--; 288: if (*cp == '\0') { 289: printf("No file specified.\n"); 290: return(NOSTR); 291: } 292: if (any(*cp, " \t")) 293: *cp++ = 0; 294: else 295: *flag = 0; 296: return(cp); 297: } 298: 299: /* 300: * Delete messages. 301: */ 302: 303: delete(msgvec) 304: int msgvec[]; 305: { 306: return(delm(msgvec)); 307: } 308: 309: /* 310: * Delete messages, then type the new dot. 311: */ 312: 313: deltype(msgvec) 314: int msgvec[]; 315: { 316: int list[2]; 317: int lastdot; 318: 319: lastdot = dot - &message[0] + 1; 320: if (delm(msgvec) >= 0) { 321: list[0] = dot - &message[0]; 322: list[0]++; 323: if (list[0] > lastdot) { 324: touch(list[0]); 325: list[1] = NULL; 326: return(type(list)); 327: } 328: printf("At EOF\n"); 329: return(0); 330: } 331: else { 332: printf("No more messages\n"); 333: return(0); 334: } 335: } 336: 337: /* 338: * Delete the indicated messages. 339: * Set dot to some nice place afterwards. 340: * Internal interface. 341: */ 342: 343: delm(msgvec) 344: int *msgvec; 345: { 346: register struct message *mp; 347: register *ip, mesg; 348: int last; 349: 350: last = NULL; 351: for (ip = msgvec; *ip != NULL; ip++) { 352: mesg = *ip; 353: touch(mesg); 354: mp = &message[mesg-1]; 355: mp->m_flag |= MDELETED|MTOUCH; 356: mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX); 357: last = mesg; 358: } 359: if (last != NULL) { 360: dot = &message[last-1]; 361: last = first(0, MDELETED); 362: if (last != NULL) { 363: dot = &message[last-1]; 364: return(0); 365: } 366: else { 367: dot = &message[0]; 368: return(-1); 369: } 370: } 371: 372: /* 373: * Following can't happen -- it keeps lint happy 374: */ 375: 376: return(-1); 377: } 378: 379: /* 380: * Undelete the indicated messages. 381: */ 382: 383: undelete(msgvec) 384: int *msgvec; 385: { 386: register struct message *mp; 387: register *ip, mesg; 388: 389: for (ip = msgvec; ip-msgvec < msgCount; ip++) { 390: mesg = *ip; 391: if (mesg == 0) 392: return; 393: touch(mesg); 394: mp = &message[mesg-1]; 395: dot = mp; 396: mp->m_flag &= ~MDELETED; 397: } 398: } 399: 400: /* 401: * Interactively dump core on "core" 402: */ 403: 404: core() 405: { 406: register int pid; 407: int status; 408: 409: if ((pid = vfork()) == -1) { 410: perror("fork"); 411: return(1); 412: } 413: if (pid == 0) { 414: sigchild(); 415: abort(); 416: _exit(1); 417: } 418: printf("Okie dokie"); 419: fflush(stdout); 420: while (wait(&status) != pid) 421: ; 422: if (status & 0200) 423: printf(" -- Core dumped\n"); 424: else 425: printf("\n"); 426: } 427: 428: /* 429: * Clobber as many bytes of stack as the user requests. 430: */ 431: clobber(argv) 432: char **argv; 433: { 434: register int times; 435: 436: if (argv[0] == 0) 437: times = 1; 438: else 439: times = (atoi(argv[0]) + 511) / 512; 440: clob1(times); 441: } 442: 443: /* 444: * Clobber the stack. 445: */ 446: clob1(n) 447: { 448: char buf[512]; 449: register char *cp; 450: 451: if (n <= 0) 452: return; 453: for (cp = buf; cp < &buf[512]; *cp++ = 0xFF) 454: ; 455: clob1(n - 1); 456: } 457: 458: /* 459: * Add the given header fields to the retained list. 460: * If no arguments, print the current list of retained fields. 461: */ 462: retfield(list) 463: char *list[]; 464: { 465: char field[BUFSIZ]; 466: register int h; 467: register struct ignore *igp; 468: char **ap; 469: 470: if (argcount(list) == 0) 471: return(retshow()); 472: for (ap = list; *ap != 0; ap++) { 473: istrcpy(field, *ap); 474: 475: if (member(field, retain)) 476: continue; 477: 478: h = hash(field); 479: igp = (struct ignore *) calloc(1, sizeof (struct ignore)); 480: igp->i_field = calloc(strlen(field) + 1, sizeof (char)); 481: strcpy(igp->i_field, field); 482: igp->i_link = retain[h]; 483: retain[h] = igp; 484: nretained++; 485: } 486: return(0); 487: } 488: 489: /* 490: * Print out all currently retained fields. 491: */ 492: retshow() 493: { 494: register int h, count; 495: struct ignore *igp; 496: char **ap, **ring; 497: int igcomp(); 498: 499: count = 0; 500: for (h = 0; h < HSHSIZE; h++) 501: for (igp = retain[h]; igp != 0; igp = igp->i_link) 502: count++; 503: if (count == 0) { 504: printf("No fields currently being retained.\n"); 505: return(0); 506: } 507: ring = (char **) salloc((count + 1) * sizeof (char *)); 508: ap = ring; 509: for (h = 0; h < HSHSIZE; h++) 510: for (igp = retain[h]; igp != 0; igp = igp->i_link) 511: *ap++ = igp->i_field; 512: *ap = 0; 513: qsort(ring, count, sizeof (char *), igcomp); 514: for (ap = ring; *ap != 0; ap++) 515: printf("%s\n", *ap); 516: return(0); 517: } 518: 519: /* 520: * Add the given header fields to the ignored list. 521: * If no arguments, print the current list of ignored fields. 522: */ 523: igfield(list) 524: char *list[]; 525: { 526: char field[BUFSIZ]; 527: register int h; 528: register struct ignore *igp; 529: char **ap; 530: 531: if (argcount(list) == 0) 532: return(igshow()); 533: for (ap = list; *ap != 0; ap++) { 534: if (isign(*ap)) 535: continue; 536: istrcpy(field, *ap); 537: h = hash(field); 538: igp = (struct ignore *) calloc(1, sizeof (struct ignore)); 539: igp->i_field = calloc(strlen(field) + 1, sizeof (char)); 540: strcpy(igp->i_field, field); 541: igp->i_link = ignore[h]; 542: ignore[h] = igp; 543: } 544: return(0); 545: } 546: 547: /* 548: * Print out all currently ignored fields. 549: */ 550: igshow() 551: { 552: register int h, count; 553: struct ignore *igp; 554: char **ap, **ring; 555: int igcomp(); 556: 557: count = 0; 558: for (h = 0; h < HSHSIZE; h++) 559: for (igp = ignore[h]; igp != 0; igp = igp->i_link) 560: count++; 561: if (count == 0) { 562: printf("No fields currently being ignored.\n"); 563: return(0); 564: } 565: ring = (char **) salloc((count + 1) * sizeof (char *)); 566: ap = ring; 567: for (h = 0; h < HSHSIZE; h++) 568: for (igp = ignore[h]; igp != 0; igp = igp->i_link) 569: *ap++ = igp->i_field; 570: *ap = 0; 571: qsort(ring, count, sizeof (char *), igcomp); 572: for (ap = ring; *ap != 0; ap++) 573: printf("%s\n", *ap); 574: return(0); 575: } 576: 577: /* 578: * Compare two names for sorting ignored field list. 579: */ 580: igcomp(l, r) 581: char **l, **r; 582: { 583: 584: return(strcmp(*l, *r)); 585: }