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*34969Sedward static char sccsid[] = "@(#)cmd2.c 5.8 (Berkeley) 07/07/88"; 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 119*34969Sedward 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 129*34969Sedward 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 */ 136*34969Sedward save1(str, mark, cmd, ignore) 1375776Skurt char str[]; 138*34969Sedward char *cmd; 139*34969Sedward struct ignoretab *ignore; 1405776Skurt { 1411224Skas register int *ip, mesg; 1421224Skas register struct message *mp; 143*34969Sedward char *file, *disp; 144*34969Sedward 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); 164*34969Sedward 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++) { 1731224Skas mesg = *ip; 1741224Skas touch(mesg); 1751224Skas mp = &message[mesg-1]; 176*34969Sedward if (send(mp, obuf, ignore, NOSTR) < 0) { 1771224Skas perror(file); 1781224Skas fclose(obuf); 1791224Skas return(1); 1801224Skas } 1815776Skurt if (mark) 1825776Skurt mp->m_flag |= MSAVED; 1831224Skas } 1841224Skas fflush(obuf); 1851224Skas if (ferror(obuf)) 1861224Skas perror(file); 1871224Skas fclose(obuf); 188*34969Sedward printf("%s\n", disp); 1891224Skas return(0); 1901224Skas } 1911224Skas 1921224Skas /* 1931224Skas * Write the indicated messages at the end of the passed 1941224Skas * file name, minus header and trailing blank line. 1951224Skas */ 1961224Skas 1971224Skas swrite(str) 1981224Skas char str[]; 1991224Skas { 2001224Skas 201*34969Sedward return save1(str, 1, "write", ignoreall); 2021224Skas } 2031224Skas 2041224Skas /* 2051224Skas * Snarf the file from the end of the command line and 2061224Skas * return a pointer to it. If there is no file attached, 2071224Skas * just return NOSTR. Put a null in front of the file 2081224Skas * name so that the message list processing won't see it, 2091224Skas * unless the file name is the only thing on the line, in 2101224Skas * which case, return 0 in the reference flag variable. 2111224Skas */ 2121224Skas 2131224Skas char * 2141224Skas snarf(linebuf, flag) 2151224Skas char linebuf[]; 2161224Skas int *flag; 2171224Skas { 2181224Skas register char *cp; 2191224Skas 2201224Skas *flag = 1; 2211224Skas cp = strlen(linebuf) + linebuf - 1; 2221224Skas 2231224Skas /* 2241224Skas * Strip away trailing blanks. 2251224Skas */ 2261224Skas 22731142Sedward while (cp > linebuf && isspace(*cp)) 2281224Skas cp--; 2291224Skas *++cp = 0; 2301224Skas 2311224Skas /* 2321224Skas * Now search for the beginning of the file name. 2331224Skas */ 2341224Skas 23531142Sedward while (cp > linebuf && !isspace(*cp)) 2361224Skas cp--; 2371224Skas if (*cp == '\0') { 2381224Skas printf("No file specified.\n"); 2391224Skas return(NOSTR); 2401224Skas } 24131142Sedward if (isspace(*cp)) 2421224Skas *cp++ = 0; 2431224Skas else 2441224Skas *flag = 0; 2451224Skas return(cp); 2461224Skas } 2471224Skas 2481224Skas /* 2491224Skas * Delete messages. 2501224Skas */ 2511224Skas 2521224Skas delete(msgvec) 2531224Skas int msgvec[]; 2541224Skas { 2551224Skas return(delm(msgvec)); 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) { 2701224Skas list[0] = dot - &message[0]; 2711224Skas list[0]++; 2724493Skurt if (list[0] > lastdot) { 2734493Skurt touch(list[0]); 2744493Skurt list[1] = NULL; 2754493Skurt return(type(list)); 2764493Skurt } 2774493Skurt printf("At EOF\n"); 2784493Skurt return(0); 2791224Skas } 2801224Skas else { 2811224Skas printf("No more messages\n"); 2821224Skas return(0); 2831224Skas } 2841224Skas } 2851224Skas 2861224Skas /* 2871224Skas * Delete the indicated messages. 2881224Skas * Set dot to some nice place afterwards. 2891224Skas * Internal interface. 2901224Skas */ 2911224Skas 2921224Skas delm(msgvec) 2931224Skas int *msgvec; 2941224Skas { 2951224Skas register struct message *mp; 2961224Skas register *ip, mesg; 2971224Skas int last; 2981224Skas 2991224Skas last = NULL; 3001224Skas for (ip = msgvec; *ip != NULL; ip++) { 3011224Skas mesg = *ip; 3021224Skas touch(mesg); 3031224Skas mp = &message[mesg-1]; 3043319Skas mp->m_flag |= MDELETED|MTOUCH; 3053319Skas mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX); 3061224Skas last = mesg; 3071224Skas } 3081224Skas if (last != NULL) { 3091224Skas dot = &message[last-1]; 3101224Skas last = first(0, MDELETED); 3111224Skas if (last != NULL) { 3121224Skas dot = &message[last-1]; 3131224Skas return(0); 3141224Skas } 3151224Skas else { 3161224Skas dot = &message[0]; 3171224Skas return(-1); 3181224Skas } 3191224Skas } 3201224Skas 3211224Skas /* 3221224Skas * Following can't happen -- it keeps lint happy 3231224Skas */ 3241224Skas 3251224Skas return(-1); 3261224Skas } 3271224Skas 3281224Skas /* 3291224Skas * Undelete the indicated messages. 3301224Skas */ 3311224Skas 3321224Skas undelete(msgvec) 3331224Skas int *msgvec; 3341224Skas { 3351224Skas register struct message *mp; 3361224Skas register *ip, mesg; 3371224Skas 3381224Skas for (ip = msgvec; ip-msgvec < msgCount; ip++) { 3391224Skas mesg = *ip; 3401224Skas if (mesg == 0) 3411224Skas return; 3421224Skas touch(mesg); 3431224Skas mp = &message[mesg-1]; 3441224Skas dot = mp; 3451224Skas mp->m_flag &= ~MDELETED; 3461224Skas } 3471224Skas } 3481224Skas 3491224Skas /* 3501224Skas * Interactively dump core on "core" 3511224Skas */ 3521224Skas 3531224Skas core() 3541224Skas { 3551224Skas register int pid; 35631142Sedward union wait status; 3571224Skas 3581224Skas if ((pid = vfork()) == -1) { 3591224Skas perror("fork"); 3601224Skas return(1); 3611224Skas } 3621224Skas if (pid == 0) { 3631224Skas abort(); 3641224Skas _exit(1); 3651224Skas } 3661224Skas printf("Okie dokie"); 3671224Skas fflush(stdout); 3681224Skas while (wait(&status) != pid) 3691224Skas ; 37031142Sedward if (status.w_coredump) 3711224Skas printf(" -- Core dumped\n"); 3721224Skas else 3731224Skas printf("\n"); 37431142Sedward return 0; 3751224Skas } 3764340Skurt 3774340Skurt /* 3784340Skurt * Clobber as many bytes of stack as the user requests. 3794340Skurt */ 3804340Skurt clobber(argv) 3814340Skurt char **argv; 3824340Skurt { 3834340Skurt register int times; 3844340Skurt 3854340Skurt if (argv[0] == 0) 3864340Skurt times = 1; 3874340Skurt else 3884340Skurt times = (atoi(argv[0]) + 511) / 512; 3897561Skurt clob1(times); 3904340Skurt } 3914340Skurt 3924340Skurt /* 3934340Skurt * Clobber the stack. 3944340Skurt */ 3957561Skurt clob1(n) 3964340Skurt { 3974340Skurt char buf[512]; 3984340Skurt register char *cp; 3994340Skurt 4004340Skurt if (n <= 0) 4014340Skurt return; 4024340Skurt for (cp = buf; cp < &buf[512]; *cp++ = 0xFF) 4034340Skurt ; 4047561Skurt clob1(n - 1); 4054340Skurt } 4067573Skurt 4077573Skurt /* 40818662Sserge * Add the given header fields to the retained list. 40918662Sserge * If no arguments, print the current list of retained fields. 41018662Sserge */ 41118662Sserge retfield(list) 41218662Sserge char *list[]; 41318662Sserge { 41418662Sserge 41534692Sedward return ignore1(list, ignore + 1, "retained"); 41618662Sserge } 41718662Sserge 41818662Sserge /* 41934692Sedward * Add the given header fields to the ignored list. 42034692Sedward * If no arguments, print the current list of ignored fields. 42118662Sserge */ 42234692Sedward igfield(list) 42334692Sedward char *list[]; 42418662Sserge { 42518662Sserge 42634692Sedward return ignore1(list, ignore, "ignored"); 42718662Sserge } 42818662Sserge 42934692Sedward saveretfield(list) 4307573Skurt char *list[]; 4317573Skurt { 43234692Sedward 43334692Sedward return ignore1(list, saveignore + 1, "retained"); 43434692Sedward } 43534692Sedward 43634692Sedward saveigfield(list) 43734692Sedward char *list[]; 43834692Sedward { 43934692Sedward 44034692Sedward return ignore1(list, saveignore, "ignored"); 44134692Sedward } 44234692Sedward 44334692Sedward ignore1(list, tab, which) 44434692Sedward char *list[]; 44534692Sedward struct ignoretab *tab; 44634692Sedward char *which; 44734692Sedward { 4487573Skurt char field[BUFSIZ]; 4497573Skurt register int h; 4507573Skurt register struct ignore *igp; 4517573Skurt char **ap; 4527573Skurt 4537573Skurt if (argcount(list) == 0) 45434692Sedward return igshow(tab, which); 4557573Skurt for (ap = list; *ap != 0; ap++) { 45634692Sedward istrcpy(field, *ap); 45734692Sedward if (member(field, tab)) 4587582Skurt continue; 4597573Skurt h = hash(field); 4607573Skurt igp = (struct ignore *) calloc(1, sizeof (struct ignore)); 46131142Sedward igp->i_field = calloc((unsigned) strlen(field) + 1, 46231142Sedward sizeof (char)); 4637573Skurt strcpy(igp->i_field, field); 46434692Sedward igp->i_link = tab->i_head[h]; 46534692Sedward tab->i_head[h] = igp; 46634692Sedward tab->i_count++; 4677573Skurt } 46834692Sedward return 0; 4697573Skurt } 4707573Skurt 4717573Skurt /* 47234692Sedward * Print out all currently retained fields. 4737573Skurt */ 47434692Sedward igshow(tab, which) 47534692Sedward struct ignoretab *tab; 47634692Sedward char *which; 4777573Skurt { 47834692Sedward register int h; 4797573Skurt struct ignore *igp; 4807582Skurt char **ap, **ring; 4817582Skurt int igcomp(); 4827573Skurt 48334692Sedward if (tab->i_count == 0) { 48434692Sedward printf("No fields currently being %s.\n", which); 48534692Sedward return 0; 4867582Skurt } 48734692Sedward ring = (char **) salloc((tab->i_count + 1) * sizeof (char *)); 4887582Skurt ap = ring; 4897582Skurt for (h = 0; h < HSHSIZE; h++) 49034692Sedward for (igp = tab->i_head[h]; igp != 0; igp = igp->i_link) 4917582Skurt *ap++ = igp->i_field; 4927582Skurt *ap = 0; 49334692Sedward qsort((char *) ring, tab->i_count, sizeof (char *), igcomp); 4947582Skurt for (ap = ring; *ap != 0; ap++) 4957582Skurt printf("%s\n", *ap); 49634692Sedward return 0; 4977573Skurt } 4987582Skurt 4997582Skurt /* 5007582Skurt * Compare two names for sorting ignored field list. 5017582Skurt */ 5027582Skurt igcomp(l, r) 5037582Skurt char **l, **r; 5047582Skurt { 5057582Skurt 50634692Sedward return strcmp(*l, *r); 5077582Skurt } 508