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*34987Sedward static char sccsid[] = "@(#)cmd2.c 5.10 (Berkeley) 07/08/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 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 { 141*34987Sedward 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++) { 173*34987Sedward mp = &message[*ip - 1]; 174*34987Sedward 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 { 2541224Skas return(delm(msgvec)); 2551224Skas } 2561224Skas 2571224Skas /* 2581224Skas * Delete messages, then type the new dot. 2591224Skas */ 2601224Skas 2611224Skas deltype(msgvec) 2621224Skas int msgvec[]; 2631224Skas { 2641224Skas int list[2]; 2654493Skurt int lastdot; 2661224Skas 2674493Skurt lastdot = dot - &message[0] + 1; 2681224Skas if (delm(msgvec) >= 0) { 269*34987Sedward list[0] = dot - &message[0] + 1; 2704493Skurt if (list[0] > lastdot) { 271*34987Sedward touch(dot); 2724493Skurt list[1] = NULL; 2734493Skurt return(type(list)); 2744493Skurt } 2754493Skurt printf("At EOF\n"); 2764493Skurt return(0); 2771224Skas } 2781224Skas else { 2791224Skas printf("No more messages\n"); 2801224Skas return(0); 2811224Skas } 2821224Skas } 2831224Skas 2841224Skas /* 2851224Skas * Delete the indicated messages. 2861224Skas * Set dot to some nice place afterwards. 2871224Skas * Internal interface. 2881224Skas */ 2891224Skas 2901224Skas delm(msgvec) 2911224Skas int *msgvec; 2921224Skas { 2931224Skas register struct message *mp; 294*34987Sedward register *ip; 2951224Skas int last; 2961224Skas 2971224Skas last = NULL; 2981224Skas for (ip = msgvec; *ip != NULL; ip++) { 299*34987Sedward mp = &message[*ip - 1]; 300*34987Sedward touch(mp); 3013319Skas mp->m_flag |= MDELETED|MTOUCH; 3023319Skas mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX); 303*34987Sedward last = *ip; 3041224Skas } 3051224Skas if (last != NULL) { 3061224Skas dot = &message[last-1]; 3071224Skas last = first(0, MDELETED); 3081224Skas if (last != NULL) { 3091224Skas dot = &message[last-1]; 3101224Skas return(0); 3111224Skas } 3121224Skas else { 3131224Skas dot = &message[0]; 3141224Skas return(-1); 3151224Skas } 3161224Skas } 3171224Skas 3181224Skas /* 3191224Skas * Following can't happen -- it keeps lint happy 3201224Skas */ 3211224Skas 3221224Skas return(-1); 3231224Skas } 3241224Skas 3251224Skas /* 3261224Skas * Undelete the indicated messages. 3271224Skas */ 3281224Skas 3291224Skas undelete(msgvec) 3301224Skas int *msgvec; 3311224Skas { 3321224Skas register struct message *mp; 333*34987Sedward register *ip; 3341224Skas 335*34987Sedward for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 336*34987Sedward mp = &message[*ip - 1]; 337*34987Sedward touch(mp); 3381224Skas dot = mp; 3391224Skas mp->m_flag &= ~MDELETED; 3401224Skas } 3411224Skas } 3421224Skas 3431224Skas /* 3441224Skas * Interactively dump core on "core" 3451224Skas */ 3461224Skas 3471224Skas core() 3481224Skas { 34934976Sedward int pid; 35034976Sedward extern union wait wait_status; 3511224Skas 35234976Sedward switch (pid = vfork()) { 35334976Sedward case -1: 3541224Skas perror("fork"); 3551224Skas return(1); 35634976Sedward case 0: 3571224Skas abort(); 3581224Skas _exit(1); 3591224Skas } 3601224Skas printf("Okie dokie"); 3611224Skas fflush(stdout); 36234976Sedward wait_child(pid); 36334976Sedward if (wait_status.w_coredump) 36434976Sedward printf(" -- Core dumped.\n"); 3651224Skas else 36634976Sedward printf(" -- Can't dump core.\n"); 36731142Sedward return 0; 3681224Skas } 3694340Skurt 3704340Skurt /* 3714340Skurt * Clobber as many bytes of stack as the user requests. 3724340Skurt */ 3734340Skurt clobber(argv) 3744340Skurt char **argv; 3754340Skurt { 3764340Skurt register int times; 3774340Skurt 3784340Skurt if (argv[0] == 0) 3794340Skurt times = 1; 3804340Skurt else 3814340Skurt times = (atoi(argv[0]) + 511) / 512; 3827561Skurt clob1(times); 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 446*34987Sedward 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