cmd1.c revision 99112
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 3688150Smikehstatic char sccsid[] = "@(#)cmd1.c 8.2 (Berkeley) 4/20/95"; 3774769Smikeh#endif 381590Srgrimes#endif /* not lint */ 3999112Sobrien#include <sys/cdefs.h> 4099112Sobrien__FBSDID("$FreeBSD: head/usr.bin/mail/cmd1.c 99112 2002-06-30 05:25:07Z obrien $"); 411590Srgrimes 421590Srgrimes#include "rcv.h" 431590Srgrimes#include "extern.h" 441590Srgrimes 451590Srgrimes/* 461590Srgrimes * Mail -- a mail program 471590Srgrimes * 481590Srgrimes * User commands. 491590Srgrimes */ 501590Srgrimes 5177274Smikehextern const struct cmd cmdtab[]; 5277274Smikeh 531590Srgrimes/* 541590Srgrimes * Print the current active headings. 551590Srgrimes * Don't change dot if invoker didn't give an argument. 561590Srgrimes */ 571590Srgrimes 581590Srgrimesstatic int screen; 591590Srgrimes 601590Srgrimesint 611590Srgrimesheaders(msgvec) 621590Srgrimes int *msgvec; 631590Srgrimes{ 6477274Smikeh int n, mesg, flag, size; 6577274Smikeh struct message *mp; 661590Srgrimes 671590Srgrimes size = screensize(); 681590Srgrimes n = msgvec[0]; 691590Srgrimes if (n != 0) 701590Srgrimes screen = (n-1)/size; 711590Srgrimes if (screen < 0) 721590Srgrimes screen = 0; 731590Srgrimes mp = &message[screen * size]; 741590Srgrimes if (mp >= &message[msgCount]) 751590Srgrimes mp = &message[msgCount - size]; 761590Srgrimes if (mp < &message[0]) 771590Srgrimes mp = &message[0]; 781590Srgrimes flag = 0; 791590Srgrimes mesg = mp - &message[0]; 801590Srgrimes if (dot != &message[n-1]) 811590Srgrimes dot = mp; 821590Srgrimes for (; mp < &message[msgCount]; mp++) { 831590Srgrimes mesg++; 841590Srgrimes if (mp->m_flag & MDELETED) 851590Srgrimes continue; 861590Srgrimes if (flag++ >= size) 871590Srgrimes break; 881590Srgrimes printhead(mesg); 891590Srgrimes } 901590Srgrimes if (flag == 0) { 911590Srgrimes printf("No more mail.\n"); 9277274Smikeh return (1); 931590Srgrimes } 9477274Smikeh return (0); 951590Srgrimes} 961590Srgrimes 971590Srgrimes/* 981590Srgrimes * Scroll to the next/previous screen 991590Srgrimes */ 1001590Srgrimesint 1011590Srgrimesscroll(arg) 1021590Srgrimes char arg[]; 1031590Srgrimes{ 10477274Smikeh int s, size; 1051590Srgrimes int cur[1]; 1061590Srgrimes 1071590Srgrimes cur[0] = 0; 1081590Srgrimes size = screensize(); 1091590Srgrimes s = screen; 1101590Srgrimes switch (*arg) { 1111590Srgrimes case 0: 1121590Srgrimes case '+': 1131590Srgrimes s++; 11488150Smikeh if (s * size >= msgCount) { 1151590Srgrimes printf("On last screenful of messages\n"); 11677274Smikeh return (0); 1171590Srgrimes } 1181590Srgrimes screen = s; 1191590Srgrimes break; 1201590Srgrimes 1211590Srgrimes case '-': 1221590Srgrimes if (--s < 0) { 1231590Srgrimes printf("On first screenful of messages\n"); 12477274Smikeh return (0); 1251590Srgrimes } 1261590Srgrimes screen = s; 1271590Srgrimes break; 1281590Srgrimes 1291590Srgrimes default: 1301590Srgrimes printf("Unrecognized scrolling command \"%s\"\n", arg); 13177274Smikeh return (1); 1321590Srgrimes } 13377274Smikeh return (headers(cur)); 1341590Srgrimes} 1351590Srgrimes 1361590Srgrimes/* 1371590Srgrimes * Compute screen size. 1381590Srgrimes */ 1391590Srgrimesint 1401590Srgrimesscreensize() 1411590Srgrimes{ 1421590Srgrimes int s; 1431590Srgrimes char *cp; 1441590Srgrimes 14577274Smikeh if ((cp = value("screen")) != NULL && (s = atoi(cp)) > 0) 14677274Smikeh return (s); 14777274Smikeh return (screenheight - 4); 1481590Srgrimes} 1491590Srgrimes 1501590Srgrimes/* 1511590Srgrimes * Print out the headlines for each message 1521590Srgrimes * in the passed message list. 1531590Srgrimes */ 1541590Srgrimesint 1551590Srgrimesfrom(msgvec) 1561590Srgrimes int *msgvec; 1571590Srgrimes{ 15877274Smikeh int *ip; 1591590Srgrimes 16029574Sphk for (ip = msgvec; *ip != 0; ip++) 1611590Srgrimes printhead(*ip); 1621590Srgrimes if (--ip >= msgvec) 1631590Srgrimes dot = &message[*ip - 1]; 16477274Smikeh return (0); 1651590Srgrimes} 1661590Srgrimes 1671590Srgrimes/* 1681590Srgrimes * Print out the header of a specific message. 1691590Srgrimes * This is a slight improvement to the standard one. 1701590Srgrimes */ 1711590Srgrimesvoid 1721590Srgrimesprinthead(mesg) 1731590Srgrimes int mesg; 1741590Srgrimes{ 1751590Srgrimes struct message *mp; 1761590Srgrimes char headline[LINESIZE], wcount[LINESIZE], *subjline, dispc, curind; 1771590Srgrimes char pbuf[BUFSIZ]; 1781590Srgrimes struct headline hl; 1791590Srgrimes int subjlen; 1801590Srgrimes char *name; 1811590Srgrimes 1821590Srgrimes mp = &message[mesg-1]; 18377274Smikeh (void)readline(setinput(mp), headline, LINESIZE); 18477274Smikeh if ((subjline = hfield("subject", mp)) == NULL) 1851590Srgrimes subjline = hfield("subj", mp); 1861590Srgrimes /* 1871590Srgrimes * Bletch! 1881590Srgrimes */ 1891590Srgrimes curind = dot == mp ? '>' : ' '; 1901590Srgrimes dispc = ' '; 1911590Srgrimes if (mp->m_flag & MSAVED) 1921590Srgrimes dispc = '*'; 1931590Srgrimes if (mp->m_flag & MPRESERVE) 1941590Srgrimes dispc = 'P'; 1951590Srgrimes if ((mp->m_flag & (MREAD|MNEW)) == MNEW) 1961590Srgrimes dispc = 'N'; 1971590Srgrimes if ((mp->m_flag & (MREAD|MNEW)) == 0) 1981590Srgrimes dispc = 'U'; 1991590Srgrimes if (mp->m_flag & MBOX) 2001590Srgrimes dispc = 'M'; 2011590Srgrimes parse(headline, &hl, pbuf); 20237453Sbde sprintf(wcount, "%3ld/%-5ld", mp->m_lines, mp->m_size); 2031590Srgrimes subjlen = screenwidth - 50 - strlen(wcount); 20477274Smikeh name = value("show-rcpt") != NULL ? 2051590Srgrimes skin(hfield("to", mp)) : nameof(mp, 0); 20677274Smikeh if (subjline == NULL || subjlen < 0) /* pretty pathetic */ 2071590Srgrimes printf("%c%c%3d %-20.20s %16.16s %s\n", 2081590Srgrimes curind, dispc, mesg, name, hl.l_date, wcount); 2091590Srgrimes else 2101590Srgrimes printf("%c%c%3d %-20.20s %16.16s %s \"%.*s\"\n", 2111590Srgrimes curind, dispc, mesg, name, hl.l_date, wcount, 2121590Srgrimes subjlen, subjline); 2131590Srgrimes} 2141590Srgrimes 2151590Srgrimes/* 2161590Srgrimes * Print out the value of dot. 2171590Srgrimes */ 2181590Srgrimesint 2191590Srgrimespdot() 2201590Srgrimes{ 2211590Srgrimes printf("%d\n", dot - &message[0] + 1); 22277274Smikeh return (0); 2231590Srgrimes} 2241590Srgrimes 2251590Srgrimes/* 2261590Srgrimes * Print out all the possible commands. 2271590Srgrimes */ 2281590Srgrimesint 2291590Srgrimespcmdlist() 2301590Srgrimes{ 23177274Smikeh const struct cmd *cp; 23277274Smikeh int cc; 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 } 24177274Smikeh if ((cp+1)->c_name != NULL) 2421590Srgrimes printf("%s, ", cp->c_name); 2431590Srgrimes else 2441590Srgrimes printf("%s\n", cp->c_name); 2451590Srgrimes } 24677274Smikeh return (0); 2471590Srgrimes} 2481590Srgrimes 2491590Srgrimes/* 2501590Srgrimes * Paginate messages, honor ignored fields. 2511590Srgrimes */ 2521590Srgrimesint 2531590Srgrimesmore(msgvec) 2541590Srgrimes int *msgvec; 2551590Srgrimes{ 25677274Smikeh 2571590Srgrimes return (type1(msgvec, 1, 1)); 2581590Srgrimes} 2591590Srgrimes 2601590Srgrimes/* 2611590Srgrimes * Paginate messages, even printing ignored fields. 2621590Srgrimes */ 2631590Srgrimesint 2641590SrgrimesMore(msgvec) 2651590Srgrimes int *msgvec; 2661590Srgrimes{ 2671590Srgrimes 2681590Srgrimes return (type1(msgvec, 0, 1)); 2691590Srgrimes} 2701590Srgrimes 2711590Srgrimes/* 2721590Srgrimes * Type out messages, honor ignored fields. 2731590Srgrimes */ 2741590Srgrimesint 2751590Srgrimestype(msgvec) 2761590Srgrimes int *msgvec; 2771590Srgrimes{ 2781590Srgrimes 27977274Smikeh return (type1(msgvec, 1, 0)); 2801590Srgrimes} 2811590Srgrimes 2821590Srgrimes/* 2831590Srgrimes * Type out messages, even printing ignored fields. 2841590Srgrimes */ 2851590Srgrimesint 2861590SrgrimesType(msgvec) 2871590Srgrimes int *msgvec; 2881590Srgrimes{ 2891590Srgrimes 29077274Smikeh return (type1(msgvec, 0, 0)); 2911590Srgrimes} 2921590Srgrimes 2931590Srgrimes/* 2941590Srgrimes * Type out the messages requested. 2951590Srgrimes */ 2961590Srgrimesjmp_buf pipestop; 2971590Srgrimesint 2981590Srgrimestype1(msgvec, doign, page) 2991590Srgrimes int *msgvec; 3001590Srgrimes int doign, page; 3011590Srgrimes{ 30277274Smikeh int nlines, *ip; 30377274Smikeh struct message *mp; 30477274Smikeh char *cp; 3051590Srgrimes FILE *obuf; 3061590Srgrimes 3071590Srgrimes obuf = stdout; 3081590Srgrimes if (setjmp(pipestop)) 3091590Srgrimes goto close_pipe; 31077274Smikeh if (value("interactive") != NULL && 31177274Smikeh (page || (cp = value("crt")) != NULL)) { 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 32677274Smikeh (void)signal(SIGPIPE, brokpipe); 3271590Srgrimes } 3281590Srgrimes } 32977274Smikeh 33077274Smikeh /* 33177274Smikeh * Send messages to the output. 33277274Smikeh * 33377274Smikeh */ 3341590Srgrimes for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) { 3351590Srgrimes mp = &message[*ip - 1]; 3361590Srgrimes touch(mp); 3371590Srgrimes dot = mp; 33877274Smikeh if (value("quiet") == NULL) 3391590Srgrimes fprintf(obuf, "Message %d:\n", *ip); 34077274Smikeh (void)sendmessage(mp, obuf, doign ? ignore : 0, NULL); 3411590Srgrimes } 34277274Smikeh 3431590Srgrimesclose_pipe: 3441590Srgrimes if (obuf != stdout) { 3451590Srgrimes /* 3461590Srgrimes * Ignore SIGPIPE so it can't cause a duplicate close. 3471590Srgrimes */ 34877274Smikeh (void)signal(SIGPIPE, SIG_IGN); 34977274Smikeh (void)Pclose(obuf); 35077274Smikeh (void)signal(SIGPIPE, SIG_DFL); 3511590Srgrimes } 35277274Smikeh return (0); 3531590Srgrimes} 3541590Srgrimes 3551590Srgrimes/* 3561590Srgrimes * Respond to a broken pipe signal -- 3571590Srgrimes * probably caused by quitting more. 3581590Srgrimes */ 35977274Smikeh/*ARGSUSED*/ 3601590Srgrimesvoid 3611590Srgrimesbrokpipe(signo) 3621590Srgrimes int signo; 3631590Srgrimes{ 3641590Srgrimes longjmp(pipestop, 1); 3651590Srgrimes} 3661590Srgrimes 3671590Srgrimes/* 3681590Srgrimes * Print the top so many lines of each desired message. 3691590Srgrimes * The number of lines is taken from the variable "toplines" 3701590Srgrimes * and defaults to 5. 3711590Srgrimes */ 3721590Srgrimesint 3731590Srgrimestop(msgvec) 3741590Srgrimes int *msgvec; 3751590Srgrimes{ 37677274Smikeh int *ip; 37777274Smikeh struct message *mp; 3781590Srgrimes int c, topl, lines, lineb; 3791590Srgrimes char *valtop, linebuf[LINESIZE]; 3801590Srgrimes FILE *ibuf; 3811590Srgrimes 3821590Srgrimes topl = 5; 3831590Srgrimes valtop = value("toplines"); 38477274Smikeh if (valtop != NULL) { 3851590Srgrimes topl = atoi(valtop); 3861590Srgrimes if (topl < 0 || topl > 10000) 3871590Srgrimes topl = 5; 3881590Srgrimes } 3891590Srgrimes lineb = 1; 3901590Srgrimes for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 3911590Srgrimes mp = &message[*ip - 1]; 3921590Srgrimes touch(mp); 3931590Srgrimes dot = mp; 39477274Smikeh if (value("quiet") == NULL) 3951590Srgrimes printf("Message %d:\n", *ip); 3961590Srgrimes ibuf = setinput(mp); 3971590Srgrimes c = mp->m_lines; 3981590Srgrimes if (!lineb) 3991590Srgrimes printf("\n"); 4001590Srgrimes for (lines = 0; lines < c && lines <= topl; lines++) { 40174769Smikeh if (readline(ibuf, linebuf, sizeof(linebuf)) < 0) 4021590Srgrimes break; 4031590Srgrimes puts(linebuf); 40474769Smikeh lineb = strspn(linebuf, " \t") == strlen(linebuf); 4051590Srgrimes } 4061590Srgrimes } 40777274Smikeh return (0); 4081590Srgrimes} 4091590Srgrimes 4101590Srgrimes/* 4111590Srgrimes * Touch all the given messages so that they will 4121590Srgrimes * get mboxed. 4131590Srgrimes */ 4141590Srgrimesint 4151590Srgrimesstouch(msgvec) 4161590Srgrimes int msgvec[]; 4171590Srgrimes{ 41877274Smikeh int *ip; 4191590Srgrimes 4201590Srgrimes for (ip = msgvec; *ip != 0; ip++) { 4211590Srgrimes dot = &message[*ip-1]; 4221590Srgrimes dot->m_flag |= MTOUCH; 4231590Srgrimes dot->m_flag &= ~MPRESERVE; 4241590Srgrimes } 42577274Smikeh return (0); 4261590Srgrimes} 4271590Srgrimes 4281590Srgrimes/* 4291590Srgrimes * Make sure all passed messages get mboxed. 4301590Srgrimes */ 4311590Srgrimesint 4321590Srgrimesmboxit(msgvec) 4331590Srgrimes int msgvec[]; 4341590Srgrimes{ 43577274Smikeh int *ip; 4361590Srgrimes 4371590Srgrimes for (ip = msgvec; *ip != 0; ip++) { 4381590Srgrimes dot = &message[*ip-1]; 4391590Srgrimes dot->m_flag |= MTOUCH|MBOX; 4401590Srgrimes dot->m_flag &= ~MPRESERVE; 4411590Srgrimes } 44277274Smikeh return (0); 4431590Srgrimes} 4441590Srgrimes 4451590Srgrimes/* 4461590Srgrimes * List the folders the user currently has. 4471590Srgrimes */ 4481590Srgrimesint 4491590Srgrimesfolders() 4501590Srgrimes{ 45174769Smikeh char dirname[PATHSIZE]; 4521590Srgrimes char *cmd; 4531590Srgrimes 45474769Smikeh if (getfold(dirname, sizeof(dirname)) < 0) { 4551590Srgrimes printf("No value set for \"folder\"\n"); 45677274Smikeh return (1); 4571590Srgrimes } 45877274Smikeh if ((cmd = value("LISTER")) == NULL) 4591590Srgrimes cmd = "ls"; 46077274Smikeh (void)run_command(cmd, 0, -1, -1, dirname, NULL, NULL); 46177274Smikeh return (0); 4621590Srgrimes} 46388150Smikeh 46488150Smikeh/* 46588150Smikeh * Update the mail file with any new messages that have 46688150Smikeh * come in since we started reading mail. 46788150Smikeh */ 46888150Smikehint 46988150Smikehinc(v) 47088150Smikeh void *v; 47188150Smikeh{ 47288150Smikeh int nmsg, mdot; 47388150Smikeh 47488150Smikeh nmsg = incfile(); 47588150Smikeh 47688150Smikeh if (nmsg == 0) 47788150Smikeh printf("No new mail.\n"); 47888150Smikeh else if (nmsg > 0) { 47988150Smikeh mdot = newfileinfo(msgCount - nmsg); 48088150Smikeh dot = &message[mdot - 1]; 48188150Smikeh } else 48288150Smikeh printf("\"inc\" command failed...\n"); 48388150Smikeh 48488150Smikeh return (0); 48588150Smikeh} 486