Home | History | Annotate | Line # | Download | only in mail
cmd1.c revision 1.1.1.3
      1 /*-
      2  * Copyright (c) 1980, 1993
      3  *	The Regents of the University of California.  All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. All advertising materials mentioning features or use of this software
     14  *    must display the following acknowledgement:
     15  *	This product includes software developed by the University of
     16  *	California, Berkeley and its contributors.
     17  * 4. Neither the name of the University nor the names of its contributors
     18  *    may be used to endorse or promote products derived from this software
     19  *    without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  * SUCH DAMAGE.
     32  */
     33 
     34 #ifndef lint
     35 static char sccsid[] = "@(#)cmd1.c	8.2 (Berkeley) 4/20/95";
     36 #endif /* not lint */
     37 
     38 #include "rcv.h"
     39 #include "extern.h"
     40 
     41 /*
     42  * Mail -- a mail program
     43  *
     44  * User commands.
     45  */
     46 
     47 /*
     48  * Print the current active headings.
     49  * Don't change dot if invoker didn't give an argument.
     50  */
     51 
     52 static int screen;
     53 
     54 int
     55 headers(msgvec)
     56 	int *msgvec;
     57 {
     58 	register int n, mesg, flag;
     59 	register struct message *mp;
     60 	int size;
     61 
     62 	size = screensize();
     63 	n = msgvec[0];
     64 	if (n != 0)
     65 		screen = (n-1)/size;
     66 	if (screen < 0)
     67 		screen = 0;
     68 	mp = &message[screen * size];
     69 	if (mp >= &message[msgCount])
     70 		mp = &message[msgCount - size];
     71 	if (mp < &message[0])
     72 		mp = &message[0];
     73 	flag = 0;
     74 	mesg = mp - &message[0];
     75 	if (dot != &message[n-1])
     76 		dot = mp;
     77 	for (; mp < &message[msgCount]; mp++) {
     78 		mesg++;
     79 		if (mp->m_flag & MDELETED)
     80 			continue;
     81 		if (flag++ >= size)
     82 			break;
     83 		printhead(mesg);
     84 	}
     85 	if (flag == 0) {
     86 		printf("No more mail.\n");
     87 		return(1);
     88 	}
     89 	return(0);
     90 }
     91 
     92 /*
     93  * Scroll to the next/previous screen
     94  */
     95 int
     96 scroll(arg)
     97 	char arg[];
     98 {
     99 	register int s, size;
    100 	int cur[1];
    101 
    102 	cur[0] = 0;
    103 	size = screensize();
    104 	s = screen;
    105 	switch (*arg) {
    106 	case 0:
    107 	case '+':
    108 		s++;
    109 		if (s * size > msgCount) {
    110 			printf("On last screenful of messages\n");
    111 			return(0);
    112 		}
    113 		screen = s;
    114 		break;
    115 
    116 	case '-':
    117 		if (--s < 0) {
    118 			printf("On first screenful of messages\n");
    119 			return(0);
    120 		}
    121 		screen = s;
    122 		break;
    123 
    124 	default:
    125 		printf("Unrecognized scrolling command \"%s\"\n", arg);
    126 		return(1);
    127 	}
    128 	return(headers(cur));
    129 }
    130 
    131 /*
    132  * Compute screen size.
    133  */
    134 int
    135 screensize()
    136 {
    137 	int s;
    138 	char *cp;
    139 
    140 	if ((cp = value("screen")) != NOSTR && (s = atoi(cp)) > 0)
    141 		return s;
    142 	return screenheight - 4;
    143 }
    144 
    145 /*
    146  * Print out the headlines for each message
    147  * in the passed message list.
    148  */
    149 int
    150 from(msgvec)
    151 	int *msgvec;
    152 {
    153 	register int *ip;
    154 
    155 	for (ip = msgvec; *ip != NULL; ip++)
    156 		printhead(*ip);
    157 	if (--ip >= msgvec)
    158 		dot = &message[*ip - 1];
    159 	return(0);
    160 }
    161 
    162 /*
    163  * Print out the header of a specific message.
    164  * This is a slight improvement to the standard one.
    165  */
    166 void
    167 printhead(mesg)
    168 	int mesg;
    169 {
    170 	struct message *mp;
    171 	char headline[LINESIZE], wcount[LINESIZE], *subjline, dispc, curind;
    172 	char pbuf[BUFSIZ];
    173 	struct headline hl;
    174 	int subjlen;
    175 	char *name;
    176 
    177 	mp = &message[mesg-1];
    178 	(void) readline(setinput(mp), headline, LINESIZE);
    179 	if ((subjline = hfield("subject", mp)) == NOSTR)
    180 		subjline = hfield("subj", mp);
    181 	/*
    182 	 * Bletch!
    183 	 */
    184 	curind = dot == mp ? '>' : ' ';
    185 	dispc = ' ';
    186 	if (mp->m_flag & MSAVED)
    187 		dispc = '*';
    188 	if (mp->m_flag & MPRESERVE)
    189 		dispc = 'P';
    190 	if ((mp->m_flag & (MREAD|MNEW)) == MNEW)
    191 		dispc = 'N';
    192 	if ((mp->m_flag & (MREAD|MNEW)) == 0)
    193 		dispc = 'U';
    194 	if (mp->m_flag & MBOX)
    195 		dispc = 'M';
    196 	parse(headline, &hl, pbuf);
    197 	sprintf(wcount, "%3d/%-5ld", mp->m_lines, mp->m_size);
    198 	subjlen = screenwidth - 50 - strlen(wcount);
    199 	name = value("show-rcpt") != NOSTR ?
    200 		skin(hfield("to", mp)) : nameof(mp, 0);
    201 	if (subjline == NOSTR || subjlen < 0)		/* pretty pathetic */
    202 		printf("%c%c%3d %-20.20s  %16.16s %s\n",
    203 			curind, dispc, mesg, name, hl.l_date, wcount);
    204 	else
    205 		printf("%c%c%3d %-20.20s  %16.16s %s \"%.*s\"\n",
    206 			curind, dispc, mesg, name, hl.l_date, wcount,
    207 			subjlen, subjline);
    208 }
    209 
    210 /*
    211  * Print out the value of dot.
    212  */
    213 int
    214 pdot()
    215 {
    216 	printf("%d\n", dot - &message[0] + 1);
    217 	return(0);
    218 }
    219 
    220 /*
    221  * Print out all the possible commands.
    222  */
    223 int
    224 pcmdlist()
    225 {
    226 	register struct cmd *cp;
    227 	register int cc;
    228 	extern struct cmd cmdtab[];
    229 
    230 	printf("Commands are:\n");
    231 	for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) {
    232 		cc += strlen(cp->c_name) + 2;
    233 		if (cc > 72) {
    234 			printf("\n");
    235 			cc = strlen(cp->c_name) + 2;
    236 		}
    237 		if ((cp+1)->c_name != NOSTR)
    238 			printf("%s, ", cp->c_name);
    239 		else
    240 			printf("%s\n", cp->c_name);
    241 	}
    242 	return(0);
    243 }
    244 
    245 /*
    246  * Paginate messages, honor ignored fields.
    247  */
    248 int
    249 more(msgvec)
    250 	int *msgvec;
    251 {
    252 	return (type1(msgvec, 1, 1));
    253 }
    254 
    255 /*
    256  * Paginate messages, even printing ignored fields.
    257  */
    258 int
    259 More(msgvec)
    260 	int *msgvec;
    261 {
    262 
    263 	return (type1(msgvec, 0, 1));
    264 }
    265 
    266 /*
    267  * Type out messages, honor ignored fields.
    268  */
    269 int
    270 type(msgvec)
    271 	int *msgvec;
    272 {
    273 
    274 	return(type1(msgvec, 1, 0));
    275 }
    276 
    277 /*
    278  * Type out messages, even printing ignored fields.
    279  */
    280 int
    281 Type(msgvec)
    282 	int *msgvec;
    283 {
    284 
    285 	return(type1(msgvec, 0, 0));
    286 }
    287 
    288 /*
    289  * Type out the messages requested.
    290  */
    291 jmp_buf	pipestop;
    292 int
    293 type1(msgvec, doign, page)
    294 	int *msgvec;
    295 	int doign, page;
    296 {
    297 	register *ip;
    298 	register struct message *mp;
    299 	register char *cp;
    300 	int nlines;
    301 	FILE *obuf;
    302 
    303 	obuf = stdout;
    304 	if (setjmp(pipestop))
    305 		goto close_pipe;
    306 	if (value("interactive") != NOSTR &&
    307 	    (page || (cp = value("crt")) != NOSTR)) {
    308 		nlines = 0;
    309 		if (!page) {
    310 			for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++)
    311 				nlines += message[*ip - 1].m_lines;
    312 		}
    313 		if (page || nlines > (*cp ? atoi(cp) : realscreenheight)) {
    314 			cp = value("PAGER");
    315 			if (cp == NULL || *cp == '\0')
    316 				cp = _PATH_MORE;
    317 			obuf = Popen(cp, "w");
    318 			if (obuf == NULL) {
    319 				perror(cp);
    320 				obuf = stdout;
    321 			} else
    322 				signal(SIGPIPE, brokpipe);
    323 		}
    324 	}
    325 	for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) {
    326 		mp = &message[*ip - 1];
    327 		touch(mp);
    328 		dot = mp;
    329 		if (value("quiet") == NOSTR)
    330 			fprintf(obuf, "Message %d:\n", *ip);
    331 		(void) send(mp, obuf, doign ? ignore : 0, NOSTR);
    332 	}
    333 close_pipe:
    334 	if (obuf != stdout) {
    335 		/*
    336 		 * Ignore SIGPIPE so it can't cause a duplicate close.
    337 		 */
    338 		signal(SIGPIPE, SIG_IGN);
    339 		Pclose(obuf);
    340 		signal(SIGPIPE, SIG_DFL);
    341 	}
    342 	return(0);
    343 }
    344 
    345 /*
    346  * Respond to a broken pipe signal --
    347  * probably caused by quitting more.
    348  */
    349 void
    350 brokpipe(signo)
    351 	int signo;
    352 {
    353 	longjmp(pipestop, 1);
    354 }
    355 
    356 /*
    357  * Print the top so many lines of each desired message.
    358  * The number of lines is taken from the variable "toplines"
    359  * and defaults to 5.
    360  */
    361 int
    362 top(msgvec)
    363 	int *msgvec;
    364 {
    365 	register int *ip;
    366 	register struct message *mp;
    367 	int c, topl, lines, lineb;
    368 	char *valtop, linebuf[LINESIZE];
    369 	FILE *ibuf;
    370 
    371 	topl = 5;
    372 	valtop = value("toplines");
    373 	if (valtop != NOSTR) {
    374 		topl = atoi(valtop);
    375 		if (topl < 0 || topl > 10000)
    376 			topl = 5;
    377 	}
    378 	lineb = 1;
    379 	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
    380 		mp = &message[*ip - 1];
    381 		touch(mp);
    382 		dot = mp;
    383 		if (value("quiet") == NOSTR)
    384 			printf("Message %d:\n", *ip);
    385 		ibuf = setinput(mp);
    386 		c = mp->m_lines;
    387 		if (!lineb)
    388 			printf("\n");
    389 		for (lines = 0; lines < c && lines <= topl; lines++) {
    390 			if (readline(ibuf, linebuf, LINESIZE) < 0)
    391 				break;
    392 			puts(linebuf);
    393 			lineb = blankline(linebuf);
    394 		}
    395 	}
    396 	return(0);
    397 }
    398 
    399 /*
    400  * Touch all the given messages so that they will
    401  * get mboxed.
    402  */
    403 int
    404 stouch(msgvec)
    405 	int msgvec[];
    406 {
    407 	register int *ip;
    408 
    409 	for (ip = msgvec; *ip != 0; ip++) {
    410 		dot = &message[*ip-1];
    411 		dot->m_flag |= MTOUCH;
    412 		dot->m_flag &= ~MPRESERVE;
    413 	}
    414 	return(0);
    415 }
    416 
    417 /*
    418  * Make sure all passed messages get mboxed.
    419  */
    420 int
    421 mboxit(msgvec)
    422 	int msgvec[];
    423 {
    424 	register int *ip;
    425 
    426 	for (ip = msgvec; *ip != 0; ip++) {
    427 		dot = &message[*ip-1];
    428 		dot->m_flag |= MTOUCH|MBOX;
    429 		dot->m_flag &= ~MPRESERVE;
    430 	}
    431 	return(0);
    432 }
    433 
    434 /*
    435  * List the folders the user currently has.
    436  */
    437 int
    438 folders()
    439 {
    440 	char dirname[BUFSIZ];
    441 	char *cmd;
    442 
    443 	if (getfold(dirname) < 0) {
    444 		printf("No value set for \"folder\"\n");
    445 		return 1;
    446 	}
    447 	if ((cmd = value("LISTER")) == NOSTR)
    448 		cmd = "ls";
    449 	(void) run_command(cmd, 0, -1, -1, dirname, NOSTR, NOSTR);
    450 	return 0;
    451 }
    452 
    453 /*
    454  * Update the mail file with any new messages that have
    455  * come in since we started reading mail.
    456  */
    457 inc()
    458 {
    459 	int nmsg, mdot;
    460 
    461 	nmsg = incfile();
    462 
    463 	if (nmsg == 0) {
    464 		printf("No new mail.\n");
    465 	} else if (nmsg > 0) {
    466 		mdot = newfileinfo(msgCount - nmsg);
    467 		dot = &message[mdot - 1];
    468 	} else {
    469 		printf("\"inc\" command failed...\n");
    470 	}
    471 
    472 	return 0;
    473 }
    474