143105Sedward /*-
262083Sbostic * Copyright (c) 1980, 1993
362083Sbostic * The Regents of the University of California. All rights reserved.
433499Sbostic *
543105Sedward * %sccs.include.redist.c%
622644Sdist */
722644Sdist
834905Sbostic #ifndef lint
9*68818Sdab static char sccsid[] = "@(#)cmd1.c 8.2 (Berkeley) 04/20/95";
1034905Sbostic #endif /* not lint */
1114523Ssam
121223Skas #include "rcv.h"
1354505Sbostic #include "extern.h"
141223Skas
151223Skas /*
161223Skas * Mail -- a mail program
171223Skas *
181223Skas * User commands.
191223Skas */
201223Skas
211223Skas /*
221223Skas * Print the current active headings.
232214Skas * Don't change dot if invoker didn't give an argument.
241223Skas */
251223Skas
261223Skas static int screen;
271223Skas
2854505Sbostic int
headers(msgvec)291223Skas headers(msgvec)
301223Skas int *msgvec;
311223Skas {
321223Skas register int n, mesg, flag;
331223Skas register struct message *mp;
346224Skurt int size;
351223Skas
366224Skurt size = screensize();
371223Skas n = msgvec[0];
381223Skas if (n != 0)
396224Skurt screen = (n-1)/size;
401223Skas if (screen < 0)
411223Skas screen = 0;
426224Skurt mp = &message[screen * size];
431223Skas if (mp >= &message[msgCount])
446224Skurt mp = &message[msgCount - size];
451223Skas if (mp < &message[0])
461223Skas mp = &message[0];
471223Skas flag = 0;
481223Skas mesg = mp - &message[0];
492214Skas if (dot != &message[n-1])
502214Skas dot = mp;
511223Skas for (; mp < &message[msgCount]; mp++) {
521223Skas mesg++;
531223Skas if (mp->m_flag & MDELETED)
541223Skas continue;
556224Skurt if (flag++ >= size)
561223Skas break;
571223Skas printhead(mesg);
581223Skas }
591223Skas if (flag == 0) {
601223Skas printf("No more mail.\n");
611223Skas return(1);
621223Skas }
631223Skas return(0);
641223Skas }
651223Skas
661223Skas /*
671223Skas * Scroll to the next/previous screen
681223Skas */
6954505Sbostic int
scroll(arg)701223Skas scroll(arg)
711223Skas char arg[];
721223Skas {
736224Skurt register int s, size;
741223Skas int cur[1];
751223Skas
761223Skas cur[0] = 0;
776224Skurt size = screensize();
781223Skas s = screen;
791223Skas switch (*arg) {
801223Skas case 0:
811223Skas case '+':
821223Skas s++;
836224Skurt if (s * size > msgCount) {
841223Skas printf("On last screenful of messages\n");
851223Skas return(0);
861223Skas }
871223Skas screen = s;
881223Skas break;
891223Skas
901223Skas case '-':
911223Skas if (--s < 0) {
921223Skas printf("On first screenful of messages\n");
931223Skas return(0);
941223Skas }
951223Skas screen = s;
961223Skas break;
971223Skas
981223Skas default:
991223Skas printf("Unrecognized scrolling command \"%s\"\n", arg);
1001223Skas return(1);
1011223Skas }
1021223Skas return(headers(cur));
1031223Skas }
1041223Skas
1056224Skurt /*
10631142Sedward * Compute screen size.
1076224Skurt */
10854505Sbostic int
screensize()1096224Skurt screensize()
1106224Skurt {
11131142Sedward int s;
11231142Sedward char *cp;
1131223Skas
11431142Sedward if ((cp = value("screen")) != NOSTR && (s = atoi(cp)) > 0)
11531142Sedward return s;
11631142Sedward return screenheight - 4;
1176224Skurt }
1186224Skurt
1191223Skas /*
1201223Skas * Print out the headlines for each message
1211223Skas * in the passed message list.
1221223Skas */
12354505Sbostic int
from(msgvec)1241223Skas from(msgvec)
1251223Skas int *msgvec;
1261223Skas {
1271223Skas register int *ip;
1281223Skas
12934968Sedward for (ip = msgvec; *ip != NULL; ip++)
1301223Skas printhead(*ip);
1311223Skas if (--ip >= msgvec)
1321223Skas dot = &message[*ip - 1];
1331223Skas return(0);
1341223Skas }
1351223Skas
1361223Skas /*
1371223Skas * Print out the header of a specific message.
1381223Skas * This is a slight improvement to the standard one.
1391223Skas */
14054505Sbostic void
printhead(mesg)1411223Skas printhead(mesg)
14254505Sbostic int mesg;
1431223Skas {
1441223Skas struct message *mp;
14524755Sserge char headline[LINESIZE], wcount[LINESIZE], *subjline, dispc, curind;
1461223Skas char pbuf[BUFSIZ];
1471223Skas struct headline hl;
14831142Sedward int subjlen;
14943105Sedward char *name;
1501223Skas
1511223Skas mp = &message[mesg-1];
15236478Sedward (void) readline(setinput(mp), headline, LINESIZE);
15331142Sedward if ((subjline = hfield("subject", mp)) == NOSTR)
1541223Skas subjline = hfield("subj", mp);
1551223Skas /*
1561223Skas * Bletch!
1571223Skas */
1582214Skas curind = dot == mp ? '>' : ' ';
1591223Skas dispc = ' ';
1601223Skas if (mp->m_flag & MSAVED)
1611223Skas dispc = '*';
1621223Skas if (mp->m_flag & MPRESERVE)
1631223Skas dispc = 'P';
1641480Skas if ((mp->m_flag & (MREAD|MNEW)) == MNEW)
1651480Skas dispc = 'N';
1661480Skas if ((mp->m_flag & (MREAD|MNEW)) == 0)
1671473Skas dispc = 'U';
1683318Skas if (mp->m_flag & MBOX)
1693318Skas dispc = 'M';
1701223Skas parse(headline, &hl, pbuf);
17143105Sedward sprintf(wcount, "%3d/%-5ld", mp->m_lines, mp->m_size);
17231142Sedward subjlen = screenwidth - 50 - strlen(wcount);
17343105Sedward name = value("show-rcpt") != NOSTR ?
17443105Sedward skin(hfield("to", mp)) : nameof(mp, 0);
17531142Sedward if (subjline == NOSTR || subjlen < 0) /* pretty pathetic */
17631142Sedward printf("%c%c%3d %-20.20s %16.16s %s\n",
17743105Sedward curind, dispc, mesg, name, hl.l_date, wcount);
1781223Skas else
17931142Sedward printf("%c%c%3d %-20.20s %16.16s %s \"%.*s\"\n",
18043105Sedward curind, dispc, mesg, name, hl.l_date, wcount,
18131142Sedward subjlen, subjline);
1821223Skas }
1831223Skas
1841223Skas /*
1851223Skas * Print out the value of dot.
1861223Skas */
18754505Sbostic int
pdot()1881223Skas pdot()
1891223Skas {
1901223Skas printf("%d\n", dot - &message[0] + 1);
1911223Skas return(0);
1921223Skas }
1931223Skas
1941223Skas /*
1951223Skas * Print out all the possible commands.
1961223Skas */
19754505Sbostic int
pcmdlist()1981223Skas pcmdlist()
1991223Skas {
2001223Skas register struct cmd *cp;
2011223Skas register int cc;
2021223Skas extern struct cmd cmdtab[];
2031223Skas
2041223Skas printf("Commands are:\n");
2051223Skas for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) {
2061223Skas cc += strlen(cp->c_name) + 2;
2071223Skas if (cc > 72) {
2081223Skas printf("\n");
2091223Skas cc = strlen(cp->c_name) + 2;
2101223Skas }
2111223Skas if ((cp+1)->c_name != NOSTR)
2121223Skas printf("%s, ", cp->c_name);
2131223Skas else
2141223Skas printf("%s\n", cp->c_name);
2151223Skas }
2161223Skas return(0);
2171223Skas }
2181223Skas
2191223Skas /*
22022604Sserge * Paginate messages, honor ignored fields.
22122604Sserge */
22254505Sbostic int
more(msgvec)22322604Sserge more(msgvec)
22422604Sserge int *msgvec;
22522604Sserge {
22622604Sserge return (type1(msgvec, 1, 1));
22722604Sserge }
22822604Sserge
22922604Sserge /*
23022604Sserge * Paginate messages, even printing ignored fields.
23122604Sserge */
23254505Sbostic int
More(msgvec)23322604Sserge More(msgvec)
23422604Sserge int *msgvec;
23522604Sserge {
23622604Sserge
23722604Sserge return (type1(msgvec, 0, 1));
23822604Sserge }
23922604Sserge
24022604Sserge /*
2417572Skurt * Type out messages, honor ignored fields.
2427572Skurt */
24354505Sbostic int
type(msgvec)2447572Skurt type(msgvec)
2457572Skurt int *msgvec;
2467572Skurt {
2477572Skurt
24822604Sserge return(type1(msgvec, 1, 0));
2497572Skurt }
2507572Skurt
2517572Skurt /*
2527572Skurt * Type out messages, even printing ignored fields.
2537572Skurt */
25454505Sbostic int
Type(msgvec)2557572Skurt Type(msgvec)
2567572Skurt int *msgvec;
2577572Skurt {
2587572Skurt
25922604Sserge return(type1(msgvec, 0, 0));
2607572Skurt }
2617572Skurt
2627572Skurt /*
2631223Skas * Type out the messages requested.
2641223Skas */
2651307Skas jmp_buf pipestop;
26654505Sbostic int
type1(msgvec,doign,page)26722604Sserge type1(msgvec, doign, page)
2681223Skas int *msgvec;
26954505Sbostic int doign, page;
2701223Skas {
2711223Skas register *ip;
2721223Skas register struct message *mp;
2731307Skas register char *cp;
27431142Sedward int nlines;
27531142Sedward FILE *obuf;
2761223Skas
2771307Skas obuf = stdout;
27843865Sedward if (setjmp(pipestop))
27943865Sedward goto close_pipe;
28034751Sedward if (value("interactive") != NOSTR &&
28134751Sedward (page || (cp = value("crt")) != NOSTR)) {
28224755Sserge nlines = 0;
28322604Sserge if (!page) {
28422604Sserge for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++)
28522604Sserge nlines += message[*ip - 1].m_lines;
28622604Sserge }
28734749Sedward if (page || nlines > (*cp ? atoi(cp) : realscreenheight)) {
28824755Sserge cp = value("PAGER");
28924755Sserge if (cp == NULL || *cp == '\0')
29037870Sbostic cp = _PATH_MORE;
29134877Sedward obuf = Popen(cp, "w");
2921307Skas if (obuf == NULL) {
29324755Sserge perror(cp);
2941307Skas obuf = stdout;
29543865Sedward } else
29631142Sedward signal(SIGPIPE, brokpipe);
2971307Skas }
2981307Skas }
29931142Sedward for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) {
30034987Sedward mp = &message[*ip - 1];
30134987Sedward touch(mp);
3021223Skas dot = mp;
30331142Sedward if (value("quiet") == NOSTR)
30434987Sedward fprintf(obuf, "Message %d:\n", *ip);
30534969Sedward (void) send(mp, obuf, doign ? ignore : 0, NOSTR);
3061223Skas }
30743865Sedward close_pipe:
3081307Skas if (obuf != stdout) {
30943865Sedward /*
31043865Sedward * Ignore SIGPIPE so it can't cause a duplicate close.
31143865Sedward */
31243865Sedward signal(SIGPIPE, SIG_IGN);
31334877Sedward Pclose(obuf);
31443865Sedward signal(SIGPIPE, SIG_DFL);
3151307Skas }
3161223Skas return(0);
3171223Skas }
3181223Skas
3191223Skas /*
3201307Skas * Respond to a broken pipe signal --
32143865Sedward * probably caused by quitting more.
3221307Skas */
32347709Sbostic void
brokpipe(signo)32454505Sbostic brokpipe(signo)
32554505Sbostic int signo;
3261307Skas {
3271307Skas longjmp(pipestop, 1);
3281307Skas }
3291307Skas
3301307Skas /*
3311223Skas * Print the top so many lines of each desired message.
3321223Skas * The number of lines is taken from the variable "toplines"
3331223Skas * and defaults to 5.
3341223Skas */
33554505Sbostic int
top(msgvec)3361223Skas top(msgvec)
3371223Skas int *msgvec;
3381223Skas {
3391223Skas register int *ip;
3401223Skas register struct message *mp;
3411223Skas int c, topl, lines, lineb;
3421223Skas char *valtop, linebuf[LINESIZE];
3431223Skas FILE *ibuf;
3441223Skas
3451223Skas topl = 5;
3461223Skas valtop = value("toplines");
3471223Skas if (valtop != NOSTR) {
3481223Skas topl = atoi(valtop);
3491223Skas if (topl < 0 || topl > 10000)
3501223Skas topl = 5;
3511223Skas }
3521223Skas lineb = 1;
3531223Skas for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
35434987Sedward mp = &message[*ip - 1];
35534987Sedward touch(mp);
3561223Skas dot = mp;
3571223Skas if (value("quiet") == NOSTR)
35834987Sedward printf("Message %d:\n", *ip);
3591223Skas ibuf = setinput(mp);
3601223Skas c = mp->m_lines;
3611223Skas if (!lineb)
3621223Skas printf("\n");
3631223Skas for (lines = 0; lines < c && lines <= topl; lines++) {
36436478Sedward if (readline(ibuf, linebuf, LINESIZE) < 0)
3651223Skas break;
3661223Skas puts(linebuf);
3671223Skas lineb = blankline(linebuf);
3681223Skas }
3691223Skas }
3701223Skas return(0);
3711223Skas }
3721223Skas
3731223Skas /*
3741223Skas * Touch all the given messages so that they will
3751223Skas * get mboxed.
3761223Skas */
37754505Sbostic int
stouch(msgvec)3781223Skas stouch(msgvec)
3791223Skas int msgvec[];
3801223Skas {
3811223Skas register int *ip;
3821223Skas
3831223Skas for (ip = msgvec; *ip != 0; ip++) {
3841223Skas dot = &message[*ip-1];
3851480Skas dot->m_flag |= MTOUCH;
3861223Skas dot->m_flag &= ~MPRESERVE;
3871223Skas }
3881223Skas return(0);
3891223Skas }
3903318Skas
3913318Skas /*
3923318Skas * Make sure all passed messages get mboxed.
3933318Skas */
39454505Sbostic int
mboxit(msgvec)3953318Skas mboxit(msgvec)
3963318Skas int msgvec[];
3973318Skas {
3983318Skas register int *ip;
3993318Skas
4003318Skas for (ip = msgvec; *ip != 0; ip++) {
4013318Skas dot = &message[*ip-1];
4023318Skas dot->m_flag |= MTOUCH|MBOX;
4033318Skas dot->m_flag &= ~MPRESERVE;
4043318Skas }
4053318Skas return(0);
4063318Skas }
4076224Skurt
4086224Skurt /*
4096224Skurt * List the folders the user currently has.
4106224Skurt */
41154505Sbostic int
folders()4126224Skurt folders()
4136224Skurt {
41431142Sedward char dirname[BUFSIZ];
41534963Sedward char *cmd;
4166224Skurt
4176224Skurt if (getfold(dirname) < 0) {
4186224Skurt printf("No value set for \"folder\"\n");
41936554Sedward return 1;
4206224Skurt }
42134963Sedward if ((cmd = value("LISTER")) == NOSTR)
42234963Sedward cmd = "ls";
42354505Sbostic (void) run_command(cmd, 0, -1, -1, dirname, NOSTR, NOSTR);
42434963Sedward return 0;
4256224Skurt }
426*68818Sdab
427*68818Sdab /*
428*68818Sdab * Update the mail file with any new messages that have
429*68818Sdab * come in since we started reading mail.
430*68818Sdab */
inc()431*68818Sdab inc()
432*68818Sdab {
433*68818Sdab int nmsg, mdot;
434*68818Sdab
435*68818Sdab nmsg = incfile();
436*68818Sdab
437*68818Sdab if (nmsg == 0) {
438*68818Sdab printf("No new mail.\n");
439*68818Sdab } else if (nmsg > 0) {
440*68818Sdab mdot = newfileinfo(msgCount - nmsg);
441*68818Sdab dot = &message[mdot - 1];
442*68818Sdab } else {
443*68818Sdab printf("\"inc\" command failed...\n");
444*68818Sdab }
445*68818Sdab
446*68818Sdab return 0;
447*68818Sdab }
448