122445Sdist /* 222445Sdist * Copyright (c) 1980 Regents of the University of California. 333499Sbostic * All rights reserved. 433499Sbostic * 533499Sbostic * Redistribution and use in source and binary forms are permitted 634905Sbostic * provided that the above copyright notice and this paragraph are 734905Sbostic * duplicated in all such forms and that any documentation, 834905Sbostic * advertising materials, and other materials related to such 934905Sbostic * distribution and use acknowledge that the software was developed 1034905Sbostic * by the University of California, Berkeley. The name of the 1134905Sbostic * University may not be used to endorse or promote products derived 1234905Sbostic * from this software without specific prior written permission. 1334905Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434905Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534905Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1622445Sdist */ 1722445Sdist 1834905Sbostic #ifndef lint 19*36687Sedward static char sccsid[] = "@(#)cmd2.c 5.12 (Berkeley) 02/06/89"; 2034905Sbostic #endif /* not lint */ 211224Skas 221224Skas #include "rcv.h" 2331142Sedward #include <sys/wait.h> 241224Skas 251224Skas /* 261224Skas * Mail -- a mail program 271224Skas * 281224Skas * More user commands. 291224Skas */ 301224Skas 311224Skas /* 321224Skas * If any arguments were given, go to the next applicable argument 331224Skas * following dot, otherwise, go to the next applicable message. 341224Skas * If given as first command with no arguments, print first message. 351224Skas */ 361224Skas 371224Skas next(msgvec) 381224Skas int *msgvec; 391224Skas { 401224Skas register struct message *mp; 411224Skas register int *ip, *ip2; 421224Skas int list[2], mdot; 431224Skas 441224Skas if (*msgvec != NULL) { 451224Skas 461224Skas /* 471224Skas * If some messages were supplied, find the 481224Skas * first applicable one following dot using 491224Skas * wrap around. 501224Skas */ 511224Skas 521224Skas mdot = dot - &message[0] + 1; 531470Skas 541470Skas /* 551470Skas * Find the first message in the supplied 561470Skas * message list which follows dot. 571470Skas */ 581470Skas 591224Skas for (ip = msgvec; *ip != NULL; ip++) 601224Skas if (*ip > mdot) 611224Skas break; 621224Skas if (*ip == NULL) 631224Skas ip = msgvec; 641224Skas ip2 = ip; 651224Skas do { 661224Skas mp = &message[*ip2 - 1]; 671224Skas if ((mp->m_flag & MDELETED) == 0) { 681224Skas dot = mp; 691224Skas goto hitit; 701224Skas } 711470Skas if (*ip2 != NULL) 721470Skas ip2++; 731470Skas if (*ip2 == NULL) 741470Skas ip2 = msgvec; 751224Skas } while (ip2 != ip); 761224Skas printf("No messages applicable\n"); 771224Skas return(1); 781224Skas } 791224Skas 801224Skas /* 811224Skas * If this is the first command, select message 1. 821224Skas * Note that this must exist for us to get here at all. 831224Skas */ 841224Skas 851481Skas if (!sawcom) 861224Skas goto hitit; 871224Skas 881224Skas /* 891224Skas * Just find the next good message after dot, no 901224Skas * wraparound. 911224Skas */ 921224Skas 931224Skas for (mp = dot+1; mp < &message[msgCount]; mp++) 941224Skas if ((mp->m_flag & (MDELETED|MSAVED)) == 0) 951224Skas break; 961224Skas if (mp >= &message[msgCount]) { 971224Skas printf("At EOF\n"); 981224Skas return(0); 991224Skas } 1001224Skas dot = mp; 1011224Skas hitit: 1021224Skas /* 1031224Skas * Print dot. 1041224Skas */ 1051224Skas 1061224Skas list[0] = dot - &message[0] + 1; 1071224Skas list[1] = NULL; 1081224Skas return(type(list)); 1091224Skas } 1101224Skas 1111224Skas /* 1125776Skurt * Save a message in a file. Mark the message as saved 1135776Skurt * so we can discard when the user quits. 1141224Skas */ 1151224Skas save(str) 1161224Skas char str[]; 1171224Skas { 1185776Skurt 11934969Sedward return save1(str, 1, "save", saveignore); 1205776Skurt } 1215776Skurt 1225776Skurt /* 1235776Skurt * Copy a message to a file without affected its saved-ness 1245776Skurt */ 1255776Skurt copycmd(str) 1265776Skurt char str[]; 1275776Skurt { 1285776Skurt 12934969Sedward return save1(str, 0, "copy", saveignore); 1305776Skurt } 1315776Skurt 1325776Skurt /* 1335776Skurt * Save/copy the indicated messages at the end of the passed file name. 1345776Skurt * If mark is true, mark the message "saved." 1355776Skurt */ 13634969Sedward save1(str, mark, cmd, ignore) 1375776Skurt char str[]; 13834969Sedward char *cmd; 13934969Sedward struct ignoretab *ignore; 1405776Skurt { 14134987Sedward register int *ip; 1421224Skas register struct message *mp; 14334969Sedward char *file, *disp; 14434969Sedward int f, *msgvec; 1451224Skas FILE *obuf; 1461224Skas 1471224Skas msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec); 1481224Skas if ((file = snarf(str, &f)) == NOSTR) 1491224Skas return(1); 1501224Skas if (!f) { 1511224Skas *msgvec = first(0, MMNORM); 1521224Skas if (*msgvec == NULL) { 1535776Skurt printf("No messages to %s.\n", cmd); 1541224Skas return(1); 1551224Skas } 1561224Skas msgvec[1] = NULL; 1571224Skas } 1581224Skas if (f && getmsglist(str, msgvec, 0) < 0) 1591224Skas return(1); 1601224Skas if ((file = expand(file)) == NOSTR) 1611224Skas return(1); 1621224Skas printf("\"%s\" ", file); 16316859Sralph fflush(stdout); 16434969Sedward if (access(file, 0) >= 0) 1651224Skas disp = "[Appended]"; 1661224Skas else 1671224Skas disp = "[New file]"; 1681224Skas if ((obuf = fopen(file, "a")) == NULL) { 1691224Skas perror(NOSTR); 1701224Skas return(1); 1711224Skas } 1721224Skas for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 17334987Sedward mp = &message[*ip - 1]; 17434987Sedward touch(mp); 17534969Sedward if (send(mp, obuf, ignore, NOSTR) < 0) { 1761224Skas perror(file); 1771224Skas fclose(obuf); 1781224Skas return(1); 1791224Skas } 1805776Skurt if (mark) 1815776Skurt mp->m_flag |= MSAVED; 1821224Skas } 1831224Skas fflush(obuf); 1841224Skas if (ferror(obuf)) 1851224Skas perror(file); 1861224Skas fclose(obuf); 18734969Sedward printf("%s\n", disp); 1881224Skas return(0); 1891224Skas } 1901224Skas 1911224Skas /* 1921224Skas * Write the indicated messages at the end of the passed 1931224Skas * file name, minus header and trailing blank line. 1941224Skas */ 1951224Skas 1961224Skas swrite(str) 1971224Skas char str[]; 1981224Skas { 1991224Skas 20034969Sedward return save1(str, 1, "write", ignoreall); 2011224Skas } 2021224Skas 2031224Skas /* 2041224Skas * Snarf the file from the end of the command line and 2051224Skas * return a pointer to it. If there is no file attached, 2061224Skas * just return NOSTR. Put a null in front of the file 2071224Skas * name so that the message list processing won't see it, 2081224Skas * unless the file name is the only thing on the line, in 2091224Skas * which case, return 0 in the reference flag variable. 2101224Skas */ 2111224Skas 2121224Skas char * 2131224Skas snarf(linebuf, flag) 2141224Skas char linebuf[]; 2151224Skas int *flag; 2161224Skas { 2171224Skas register char *cp; 2181224Skas 2191224Skas *flag = 1; 2201224Skas cp = strlen(linebuf) + linebuf - 1; 2211224Skas 2221224Skas /* 2231224Skas * Strip away trailing blanks. 2241224Skas */ 2251224Skas 22631142Sedward while (cp > linebuf && isspace(*cp)) 2271224Skas cp--; 2281224Skas *++cp = 0; 2291224Skas 2301224Skas /* 2311224Skas * Now search for the beginning of the file name. 2321224Skas */ 2331224Skas 23431142Sedward while (cp > linebuf && !isspace(*cp)) 2351224Skas cp--; 2361224Skas if (*cp == '\0') { 2371224Skas printf("No file specified.\n"); 2381224Skas return(NOSTR); 2391224Skas } 24031142Sedward if (isspace(*cp)) 2411224Skas *cp++ = 0; 2421224Skas else 2431224Skas *flag = 0; 2441224Skas return(cp); 2451224Skas } 2461224Skas 2471224Skas /* 2481224Skas * Delete messages. 2491224Skas */ 2501224Skas 2511224Skas delete(msgvec) 2521224Skas int msgvec[]; 2531224Skas { 25436554Sedward delm(msgvec); 25536554Sedward return 0; 2561224Skas } 2571224Skas 2581224Skas /* 2591224Skas * Delete messages, then type the new dot. 2601224Skas */ 2611224Skas 2621224Skas deltype(msgvec) 2631224Skas int msgvec[]; 2641224Skas { 2651224Skas int list[2]; 2664493Skurt int lastdot; 2671224Skas 2684493Skurt lastdot = dot - &message[0] + 1; 2691224Skas if (delm(msgvec) >= 0) { 27034987Sedward list[0] = dot - &message[0] + 1; 2714493Skurt if (list[0] > lastdot) { 27234987Sedward touch(dot); 2734493Skurt list[1] = NULL; 2744493Skurt return(type(list)); 2754493Skurt } 2764493Skurt printf("At EOF\n"); 27736554Sedward } else 2781224Skas printf("No more messages\n"); 27936554Sedward return(0); 2801224Skas } 2811224Skas 2821224Skas /* 2831224Skas * Delete the indicated messages. 2841224Skas * Set dot to some nice place afterwards. 2851224Skas * Internal interface. 2861224Skas */ 2871224Skas 2881224Skas delm(msgvec) 2891224Skas int *msgvec; 2901224Skas { 2911224Skas register struct message *mp; 29234987Sedward register *ip; 2931224Skas int last; 2941224Skas 2951224Skas last = NULL; 2961224Skas for (ip = msgvec; *ip != NULL; ip++) { 29734987Sedward mp = &message[*ip - 1]; 29834987Sedward touch(mp); 2993319Skas mp->m_flag |= MDELETED|MTOUCH; 3003319Skas mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX); 30134987Sedward last = *ip; 3021224Skas } 3031224Skas if (last != NULL) { 3041224Skas dot = &message[last-1]; 3051224Skas last = first(0, MDELETED); 3061224Skas if (last != NULL) { 3071224Skas dot = &message[last-1]; 3081224Skas return(0); 3091224Skas } 3101224Skas else { 3111224Skas dot = &message[0]; 3121224Skas return(-1); 3131224Skas } 3141224Skas } 3151224Skas 3161224Skas /* 3171224Skas * Following can't happen -- it keeps lint happy 3181224Skas */ 3191224Skas 3201224Skas return(-1); 3211224Skas } 3221224Skas 3231224Skas /* 3241224Skas * Undelete the indicated messages. 3251224Skas */ 3261224Skas 3271224Skas undelete(msgvec) 3281224Skas int *msgvec; 3291224Skas { 3301224Skas register struct message *mp; 33134987Sedward register *ip; 3321224Skas 33334987Sedward for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 33434987Sedward mp = &message[*ip - 1]; 33534987Sedward touch(mp); 3361224Skas dot = mp; 3371224Skas mp->m_flag &= ~MDELETED; 3381224Skas } 339*36687Sedward return 0; 3401224Skas } 3411224Skas 3421224Skas /* 3431224Skas * Interactively dump core on "core" 3441224Skas */ 3451224Skas 3461224Skas core() 3471224Skas { 34834976Sedward int pid; 34934976Sedward extern union wait wait_status; 3501224Skas 35134976Sedward switch (pid = vfork()) { 35234976Sedward case -1: 3531224Skas perror("fork"); 3541224Skas return(1); 35534976Sedward case 0: 3561224Skas abort(); 3571224Skas _exit(1); 3581224Skas } 3591224Skas printf("Okie dokie"); 3601224Skas fflush(stdout); 36134976Sedward wait_child(pid); 36234976Sedward if (wait_status.w_coredump) 36334976Sedward printf(" -- Core dumped.\n"); 3641224Skas else 36534976Sedward printf(" -- Can't dump core.\n"); 36631142Sedward return 0; 3671224Skas } 3684340Skurt 3694340Skurt /* 3704340Skurt * Clobber as many bytes of stack as the user requests. 3714340Skurt */ 3724340Skurt clobber(argv) 3734340Skurt char **argv; 3744340Skurt { 3754340Skurt register int times; 3764340Skurt 3774340Skurt if (argv[0] == 0) 3784340Skurt times = 1; 3794340Skurt else 3804340Skurt times = (atoi(argv[0]) + 511) / 512; 3817561Skurt clob1(times); 382*36687Sedward return 0; 3834340Skurt } 3844340Skurt 3854340Skurt /* 3864340Skurt * Clobber the stack. 3874340Skurt */ 3887561Skurt clob1(n) 3894340Skurt { 3904340Skurt char buf[512]; 3914340Skurt register char *cp; 3924340Skurt 3934340Skurt if (n <= 0) 3944340Skurt return; 3954340Skurt for (cp = buf; cp < &buf[512]; *cp++ = 0xFF) 3964340Skurt ; 3977561Skurt clob1(n - 1); 3984340Skurt } 3997573Skurt 4007573Skurt /* 40118662Sserge * Add the given header fields to the retained list. 40218662Sserge * If no arguments, print the current list of retained fields. 40318662Sserge */ 40418662Sserge retfield(list) 40518662Sserge char *list[]; 40618662Sserge { 40718662Sserge 40834692Sedward return ignore1(list, ignore + 1, "retained"); 40918662Sserge } 41018662Sserge 41118662Sserge /* 41234692Sedward * Add the given header fields to the ignored list. 41334692Sedward * If no arguments, print the current list of ignored fields. 41418662Sserge */ 41534692Sedward igfield(list) 41634692Sedward char *list[]; 41718662Sserge { 41818662Sserge 41934692Sedward return ignore1(list, ignore, "ignored"); 42018662Sserge } 42118662Sserge 42234692Sedward saveretfield(list) 4237573Skurt char *list[]; 4247573Skurt { 42534692Sedward 42634692Sedward return ignore1(list, saveignore + 1, "retained"); 42734692Sedward } 42834692Sedward 42934692Sedward saveigfield(list) 43034692Sedward char *list[]; 43134692Sedward { 43234692Sedward 43334692Sedward return ignore1(list, saveignore, "ignored"); 43434692Sedward } 43534692Sedward 43634692Sedward ignore1(list, tab, which) 43734692Sedward char *list[]; 43834692Sedward struct ignoretab *tab; 43934692Sedward char *which; 44034692Sedward { 4417573Skurt char field[BUFSIZ]; 4427573Skurt register int h; 4437573Skurt register struct ignore *igp; 4447573Skurt char **ap; 4457573Skurt 44634987Sedward if (*list == NOSTR) 44734692Sedward return igshow(tab, which); 4487573Skurt for (ap = list; *ap != 0; ap++) { 44934692Sedward istrcpy(field, *ap); 45034692Sedward if (member(field, tab)) 4517582Skurt continue; 4527573Skurt h = hash(field); 4537573Skurt igp = (struct ignore *) calloc(1, sizeof (struct ignore)); 45431142Sedward igp->i_field = calloc((unsigned) strlen(field) + 1, 45531142Sedward sizeof (char)); 4567573Skurt strcpy(igp->i_field, field); 45734692Sedward igp->i_link = tab->i_head[h]; 45834692Sedward tab->i_head[h] = igp; 45934692Sedward tab->i_count++; 4607573Skurt } 46134692Sedward return 0; 4627573Skurt } 4637573Skurt 4647573Skurt /* 46534692Sedward * Print out all currently retained fields. 4667573Skurt */ 46734692Sedward igshow(tab, which) 46834692Sedward struct ignoretab *tab; 46934692Sedward char *which; 4707573Skurt { 47134692Sedward register int h; 4727573Skurt struct ignore *igp; 4737582Skurt char **ap, **ring; 4747582Skurt int igcomp(); 4757573Skurt 47634692Sedward if (tab->i_count == 0) { 47734692Sedward printf("No fields currently being %s.\n", which); 47834692Sedward return 0; 4797582Skurt } 48034692Sedward ring = (char **) salloc((tab->i_count + 1) * sizeof (char *)); 4817582Skurt ap = ring; 4827582Skurt for (h = 0; h < HSHSIZE; h++) 48334692Sedward for (igp = tab->i_head[h]; igp != 0; igp = igp->i_link) 4847582Skurt *ap++ = igp->i_field; 4857582Skurt *ap = 0; 48634692Sedward qsort((char *) ring, tab->i_count, sizeof (char *), igcomp); 4877582Skurt for (ap = ring; *ap != 0; ap++) 4887582Skurt printf("%s\n", *ap); 48934692Sedward return 0; 4907573Skurt } 4917582Skurt 4927582Skurt /* 4937582Skurt * Compare two names for sorting ignored field list. 4947582Skurt */ 4957582Skurt igcomp(l, r) 4967582Skurt char **l, **r; 4977582Skurt { 4987582Skurt 49934692Sedward return strcmp(*l, *r); 5007582Skurt } 501