122445Sdist /* 222445Sdist * Copyright (c) 1980 Regents of the University of California. 333499Sbostic * All rights reserved. 433499Sbostic * 542741Sbostic * %sccs.include.redist.c% 622445Sdist */ 722445Sdist 834905Sbostic #ifndef lint 9*54505Sbostic static char sccsid[] = "@(#)cmd2.c 5.15 (Berkeley) 06/26/92"; 1034905Sbostic #endif /* not lint */ 111224Skas 121224Skas #include "rcv.h" 1331142Sedward #include <sys/wait.h> 14*54505Sbostic #include "extern.h" 151224Skas 161224Skas /* 171224Skas * Mail -- a mail program 181224Skas * 191224Skas * More user commands. 201224Skas */ 211224Skas 221224Skas /* 231224Skas * If any arguments were given, go to the next applicable argument 241224Skas * following dot, otherwise, go to the next applicable message. 251224Skas * If given as first command with no arguments, print first message. 261224Skas */ 27*54505Sbostic int 281224Skas next(msgvec) 291224Skas int *msgvec; 301224Skas { 311224Skas register struct message *mp; 321224Skas register int *ip, *ip2; 331224Skas int list[2], mdot; 341224Skas 351224Skas if (*msgvec != NULL) { 361224Skas 371224Skas /* 381224Skas * If some messages were supplied, find the 391224Skas * first applicable one following dot using 401224Skas * wrap around. 411224Skas */ 421224Skas 431224Skas mdot = dot - &message[0] + 1; 441470Skas 451470Skas /* 461470Skas * Find the first message in the supplied 471470Skas * message list which follows dot. 481470Skas */ 491470Skas 501224Skas for (ip = msgvec; *ip != NULL; ip++) 511224Skas if (*ip > mdot) 521224Skas break; 531224Skas if (*ip == NULL) 541224Skas ip = msgvec; 551224Skas ip2 = ip; 561224Skas do { 571224Skas mp = &message[*ip2 - 1]; 581224Skas if ((mp->m_flag & MDELETED) == 0) { 591224Skas dot = mp; 601224Skas goto hitit; 611224Skas } 621470Skas if (*ip2 != NULL) 631470Skas ip2++; 641470Skas if (*ip2 == NULL) 651470Skas ip2 = msgvec; 661224Skas } while (ip2 != ip); 671224Skas printf("No messages applicable\n"); 681224Skas return(1); 691224Skas } 701224Skas 711224Skas /* 721224Skas * If this is the first command, select message 1. 731224Skas * Note that this must exist for us to get here at all. 741224Skas */ 751224Skas 761481Skas if (!sawcom) 771224Skas goto hitit; 781224Skas 791224Skas /* 801224Skas * Just find the next good message after dot, no 811224Skas * wraparound. 821224Skas */ 831224Skas 841224Skas for (mp = dot+1; mp < &message[msgCount]; mp++) 851224Skas if ((mp->m_flag & (MDELETED|MSAVED)) == 0) 861224Skas break; 871224Skas if (mp >= &message[msgCount]) { 881224Skas printf("At EOF\n"); 891224Skas return(0); 901224Skas } 911224Skas dot = mp; 921224Skas hitit: 931224Skas /* 941224Skas * Print dot. 951224Skas */ 961224Skas 971224Skas list[0] = dot - &message[0] + 1; 981224Skas list[1] = NULL; 991224Skas return(type(list)); 1001224Skas } 1011224Skas 1021224Skas /* 1035776Skurt * Save a message in a file. Mark the message as saved 1045776Skurt * so we can discard when the user quits. 1051224Skas */ 106*54505Sbostic int 1071224Skas save(str) 1081224Skas char str[]; 1091224Skas { 1105776Skurt 11134969Sedward return save1(str, 1, "save", saveignore); 1125776Skurt } 1135776Skurt 1145776Skurt /* 1155776Skurt * Copy a message to a file without affected its saved-ness 1165776Skurt */ 117*54505Sbostic int 1185776Skurt copycmd(str) 1195776Skurt char str[]; 1205776Skurt { 1215776Skurt 12234969Sedward return save1(str, 0, "copy", saveignore); 1235776Skurt } 1245776Skurt 1255776Skurt /* 1265776Skurt * Save/copy the indicated messages at the end of the passed file name. 1275776Skurt * If mark is true, mark the message "saved." 1285776Skurt */ 129*54505Sbostic int 13034969Sedward save1(str, mark, cmd, ignore) 1315776Skurt char str[]; 132*54505Sbostic int mark; 13334969Sedward char *cmd; 13434969Sedward struct ignoretab *ignore; 1355776Skurt { 13634987Sedward register int *ip; 1371224Skas register struct message *mp; 13834969Sedward char *file, *disp; 13934969Sedward int f, *msgvec; 1401224Skas FILE *obuf; 1411224Skas 1421224Skas msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec); 1431224Skas if ((file = snarf(str, &f)) == NOSTR) 1441224Skas return(1); 1451224Skas if (!f) { 1461224Skas *msgvec = first(0, MMNORM); 1471224Skas if (*msgvec == NULL) { 1485776Skurt printf("No messages to %s.\n", cmd); 1491224Skas return(1); 1501224Skas } 1511224Skas msgvec[1] = NULL; 1521224Skas } 1531224Skas if (f && getmsglist(str, msgvec, 0) < 0) 1541224Skas return(1); 1551224Skas if ((file = expand(file)) == NOSTR) 1561224Skas return(1); 1571224Skas printf("\"%s\" ", file); 15816859Sralph fflush(stdout); 15934969Sedward if (access(file, 0) >= 0) 1601224Skas disp = "[Appended]"; 1611224Skas else 1621224Skas disp = "[New file]"; 16343865Sedward if ((obuf = Fopen(file, "a")) == NULL) { 1641224Skas perror(NOSTR); 1651224Skas return(1); 1661224Skas } 1671224Skas for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 16834987Sedward mp = &message[*ip - 1]; 16934987Sedward touch(mp); 17034969Sedward if (send(mp, obuf, ignore, NOSTR) < 0) { 1711224Skas perror(file); 17243865Sedward Fclose(obuf); 1731224Skas return(1); 1741224Skas } 1755776Skurt if (mark) 1765776Skurt mp->m_flag |= MSAVED; 1771224Skas } 1781224Skas fflush(obuf); 1791224Skas if (ferror(obuf)) 1801224Skas perror(file); 18143865Sedward Fclose(obuf); 18234969Sedward printf("%s\n", disp); 1831224Skas return(0); 1841224Skas } 1851224Skas 1861224Skas /* 1871224Skas * Write the indicated messages at the end of the passed 1881224Skas * file name, minus header and trailing blank line. 1891224Skas */ 190*54505Sbostic int 1911224Skas swrite(str) 1921224Skas char str[]; 1931224Skas { 1941224Skas 19534969Sedward return save1(str, 1, "write", ignoreall); 1961224Skas } 1971224Skas 1981224Skas /* 1991224Skas * Snarf the file from the end of the command line and 2001224Skas * return a pointer to it. If there is no file attached, 2011224Skas * just return NOSTR. Put a null in front of the file 2021224Skas * name so that the message list processing won't see it, 2031224Skas * unless the file name is the only thing on the line, in 2041224Skas * which case, return 0 in the reference flag variable. 2051224Skas */ 2061224Skas 2071224Skas char * 2081224Skas snarf(linebuf, flag) 2091224Skas char linebuf[]; 2101224Skas int *flag; 2111224Skas { 2121224Skas register char *cp; 2131224Skas 2141224Skas *flag = 1; 2151224Skas cp = strlen(linebuf) + linebuf - 1; 2161224Skas 2171224Skas /* 2181224Skas * Strip away trailing blanks. 2191224Skas */ 2201224Skas 22131142Sedward while (cp > linebuf && isspace(*cp)) 2221224Skas cp--; 2231224Skas *++cp = 0; 2241224Skas 2251224Skas /* 2261224Skas * Now search for the beginning of the file name. 2271224Skas */ 2281224Skas 22931142Sedward while (cp > linebuf && !isspace(*cp)) 2301224Skas cp--; 2311224Skas if (*cp == '\0') { 2321224Skas printf("No file specified.\n"); 2331224Skas return(NOSTR); 2341224Skas } 23531142Sedward if (isspace(*cp)) 2361224Skas *cp++ = 0; 2371224Skas else 2381224Skas *flag = 0; 2391224Skas return(cp); 2401224Skas } 2411224Skas 2421224Skas /* 2431224Skas * Delete messages. 2441224Skas */ 245*54505Sbostic int 2461224Skas delete(msgvec) 2471224Skas int msgvec[]; 2481224Skas { 24936554Sedward delm(msgvec); 25036554Sedward return 0; 2511224Skas } 2521224Skas 2531224Skas /* 2541224Skas * Delete messages, then type the new dot. 2551224Skas */ 256*54505Sbostic int 2571224Skas deltype(msgvec) 2581224Skas int msgvec[]; 2591224Skas { 2601224Skas int list[2]; 2614493Skurt int lastdot; 2621224Skas 2634493Skurt lastdot = dot - &message[0] + 1; 2641224Skas if (delm(msgvec) >= 0) { 26534987Sedward list[0] = dot - &message[0] + 1; 2664493Skurt if (list[0] > lastdot) { 26734987Sedward touch(dot); 2684493Skurt list[1] = NULL; 2694493Skurt return(type(list)); 2704493Skurt } 2714493Skurt printf("At EOF\n"); 27236554Sedward } else 2731224Skas printf("No more messages\n"); 27436554Sedward return(0); 2751224Skas } 2761224Skas 2771224Skas /* 2781224Skas * Delete the indicated messages. 2791224Skas * Set dot to some nice place afterwards. 2801224Skas * Internal interface. 2811224Skas */ 282*54505Sbostic int 2831224Skas delm(msgvec) 2841224Skas int *msgvec; 2851224Skas { 2861224Skas register struct message *mp; 28734987Sedward register *ip; 2881224Skas int last; 2891224Skas 2901224Skas last = NULL; 2911224Skas for (ip = msgvec; *ip != NULL; ip++) { 29234987Sedward mp = &message[*ip - 1]; 29334987Sedward touch(mp); 2943319Skas mp->m_flag |= MDELETED|MTOUCH; 2953319Skas mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX); 29634987Sedward last = *ip; 2971224Skas } 2981224Skas if (last != NULL) { 2991224Skas dot = &message[last-1]; 3001224Skas last = first(0, MDELETED); 3011224Skas if (last != NULL) { 3021224Skas dot = &message[last-1]; 3031224Skas return(0); 3041224Skas } 3051224Skas else { 3061224Skas dot = &message[0]; 3071224Skas return(-1); 3081224Skas } 3091224Skas } 3101224Skas 3111224Skas /* 3121224Skas * Following can't happen -- it keeps lint happy 3131224Skas */ 3141224Skas 3151224Skas return(-1); 3161224Skas } 3171224Skas 3181224Skas /* 3191224Skas * Undelete the indicated messages. 3201224Skas */ 321*54505Sbostic int 3221224Skas undelete(msgvec) 3231224Skas int *msgvec; 3241224Skas { 3251224Skas register struct message *mp; 32634987Sedward register *ip; 3271224Skas 32834987Sedward for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 32934987Sedward mp = &message[*ip - 1]; 33034987Sedward touch(mp); 3311224Skas dot = mp; 3321224Skas mp->m_flag &= ~MDELETED; 3331224Skas } 33436687Sedward return 0; 3351224Skas } 3361224Skas 3371224Skas /* 3381224Skas * Interactively dump core on "core" 3391224Skas */ 340*54505Sbostic int 3411224Skas core() 3421224Skas { 34334976Sedward int pid; 34434976Sedward extern union wait wait_status; 3451224Skas 34634976Sedward switch (pid = vfork()) { 34734976Sedward case -1: 3481224Skas perror("fork"); 3491224Skas return(1); 35034976Sedward case 0: 3511224Skas abort(); 3521224Skas _exit(1); 3531224Skas } 3541224Skas printf("Okie dokie"); 3551224Skas fflush(stdout); 35634976Sedward wait_child(pid); 35734976Sedward if (wait_status.w_coredump) 35834976Sedward printf(" -- Core dumped.\n"); 3591224Skas else 36034976Sedward printf(" -- Can't dump core.\n"); 36131142Sedward return 0; 3621224Skas } 3634340Skurt 3644340Skurt /* 3654340Skurt * Clobber as many bytes of stack as the user requests. 3664340Skurt */ 367*54505Sbostic int 3684340Skurt clobber(argv) 3694340Skurt char **argv; 3704340Skurt { 3714340Skurt register int times; 3724340Skurt 3734340Skurt if (argv[0] == 0) 3744340Skurt times = 1; 3754340Skurt else 3764340Skurt times = (atoi(argv[0]) + 511) / 512; 3777561Skurt clob1(times); 37836687Sedward return 0; 3794340Skurt } 3804340Skurt 3814340Skurt /* 3824340Skurt * Clobber the stack. 3834340Skurt */ 384*54505Sbostic void 3857561Skurt clob1(n) 386*54505Sbostic int n; 3874340Skurt { 3884340Skurt char buf[512]; 3894340Skurt register char *cp; 3904340Skurt 3914340Skurt if (n <= 0) 3924340Skurt return; 3934340Skurt for (cp = buf; cp < &buf[512]; *cp++ = 0xFF) 3944340Skurt ; 3957561Skurt clob1(n - 1); 3964340Skurt } 3977573Skurt 3987573Skurt /* 39918662Sserge * Add the given header fields to the retained list. 40018662Sserge * If no arguments, print the current list of retained fields. 40118662Sserge */ 402*54505Sbostic int 40318662Sserge retfield(list) 40418662Sserge char *list[]; 40518662Sserge { 40618662Sserge 40734692Sedward return ignore1(list, ignore + 1, "retained"); 40818662Sserge } 40918662Sserge 41018662Sserge /* 41134692Sedward * Add the given header fields to the ignored list. 41234692Sedward * If no arguments, print the current list of ignored fields. 41318662Sserge */ 414*54505Sbostic int 41534692Sedward igfield(list) 41634692Sedward char *list[]; 41718662Sserge { 41818662Sserge 41934692Sedward return ignore1(list, ignore, "ignored"); 42018662Sserge } 42118662Sserge 422*54505Sbostic int 42334692Sedward saveretfield(list) 4247573Skurt char *list[]; 4257573Skurt { 42634692Sedward 42734692Sedward return ignore1(list, saveignore + 1, "retained"); 42834692Sedward } 42934692Sedward 430*54505Sbostic int 43134692Sedward saveigfield(list) 43234692Sedward char *list[]; 43334692Sedward { 43434692Sedward 43534692Sedward return ignore1(list, saveignore, "ignored"); 43634692Sedward } 43734692Sedward 438*54505Sbostic int 43934692Sedward ignore1(list, tab, which) 44034692Sedward char *list[]; 44134692Sedward struct ignoretab *tab; 44234692Sedward char *which; 44334692Sedward { 4447573Skurt char field[BUFSIZ]; 4457573Skurt register int h; 4467573Skurt register struct ignore *igp; 4477573Skurt char **ap; 4487573Skurt 44934987Sedward if (*list == NOSTR) 45034692Sedward return igshow(tab, which); 4517573Skurt for (ap = list; *ap != 0; ap++) { 45234692Sedward istrcpy(field, *ap); 45334692Sedward if (member(field, tab)) 4547582Skurt continue; 4557573Skurt h = hash(field); 4567573Skurt igp = (struct ignore *) calloc(1, sizeof (struct ignore)); 45731142Sedward igp->i_field = calloc((unsigned) strlen(field) + 1, 45831142Sedward sizeof (char)); 4597573Skurt strcpy(igp->i_field, field); 46034692Sedward igp->i_link = tab->i_head[h]; 46134692Sedward tab->i_head[h] = igp; 46234692Sedward tab->i_count++; 4637573Skurt } 46434692Sedward return 0; 4657573Skurt } 4667573Skurt 4677573Skurt /* 46834692Sedward * Print out all currently retained fields. 4697573Skurt */ 470*54505Sbostic int 47134692Sedward igshow(tab, which) 47234692Sedward struct ignoretab *tab; 47334692Sedward char *which; 4747573Skurt { 47534692Sedward register int h; 4767573Skurt struct ignore *igp; 4777582Skurt char **ap, **ring; 4787582Skurt int igcomp(); 4797573Skurt 48034692Sedward if (tab->i_count == 0) { 48134692Sedward printf("No fields currently being %s.\n", which); 48234692Sedward return 0; 4837582Skurt } 48434692Sedward ring = (char **) salloc((tab->i_count + 1) * sizeof (char *)); 4857582Skurt ap = ring; 4867582Skurt for (h = 0; h < HSHSIZE; h++) 48734692Sedward for (igp = tab->i_head[h]; igp != 0; igp = igp->i_link) 4887582Skurt *ap++ = igp->i_field; 4897582Skurt *ap = 0; 490*54505Sbostic qsort(ring, tab->i_count, sizeof (char *), igcomp); 4917582Skurt for (ap = ring; *ap != 0; ap++) 4927582Skurt printf("%s\n", *ap); 49334692Sedward return 0; 4947573Skurt } 4957582Skurt 4967582Skurt /* 4977582Skurt * Compare two names for sorting ignored field list. 4987582Skurt */ 499*54505Sbostic int 5007582Skurt igcomp(l, r) 501*54505Sbostic const void *l, *r; 5027582Skurt { 503*54505Sbostic return (strcmp(*(char **)l, *(char **)r)); 5047582Skurt } 505