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