cmd1.c revision 1590
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 351590Srgrimesstatic char sccsid[] = "@(#)cmd1.c 8.1 (Berkeley) 6/6/93"; 361590Srgrimes#endif /* not lint */ 371590Srgrimes 381590Srgrimes#include "rcv.h" 391590Srgrimes#include "extern.h" 401590Srgrimes 411590Srgrimes/* 421590Srgrimes * Mail -- a mail program 431590Srgrimes * 441590Srgrimes * User commands. 451590Srgrimes */ 461590Srgrimes 471590Srgrimes/* 481590Srgrimes * Print the current active headings. 491590Srgrimes * Don't change dot if invoker didn't give an argument. 501590Srgrimes */ 511590Srgrimes 521590Srgrimesstatic int screen; 531590Srgrimes 541590Srgrimesint 551590Srgrimesheaders(msgvec) 561590Srgrimes int *msgvec; 571590Srgrimes{ 581590Srgrimes register int n, mesg, flag; 591590Srgrimes register struct message *mp; 601590Srgrimes int size; 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"); 871590Srgrimes return(1); 881590Srgrimes } 891590Srgrimes return(0); 901590Srgrimes} 911590Srgrimes 921590Srgrimes/* 931590Srgrimes * Scroll to the next/previous screen 941590Srgrimes */ 951590Srgrimesint 961590Srgrimesscroll(arg) 971590Srgrimes char arg[]; 981590Srgrimes{ 991590Srgrimes register int s, size; 1001590Srgrimes int cur[1]; 1011590Srgrimes 1021590Srgrimes cur[0] = 0; 1031590Srgrimes size = screensize(); 1041590Srgrimes s = screen; 1051590Srgrimes switch (*arg) { 1061590Srgrimes case 0: 1071590Srgrimes case '+': 1081590Srgrimes s++; 1091590Srgrimes if (s * size > msgCount) { 1101590Srgrimes printf("On last screenful of messages\n"); 1111590Srgrimes return(0); 1121590Srgrimes } 1131590Srgrimes screen = s; 1141590Srgrimes break; 1151590Srgrimes 1161590Srgrimes case '-': 1171590Srgrimes if (--s < 0) { 1181590Srgrimes printf("On first screenful of messages\n"); 1191590Srgrimes return(0); 1201590Srgrimes } 1211590Srgrimes screen = s; 1221590Srgrimes break; 1231590Srgrimes 1241590Srgrimes default: 1251590Srgrimes printf("Unrecognized scrolling command \"%s\"\n", arg); 1261590Srgrimes return(1); 1271590Srgrimes } 1281590Srgrimes return(headers(cur)); 1291590Srgrimes} 1301590Srgrimes 1311590Srgrimes/* 1321590Srgrimes * Compute screen size. 1331590Srgrimes */ 1341590Srgrimesint 1351590Srgrimesscreensize() 1361590Srgrimes{ 1371590Srgrimes int s; 1381590Srgrimes char *cp; 1391590Srgrimes 1401590Srgrimes if ((cp = value("screen")) != NOSTR && (s = atoi(cp)) > 0) 1411590Srgrimes return s; 1421590Srgrimes return screenheight - 4; 1431590Srgrimes} 1441590Srgrimes 1451590Srgrimes/* 1461590Srgrimes * Print out the headlines for each message 1471590Srgrimes * in the passed message list. 1481590Srgrimes */ 1491590Srgrimesint 1501590Srgrimesfrom(msgvec) 1511590Srgrimes int *msgvec; 1521590Srgrimes{ 1531590Srgrimes register int *ip; 1541590Srgrimes 1551590Srgrimes for (ip = msgvec; *ip != NULL; ip++) 1561590Srgrimes printhead(*ip); 1571590Srgrimes if (--ip >= msgvec) 1581590Srgrimes dot = &message[*ip - 1]; 1591590Srgrimes return(0); 1601590Srgrimes} 1611590Srgrimes 1621590Srgrimes/* 1631590Srgrimes * Print out the header of a specific message. 1641590Srgrimes * This is a slight improvement to the standard one. 1651590Srgrimes */ 1661590Srgrimesvoid 1671590Srgrimesprinthead(mesg) 1681590Srgrimes int mesg; 1691590Srgrimes{ 1701590Srgrimes struct message *mp; 1711590Srgrimes char headline[LINESIZE], wcount[LINESIZE], *subjline, dispc, curind; 1721590Srgrimes char pbuf[BUFSIZ]; 1731590Srgrimes struct headline hl; 1741590Srgrimes int subjlen; 1751590Srgrimes char *name; 1761590Srgrimes 1771590Srgrimes mp = &message[mesg-1]; 1781590Srgrimes (void) readline(setinput(mp), headline, LINESIZE); 1791590Srgrimes if ((subjline = hfield("subject", mp)) == NOSTR) 1801590Srgrimes subjline = hfield("subj", mp); 1811590Srgrimes /* 1821590Srgrimes * Bletch! 1831590Srgrimes */ 1841590Srgrimes curind = dot == mp ? '>' : ' '; 1851590Srgrimes dispc = ' '; 1861590Srgrimes if (mp->m_flag & MSAVED) 1871590Srgrimes dispc = '*'; 1881590Srgrimes if (mp->m_flag & MPRESERVE) 1891590Srgrimes dispc = 'P'; 1901590Srgrimes if ((mp->m_flag & (MREAD|MNEW)) == MNEW) 1911590Srgrimes dispc = 'N'; 1921590Srgrimes if ((mp->m_flag & (MREAD|MNEW)) == 0) 1931590Srgrimes dispc = 'U'; 1941590Srgrimes if (mp->m_flag & MBOX) 1951590Srgrimes dispc = 'M'; 1961590Srgrimes parse(headline, &hl, pbuf); 1971590Srgrimes sprintf(wcount, "%3d/%-5ld", mp->m_lines, mp->m_size); 1981590Srgrimes subjlen = screenwidth - 50 - strlen(wcount); 1991590Srgrimes name = value("show-rcpt") != NOSTR ? 2001590Srgrimes skin(hfield("to", mp)) : nameof(mp, 0); 2011590Srgrimes if (subjline == NOSTR || subjlen < 0) /* pretty pathetic */ 2021590Srgrimes printf("%c%c%3d %-20.20s %16.16s %s\n", 2031590Srgrimes curind, dispc, mesg, name, hl.l_date, wcount); 2041590Srgrimes else 2051590Srgrimes printf("%c%c%3d %-20.20s %16.16s %s \"%.*s\"\n", 2061590Srgrimes curind, dispc, mesg, name, hl.l_date, wcount, 2071590Srgrimes subjlen, subjline); 2081590Srgrimes} 2091590Srgrimes 2101590Srgrimes/* 2111590Srgrimes * Print out the value of dot. 2121590Srgrimes */ 2131590Srgrimesint 2141590Srgrimespdot() 2151590Srgrimes{ 2161590Srgrimes printf("%d\n", dot - &message[0] + 1); 2171590Srgrimes return(0); 2181590Srgrimes} 2191590Srgrimes 2201590Srgrimes/* 2211590Srgrimes * Print out all the possible commands. 2221590Srgrimes */ 2231590Srgrimesint 2241590Srgrimespcmdlist() 2251590Srgrimes{ 2261590Srgrimes register struct cmd *cp; 2271590Srgrimes register int cc; 2281590Srgrimes extern struct cmd cmdtab[]; 2291590Srgrimes 2301590Srgrimes printf("Commands are:\n"); 2311590Srgrimes for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) { 2321590Srgrimes cc += strlen(cp->c_name) + 2; 2331590Srgrimes if (cc > 72) { 2341590Srgrimes printf("\n"); 2351590Srgrimes cc = strlen(cp->c_name) + 2; 2361590Srgrimes } 2371590Srgrimes if ((cp+1)->c_name != NOSTR) 2381590Srgrimes printf("%s, ", cp->c_name); 2391590Srgrimes else 2401590Srgrimes printf("%s\n", cp->c_name); 2411590Srgrimes } 2421590Srgrimes return(0); 2431590Srgrimes} 2441590Srgrimes 2451590Srgrimes/* 2461590Srgrimes * Paginate messages, honor ignored fields. 2471590Srgrimes */ 2481590Srgrimesint 2491590Srgrimesmore(msgvec) 2501590Srgrimes int *msgvec; 2511590Srgrimes{ 2521590Srgrimes return (type1(msgvec, 1, 1)); 2531590Srgrimes} 2541590Srgrimes 2551590Srgrimes/* 2561590Srgrimes * Paginate messages, even printing ignored fields. 2571590Srgrimes */ 2581590Srgrimesint 2591590SrgrimesMore(msgvec) 2601590Srgrimes int *msgvec; 2611590Srgrimes{ 2621590Srgrimes 2631590Srgrimes return (type1(msgvec, 0, 1)); 2641590Srgrimes} 2651590Srgrimes 2661590Srgrimes/* 2671590Srgrimes * Type out messages, honor ignored fields. 2681590Srgrimes */ 2691590Srgrimesint 2701590Srgrimestype(msgvec) 2711590Srgrimes int *msgvec; 2721590Srgrimes{ 2731590Srgrimes 2741590Srgrimes return(type1(msgvec, 1, 0)); 2751590Srgrimes} 2761590Srgrimes 2771590Srgrimes/* 2781590Srgrimes * Type out messages, even printing ignored fields. 2791590Srgrimes */ 2801590Srgrimesint 2811590SrgrimesType(msgvec) 2821590Srgrimes int *msgvec; 2831590Srgrimes{ 2841590Srgrimes 2851590Srgrimes return(type1(msgvec, 0, 0)); 2861590Srgrimes} 2871590Srgrimes 2881590Srgrimes/* 2891590Srgrimes * Type out the messages requested. 2901590Srgrimes */ 2911590Srgrimesjmp_buf pipestop; 2921590Srgrimesint 2931590Srgrimestype1(msgvec, doign, page) 2941590Srgrimes int *msgvec; 2951590Srgrimes int doign, page; 2961590Srgrimes{ 2971590Srgrimes register *ip; 2981590Srgrimes register struct message *mp; 2991590Srgrimes register char *cp; 3001590Srgrimes int nlines; 3011590Srgrimes FILE *obuf; 3021590Srgrimes 3031590Srgrimes obuf = stdout; 3041590Srgrimes if (setjmp(pipestop)) 3051590Srgrimes goto close_pipe; 3061590Srgrimes if (value("interactive") != NOSTR && 3071590Srgrimes (page || (cp = value("crt")) != NOSTR)) { 3081590Srgrimes nlines = 0; 3091590Srgrimes if (!page) { 3101590Srgrimes for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) 3111590Srgrimes nlines += message[*ip - 1].m_lines; 3121590Srgrimes } 3131590Srgrimes if (page || nlines > (*cp ? atoi(cp) : realscreenheight)) { 3141590Srgrimes cp = value("PAGER"); 3151590Srgrimes if (cp == NULL || *cp == '\0') 3161590Srgrimes cp = _PATH_MORE; 3171590Srgrimes obuf = Popen(cp, "w"); 3181590Srgrimes if (obuf == NULL) { 3191590Srgrimes perror(cp); 3201590Srgrimes obuf = stdout; 3211590Srgrimes } else 3221590Srgrimes signal(SIGPIPE, brokpipe); 3231590Srgrimes } 3241590Srgrimes } 3251590Srgrimes for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) { 3261590Srgrimes mp = &message[*ip - 1]; 3271590Srgrimes touch(mp); 3281590Srgrimes dot = mp; 3291590Srgrimes if (value("quiet") == NOSTR) 3301590Srgrimes fprintf(obuf, "Message %d:\n", *ip); 3311590Srgrimes (void) send(mp, obuf, doign ? ignore : 0, NOSTR); 3321590Srgrimes } 3331590Srgrimesclose_pipe: 3341590Srgrimes if (obuf != stdout) { 3351590Srgrimes /* 3361590Srgrimes * Ignore SIGPIPE so it can't cause a duplicate close. 3371590Srgrimes */ 3381590Srgrimes signal(SIGPIPE, SIG_IGN); 3391590Srgrimes Pclose(obuf); 3401590Srgrimes signal(SIGPIPE, SIG_DFL); 3411590Srgrimes } 3421590Srgrimes return(0); 3431590Srgrimes} 3441590Srgrimes 3451590Srgrimes/* 3461590Srgrimes * Respond to a broken pipe signal -- 3471590Srgrimes * probably caused by quitting more. 3481590Srgrimes */ 3491590Srgrimesvoid 3501590Srgrimesbrokpipe(signo) 3511590Srgrimes int signo; 3521590Srgrimes{ 3531590Srgrimes longjmp(pipestop, 1); 3541590Srgrimes} 3551590Srgrimes 3561590Srgrimes/* 3571590Srgrimes * Print the top so many lines of each desired message. 3581590Srgrimes * The number of lines is taken from the variable "toplines" 3591590Srgrimes * and defaults to 5. 3601590Srgrimes */ 3611590Srgrimesint 3621590Srgrimestop(msgvec) 3631590Srgrimes int *msgvec; 3641590Srgrimes{ 3651590Srgrimes register int *ip; 3661590Srgrimes register struct message *mp; 3671590Srgrimes int c, topl, lines, lineb; 3681590Srgrimes char *valtop, linebuf[LINESIZE]; 3691590Srgrimes FILE *ibuf; 3701590Srgrimes 3711590Srgrimes topl = 5; 3721590Srgrimes valtop = value("toplines"); 3731590Srgrimes if (valtop != NOSTR) { 3741590Srgrimes topl = atoi(valtop); 3751590Srgrimes if (topl < 0 || topl > 10000) 3761590Srgrimes topl = 5; 3771590Srgrimes } 3781590Srgrimes lineb = 1; 3791590Srgrimes for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { 3801590Srgrimes mp = &message[*ip - 1]; 3811590Srgrimes touch(mp); 3821590Srgrimes dot = mp; 3831590Srgrimes if (value("quiet") == NOSTR) 3841590Srgrimes printf("Message %d:\n", *ip); 3851590Srgrimes ibuf = setinput(mp); 3861590Srgrimes c = mp->m_lines; 3871590Srgrimes if (!lineb) 3881590Srgrimes printf("\n"); 3891590Srgrimes for (lines = 0; lines < c && lines <= topl; lines++) { 3901590Srgrimes if (readline(ibuf, linebuf, LINESIZE) < 0) 3911590Srgrimes break; 3921590Srgrimes puts(linebuf); 3931590Srgrimes lineb = blankline(linebuf); 3941590Srgrimes } 3951590Srgrimes } 3961590Srgrimes return(0); 3971590Srgrimes} 3981590Srgrimes 3991590Srgrimes/* 4001590Srgrimes * Touch all the given messages so that they will 4011590Srgrimes * get mboxed. 4021590Srgrimes */ 4031590Srgrimesint 4041590Srgrimesstouch(msgvec) 4051590Srgrimes int msgvec[]; 4061590Srgrimes{ 4071590Srgrimes register int *ip; 4081590Srgrimes 4091590Srgrimes for (ip = msgvec; *ip != 0; ip++) { 4101590Srgrimes dot = &message[*ip-1]; 4111590Srgrimes dot->m_flag |= MTOUCH; 4121590Srgrimes dot->m_flag &= ~MPRESERVE; 4131590Srgrimes } 4141590Srgrimes return(0); 4151590Srgrimes} 4161590Srgrimes 4171590Srgrimes/* 4181590Srgrimes * Make sure all passed messages get mboxed. 4191590Srgrimes */ 4201590Srgrimesint 4211590Srgrimesmboxit(msgvec) 4221590Srgrimes int msgvec[]; 4231590Srgrimes{ 4241590Srgrimes register int *ip; 4251590Srgrimes 4261590Srgrimes for (ip = msgvec; *ip != 0; ip++) { 4271590Srgrimes dot = &message[*ip-1]; 4281590Srgrimes dot->m_flag |= MTOUCH|MBOX; 4291590Srgrimes dot->m_flag &= ~MPRESERVE; 4301590Srgrimes } 4311590Srgrimes return(0); 4321590Srgrimes} 4331590Srgrimes 4341590Srgrimes/* 4351590Srgrimes * List the folders the user currently has. 4361590Srgrimes */ 4371590Srgrimesint 4381590Srgrimesfolders() 4391590Srgrimes{ 4401590Srgrimes char dirname[BUFSIZ]; 4411590Srgrimes char *cmd; 4421590Srgrimes 4431590Srgrimes if (getfold(dirname) < 0) { 4441590Srgrimes printf("No value set for \"folder\"\n"); 4451590Srgrimes return 1; 4461590Srgrimes } 4471590Srgrimes if ((cmd = value("LISTER")) == NOSTR) 4481590Srgrimes cmd = "ls"; 4491590Srgrimes (void) run_command(cmd, 0, -1, -1, dirname, NOSTR, NOSTR); 4501590Srgrimes return 0; 4511590Srgrimes} 452