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