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 6*34905Sbostic * provided that the above copyright notice and this paragraph are 7*34905Sbostic * duplicated in all such forms and that any documentation, 8*34905Sbostic * advertising materials, and other materials related to such 9*34905Sbostic * distribution and use acknowledge that the software was developed 10*34905Sbostic * by the University of California, Berkeley. The name of the 11*34905Sbostic * University may not be used to endorse or promote products derived 12*34905Sbostic * from this software without specific prior written permission. 13*34905Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*34905Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*34905Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1622445Sdist */ 1722445Sdist 18*34905Sbostic #ifndef lint 19*34905Sbostic static char sccsid[] = "@(#)cmd2.c 5.7 (Berkeley) 06/29/88"; 20*34905Sbostic #endif /* not lint */ 211224Skas 221224Skas #include "rcv.h" 231224Skas #include <sys/stat.h> 2431142Sedward #include <sys/wait.h> 251224Skas 261224Skas /* 271224Skas * Mail -- a mail program 281224Skas * 291224Skas * More user commands. 301224Skas */ 311224Skas 321224Skas /* 331224Skas * If any arguments were given, go to the next applicable argument 341224Skas * following dot, otherwise, go to the next applicable message. 351224Skas * If given as first command with no arguments, print first message. 361224Skas */ 371224Skas 381224Skas next(msgvec) 391224Skas int *msgvec; 401224Skas { 411224Skas register struct message *mp; 421224Skas register int *ip, *ip2; 431224Skas int list[2], mdot; 441224Skas 451224Skas if (*msgvec != NULL) { 461224Skas 471224Skas /* 481224Skas * If some messages were supplied, find the 491224Skas * first applicable one following dot using 501224Skas * wrap around. 511224Skas */ 521224Skas 531224Skas mdot = dot - &message[0] + 1; 541470Skas 551470Skas /* 561470Skas * Find the first message in the supplied 571470Skas * message list which follows dot. 581470Skas */ 591470Skas 601224Skas for (ip = msgvec; *ip != NULL; ip++) 611224Skas if (*ip > mdot) 621224Skas break; 631224Skas if (*ip == NULL) 641224Skas ip = msgvec; 651224Skas ip2 = ip; 661224Skas do { 671224Skas mp = &message[*ip2 - 1]; 681224Skas if ((mp->m_flag & MDELETED) == 0) { 691224Skas dot = mp; 701224Skas goto hitit; 711224Skas } 721470Skas if (*ip2 != NULL) 731470Skas ip2++; 741470Skas if (*ip2 == NULL) 751470Skas ip2 = msgvec; 761224Skas } while (ip2 != ip); 771224Skas printf("No messages applicable\n"); 781224Skas return(1); 791224Skas } 801224Skas 811224Skas /* 821224Skas * If this is the first command, select message 1. 831224Skas * Note that this must exist for us to get here at all. 841224Skas */ 851224Skas 861481Skas if (!sawcom) 871224Skas goto hitit; 881224Skas 891224Skas /* 901224Skas * Just find the next good message after dot, no 911224Skas * wraparound. 921224Skas */ 931224Skas 941224Skas for (mp = dot+1; mp < &message[msgCount]; mp++) 951224Skas if ((mp->m_flag & (MDELETED|MSAVED)) == 0) 961224Skas break; 971224Skas if (mp >= &message[msgCount]) { 981224Skas printf("At EOF\n"); 991224Skas return(0); 1001224Skas } 1011224Skas dot = mp; 1021224Skas hitit: 1031224Skas /* 1041224Skas * Print dot. 1051224Skas */ 1061224Skas 1071224Skas list[0] = dot - &message[0] + 1; 1081224Skas list[1] = NULL; 1091224Skas return(type(list)); 1101224Skas } 1111224Skas 1121224Skas /* 1135776Skurt * Save a message in a file. Mark the message as saved 1145776Skurt * so we can discard when the user quits. 1151224Skas */ 1161224Skas save(str) 1171224Skas char str[]; 1181224Skas { 1195776Skurt 1205776Skurt return(save1(str, 1)); 1215776Skurt } 1225776Skurt 1235776Skurt /* 1245776Skurt * Copy a message to a file without affected its saved-ness 1255776Skurt */ 1265776Skurt copycmd(str) 1275776Skurt char str[]; 1285776Skurt { 1295776Skurt 1305776Skurt return(save1(str, 0)); 1315776Skurt } 1325776Skurt 1335776Skurt /* 1345776Skurt * Save/copy the indicated messages at the end of the passed file name. 1355776Skurt * If mark is true, mark the message "saved." 1365776Skurt */ 1375776Skurt save1(str, mark) 1385776Skurt char str[]; 1395776Skurt { 1401224Skas register int *ip, mesg; 1411224Skas register struct message *mp; 1425776Skurt char *file, *disp, *cmd; 1438747Scarl int f, *msgvec, lc, t; 1448747Scarl long cc; 1451224Skas FILE *obuf; 1461224Skas struct stat statb; 1471224Skas 1485776Skurt cmd = mark ? "save" : "copy"; 1491224Skas msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec); 1501224Skas if ((file = snarf(str, &f)) == NOSTR) 1511224Skas return(1); 1521224Skas if (!f) { 1531224Skas *msgvec = first(0, MMNORM); 1541224Skas if (*msgvec == NULL) { 1555776Skurt printf("No messages to %s.\n", cmd); 1561224Skas return(1); 1571224Skas } 1581224Skas msgvec[1] = NULL; 1591224Skas } 1601224Skas if (f && getmsglist(str, msgvec, 0) < 0) 1611224Skas return(1); 1621224Skas if ((file = expand(file)) == NOSTR) 1631224Skas return(1); 1641224Skas printf("\"%s\" ", file); 16516859Sralph fflush(stdout); 1661224Skas if (stat(file, &statb) >= 0) 1671224Skas disp = "[Appended]"; 1681224Skas else 1691224Skas disp = "[New file]"; 1701224Skas if ((obuf = fopen(file, "a")) == NULL) { 1711224Skas perror(NOSTR); 1721224Skas return(1); 1731224Skas } 1748747Scarl cc = 0L; 1758747Scarl lc = 0; 1761224Skas for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 1771224Skas mesg = *ip; 1781224Skas touch(mesg); 1791224Skas mp = &message[mesg-1]; 18034692Sedward if ((t = send(mp, obuf, saveignore)) < 0) { 1811224Skas perror(file); 1821224Skas fclose(obuf); 1831224Skas return(1); 1841224Skas } 1851224Skas lc += t; 1868747Scarl cc += mp->m_size; 1875776Skurt if (mark) 1885776Skurt mp->m_flag |= MSAVED; 1891224Skas } 1901224Skas fflush(obuf); 1911224Skas if (ferror(obuf)) 1921224Skas perror(file); 1931224Skas fclose(obuf); 1948747Scarl printf("%s %d/%ld\n", disp, lc, cc); 1951224Skas return(0); 1961224Skas } 1971224Skas 1981224Skas /* 1991224Skas * Write the indicated messages at the end of the passed 2001224Skas * file name, minus header and trailing blank line. 2011224Skas */ 2021224Skas 2031224Skas swrite(str) 2041224Skas char str[]; 2051224Skas { 2061224Skas register int *ip, mesg; 2071224Skas register struct message *mp; 2081224Skas register char *file, *disp; 2091224Skas char linebuf[BUFSIZ]; 2101224Skas int f, *msgvec, lc, cc, t; 2111224Skas FILE *obuf, *mesf; 2121224Skas struct stat statb; 2131224Skas 2141224Skas msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec); 2151224Skas if ((file = snarf(str, &f)) == NOSTR) 2161224Skas return(1); 2171224Skas if ((file = expand(file)) == NOSTR) 2181224Skas return(1); 2191224Skas if (!f) { 2201224Skas *msgvec = first(0, MMNORM); 2211224Skas if (*msgvec == NULL) { 2221224Skas printf("No messages to write.\n"); 2231224Skas return(1); 2241224Skas } 2251224Skas msgvec[1] = NULL; 2261224Skas } 2271224Skas if (f && getmsglist(str, msgvec, 0) < 0) 2281224Skas return(1); 2291224Skas printf("\"%s\" ", file); 23016859Sralph fflush(stdout); 2311224Skas if (stat(file, &statb) >= 0) 2321224Skas disp = "[Appended]"; 2331224Skas else 2341224Skas disp = "[New file]"; 2351224Skas if ((obuf = fopen(file, "a")) == NULL) { 2361224Skas perror(NOSTR); 2371224Skas return(1); 2381224Skas } 2391224Skas cc = lc = 0; 2401224Skas for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 2411224Skas mesg = *ip; 2421224Skas touch(mesg); 2431224Skas mp = &message[mesg-1]; 2441224Skas mesf = setinput(mp); 24524681Sserge t = mp->m_lines - 1; 2461224Skas while (t-- > 0) { 24724681Sserge readline(mesf, linebuf); 24824681Sserge if (blankline(linebuf)) 24924681Sserge break; 25024681Sserge } 25124681Sserge while (t-- > 0) { 2521224Skas fgets(linebuf, BUFSIZ, mesf); 2531224Skas fputs(linebuf, obuf); 2541224Skas cc += strlen(linebuf); 2551224Skas } 2561224Skas lc += mp->m_lines - 2; 2571224Skas mp->m_flag |= MSAVED; 2581224Skas } 2591224Skas fflush(obuf); 2601224Skas if (ferror(obuf)) 2611224Skas perror(file); 2621224Skas fclose(obuf); 2631224Skas printf("%s %d/%d\n", disp, lc, cc); 2641224Skas return(0); 2651224Skas } 2661224Skas 2671224Skas /* 2681224Skas * Snarf the file from the end of the command line and 2691224Skas * return a pointer to it. If there is no file attached, 2701224Skas * just return NOSTR. Put a null in front of the file 2711224Skas * name so that the message list processing won't see it, 2721224Skas * unless the file name is the only thing on the line, in 2731224Skas * which case, return 0 in the reference flag variable. 2741224Skas */ 2751224Skas 2761224Skas char * 2771224Skas snarf(linebuf, flag) 2781224Skas char linebuf[]; 2791224Skas int *flag; 2801224Skas { 2811224Skas register char *cp; 2821224Skas 2831224Skas *flag = 1; 2841224Skas cp = strlen(linebuf) + linebuf - 1; 2851224Skas 2861224Skas /* 2871224Skas * Strip away trailing blanks. 2881224Skas */ 2891224Skas 29031142Sedward while (cp > linebuf && isspace(*cp)) 2911224Skas cp--; 2921224Skas *++cp = 0; 2931224Skas 2941224Skas /* 2951224Skas * Now search for the beginning of the file name. 2961224Skas */ 2971224Skas 29831142Sedward while (cp > linebuf && !isspace(*cp)) 2991224Skas cp--; 3001224Skas if (*cp == '\0') { 3011224Skas printf("No file specified.\n"); 3021224Skas return(NOSTR); 3031224Skas } 30431142Sedward if (isspace(*cp)) 3051224Skas *cp++ = 0; 3061224Skas else 3071224Skas *flag = 0; 3081224Skas return(cp); 3091224Skas } 3101224Skas 3111224Skas /* 3121224Skas * Delete messages. 3131224Skas */ 3141224Skas 3151224Skas delete(msgvec) 3161224Skas int msgvec[]; 3171224Skas { 3181224Skas return(delm(msgvec)); 3191224Skas } 3201224Skas 3211224Skas /* 3221224Skas * Delete messages, then type the new dot. 3231224Skas */ 3241224Skas 3251224Skas deltype(msgvec) 3261224Skas int msgvec[]; 3271224Skas { 3281224Skas int list[2]; 3294493Skurt int lastdot; 3301224Skas 3314493Skurt lastdot = dot - &message[0] + 1; 3321224Skas if (delm(msgvec) >= 0) { 3331224Skas list[0] = dot - &message[0]; 3341224Skas list[0]++; 3354493Skurt if (list[0] > lastdot) { 3364493Skurt touch(list[0]); 3374493Skurt list[1] = NULL; 3384493Skurt return(type(list)); 3394493Skurt } 3404493Skurt printf("At EOF\n"); 3414493Skurt return(0); 3421224Skas } 3431224Skas else { 3441224Skas printf("No more messages\n"); 3451224Skas return(0); 3461224Skas } 3471224Skas } 3481224Skas 3491224Skas /* 3501224Skas * Delete the indicated messages. 3511224Skas * Set dot to some nice place afterwards. 3521224Skas * Internal interface. 3531224Skas */ 3541224Skas 3551224Skas delm(msgvec) 3561224Skas int *msgvec; 3571224Skas { 3581224Skas register struct message *mp; 3591224Skas register *ip, mesg; 3601224Skas int last; 3611224Skas 3621224Skas last = NULL; 3631224Skas for (ip = msgvec; *ip != NULL; ip++) { 3641224Skas mesg = *ip; 3651224Skas touch(mesg); 3661224Skas mp = &message[mesg-1]; 3673319Skas mp->m_flag |= MDELETED|MTOUCH; 3683319Skas mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX); 3691224Skas last = mesg; 3701224Skas } 3711224Skas if (last != NULL) { 3721224Skas dot = &message[last-1]; 3731224Skas last = first(0, MDELETED); 3741224Skas if (last != NULL) { 3751224Skas dot = &message[last-1]; 3761224Skas return(0); 3771224Skas } 3781224Skas else { 3791224Skas dot = &message[0]; 3801224Skas return(-1); 3811224Skas } 3821224Skas } 3831224Skas 3841224Skas /* 3851224Skas * Following can't happen -- it keeps lint happy 3861224Skas */ 3871224Skas 3881224Skas return(-1); 3891224Skas } 3901224Skas 3911224Skas /* 3921224Skas * Undelete the indicated messages. 3931224Skas */ 3941224Skas 3951224Skas undelete(msgvec) 3961224Skas int *msgvec; 3971224Skas { 3981224Skas register struct message *mp; 3991224Skas register *ip, mesg; 4001224Skas 4011224Skas for (ip = msgvec; ip-msgvec < msgCount; ip++) { 4021224Skas mesg = *ip; 4031224Skas if (mesg == 0) 4041224Skas return; 4051224Skas touch(mesg); 4061224Skas mp = &message[mesg-1]; 4071224Skas dot = mp; 4081224Skas mp->m_flag &= ~MDELETED; 4091224Skas } 4101224Skas } 4111224Skas 4121224Skas /* 4131224Skas * Interactively dump core on "core" 4141224Skas */ 4151224Skas 4161224Skas core() 4171224Skas { 4181224Skas register int pid; 41931142Sedward union wait status; 4201224Skas 4211224Skas if ((pid = vfork()) == -1) { 4221224Skas perror("fork"); 4231224Skas return(1); 4241224Skas } 4251224Skas if (pid == 0) { 4261224Skas abort(); 4271224Skas _exit(1); 4281224Skas } 4291224Skas printf("Okie dokie"); 4301224Skas fflush(stdout); 4311224Skas while (wait(&status) != pid) 4321224Skas ; 43331142Sedward if (status.w_coredump) 4341224Skas printf(" -- Core dumped\n"); 4351224Skas else 4361224Skas printf("\n"); 43731142Sedward return 0; 4381224Skas } 4394340Skurt 4404340Skurt /* 4414340Skurt * Clobber as many bytes of stack as the user requests. 4424340Skurt */ 4434340Skurt clobber(argv) 4444340Skurt char **argv; 4454340Skurt { 4464340Skurt register int times; 4474340Skurt 4484340Skurt if (argv[0] == 0) 4494340Skurt times = 1; 4504340Skurt else 4514340Skurt times = (atoi(argv[0]) + 511) / 512; 4527561Skurt clob1(times); 4534340Skurt } 4544340Skurt 4554340Skurt /* 4564340Skurt * Clobber the stack. 4574340Skurt */ 4587561Skurt clob1(n) 4594340Skurt { 4604340Skurt char buf[512]; 4614340Skurt register char *cp; 4624340Skurt 4634340Skurt if (n <= 0) 4644340Skurt return; 4654340Skurt for (cp = buf; cp < &buf[512]; *cp++ = 0xFF) 4664340Skurt ; 4677561Skurt clob1(n - 1); 4684340Skurt } 4697573Skurt 4707573Skurt /* 47118662Sserge * Add the given header fields to the retained list. 47218662Sserge * If no arguments, print the current list of retained fields. 47318662Sserge */ 47418662Sserge retfield(list) 47518662Sserge char *list[]; 47618662Sserge { 47718662Sserge 47834692Sedward return ignore1(list, ignore + 1, "retained"); 47918662Sserge } 48018662Sserge 48118662Sserge /* 48234692Sedward * Add the given header fields to the ignored list. 48334692Sedward * If no arguments, print the current list of ignored fields. 48418662Sserge */ 48534692Sedward igfield(list) 48634692Sedward char *list[]; 48718662Sserge { 48818662Sserge 48934692Sedward return ignore1(list, ignore, "ignored"); 49018662Sserge } 49118662Sserge 49234692Sedward saveretfield(list) 4937573Skurt char *list[]; 4947573Skurt { 49534692Sedward 49634692Sedward return ignore1(list, saveignore + 1, "retained"); 49734692Sedward } 49834692Sedward 49934692Sedward saveigfield(list) 50034692Sedward char *list[]; 50134692Sedward { 50234692Sedward 50334692Sedward return ignore1(list, saveignore, "ignored"); 50434692Sedward } 50534692Sedward 50634692Sedward ignore1(list, tab, which) 50734692Sedward char *list[]; 50834692Sedward struct ignoretab *tab; 50934692Sedward char *which; 51034692Sedward { 5117573Skurt char field[BUFSIZ]; 5127573Skurt register int h; 5137573Skurt register struct ignore *igp; 5147573Skurt char **ap; 5157573Skurt 5167573Skurt if (argcount(list) == 0) 51734692Sedward return igshow(tab, which); 5187573Skurt for (ap = list; *ap != 0; ap++) { 51934692Sedward istrcpy(field, *ap); 52034692Sedward if (member(field, tab)) 5217582Skurt continue; 5227573Skurt h = hash(field); 5237573Skurt igp = (struct ignore *) calloc(1, sizeof (struct ignore)); 52431142Sedward igp->i_field = calloc((unsigned) strlen(field) + 1, 52531142Sedward sizeof (char)); 5267573Skurt strcpy(igp->i_field, field); 52734692Sedward igp->i_link = tab->i_head[h]; 52834692Sedward tab->i_head[h] = igp; 52934692Sedward tab->i_count++; 5307573Skurt } 53134692Sedward return 0; 5327573Skurt } 5337573Skurt 5347573Skurt /* 53534692Sedward * Print out all currently retained fields. 5367573Skurt */ 53734692Sedward igshow(tab, which) 53834692Sedward struct ignoretab *tab; 53934692Sedward char *which; 5407573Skurt { 54134692Sedward register int h; 5427573Skurt struct ignore *igp; 5437582Skurt char **ap, **ring; 5447582Skurt int igcomp(); 5457573Skurt 54634692Sedward if (tab->i_count == 0) { 54734692Sedward printf("No fields currently being %s.\n", which); 54834692Sedward return 0; 5497582Skurt } 55034692Sedward ring = (char **) salloc((tab->i_count + 1) * sizeof (char *)); 5517582Skurt ap = ring; 5527582Skurt for (h = 0; h < HSHSIZE; h++) 55334692Sedward for (igp = tab->i_head[h]; igp != 0; igp = igp->i_link) 5547582Skurt *ap++ = igp->i_field; 5557582Skurt *ap = 0; 55634692Sedward qsort((char *) ring, tab->i_count, sizeof (char *), igcomp); 5577582Skurt for (ap = ring; *ap != 0; ap++) 5587582Skurt printf("%s\n", *ap); 55934692Sedward return 0; 5607573Skurt } 5617582Skurt 5627582Skurt /* 5637582Skurt * Compare two names for sorting ignored field list. 5647582Skurt */ 5657582Skurt igcomp(l, r) 5667582Skurt char **l, **r; 5677582Skurt { 5687582Skurt 56934692Sedward return strcmp(*l, *r); 5707582Skurt } 571