cmd1.c revision 74769
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 * 3. All advertising materials mentioning features or use of this software 141590Srgrimes * must display the following acknowledgement: 151590Srgrimes * This product includes software developed by the University of 161590Srgrimes * California, Berkeley and its contributors. 171590Srgrimes * 4. Neither the name of the University nor the names of its contributors 181590Srgrimes * may be used to endorse or promote products derived from this software 191590Srgrimes * without specific prior written permission. 201590Srgrimes * 211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311590Srgrimes * SUCH DAMAGE. 321590Srgrimes */ 331590Srgrimes 341590Srgrimes#ifndef lint 3574769Smikeh#if 0 361590Srgrimesstatic char sccsid[] = "@(#)cmd1.c 8.1 (Berkeley) 6/6/93"; 3774769Smikeh#endif 3874769Smikehstatic const char rcsid[] = 3974769Smikeh "$FreeBSD: head/usr.bin/mail/cmd1.c 74769 2001-03-25 04:57:05Z mikeh $"; 401590Srgrimes#endif /* not lint */ 411590Srgrimes 421590Srgrimes#include "rcv.h" 431590Srgrimes#include "extern.h" 441590Srgrimes 451590Srgrimes/* 461590Srgrimes * Mail -- a mail program 471590Srgrimes * 481590Srgrimes * User commands. 491590Srgrimes */ 501590Srgrimes 511590Srgrimes/* 521590Srgrimes * Print the current active headings. 531590Srgrimes * Don't change dot if invoker didn't give an argument. 541590Srgrimes */ 551590Srgrimes 561590Srgrimesstatic int screen; 571590Srgrimes 581590Srgrimesint 591590Srgrimesheaders(msgvec) 601590Srgrimes int *msgvec; 611590Srgrimes{ 621590Srgrimes register int n, mesg, flag; 631590Srgrimes register struct message *mp; 641590Srgrimes int size; 651590Srgrimes 661590Srgrimes size = screensize(); 671590Srgrimes n = msgvec[0]; 681590Srgrimes if (n != 0) 691590Srgrimes screen = (n-1)/size; 701590Srgrimes if (screen < 0) 711590Srgrimes screen = 0; 721590Srgrimes mp = &message[screen * size]; 731590Srgrimes if (mp >= &message[msgCount]) 741590Srgrimes mp = &message[msgCount - size]; 751590Srgrimes if (mp < &message[0]) 761590Srgrimes mp = &message[0]; 771590Srgrimes flag = 0; 781590Srgrimes mesg = mp - &message[0]; 791590Srgrimes if (dot != &message[n-1]) 801590Srgrimes dot = mp; 811590Srgrimes for (; mp < &message[msgCount]; mp++) { 821590Srgrimes mesg++; 831590Srgrimes if (mp->m_flag & MDELETED) 841590Srgrimes continue; 851590Srgrimes if (flag++ >= size) 861590Srgrimes break; 871590Srgrimes printhead(mesg); 881590Srgrimes } 891590Srgrimes if (flag == 0) { 901590Srgrimes printf("No more mail.\n"); 911590Srgrimes return(1); 921590Srgrimes } 931590Srgrimes return(0); 941590Srgrimes} 951590Srgrimes 961590Srgrimes/* 971590Srgrimes * Scroll to the next/previous screen 981590Srgrimes */ 991590Srgrimesint 1001590Srgrimesscroll(arg) 1011590Srgrimes char arg[]; 1021590Srgrimes{ 1031590Srgrimes register int s, size; 1041590Srgrimes int cur[1]; 1051590Srgrimes 1061590Srgrimes cur[0] = 0; 1071590Srgrimes size = screensize(); 1081590Srgrimes s = screen; 1091590Srgrimes switch (*arg) { 1101590Srgrimes case 0: 1111590Srgrimes case '+': 1121590Srgrimes s++; 1131590Srgrimes if (s * size > msgCount) { 1141590Srgrimes printf("On last screenful of messages\n"); 1151590Srgrimes return(0); 1161590Srgrimes } 1171590Srgrimes screen = s; 1181590Srgrimes break; 1191590Srgrimes 1201590Srgrimes case '-': 1211590Srgrimes if (--s < 0) { 1221590Srgrimes printf("On first screenful of messages\n"); 1231590Srgrimes return(0); 1241590Srgrimes } 1251590Srgrimes screen = s; 1261590Srgrimes break; 1271590Srgrimes 1281590Srgrimes default: 1291590Srgrimes printf("Unrecognized scrolling command \"%s\"\n", arg); 1301590Srgrimes return(1); 1311590Srgrimes } 1321590Srgrimes return(headers(cur)); 1331590Srgrimes} 1341590Srgrimes 1351590Srgrimes/* 1361590Srgrimes * Compute screen size. 1371590Srgrimes */ 1381590Srgrimesint 1391590Srgrimesscreensize() 1401590Srgrimes{ 1411590Srgrimes int s; 1421590Srgrimes char *cp; 1431590Srgrimes 1441590Srgrimes if ((cp = value("screen")) != NOSTR && (s = atoi(cp)) > 0) 1451590Srgrimes return s; 1461590Srgrimes return screenheight - 4; 1471590Srgrimes} 1481590Srgrimes 1491590Srgrimes/* 1501590Srgrimes * Print out the headlines for each message 1511590Srgrimes * in the passed message list. 1521590Srgrimes */ 1531590Srgrimesint 1541590Srgrimesfrom(msgvec) 1551590Srgrimes int *msgvec; 1561590Srgrimes{ 1571590Srgrimes register int *ip; 1581590Srgrimes 15929574Sphk for (ip = msgvec; *ip != 0; ip++) 1601590Srgrimes printhead(*ip); 1611590Srgrimes if (--ip >= msgvec) 1621590Srgrimes dot = &message[*ip - 1]; 1631590Srgrimes return(0); 1641590Srgrimes} 1651590Srgrimes 1661590Srgrimes/* 1671590Srgrimes * Print out the header of a specific message. 1681590Srgrimes * This is a slight improvement to the standard one. 1691590Srgrimes */ 1701590Srgrimesvoid 1711590Srgrimesprinthead(mesg) 1721590Srgrimes int mesg; 1731590Srgrimes{ 1741590Srgrimes struct message *mp; 1751590Srgrimes char headline[LINESIZE], wcount[LINESIZE], *subjline, dispc, curind; 1761590Srgrimes char pbuf[BUFSIZ]; 1771590Srgrimes struct headline hl; 1781590Srgrimes int subjlen; 1791590Srgrimes char *name; 1801590Srgrimes 1811590Srgrimes mp = &message[mesg-1]; 1821590Srgrimes (void) readline(setinput(mp), headline, LINESIZE); 1831590Srgrimes if ((subjline = hfield("subject", mp)) == NOSTR) 1841590Srgrimes subjline = hfield("subj", mp); 1851590Srgrimes /* 1861590Srgrimes * Bletch! 1871590Srgrimes */ 1881590Srgrimes curind = dot == mp ? '>' : ' '; 1891590Srgrimes dispc = ' '; 1901590Srgrimes if (mp->m_flag & MSAVED) 1911590Srgrimes dispc = '*'; 1921590Srgrimes if (mp->m_flag & MPRESERVE) 1931590Srgrimes dispc = 'P'; 1941590Srgrimes if ((mp->m_flag & (MREAD|MNEW)) == MNEW) 1951590Srgrimes dispc = 'N'; 1961590Srgrimes if ((mp->m_flag & (MREAD|MNEW)) == 0) 1971590Srgrimes dispc = 'U'; 1981590Srgrimes if (mp->m_flag & MBOX) 1991590Srgrimes dispc = 'M'; 2001590Srgrimes parse(headline, &hl, pbuf); 20137453Sbde sprintf(wcount, "%3ld/%-5ld", mp->m_lines, mp->m_size); 2021590Srgrimes subjlen = screenwidth - 50 - strlen(wcount); 2031590Srgrimes name = value("show-rcpt") != NOSTR ? 2041590Srgrimes skin(hfield("to", mp)) : nameof(mp, 0); 2051590Srgrimes if (subjline == NOSTR || subjlen < 0) /* pretty pathetic */ 2061590Srgrimes printf("%c%c%3d %-20.20s %16.16s %s\n", 2071590Srgrimes curind, dispc, mesg, name, hl.l_date, wcount); 2081590Srgrimes else 2091590Srgrimes printf("%c%c%3d %-20.20s %16.16s %s \"%.*s\"\n", 2101590Srgrimes curind, dispc, mesg, name, hl.l_date, wcount, 2111590Srgrimes subjlen, subjline); 2121590Srgrimes} 2131590Srgrimes 2141590Srgrimes/* 2151590Srgrimes * Print out the value of dot. 2161590Srgrimes */ 2171590Srgrimesint 2181590Srgrimespdot() 2191590Srgrimes{ 2201590Srgrimes printf("%d\n", dot - &message[0] + 1); 2211590Srgrimes return(0); 2221590Srgrimes} 2231590Srgrimes 2241590Srgrimes/* 2251590Srgrimes * Print out all the possible commands. 2261590Srgrimes */ 2271590Srgrimesint 2281590Srgrimespcmdlist() 2291590Srgrimes{ 2301590Srgrimes register struct cmd *cp; 2311590Srgrimes register int cc; 2321590Srgrimes extern struct cmd cmdtab[]; 2331590Srgrimes 2341590Srgrimes printf("Commands are:\n"); 2351590Srgrimes for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) { 2361590Srgrimes cc += strlen(cp->c_name) + 2; 2371590Srgrimes if (cc > 72) { 2381590Srgrimes printf("\n"); 2391590Srgrimes cc = strlen(cp->c_name) + 2; 2401590Srgrimes } 2411590Srgrimes if ((cp+1)->c_name != NOSTR) 2421590Srgrimes printf("%s, ", cp->c_name); 2431590Srgrimes else 2441590Srgrimes printf("%s\n", cp->c_name); 2451590Srgrimes } 2461590Srgrimes return(0); 2471590Srgrimes} 2481590Srgrimes 2491590Srgrimes/* 2501590Srgrimes * Paginate messages, honor ignored fields. 2511590Srgrimes */ 2521590Srgrimesint 2531590Srgrimesmore(msgvec) 2541590Srgrimes int *msgvec; 2551590Srgrimes{ 2561590Srgrimes return (type1(msgvec, 1, 1)); 2571590Srgrimes} 2581590Srgrimes 2591590Srgrimes/* 2601590Srgrimes * Paginate messages, even printing ignored fields. 2611590Srgrimes */ 2621590Srgrimesint 2631590SrgrimesMore(msgvec) 2641590Srgrimes int *msgvec; 2651590Srgrimes{ 2661590Srgrimes 2671590Srgrimes return (type1(msgvec, 0, 1)); 2681590Srgrimes} 2691590Srgrimes 2701590Srgrimes/* 2711590Srgrimes * Type out messages, honor ignored fields. 2721590Srgrimes */ 2731590Srgrimesint 2741590Srgrimestype(msgvec) 2751590Srgrimes int *msgvec; 2761590Srgrimes{ 2771590Srgrimes 2781590Srgrimes return(type1(msgvec, 1, 0)); 2791590Srgrimes} 2801590Srgrimes 2811590Srgrimes/* 2821590Srgrimes * Type out messages, even printing ignored fields. 2831590Srgrimes */ 2841590Srgrimesint 2851590SrgrimesType(msgvec) 2861590Srgrimes int *msgvec; 2871590Srgrimes{ 2881590Srgrimes 2891590Srgrimes return(type1(msgvec, 0, 0)); 2901590Srgrimes} 2911590Srgrimes 2921590Srgrimes/* 2931590Srgrimes * Type out the messages requested. 2941590Srgrimes */ 2951590Srgrimesjmp_buf pipestop; 2961590Srgrimesint 2971590Srgrimestype1(msgvec, doign, page) 2981590Srgrimes int *msgvec; 2991590Srgrimes int doign, page; 3001590Srgrimes{ 3011590Srgrimes register *ip; 3021590Srgrimes register struct message *mp; 3031590Srgrimes register char *cp; 3041590Srgrimes int nlines; 3051590Srgrimes FILE *obuf; 3061590Srgrimes 3071590Srgrimes obuf = stdout; 3081590Srgrimes if (setjmp(pipestop)) 3091590Srgrimes goto close_pipe; 3101590Srgrimes if (value("interactive") != NOSTR && 3111590Srgrimes (page || (cp = value("crt")) != NOSTR)) { 3121590Srgrimes nlines = 0; 3131590Srgrimes if (!page) { 3141590Srgrimes for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) 3151590Srgrimes nlines += message[*ip - 1].m_lines; 3161590Srgrimes } 3171590Srgrimes if (page || nlines > (*cp ? atoi(cp) : realscreenheight)) { 3181590Srgrimes cp = value("PAGER"); 3191590Srgrimes if (cp == NULL || *cp == '\0') 3201590Srgrimes cp = _PATH_MORE; 3211590Srgrimes obuf = Popen(cp, "w"); 3221590Srgrimes if (obuf == NULL) { 32374769Smikeh warnx("%s", cp); 3241590Srgrimes obuf = stdout; 3251590Srgrimes } else 3261590Srgrimes signal(SIGPIPE, brokpipe); 3271590Srgrimes } 3281590Srgrimes } 3291590Srgrimes for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) { 3301590Srgrimes mp = &message[*ip - 1]; 3311590Srgrimes touch(mp); 3321590Srgrimes dot = mp; 3331590Srgrimes if (value("quiet") == NOSTR) 3341590Srgrimes fprintf(obuf, "Message %d:\n", *ip); 33574769Smikeh (void) sendmessage(mp, obuf, doign ? ignore : 0, NOSTR); 3361590Srgrimes } 3371590Srgrimesclose_pipe: 3381590Srgrimes if (obuf != stdout) { 3391590Srgrimes /* 3401590Srgrimes * Ignore SIGPIPE so it can't cause a duplicate close. 3411590Srgrimes */ 3421590Srgrimes signal(SIGPIPE, SIG_IGN); 3431590Srgrimes Pclose(obuf); 3441590Srgrimes signal(SIGPIPE, SIG_DFL); 3451590Srgrimes } 3461590Srgrimes return(0); 3471590Srgrimes} 3481590Srgrimes 3491590Srgrimes/* 3501590Srgrimes * Respond to a broken pipe signal -- 3511590Srgrimes * probably caused by quitting more. 3521590Srgrimes */ 3531590Srgrimesvoid 3541590Srgrimesbrokpipe(signo) 3551590Srgrimes int signo; 3561590Srgrimes{ 3571590Srgrimes longjmp(pipestop, 1); 3581590Srgrimes} 3591590Srgrimes 3601590Srgrimes/* 3611590Srgrimes * Print the top so many lines of each desired message. 3621590Srgrimes * The number of lines is taken from the variable "toplines" 3631590Srgrimes * and defaults to 5. 3641590Srgrimes */ 3651590Srgrimesint 3661590Srgrimestop(msgvec) 3671590Srgrimes int *msgvec; 3681590Srgrimes{ 3691590Srgrimes register int *ip; 3701590Srgrimes register struct message *mp; 3711590Srgrimes int c, topl, lines, lineb; 3721590Srgrimes char *valtop, linebuf[LINESIZE]; 3731590Srgrimes FILE *ibuf; 3741590Srgrimes 3751590Srgrimes topl = 5; 3761590Srgrimes valtop = value("toplines"); 3771590Srgrimes if (valtop != NOSTR) { 3781590Srgrimes topl = atoi(valtop); 3791590Srgrimes if (topl < 0 || topl > 10000) 3801590Srgrimes topl = 5; 3811590Srgrimes } 3821590Srgrimes lineb = 1; 3831590Srgrimes for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 3841590Srgrimes mp = &message[*ip - 1]; 3851590Srgrimes touch(mp); 3861590Srgrimes dot = mp; 3871590Srgrimes if (value("quiet") == NOSTR) 3881590Srgrimes printf("Message %d:\n", *ip); 3891590Srgrimes ibuf = setinput(mp); 3901590Srgrimes c = mp->m_lines; 3911590Srgrimes if (!lineb) 3921590Srgrimes printf("\n"); 3931590Srgrimes for (lines = 0; lines < c && lines <= topl; lines++) { 39474769Smikeh if (readline(ibuf, linebuf, sizeof(linebuf)) < 0) 3951590Srgrimes break; 3961590Srgrimes puts(linebuf); 39774769Smikeh lineb = strspn(linebuf, " \t") == strlen(linebuf); 3981590Srgrimes } 3991590Srgrimes } 4001590Srgrimes return(0); 4011590Srgrimes} 4021590Srgrimes 4031590Srgrimes/* 4041590Srgrimes * Touch all the given messages so that they will 4051590Srgrimes * get mboxed. 4061590Srgrimes */ 4071590Srgrimesint 4081590Srgrimesstouch(msgvec) 4091590Srgrimes int msgvec[]; 4101590Srgrimes{ 4111590Srgrimes register int *ip; 4121590Srgrimes 4131590Srgrimes for (ip = msgvec; *ip != 0; ip++) { 4141590Srgrimes dot = &message[*ip-1]; 4151590Srgrimes dot->m_flag |= MTOUCH; 4161590Srgrimes dot->m_flag &= ~MPRESERVE; 4171590Srgrimes } 4181590Srgrimes return(0); 4191590Srgrimes} 4201590Srgrimes 4211590Srgrimes/* 4221590Srgrimes * Make sure all passed messages get mboxed. 4231590Srgrimes */ 4241590Srgrimesint 4251590Srgrimesmboxit(msgvec) 4261590Srgrimes int msgvec[]; 4271590Srgrimes{ 4281590Srgrimes register int *ip; 4291590Srgrimes 4301590Srgrimes for (ip = msgvec; *ip != 0; ip++) { 4311590Srgrimes dot = &message[*ip-1]; 4321590Srgrimes dot->m_flag |= MTOUCH|MBOX; 4331590Srgrimes dot->m_flag &= ~MPRESERVE; 4341590Srgrimes } 4351590Srgrimes return(0); 4361590Srgrimes} 4371590Srgrimes 4381590Srgrimes/* 4391590Srgrimes * List the folders the user currently has. 4401590Srgrimes */ 4411590Srgrimesint 4421590Srgrimesfolders() 4431590Srgrimes{ 44474769Smikeh char dirname[PATHSIZE]; 4451590Srgrimes char *cmd; 4461590Srgrimes 44774769Smikeh if (getfold(dirname, sizeof(dirname)) < 0) { 4481590Srgrimes printf("No value set for \"folder\"\n"); 4491590Srgrimes return 1; 4501590Srgrimes } 4511590Srgrimes if ((cmd = value("LISTER")) == NOSTR) 4521590Srgrimes cmd = "ls"; 4531590Srgrimes (void) run_command(cmd, 0, -1, -1, dirname, NOSTR, NOSTR); 4541590Srgrimes return 0; 4551590Srgrimes} 456