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 3288150Smikehstatic char sccsid[] = "@(#)cmd1.c 8.2 (Berkeley) 4/20/95"; 3374769Smikeh#endif 341590Srgrimes#endif /* not lint */ 3599112Sobrien#include <sys/cdefs.h> 3699112Sobrien__FBSDID("$FreeBSD$"); 371590Srgrimes 381590Srgrimes#include "rcv.h" 391590Srgrimes#include "extern.h" 401590Srgrimes 411590Srgrimes/* 421590Srgrimes * Mail -- a mail program 431590Srgrimes * 441590Srgrimes * User commands. 451590Srgrimes */ 461590Srgrimes 4777274Smikehextern const struct cmd cmdtab[]; 4877274Smikeh 491590Srgrimes/* 501590Srgrimes * Print the current active headings. 511590Srgrimes * Don't change dot if invoker didn't give an argument. 521590Srgrimes */ 531590Srgrimes 541590Srgrimesstatic int screen; 551590Srgrimes 561590Srgrimesint 57216562Scharnierheaders(int *msgvec) 581590Srgrimes{ 5977274Smikeh int n, mesg, flag, size; 6077274Smikeh struct message *mp; 611590Srgrimes 621590Srgrimes size = screensize(); 631590Srgrimes n = msgvec[0]; 641590Srgrimes if (n != 0) 651590Srgrimes screen = (n-1)/size; 661590Srgrimes if (screen < 0) 671590Srgrimes screen = 0; 681590Srgrimes mp = &message[screen * size]; 691590Srgrimes if (mp >= &message[msgCount]) 701590Srgrimes mp = &message[msgCount - size]; 711590Srgrimes if (mp < &message[0]) 721590Srgrimes mp = &message[0]; 731590Srgrimes flag = 0; 741590Srgrimes mesg = mp - &message[0]; 751590Srgrimes if (dot != &message[n-1]) 761590Srgrimes dot = mp; 771590Srgrimes for (; mp < &message[msgCount]; mp++) { 781590Srgrimes mesg++; 791590Srgrimes if (mp->m_flag & MDELETED) 801590Srgrimes continue; 811590Srgrimes if (flag++ >= size) 821590Srgrimes break; 831590Srgrimes printhead(mesg); 841590Srgrimes } 851590Srgrimes if (flag == 0) { 861590Srgrimes printf("No more mail.\n"); 8777274Smikeh return (1); 881590Srgrimes } 8977274Smikeh return (0); 901590Srgrimes} 911590Srgrimes 921590Srgrimes/* 931590Srgrimes * Scroll to the next/previous screen 941590Srgrimes */ 951590Srgrimesint 96216562Scharnierscroll(char arg[]) 971590Srgrimes{ 9877274Smikeh int s, size; 991590Srgrimes int cur[1]; 1001590Srgrimes 1011590Srgrimes cur[0] = 0; 1021590Srgrimes size = screensize(); 1031590Srgrimes s = screen; 1041590Srgrimes switch (*arg) { 1051590Srgrimes case 0: 1061590Srgrimes case '+': 1071590Srgrimes s++; 10888150Smikeh if (s * size >= msgCount) { 1091590Srgrimes printf("On last screenful of messages\n"); 11077274Smikeh return (0); 1111590Srgrimes } 1121590Srgrimes screen = s; 1131590Srgrimes break; 1141590Srgrimes 1151590Srgrimes case '-': 1161590Srgrimes if (--s < 0) { 1171590Srgrimes printf("On first screenful of messages\n"); 11877274Smikeh return (0); 1191590Srgrimes } 1201590Srgrimes screen = s; 1211590Srgrimes break; 1221590Srgrimes 1231590Srgrimes default: 1241590Srgrimes printf("Unrecognized scrolling command \"%s\"\n", arg); 12577274Smikeh return (1); 1261590Srgrimes } 12777274Smikeh return (headers(cur)); 1281590Srgrimes} 1291590Srgrimes 1301590Srgrimes/* 1311590Srgrimes * Compute screen size. 1321590Srgrimes */ 1331590Srgrimesint 134216562Scharnierscreensize(void) 1351590Srgrimes{ 1361590Srgrimes int s; 1371590Srgrimes char *cp; 1381590Srgrimes 13977274Smikeh if ((cp = value("screen")) != NULL && (s = atoi(cp)) > 0) 14077274Smikeh return (s); 14177274Smikeh return (screenheight - 4); 1421590Srgrimes} 1431590Srgrimes 1441590Srgrimes/* 1451590Srgrimes * Print out the headlines for each message 1461590Srgrimes * in the passed message list. 1471590Srgrimes */ 1481590Srgrimesint 149216562Scharnierfrom(int *msgvec) 1501590Srgrimes{ 15177274Smikeh int *ip; 1521590Srgrimes 15329574Sphk for (ip = msgvec; *ip != 0; ip++) 1541590Srgrimes printhead(*ip); 1551590Srgrimes if (--ip >= msgvec) 1561590Srgrimes dot = &message[*ip - 1]; 15777274Smikeh return (0); 1581590Srgrimes} 1591590Srgrimes 1601590Srgrimes/* 1611590Srgrimes * Print out the header of a specific message. 1621590Srgrimes * This is a slight improvement to the standard one. 1631590Srgrimes */ 1641590Srgrimesvoid 165216562Scharnierprinthead(int mesg) 1661590Srgrimes{ 1671590Srgrimes struct message *mp; 1681590Srgrimes char headline[LINESIZE], wcount[LINESIZE], *subjline, dispc, curind; 1691590Srgrimes char pbuf[BUFSIZ]; 1701590Srgrimes struct headline hl; 1711590Srgrimes int subjlen; 1721590Srgrimes char *name; 1731590Srgrimes 1741590Srgrimes mp = &message[mesg-1]; 17577274Smikeh (void)readline(setinput(mp), headline, LINESIZE); 17677274Smikeh if ((subjline = hfield("subject", mp)) == NULL) 1771590Srgrimes subjline = hfield("subj", mp); 1781590Srgrimes /* 1791590Srgrimes * Bletch! 1801590Srgrimes */ 1811590Srgrimes curind = dot == mp ? '>' : ' '; 1821590Srgrimes dispc = ' '; 1831590Srgrimes if (mp->m_flag & MSAVED) 1841590Srgrimes dispc = '*'; 1851590Srgrimes if (mp->m_flag & MPRESERVE) 1861590Srgrimes dispc = 'P'; 1871590Srgrimes if ((mp->m_flag & (MREAD|MNEW)) == MNEW) 1881590Srgrimes dispc = 'N'; 1891590Srgrimes if ((mp->m_flag & (MREAD|MNEW)) == 0) 1901590Srgrimes dispc = 'U'; 1911590Srgrimes if (mp->m_flag & MBOX) 1921590Srgrimes dispc = 'M'; 1931590Srgrimes parse(headline, &hl, pbuf); 19437453Sbde sprintf(wcount, "%3ld/%-5ld", mp->m_lines, mp->m_size); 1951590Srgrimes subjlen = screenwidth - 50 - strlen(wcount); 19677274Smikeh name = value("show-rcpt") != NULL ? 1971590Srgrimes skin(hfield("to", mp)) : nameof(mp, 0); 19877274Smikeh if (subjline == NULL || subjlen < 0) /* pretty pathetic */ 1991590Srgrimes printf("%c%c%3d %-20.20s %16.16s %s\n", 2001590Srgrimes curind, dispc, mesg, name, hl.l_date, wcount); 2011590Srgrimes else 2021590Srgrimes printf("%c%c%3d %-20.20s %16.16s %s \"%.*s\"\n", 2031590Srgrimes curind, dispc, mesg, name, hl.l_date, wcount, 2041590Srgrimes subjlen, subjline); 2051590Srgrimes} 2061590Srgrimes 2071590Srgrimes/* 2081590Srgrimes * Print out the value of dot. 2091590Srgrimes */ 2101590Srgrimesint 211216562Scharnierpdot(void) 2121590Srgrimes{ 213228647Sdim printf("%td\n", dot - &message[0] + 1); 21477274Smikeh return (0); 2151590Srgrimes} 2161590Srgrimes 2171590Srgrimes/* 2181590Srgrimes * Print out all the possible commands. 2191590Srgrimes */ 2201590Srgrimesint 221216562Scharnierpcmdlist(void) 2221590Srgrimes{ 22377274Smikeh const struct cmd *cp; 22477274Smikeh int cc; 2251590Srgrimes 2261590Srgrimes printf("Commands are:\n"); 2271590Srgrimes for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) { 2281590Srgrimes cc += strlen(cp->c_name) + 2; 2291590Srgrimes if (cc > 72) { 2301590Srgrimes printf("\n"); 2311590Srgrimes cc = strlen(cp->c_name) + 2; 2321590Srgrimes } 23377274Smikeh if ((cp+1)->c_name != NULL) 2341590Srgrimes printf("%s, ", cp->c_name); 2351590Srgrimes else 2361590Srgrimes printf("%s\n", cp->c_name); 2371590Srgrimes } 23877274Smikeh return (0); 2391590Srgrimes} 2401590Srgrimes 2411590Srgrimes/* 2421590Srgrimes * Paginate messages, honor ignored fields. 2431590Srgrimes */ 2441590Srgrimesint 245216562Scharniermore(int *msgvec) 2461590Srgrimes{ 24777274Smikeh 2481590Srgrimes return (type1(msgvec, 1, 1)); 2491590Srgrimes} 2501590Srgrimes 2511590Srgrimes/* 2521590Srgrimes * Paginate messages, even printing ignored fields. 2531590Srgrimes */ 2541590Srgrimesint 255216562ScharnierMore(int *msgvec) 2561590Srgrimes{ 2571590Srgrimes 2581590Srgrimes return (type1(msgvec, 0, 1)); 2591590Srgrimes} 2601590Srgrimes 2611590Srgrimes/* 2621590Srgrimes * Type out messages, honor ignored fields. 2631590Srgrimes */ 2641590Srgrimesint 265216562Scharniertype(int *msgvec) 2661590Srgrimes{ 2671590Srgrimes 26877274Smikeh return (type1(msgvec, 1, 0)); 2691590Srgrimes} 2701590Srgrimes 2711590Srgrimes/* 2721590Srgrimes * Type out messages, even printing ignored fields. 2731590Srgrimes */ 2741590Srgrimesint 275216562ScharnierType(int *msgvec) 2761590Srgrimes{ 2771590Srgrimes 27877274Smikeh return (type1(msgvec, 0, 0)); 2791590Srgrimes} 2801590Srgrimes 2811590Srgrimes/* 2821590Srgrimes * Type out the messages requested. 2831590Srgrimes */ 284173439Sddsstatic jmp_buf pipestop; 2851590Srgrimesint 286216562Scharniertype1(int *msgvec, int doign, int page) 2871590Srgrimes{ 28877274Smikeh int nlines, *ip; 28977274Smikeh struct message *mp; 29077274Smikeh char *cp; 2911590Srgrimes FILE *obuf; 2921590Srgrimes 2931590Srgrimes obuf = stdout; 2941590Srgrimes if (setjmp(pipestop)) 2951590Srgrimes goto close_pipe; 29677274Smikeh if (value("interactive") != NULL && 29777274Smikeh (page || (cp = value("crt")) != NULL)) { 2981590Srgrimes nlines = 0; 2991590Srgrimes if (!page) { 3001590Srgrimes for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) 3011590Srgrimes nlines += message[*ip - 1].m_lines; 3021590Srgrimes } 3031590Srgrimes if (page || nlines > (*cp ? atoi(cp) : realscreenheight)) { 3041590Srgrimes cp = value("PAGER"); 3051590Srgrimes if (cp == NULL || *cp == '\0') 3061590Srgrimes cp = _PATH_MORE; 3071590Srgrimes obuf = Popen(cp, "w"); 3081590Srgrimes if (obuf == NULL) { 30974769Smikeh warnx("%s", cp); 3101590Srgrimes obuf = stdout; 3111590Srgrimes } else 31277274Smikeh (void)signal(SIGPIPE, brokpipe); 3131590Srgrimes } 3141590Srgrimes } 31577274Smikeh 31677274Smikeh /* 31777274Smikeh * Send messages to the output. 31877274Smikeh * 31977274Smikeh */ 3201590Srgrimes for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) { 3211590Srgrimes mp = &message[*ip - 1]; 3221590Srgrimes touch(mp); 3231590Srgrimes dot = mp; 32477274Smikeh if (value("quiet") == NULL) 3251590Srgrimes fprintf(obuf, "Message %d:\n", *ip); 32677274Smikeh (void)sendmessage(mp, obuf, doign ? ignore : 0, NULL); 3271590Srgrimes } 32877274Smikeh 3291590Srgrimesclose_pipe: 3301590Srgrimes if (obuf != stdout) { 3311590Srgrimes /* 3321590Srgrimes * Ignore SIGPIPE so it can't cause a duplicate close. 3331590Srgrimes */ 33477274Smikeh (void)signal(SIGPIPE, SIG_IGN); 33577274Smikeh (void)Pclose(obuf); 33677274Smikeh (void)signal(SIGPIPE, SIG_DFL); 3371590Srgrimes } 33877274Smikeh return (0); 3391590Srgrimes} 3401590Srgrimes 3411590Srgrimes/* 3421590Srgrimes * Respond to a broken pipe signal -- 3431590Srgrimes * probably caused by quitting more. 3441590Srgrimes */ 34577274Smikeh/*ARGSUSED*/ 3461590Srgrimesvoid 347216562Scharnierbrokpipe(int signo __unused) 3481590Srgrimes{ 3491590Srgrimes longjmp(pipestop, 1); 3501590Srgrimes} 3511590Srgrimes 3521590Srgrimes/* 3531590Srgrimes * Print the top so many lines of each desired message. 3541590Srgrimes * The number of lines is taken from the variable "toplines" 3551590Srgrimes * and defaults to 5. 3561590Srgrimes */ 3571590Srgrimesint 358216562Scharniertop(int *msgvec) 3591590Srgrimes{ 36077274Smikeh int *ip; 36177274Smikeh struct message *mp; 3621590Srgrimes int c, topl, lines, lineb; 3631590Srgrimes char *valtop, linebuf[LINESIZE]; 3641590Srgrimes FILE *ibuf; 3651590Srgrimes 3661590Srgrimes topl = 5; 3671590Srgrimes valtop = value("toplines"); 36877274Smikeh if (valtop != NULL) { 3691590Srgrimes topl = atoi(valtop); 3701590Srgrimes if (topl < 0 || topl > 10000) 3711590Srgrimes topl = 5; 3721590Srgrimes } 3731590Srgrimes lineb = 1; 3741590Srgrimes for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 3751590Srgrimes mp = &message[*ip - 1]; 3761590Srgrimes touch(mp); 3771590Srgrimes dot = mp; 37877274Smikeh if (value("quiet") == NULL) 3791590Srgrimes printf("Message %d:\n", *ip); 3801590Srgrimes ibuf = setinput(mp); 3811590Srgrimes c = mp->m_lines; 3821590Srgrimes if (!lineb) 3831590Srgrimes printf("\n"); 3841590Srgrimes for (lines = 0; lines < c && lines <= topl; lines++) { 38574769Smikeh if (readline(ibuf, linebuf, sizeof(linebuf)) < 0) 3861590Srgrimes break; 3871590Srgrimes puts(linebuf); 38874769Smikeh lineb = strspn(linebuf, " \t") == strlen(linebuf); 3891590Srgrimes } 3901590Srgrimes } 39177274Smikeh return (0); 3921590Srgrimes} 3931590Srgrimes 3941590Srgrimes/* 3951590Srgrimes * Touch all the given messages so that they will 3961590Srgrimes * get mboxed. 3971590Srgrimes */ 3981590Srgrimesint 399216562Scharnierstouch(int msgvec[]) 4001590Srgrimes{ 40177274Smikeh int *ip; 4021590Srgrimes 4031590Srgrimes for (ip = msgvec; *ip != 0; ip++) { 4041590Srgrimes dot = &message[*ip-1]; 4051590Srgrimes dot->m_flag |= MTOUCH; 4061590Srgrimes dot->m_flag &= ~MPRESERVE; 4071590Srgrimes } 40877274Smikeh return (0); 4091590Srgrimes} 4101590Srgrimes 4111590Srgrimes/* 4121590Srgrimes * Make sure all passed messages get mboxed. 4131590Srgrimes */ 4141590Srgrimesint 415216562Scharniermboxit(int msgvec[]) 4161590Srgrimes{ 41777274Smikeh int *ip; 4181590Srgrimes 4191590Srgrimes for (ip = msgvec; *ip != 0; ip++) { 4201590Srgrimes dot = &message[*ip-1]; 4211590Srgrimes dot->m_flag |= MTOUCH|MBOX; 4221590Srgrimes dot->m_flag &= ~MPRESERVE; 4231590Srgrimes } 42477274Smikeh return (0); 4251590Srgrimes} 4261590Srgrimes 4271590Srgrimes/* 4281590Srgrimes * List the folders the user currently has. 4291590Srgrimes */ 4301590Srgrimesint 431216562Scharnierfolders(void) 4321590Srgrimes{ 43374769Smikeh char dirname[PATHSIZE]; 4341590Srgrimes char *cmd; 4351590Srgrimes 43674769Smikeh if (getfold(dirname, sizeof(dirname)) < 0) { 4371590Srgrimes printf("No value set for \"folder\"\n"); 43877274Smikeh return (1); 4391590Srgrimes } 44077274Smikeh if ((cmd = value("LISTER")) == NULL) 4411590Srgrimes cmd = "ls"; 44277274Smikeh (void)run_command(cmd, 0, -1, -1, dirname, NULL, NULL); 44377274Smikeh return (0); 4441590Srgrimes} 44588150Smikeh 44688150Smikeh/* 44788150Smikeh * Update the mail file with any new messages that have 44888150Smikeh * come in since we started reading mail. 44988150Smikeh */ 45088150Smikehint 451216562Scharnierinc(void *v __unused) 45288150Smikeh{ 45388150Smikeh int nmsg, mdot; 45488150Smikeh 45588150Smikeh nmsg = incfile(); 45688150Smikeh 45788150Smikeh if (nmsg == 0) 45888150Smikeh printf("No new mail.\n"); 45988150Smikeh else if (nmsg > 0) { 46088150Smikeh mdot = newfileinfo(msgCount - nmsg); 46188150Smikeh dot = &message[mdot - 1]; 46288150Smikeh } else 46388150Smikeh printf("\"inc\" command failed...\n"); 46488150Smikeh 46588150Smikeh return (0); 46688150Smikeh} 467