11590Srgrimes/* 21590Srgrimes * Copyright (c) 1980, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 4. Neither the name of the University nor the names of its contributors 141590Srgrimes * may be used to endorse or promote products derived from this software 151590Srgrimes * without specific prior written permission. 161590Srgrimes * 171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271590Srgrimes * SUCH DAMAGE. 281590Srgrimes */ 291590Srgrimes 301590Srgrimes#ifndef lint 3174769Smikeh#if 0 321590Srgrimesstatic char sccsid[] = "@(#)cmd2.c 8.1 (Berkeley) 6/6/93"; 3374769Smikeh#endif 341590Srgrimes#endif /* not lint */ 3599112Sobrien#include <sys/cdefs.h> 3699112Sobrien__FBSDID("$FreeBSD$"); 371590Srgrimes 381590Srgrimes#include "rcv.h" 391590Srgrimes#include <sys/wait.h> 401590Srgrimes#include "extern.h" 411590Srgrimes 421590Srgrimes/* 431590Srgrimes * Mail -- a mail program 441590Srgrimes * 451590Srgrimes * More user commands. 461590Srgrimes */ 471590Srgrimes 4877274Smikehextern int wait_status; 4977274Smikeh 501590Srgrimes/* 511590Srgrimes * If any arguments were given, go to the next applicable argument 521590Srgrimes * following dot, otherwise, go to the next applicable message. 531590Srgrimes * If given as first command with no arguments, print first message. 541590Srgrimes */ 551590Srgrimesint 56216564Scharniernext(int *msgvec) 571590Srgrimes{ 5877274Smikeh struct message *mp; 5977274Smikeh int *ip, *ip2, list[2], mdot; 601590Srgrimes 6129574Sphk if (*msgvec != 0) { 621590Srgrimes 631590Srgrimes /* 648874Srgrimes * If some messages were supplied, find the 651590Srgrimes * first applicable one following dot using 661590Srgrimes * wrap around. 671590Srgrimes */ 681590Srgrimes 691590Srgrimes mdot = dot - &message[0] + 1; 701590Srgrimes 711590Srgrimes /* 721590Srgrimes * Find the first message in the supplied 731590Srgrimes * message list which follows dot. 741590Srgrimes */ 751590Srgrimes 7629574Sphk for (ip = msgvec; *ip != 0; ip++) 771590Srgrimes if (*ip > mdot) 781590Srgrimes break; 7929574Sphk if (*ip == 0) 801590Srgrimes ip = msgvec; 811590Srgrimes ip2 = ip; 821590Srgrimes do { 831590Srgrimes mp = &message[*ip2 - 1]; 841590Srgrimes if ((mp->m_flag & MDELETED) == 0) { 851590Srgrimes dot = mp; 861590Srgrimes goto hitit; 871590Srgrimes } 8829574Sphk if (*ip2 != 0) 891590Srgrimes ip2++; 9029574Sphk if (*ip2 == 0) 911590Srgrimes ip2 = msgvec; 921590Srgrimes } while (ip2 != ip); 931590Srgrimes printf("No messages applicable\n"); 9477274Smikeh return (1); 951590Srgrimes } 961590Srgrimes 971590Srgrimes /* 981590Srgrimes * If this is the first command, select message 1. 991590Srgrimes * Note that this must exist for us to get here at all. 1001590Srgrimes */ 1011590Srgrimes 1021590Srgrimes if (!sawcom) 1031590Srgrimes goto hitit; 1041590Srgrimes 1051590Srgrimes /* 1061590Srgrimes * Just find the next good message after dot, no 1071590Srgrimes * wraparound. 1081590Srgrimes */ 1091590Srgrimes 1101590Srgrimes for (mp = dot+1; mp < &message[msgCount]; mp++) 1111590Srgrimes if ((mp->m_flag & (MDELETED|MSAVED)) == 0) 1121590Srgrimes break; 1131590Srgrimes if (mp >= &message[msgCount]) { 1141590Srgrimes printf("At EOF\n"); 11577274Smikeh return (0); 1161590Srgrimes } 1171590Srgrimes dot = mp; 1181590Srgrimeshitit: 1191590Srgrimes /* 1201590Srgrimes * Print dot. 1211590Srgrimes */ 1221590Srgrimes 1231590Srgrimes list[0] = dot - &message[0] + 1; 12429574Sphk list[1] = 0; 12577274Smikeh return (type(list)); 1261590Srgrimes} 1271590Srgrimes 1281590Srgrimes/* 1291590Srgrimes * Save a message in a file. Mark the message as saved 1301590Srgrimes * so we can discard when the user quits. 1311590Srgrimes */ 1321590Srgrimesint 133216564Scharniersave(char str[]) 1341590Srgrimes{ 1351590Srgrimes 13677274Smikeh return (save1(str, 1, "save", saveignore)); 1371590Srgrimes} 1381590Srgrimes 1391590Srgrimes/* 1401590Srgrimes * Copy a message to a file without affected its saved-ness 1411590Srgrimes */ 1421590Srgrimesint 143216564Scharniercopycmd(char str[]) 1441590Srgrimes{ 1451590Srgrimes 14677274Smikeh return (save1(str, 0, "copy", saveignore)); 1471590Srgrimes} 1481590Srgrimes 1491590Srgrimes/* 1501590Srgrimes * Save/copy the indicated messages at the end of the passed file name. 1511590Srgrimes * If mark is true, mark the message "saved." 1521590Srgrimes */ 1531590Srgrimesint 154216564Scharniersave1(char str[], int mark, const char *cmd, struct ignoretab *ignore) 1551590Srgrimes{ 15677274Smikeh struct message *mp; 15777274Smikeh char *file; 15877274Smikeh const char *disp; 15977274Smikeh int f, *msgvec, *ip; 1601590Srgrimes FILE *obuf; 1611590Srgrimes 16277274Smikeh msgvec = (int *)salloc((msgCount + 2) * sizeof(*msgvec)); 16377274Smikeh if ((file = snarf(str, &f)) == NULL) 16477274Smikeh return (1); 1651590Srgrimes if (!f) { 1661590Srgrimes *msgvec = first(0, MMNORM); 16729574Sphk if (*msgvec == 0) { 1681590Srgrimes printf("No messages to %s.\n", cmd); 16977274Smikeh return (1); 1701590Srgrimes } 17129574Sphk msgvec[1] = 0; 1721590Srgrimes } 1731590Srgrimes if (f && getmsglist(str, msgvec, 0) < 0) 17477274Smikeh return (1); 17577274Smikeh if ((file = expand(file)) == NULL) 17677274Smikeh return (1); 1771590Srgrimes printf("\"%s\" ", file); 17877274Smikeh (void)fflush(stdout); 1791590Srgrimes if (access(file, 0) >= 0) 1801590Srgrimes disp = "[Appended]"; 1811590Srgrimes else 1821590Srgrimes disp = "[New file]"; 1831590Srgrimes if ((obuf = Fopen(file, "a")) == NULL) { 18477274Smikeh warn((char *)NULL); 18577274Smikeh return (1); 1861590Srgrimes } 1871590Srgrimes for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 1881590Srgrimes mp = &message[*ip - 1]; 1891590Srgrimes touch(mp); 19077274Smikeh if (sendmessage(mp, obuf, ignore, NULL) < 0) { 19174769Smikeh warnx("%s", file); 19277274Smikeh (void)Fclose(obuf); 19377274Smikeh return (1); 1941590Srgrimes } 1951590Srgrimes if (mark) 1961590Srgrimes mp->m_flag |= MSAVED; 1971590Srgrimes } 19877274Smikeh (void)fflush(obuf); 1991590Srgrimes if (ferror(obuf)) 20074769Smikeh warn("%s", file); 20177274Smikeh (void)Fclose(obuf); 2021590Srgrimes printf("%s\n", disp); 20377274Smikeh return (0); 2041590Srgrimes} 2051590Srgrimes 2061590Srgrimes/* 2071590Srgrimes * Write the indicated messages at the end of the passed 2081590Srgrimes * file name, minus header and trailing blank line. 2091590Srgrimes */ 2101590Srgrimesint 211216564Scharnierswrite(char str[]) 2121590Srgrimes{ 2131590Srgrimes 21477274Smikeh return (save1(str, 1, "write", ignoreall)); 2151590Srgrimes} 2161590Srgrimes 2171590Srgrimes/* 2181590Srgrimes * Snarf the file from the end of the command line and 2191590Srgrimes * return a pointer to it. If there is no file attached, 22077274Smikeh * just return NULL. Put a null in front of the file 2211590Srgrimes * name so that the message list processing won't see it, 2221590Srgrimes * unless the file name is the only thing on the line, in 2231590Srgrimes * which case, return 0 in the reference flag variable. 2241590Srgrimes */ 2251590Srgrimes 2261590Srgrimeschar * 227216564Scharniersnarf(char linebuf[], int *flag) 2281590Srgrimes{ 22977274Smikeh char *cp; 2301590Srgrimes 2311590Srgrimes *flag = 1; 2321590Srgrimes cp = strlen(linebuf) + linebuf - 1; 2331590Srgrimes 2341590Srgrimes /* 2351590Srgrimes * Strip away trailing blanks. 2361590Srgrimes */ 2371590Srgrimes 23888227Sache while (cp > linebuf && isspace((unsigned char)*cp)) 2391590Srgrimes cp--; 24077274Smikeh *++cp = '\0'; 2411590Srgrimes 2421590Srgrimes /* 2431590Srgrimes * Now search for the beginning of the file name. 2441590Srgrimes */ 2451590Srgrimes 24688227Sache while (cp > linebuf && !isspace((unsigned char)*cp)) 2471590Srgrimes cp--; 2481590Srgrimes if (*cp == '\0') { 2491590Srgrimes printf("No file specified.\n"); 25077274Smikeh return (NULL); 2511590Srgrimes } 25288227Sache if (isspace((unsigned char)*cp)) 25377274Smikeh *cp++ = '\0'; 2541590Srgrimes else 2551590Srgrimes *flag = 0; 25677274Smikeh return (cp); 2571590Srgrimes} 2581590Srgrimes 2591590Srgrimes/* 2601590Srgrimes * Delete messages. 2611590Srgrimes */ 2621590Srgrimesint 263216564Scharnierdelete(int msgvec[]) 2641590Srgrimes{ 26577274Smikeh 2661590Srgrimes delm(msgvec); 26777274Smikeh return (0); 2681590Srgrimes} 2691590Srgrimes 2701590Srgrimes/* 2711590Srgrimes * Delete messages, then type the new dot. 2721590Srgrimes */ 2731590Srgrimesint 274216564Scharnierdeltype(int msgvec[]) 2751590Srgrimes{ 2761590Srgrimes int list[2]; 2771590Srgrimes int lastdot; 2781590Srgrimes 2791590Srgrimes lastdot = dot - &message[0] + 1; 2801590Srgrimes if (delm(msgvec) >= 0) { 2811590Srgrimes list[0] = dot - &message[0] + 1; 2821590Srgrimes if (list[0] > lastdot) { 2831590Srgrimes touch(dot); 28429574Sphk list[1] = 0; 28577274Smikeh return (type(list)); 2861590Srgrimes } 2871590Srgrimes printf("At EOF\n"); 2881590Srgrimes } else 2891590Srgrimes printf("No more messages\n"); 29077274Smikeh return (0); 2911590Srgrimes} 2921590Srgrimes 2931590Srgrimes/* 2941590Srgrimes * Delete the indicated messages. 2951590Srgrimes * Set dot to some nice place afterwards. 2961590Srgrimes * Internal interface. 2971590Srgrimes */ 2981590Srgrimesint 299216564Scharnierdelm(int *msgvec) 3001590Srgrimes{ 30177274Smikeh struct message *mp; 30277274Smikeh int *ip, last; 3031590Srgrimes 30429574Sphk last = 0; 30529574Sphk for (ip = msgvec; *ip != 0; ip++) { 3061590Srgrimes mp = &message[*ip - 1]; 3071590Srgrimes touch(mp); 3081590Srgrimes mp->m_flag |= MDELETED|MTOUCH; 3091590Srgrimes mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX); 3101590Srgrimes last = *ip; 3111590Srgrimes } 31229574Sphk if (last != 0) { 3131590Srgrimes dot = &message[last-1]; 3141590Srgrimes last = first(0, MDELETED); 31529574Sphk if (last != 0) { 3161590Srgrimes dot = &message[last-1]; 31777274Smikeh return (0); 3181590Srgrimes } 3191590Srgrimes else { 3201590Srgrimes dot = &message[0]; 32177274Smikeh return (-1); 3221590Srgrimes } 3231590Srgrimes } 3241590Srgrimes 3251590Srgrimes /* 3261590Srgrimes * Following can't happen -- it keeps lint happy 3271590Srgrimes */ 3281590Srgrimes 32977274Smikeh return (-1); 3301590Srgrimes} 3311590Srgrimes 3321590Srgrimes/* 3331590Srgrimes * Undelete the indicated messages. 3341590Srgrimes */ 3351590Srgrimesint 336216564Scharnierundelete_messages(int *msgvec) 3371590Srgrimes{ 33877274Smikeh struct message *mp; 33977274Smikeh int *ip; 3401590Srgrimes 3411590Srgrimes for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 3421590Srgrimes mp = &message[*ip - 1]; 3431590Srgrimes touch(mp); 3441590Srgrimes dot = mp; 3451590Srgrimes mp->m_flag &= ~MDELETED; 3461590Srgrimes } 34777274Smikeh return (0); 3481590Srgrimes} 3491590Srgrimes 3501590Srgrimes/* 3511590Srgrimes * Interactively dump core on "core" 3521590Srgrimes */ 3531590Srgrimesint 354216564Scharniercore(void) 3551590Srgrimes{ 3561590Srgrimes int pid; 3571590Srgrimes 35840189Sbde switch (pid = fork()) { 3591590Srgrimes case -1: 36074769Smikeh warn("fork"); 36177274Smikeh return (1); 3621590Srgrimes case 0: 3631590Srgrimes abort(); 3641590Srgrimes _exit(1); 3651590Srgrimes } 3661590Srgrimes printf("Okie dokie"); 36777274Smikeh (void)fflush(stdout); 3681590Srgrimes wait_child(pid); 36974769Smikeh if (WIFSIGNALED(wait_status) && WCOREDUMP(wait_status)) 3701590Srgrimes printf(" -- Core dumped.\n"); 3711590Srgrimes else 3721590Srgrimes printf(" -- Can't dump core.\n"); 37377274Smikeh return (0); 3741590Srgrimes} 3751590Srgrimes 3761590Srgrimes/* 3771590Srgrimes * Clobber as many bytes of stack as the user requests. 3781590Srgrimes */ 3791590Srgrimesint 380216564Scharnierclobber(char **argv) 3811590Srgrimes{ 38277274Smikeh int times; 3831590Srgrimes 3841590Srgrimes if (argv[0] == 0) 3851590Srgrimes times = 1; 3861590Srgrimes else 3871590Srgrimes times = (atoi(argv[0]) + 511) / 512; 3881590Srgrimes clob1(times); 38977274Smikeh return (0); 3901590Srgrimes} 3911590Srgrimes 3921590Srgrimes/* 3931590Srgrimes * Clobber the stack. 3941590Srgrimes */ 3951590Srgrimesvoid 396216564Scharnierclob1(int n) 3971590Srgrimes{ 3981590Srgrimes char buf[512]; 39977274Smikeh char *cp; 4001590Srgrimes 4011590Srgrimes if (n <= 0) 4021590Srgrimes return; 4031590Srgrimes for (cp = buf; cp < &buf[512]; *cp++ = 0xFF) 4041590Srgrimes ; 4051590Srgrimes clob1(n - 1); 4061590Srgrimes} 4071590Srgrimes 4081590Srgrimes/* 4091590Srgrimes * Add the given header fields to the retained list. 4101590Srgrimes * If no arguments, print the current list of retained fields. 4111590Srgrimes */ 4121590Srgrimesint 413216564Scharnierretfield(char *list[]) 4141590Srgrimes{ 4151590Srgrimes 41677274Smikeh return (ignore1(list, ignore + 1, "retained")); 4171590Srgrimes} 4181590Srgrimes 4191590Srgrimes/* 4201590Srgrimes * Add the given header fields to the ignored list. 4211590Srgrimes * If no arguments, print the current list of ignored fields. 4221590Srgrimes */ 4231590Srgrimesint 424216564Scharnierigfield(char *list[]) 4251590Srgrimes{ 4261590Srgrimes 42777274Smikeh return (ignore1(list, ignore, "ignored")); 4281590Srgrimes} 4291590Srgrimes 4301590Srgrimesint 431216564Scharniersaveretfield(char *list[]) 4321590Srgrimes{ 4331590Srgrimes 43477274Smikeh return (ignore1(list, saveignore + 1, "retained")); 4351590Srgrimes} 4361590Srgrimes 4371590Srgrimesint 438216564Scharniersaveigfield(char *list[]) 4391590Srgrimes{ 4401590Srgrimes 44177274Smikeh return (ignore1(list, saveignore, "ignored")); 4421590Srgrimes} 4431590Srgrimes 4441590Srgrimesint 445216564Scharnierignore1(char *list[], struct ignoretab *tab, const char *which) 4461590Srgrimes{ 44774769Smikeh char field[LINESIZE]; 44877274Smikeh int h; 44977274Smikeh struct ignore *igp; 4501590Srgrimes char **ap; 4511590Srgrimes 45277274Smikeh if (*list == NULL) 45377274Smikeh return (igshow(tab, which)); 4541590Srgrimes for (ap = list; *ap != 0; ap++) { 45574769Smikeh istrncpy(field, *ap, sizeof(field)); 4561590Srgrimes if (member(field, tab)) 4571590Srgrimes continue; 4581590Srgrimes h = hash(field); 45977274Smikeh igp = calloc(1, sizeof(struct ignore)); 46077274Smikeh igp->i_field = calloc((unsigned)strlen(field) + 1, 46177274Smikeh sizeof(char)); 4621590Srgrimes strcpy(igp->i_field, field); 4631590Srgrimes igp->i_link = tab->i_head[h]; 4641590Srgrimes tab->i_head[h] = igp; 4651590Srgrimes tab->i_count++; 4661590Srgrimes } 46777274Smikeh return (0); 4681590Srgrimes} 4691590Srgrimes 4701590Srgrimes/* 4711590Srgrimes * Print out all currently retained fields. 4721590Srgrimes */ 4731590Srgrimesint 474216564Scharnierigshow(struct ignoretab *tab, const char *which) 4751590Srgrimes{ 47677274Smikeh int h; 4771590Srgrimes struct ignore *igp; 4781590Srgrimes char **ap, **ring; 4791590Srgrimes 4801590Srgrimes if (tab->i_count == 0) { 4811590Srgrimes printf("No fields currently being %s.\n", which); 48277274Smikeh return (0); 4831590Srgrimes } 48477274Smikeh ring = (char **)salloc((tab->i_count + 1) * sizeof(char *)); 4851590Srgrimes ap = ring; 4861590Srgrimes for (h = 0; h < HSHSIZE; h++) 48777274Smikeh for (igp = tab->i_head[h]; igp != NULL; igp = igp->i_link) 4881590Srgrimes *ap++ = igp->i_field; 4891590Srgrimes *ap = 0; 49077274Smikeh qsort(ring, tab->i_count, sizeof(char *), igcomp); 4911590Srgrimes for (ap = ring; *ap != 0; ap++) 4921590Srgrimes printf("%s\n", *ap); 49377274Smikeh return (0); 4941590Srgrimes} 4951590Srgrimes 4961590Srgrimes/* 4971590Srgrimes * Compare two names for sorting ignored field list. 4981590Srgrimes */ 4991590Srgrimesint 500216564Scharnierigcomp(const void *l, const void *r) 5011590Srgrimes{ 50277274Smikeh 50377274Smikeh return (strcmp(*(const char **)l, *(const char **)r)); 5041590Srgrimes} 505