122445Sdist /*
2*62083Sbostic * Copyright (c) 1980, 1993
3*62083Sbostic * The Regents of the University of California. All rights reserved.
433499Sbostic *
542741Sbostic * %sccs.include.redist.c%
622445Sdist */
722445Sdist
834905Sbostic #ifndef lint
9*62083Sbostic static char sccsid[] = "@(#)cmd2.c 8.1 (Berkeley) 06/06/93";
1034905Sbostic #endif /* not lint */
111224Skas
121224Skas #include "rcv.h"
1331142Sedward #include <sys/wait.h>
1454505Sbostic #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 */
2754505Sbostic int
next(msgvec)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 */
10654505Sbostic int
save(str)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 */
11754505Sbostic int
copycmd(str)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 */
12954505Sbostic int
save1(str,mark,cmd,ignore)13034969Sedward save1(str, mark, cmd, ignore)
1315776Skurt char str[];
13254505Sbostic 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 */
19054505Sbostic int
swrite(str)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 *
snarf(linebuf,flag)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 */
24554505Sbostic int
delete(msgvec)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 */
25654505Sbostic int
deltype(msgvec)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 */
28254505Sbostic int
delm(msgvec)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 */
32154505Sbostic int
undelete(msgvec)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 */
34054505Sbostic int
core()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 */
36754505Sbostic int
clobber(argv)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 */
38454505Sbostic void
clob1(n)3857561Skurt clob1(n)
38654505Sbostic 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 */
40254505Sbostic int
retfield(list)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 */
41454505Sbostic int
igfield(list)41534692Sedward igfield(list)
41634692Sedward char *list[];
41718662Sserge {
41818662Sserge
41934692Sedward return ignore1(list, ignore, "ignored");
42018662Sserge }
42118662Sserge
42254505Sbostic int
saveretfield(list)42334692Sedward saveretfield(list)
4247573Skurt char *list[];
4257573Skurt {
42634692Sedward
42734692Sedward return ignore1(list, saveignore + 1, "retained");
42834692Sedward }
42934692Sedward
43054505Sbostic int
saveigfield(list)43134692Sedward saveigfield(list)
43234692Sedward char *list[];
43334692Sedward {
43434692Sedward
43534692Sedward return ignore1(list, saveignore, "ignored");
43634692Sedward }
43734692Sedward
43854505Sbostic int
ignore1(list,tab,which)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 */
47054505Sbostic int
igshow(tab,which)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;
49054505Sbostic 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 */
49954505Sbostic int
igcomp(l,r)5007582Skurt igcomp(l, r)
50154505Sbostic const void *l, *r;
5027582Skurt {
50354505Sbostic return (strcmp(*(char **)l, *(char **)r));
5047582Skurt }
505