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