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, with or without 6: * modification, are permitted provided that the following conditions 7: * are met: 8: * 1. Redistributions of source code must retain the above copyright 9: * notice, this list of conditions and the following disclaimer. 10: * 2. Redistributions in binary form must reproduce the above copyright 11: * notice, this list of conditions and the following disclaimer in the 12: * documentation and/or other materials provided with the distribution. 13: * 3. All advertising materials mentioning features or use of this software 14: * must display the following acknowledgement: 15: * This product includes software developed by the University of 16: * California, Berkeley and its contributors. 17: * 4. Neither the name of the University nor the names of its contributors 18: * may be used to endorse or promote products derived from this software 19: * without specific prior written permission. 20: * 21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31: * SUCH DAMAGE. 32: */ 33: 34: #if !defined(lint) && defined(DOSCCS) 35: static char sccsid[] = "@(#)cmd2.c 5.14 (Berkeley) 6/25/90"; 36: #endif 37: 38: #include "rcv.h" 39: #include <sys/wait.h> 40: 41: /* 42: * Mail -- a mail program 43: * 44: * More user commands. 45: */ 46: 47: /* 48: * If any arguments were given, go to the next applicable argument 49: * following dot, otherwise, go to the next applicable message. 50: * If given as first command with no arguments, print first message. 51: */ 52: 53: next(msgvec) 54: int *msgvec; 55: { 56: register struct message *mp; 57: register int *ip, *ip2; 58: int list[2], mdot; 59: 60: if (*msgvec != NULL) { 61: 62: /* 63: * If some messages were supplied, find the 64: * first applicable one following dot using 65: * wrap around. 66: */ 67: 68: mdot = dot - &message[0] + 1; 69: 70: /* 71: * Find the first message in the supplied 72: * message list which follows dot. 73: */ 74: 75: for (ip = msgvec; *ip != NULL; ip++) 76: if (*ip > mdot) 77: break; 78: if (*ip == NULL) 79: ip = msgvec; 80: ip2 = ip; 81: do { 82: mp = &message[*ip2 - 1]; 83: if ((mp->m_flag & MDELETED) == 0) { 84: dot = mp; 85: goto hitit; 86: } 87: if (*ip2 != NULL) 88: ip2++; 89: if (*ip2 == NULL) 90: ip2 = msgvec; 91: } while (ip2 != ip); 92: printf("No messages applicable\n"); 93: return(1); 94: } 95: 96: /* 97: * If this is the first command, select message 1. 98: * Note that this must exist for us to get here at all. 99: */ 100: 101: if (!sawcom) 102: goto hitit; 103: 104: /* 105: * Just find the next good message after dot, no 106: * wraparound. 107: */ 108: 109: for (mp = dot+1; mp < &message[msgCount]; mp++) 110: if ((mp->m_flag & (MDELETED|MSAVED)) == 0) 111: break; 112: if (mp >= &message[msgCount]) { 113: printf("At EOF\n"); 114: return(0); 115: } 116: dot = mp; 117: hitit: 118: /* 119: * Print dot. 120: */ 121: 122: list[0] = dot - &message[0] + 1; 123: list[1] = NULL; 124: return(type(list)); 125: } 126: 127: /* 128: * Save a message in a file. Mark the message as saved 129: * so we can discard when the user quits. 130: */ 131: save(str) 132: char str[]; 133: { 134: 135: return save1(str, 1, "save", saveignore); 136: } 137: 138: /* 139: * Copy a message to a file without affected its saved-ness 140: */ 141: copycmd(str) 142: char str[]; 143: { 144: 145: return save1(str, 0, "copy", saveignore); 146: } 147: 148: /* 149: * Save/copy the indicated messages at the end of the passed file name. 150: * If mark is true, mark the message "saved." 151: */ 152: save1(str, mark, cmd, ignore) 153: char str[]; 154: char *cmd; 155: struct ignoretab *ignore; 156: { 157: register int *ip; 158: register struct message *mp; 159: char *file, *disp; 160: int f, *msgvec; 161: FILE *obuf; 162: 163: msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec); 164: if ((file = snarf(str, &f)) == NOSTR) 165: return(1); 166: if (!f) { 167: *msgvec = first(0, MMNORM); 168: if (*msgvec == NULL) { 169: printf("No messages to %s.\n", cmd); 170: return(1); 171: } 172: msgvec[1] = NULL; 173: } 174: if (f && getmsglist(str, msgvec, 0) < 0) 175: return(1); 176: if ((file = expand(file)) == NOSTR) 177: return(1); 178: printf("\"%s\" ", file); 179: fflush(stdout); 180: if (access(file, 0) >= 0) 181: disp = "[Appended]"; 182: else 183: disp = "[New file]"; 184: if ((obuf = Fopen(file, "a")) == NULL) { 185: perror(NOSTR); 186: return(1); 187: } 188: for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 189: mp = &message[*ip - 1]; 190: touch(mp); 191: if (send(mp, obuf, ignore, NOSTR) < 0) { 192: perror(file); 193: Fclose(obuf); 194: return(1); 195: } 196: if (mark) 197: mp->m_flag |= MSAVED; 198: } 199: fflush(obuf); 200: if (ferror(obuf)) 201: perror(file); 202: Fclose(obuf); 203: printf("%s\n", disp); 204: return(0); 205: } 206: 207: /* 208: * Write the indicated messages at the end of the passed 209: * file name, minus header and trailing blank line. 210: */ 211: 212: swrite(str) 213: char str[]; 214: { 215: 216: return save1(str, 1, "write", ignoreall); 217: } 218: 219: /* 220: * Snarf the file from the end of the command line and 221: * return a pointer to it. If there is no file attached, 222: * just return NOSTR. Put a null in front of the file 223: * name so that the message list processing won't see it, 224: * unless the file name is the only thing on the line, in 225: * which case, return 0 in the reference flag variable. 226: */ 227: 228: char * 229: snarf(linebuf, flag) 230: char linebuf[]; 231: int *flag; 232: { 233: register char *cp; 234: 235: *flag = 1; 236: cp = strlen(linebuf) + linebuf - 1; 237: 238: /* 239: * Strip away trailing blanks. 240: */ 241: 242: while (cp > linebuf && isspace(*cp)) 243: cp--; 244: *++cp = 0; 245: 246: /* 247: * Now search for the beginning of the file name. 248: */ 249: 250: while (cp > linebuf && !isspace(*cp)) 251: cp--; 252: if (*cp == '\0') { 253: printf("No file specified.\n"); 254: return(NOSTR); 255: } 256: if (isspace(*cp)) 257: *cp++ = 0; 258: else 259: *flag = 0; 260: return(cp); 261: } 262: 263: /* 264: * Delete messages. 265: */ 266: 267: delete(msgvec) 268: int msgvec[]; 269: { 270: delm(msgvec); 271: return 0; 272: } 273: 274: /* 275: * Delete messages, then type the new dot. 276: */ 277: 278: deltype(msgvec) 279: int msgvec[]; 280: { 281: int list[2]; 282: int lastdot; 283: 284: lastdot = dot - &message[0] + 1; 285: if (delm(msgvec) >= 0) { 286: list[0] = dot - &message[0] + 1; 287: if (list[0] > lastdot) { 288: touch(dot); 289: list[1] = NULL; 290: return(type(list)); 291: } 292: printf("At EOF\n"); 293: } else 294: printf("No more messages\n"); 295: return(0); 296: } 297: 298: /* 299: * Delete the indicated messages. 300: * Set dot to some nice place afterwards. 301: * Internal interface. 302: */ 303: 304: delm(msgvec) 305: int *msgvec; 306: { 307: register struct message *mp; 308: register *ip; 309: int last; 310: 311: last = NULL; 312: for (ip = msgvec; *ip != NULL; ip++) { 313: mp = &message[*ip - 1]; 314: touch(mp); 315: mp->m_flag |= MDELETED|MTOUCH; 316: mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX); 317: last = *ip; 318: } 319: if (last != NULL) { 320: dot = &message[last-1]; 321: last = first(0, MDELETED); 322: if (last != NULL) { 323: dot = &message[last-1]; 324: return(0); 325: } 326: else { 327: dot = &message[0]; 328: return(-1); 329: } 330: } 331: 332: /* 333: * Following can't happen -- it keeps lint happy 334: */ 335: 336: return(-1); 337: } 338: 339: /* 340: * Undelete the indicated messages. 341: */ 342: 343: undelete(msgvec) 344: int *msgvec; 345: { 346: register struct message *mp; 347: register *ip; 348: 349: for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 350: mp = &message[*ip - 1]; 351: touch(mp); 352: dot = mp; 353: mp->m_flag &= ~MDELETED; 354: } 355: return 0; 356: } 357: 358: /* 359: * Interactively dump core on "core" 360: */ 361: 362: core() 363: { 364: int pid; 365: extern union wait wait_status; 366: 367: switch (pid = vfork()) { 368: case -1: 369: perror("fork"); 370: return(1); 371: case 0: 372: abort(); 373: _exit(1); 374: } 375: printf("Okie dokie"); 376: fflush(stdout); 377: wait_child(pid); 378: if (wait_status.w_coredump) 379: printf(" -- Core dumped.\n"); 380: else 381: printf(" -- Can't dump core.\n"); 382: return 0; 383: } 384: 385: /* 386: * Clobber as many bytes of stack as the user requests. 387: */ 388: clobber(argv) 389: char **argv; 390: { 391: register int times; 392: 393: if (argv[0] == 0) 394: times = 1; 395: else 396: times = (atoi(argv[0]) + 511) / 512; 397: clob1(times); 398: return 0; 399: } 400: 401: /* 402: * Clobber the stack. 403: */ 404: clob1(n) 405: { 406: char buf[512]; 407: register char *cp; 408: 409: if (n <= 0) 410: return; 411: for (cp = buf; cp < &buf[512]; *cp++ = 0xFF) 412: ; 413: clob1(n - 1); 414: } 415: 416: /* 417: * Add the given header fields to the retained list. 418: * If no arguments, print the current list of retained fields. 419: */ 420: retfield(list) 421: char *list[]; 422: { 423: 424: return ignore1(list, ignore + 1, "retained"); 425: } 426: 427: /* 428: * Add the given header fields to the ignored list. 429: * If no arguments, print the current list of ignored fields. 430: */ 431: igfield(list) 432: char *list[]; 433: { 434: 435: return ignore1(list, ignore, "ignored"); 436: } 437: 438: saveretfield(list) 439: char *list[]; 440: { 441: 442: return ignore1(list, saveignore + 1, "retained"); 443: } 444: 445: saveigfield(list) 446: char *list[]; 447: { 448: 449: return ignore1(list, saveignore, "ignored"); 450: } 451: 452: ignore1(list, tab, which) 453: char *list[]; 454: struct ignoretab *tab; 455: char *which; 456: { 457: char field[BUFSIZ]; 458: register int h; 459: register struct ignore *igp; 460: char **ap; 461: 462: if (*list == NOSTR) 463: return igshow(tab, which); 464: for (ap = list; *ap != 0; ap++) { 465: istrcpy(field, *ap); 466: if (member(field, tab)) 467: continue; 468: h = hash(field); 469: igp = (struct ignore *) calloc(1, sizeof (struct ignore)); 470: igp->i_field = calloc((unsigned) strlen(field) + 1, 471: sizeof (char)); 472: strcpy(igp->i_field, field); 473: igp->i_link = tab->i_head[h]; 474: tab->i_head[h] = igp; 475: tab->i_count++; 476: } 477: return 0; 478: } 479: 480: /* 481: * Print out all currently retained fields. 482: */ 483: igshow(tab, which) 484: struct ignoretab *tab; 485: char *which; 486: { 487: register int h; 488: struct ignore *igp; 489: char **ap, **ring; 490: int igcomp(); 491: 492: if (tab->i_count == 0) { 493: printf("No fields currently being %s.\n", which); 494: return 0; 495: } 496: ring = (char **) salloc((tab->i_count + 1) * sizeof (char *)); 497: ap = ring; 498: for (h = 0; h < HSHSIZE; h++) 499: for (igp = tab->i_head[h]; igp != 0; igp = igp->i_link) 500: *ap++ = igp->i_field; 501: *ap = 0; 502: qsort((char *) ring, tab->i_count, sizeof (char *), igcomp); 503: for (ap = ring; *ap != 0; ap++) 504: printf("%s\n", *ap); 505: return 0; 506: } 507: 508: /* 509: * Compare two names for sorting ignored field list. 510: */ 511: igcomp(l, r) 512: char **l, **r; 513: { 514: 515: return strcmp(*l, *r); 516: }