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