xref: /netbsd-src/usr.bin/mail/cmd1.c (revision f49cbbddb9e752ee7256372d9a49971010cdbadd)
1*f49cbbddSchristos /*	$NetBSD: cmd1.c,v 1.34 2013/10/18 20:17:59 christos Exp $	*/
288b833a7Schristos 
361f28255Scgd /*-
42cb5542fSderaadt  * Copyright (c) 1980, 1993
52cb5542fSderaadt  *	The Regents of the University of California.  All rights reserved.
661f28255Scgd  *
761f28255Scgd  * Redistribution and use in source and binary forms, with or without
861f28255Scgd  * modification, are permitted provided that the following conditions
961f28255Scgd  * are met:
1061f28255Scgd  * 1. Redistributions of source code must retain the above copyright
1161f28255Scgd  *    notice, this list of conditions and the following disclaimer.
1261f28255Scgd  * 2. Redistributions in binary form must reproduce the above copyright
1361f28255Scgd  *    notice, this list of conditions and the following disclaimer in the
1461f28255Scgd  *    documentation and/or other materials provided with the distribution.
1589aaa1bbSagc  * 3. Neither the name of the University nor the names of its contributors
1661f28255Scgd  *    may be used to endorse or promote products derived from this software
1761f28255Scgd  *    without specific prior written permission.
1861f28255Scgd  *
1961f28255Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2061f28255Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2161f28255Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2261f28255Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2361f28255Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2461f28255Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2561f28255Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2661f28255Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2761f28255Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2861f28255Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2961f28255Scgd  * SUCH DAMAGE.
3061f28255Scgd  */
3161f28255Scgd 
327c81c8f3Slukem #include <sys/cdefs.h>
3361f28255Scgd #ifndef lint
3488b833a7Schristos #if 0
3519d35cbcStls static char sccsid[] = "@(#)cmd1.c	8.2 (Berkeley) 4/20/95";
3688b833a7Schristos #else
37*f49cbbddSchristos __RCSID("$NetBSD: cmd1.c,v 1.34 2013/10/18 20:17:59 christos Exp $");
3888b833a7Schristos #endif
3961f28255Scgd #endif /* not lint */
4061f28255Scgd 
41f3098750Schristos #include <assert.h>
42f3098750Schristos 
4361f28255Scgd #include "rcv.h"
442cb5542fSderaadt #include "extern.h"
45798fbc60Schristos #include "format.h"
468207b28aSchristos #ifdef MIME_SUPPORT
478207b28aSchristos #include "mime.h"
488207b28aSchristos #endif
49ca13337dSchristos #include "sig.h"
50f3098750Schristos #include "thread.h"
51f3098750Schristos 
5261f28255Scgd 
5361f28255Scgd /*
5461f28255Scgd  * Mail -- a mail program
5561f28255Scgd  *
5661f28255Scgd  * User commands.
5761f28255Scgd  */
5861f28255Scgd 
59f3098750Schristos static int screen;
60f3098750Schristos 
61f3098750Schristos /*
62f3098750Schristos  * Compute screen size.
63f3098750Schristos  */
64f3098750Schristos static int
screensize(void)65f3098750Schristos screensize(void)
66f3098750Schristos {
67f3098750Schristos 	int s;
68f3098750Schristos 	char *cp;
69f3098750Schristos 
70f3098750Schristos 	if ((cp = value(ENAME_SCREEN)) != NULL && (s = atoi(cp)) > 0)
71f3098750Schristos 		return s;
72f3098750Schristos 	return screenheight - 4;
73f3098750Schristos }
74f3098750Schristos 
75f3098750Schristos /*
76f3098750Schristos  * Print out the header of a specific message.
77f3098750Schristos  * This is a slight improvement to the standard one.
78f3098750Schristos  */
79f3098750Schristos PUBLIC void
printhead(int mesg)80f3098750Schristos printhead(int mesg)
81f3098750Schristos {
82f3098750Schristos 	const char *fmtstr;
83f3098750Schristos 	char *msgline;
84f3098750Schristos 
85f3098750Schristos 	fmtstr = value(ENAME_HEADER_FORMAT);
86f3098750Schristos 	if (fmtstr == NULL)
87f3098750Schristos 		fmtstr = DEFAULT_HEADER_FORMAT;
88f3098750Schristos 	msgline = smsgprintf(fmtstr, get_message(mesg));
89f3098750Schristos 	if (screenwidth > 0)
90f3098750Schristos 		msgline[screenwidth] = '\0';
91f3098750Schristos 	(void)printf("%s\n", msgline);
92ca13337dSchristos 	sig_check();
93f3098750Schristos }
94f3098750Schristos 
9561f28255Scgd /*
9661f28255Scgd  * Print the current active headings.
9761f28255Scgd  * Don't change dot if invoker didn't give an argument.
9861f28255Scgd  */
99f3098750Schristos PUBLIC int
headers(void * v)100b127ccccSwiz headers(void *v)
10161f28255Scgd {
102ca13337dSchristos 	int *msgvec;
103ca13337dSchristos 	int n;
104ca13337dSchristos 	int flag;
1057c81c8f3Slukem 	struct message *mp;
10661f28255Scgd 	int size;
10761f28255Scgd 
108ca13337dSchristos 	msgvec = v;
10961f28255Scgd 	size = screensize();
11061f28255Scgd 	n = msgvec[0];
11161f28255Scgd 	if (n != 0)
11261f28255Scgd 		screen = (n - 1)/size;
11361f28255Scgd 	if (screen < 0)
11461f28255Scgd 		screen = 0;
115f3098750Schristos 
116f3098750Schristos 	if ((mp = get_message(screen * size + 1)) == NULL) {
117f3098750Schristos 		int msgCount;
118f3098750Schristos 		msgCount = get_msgCount();
119f3098750Schristos 		if (screen * size + 1 > msgCount)
120f3098750Schristos 			mp = get_message(msgCount - size + 1);
121f3098750Schristos 		if (mp == NULL)
122f3098750Schristos 			mp = get_message(1);
123f3098750Schristos 	}
12461f28255Scgd 	flag = 0;
125f3098750Schristos 	if (dot != get_message(n))
12661f28255Scgd 		dot = mp;
127f3098750Schristos 	for (/*EMPTY*/; mp; mp = next_message(mp)) {
12861f28255Scgd 		if (mp->m_flag & MDELETED)
12961f28255Scgd 			continue;
13061f28255Scgd 		if (flag++ >= size)
13161f28255Scgd 			break;
132f3098750Schristos 		printhead(get_msgnum(mp));
13361f28255Scgd 	}
13461f28255Scgd 	if (flag == 0) {
135ca286310Schristos 		(void)printf("No more mail.\n");
136f3098750Schristos 		return 1;
13761f28255Scgd 	}
138f3098750Schristos 	return 0;
13961f28255Scgd }
14061f28255Scgd 
14161f28255Scgd /*
14261f28255Scgd  * Scroll to the next/previous screen
14361f28255Scgd  */
144f3098750Schristos PUBLIC int
scroll(void * v)145b127ccccSwiz scroll(void *v)
14661f28255Scgd {
147ca13337dSchristos 	char *arg;
148ca13337dSchristos 	int s;
149ca13337dSchristos 	int size;
15061f28255Scgd 	int cur[1];
15161f28255Scgd 
152ca13337dSchristos 	arg = v;
15361f28255Scgd 	cur[0] = 0;
15461f28255Scgd 	size = screensize();
15561f28255Scgd 	s = screen;
15661f28255Scgd 	switch (*arg) {
15761f28255Scgd 	case 0:
15861f28255Scgd 	case '+':
15961f28255Scgd 		s++;
160f3098750Schristos 		if (s * size >= get_msgCount()) {
161ca286310Schristos 			(void)printf("On last screenful of messages\n");
162f3098750Schristos 			return 0;
16361f28255Scgd 		}
16461f28255Scgd 		screen = s;
16561f28255Scgd 		break;
16661f28255Scgd 
16761f28255Scgd 	case '-':
16861f28255Scgd 		if (--s < 0) {
169ca286310Schristos 			(void)printf("On first screenful of messages\n");
170f3098750Schristos 			return 0;
17161f28255Scgd 		}
17261f28255Scgd 		screen = s;
17361f28255Scgd 		break;
17461f28255Scgd 
17561f28255Scgd 	default:
176ca286310Schristos 		(void)printf("Unrecognized scrolling command \"%s\"\n", arg);
177f3098750Schristos 		return 1;
17861f28255Scgd 	}
179f3098750Schristos 	return headers(cur);
18061f28255Scgd }
18161f28255Scgd 
18261f28255Scgd /*
18361f28255Scgd  * Print out the headlines for each message
18461f28255Scgd  * in the passed message list.
18561f28255Scgd  */
186f3098750Schristos PUBLIC int
from(void * v)187b127ccccSwiz from(void *v)
18861f28255Scgd {
189ca13337dSchristos 	int *msgvec;
1907c81c8f3Slukem 	int *ip;
19161f28255Scgd 
192ca13337dSchristos 	msgvec = v;
193f890b048Spk 	for (ip = msgvec; *ip != 0; ip++)
19461f28255Scgd 		printhead(*ip);
19561f28255Scgd 	if (--ip >= msgvec)
196f3098750Schristos 		dot = get_message(*ip);
197f3098750Schristos 	return 0;
19861f28255Scgd }
19961f28255Scgd 
20061f28255Scgd /*
20161f28255Scgd  * Print out the value of dot.
20261f28255Scgd  */
203ca286310Schristos /*ARGSUSED*/
204f3098750Schristos PUBLIC int
pdot(void * v)205f3098750Schristos pdot(void *v)
20661f28255Scgd {
207f3098750Schristos 	int *msgvec;
208f3098750Schristos 
209f3098750Schristos 	msgvec = v;
210f3098750Schristos 	dot = get_message(msgvec[0]);
211f3098750Schristos 
212f3098750Schristos 	(void)printf("%d\n", get_msgnum(dot));
213f3098750Schristos 	return 0;
21461f28255Scgd }
21561f28255Scgd 
21661f28255Scgd /*
21761f28255Scgd  * Print out all the possible commands.
21861f28255Scgd  */
219ca286310Schristos /*ARGSUSED*/
220f3098750Schristos PUBLIC int
pcmdlist(void * v __unused)2218207b28aSchristos pcmdlist(void *v __unused)
22261f28255Scgd {
2237c81c8f3Slukem 	const struct cmd *cp;
224ca13337dSchristos 	size_t cc;
22561f28255Scgd 
226ca286310Schristos 	(void)printf("Commands are:\n");
227ca13337dSchristos 	cc = 0;
228ca13337dSchristos 	for (cp = cmdtab; cp->c_name != NULL; cp++) {
22961f28255Scgd 		cc += strlen(cp->c_name) + 2;
23061f28255Scgd 		if (cc > 72) {
231ca286310Schristos 			(void)printf("\n");
23261f28255Scgd 			cc = strlen(cp->c_name) + 2;
23361f28255Scgd 		}
234ab850155Swiz 		if ((cp + 1)->c_name != NULL)
235ca286310Schristos 			(void)printf("%s, ", cp->c_name);
23661f28255Scgd 		else
237ca286310Schristos 			(void)printf("%s\n", cp->c_name);
238ca13337dSchristos 		sig_check();
23961f28255Scgd 	}
240f3098750Schristos 	return 0;
24161f28255Scgd }
24261f28255Scgd 
243f3098750Schristos 
244f3098750Schristos PUBLIC char *
sget_msgnum(struct message * mp,struct message * parent)245f3098750Schristos sget_msgnum(struct message *mp, struct message *parent)
246f3098750Schristos {
247f3098750Schristos 	char *p;
248ca13337dSchristos 
249f3098750Schristos 	if (parent == NULL || parent == mp) {
250f3098750Schristos 		(void)sasprintf(&p, "%d", mp->m_index);
251f3098750Schristos 		return p;
252f3098750Schristos 	}
253f3098750Schristos 	p = sget_msgnum(mp->m_plink, parent);
254f3098750Schristos 
255f3098750Schristos 	(void)sasprintf(&p, "%s.%d", p, mp->m_index);
256f3098750Schristos 	return p;
257f3098750Schristos }
258f3098750Schristos 
259f3098750Schristos PUBLIC void
show_msgnum(FILE * obuf,struct message * mp,struct message * parent)260f3098750Schristos show_msgnum(FILE *obuf, struct message *mp, struct message *parent)
261f3098750Schristos {
262ca13337dSchristos 
263f3098750Schristos 	if (value(ENAME_QUIET) == NULL)
264f3098750Schristos 		(void)fprintf(obuf, "Message %s:\n", sget_msgnum(mp, parent));
265f3098750Schristos }
266f3098750Schristos 
267f3098750Schristos struct type1_core_args_s {
268f3098750Schristos 	FILE *obuf;
269f3098750Schristos 	struct message *parent;
270f3098750Schristos 	struct ignoretab *igtab;
271f3098750Schristos 	struct mime_info **mip;
272f3098750Schristos };
2738207b28aSchristos static int
type1_core(struct message * mp,void * v)274f3098750Schristos type1_core(struct message *mp, void *v)
2758207b28aSchristos {
276f3098750Schristos 	struct type1_core_args_s *args;
2778207b28aSchristos 
278f3098750Schristos 	args = v;
27961f28255Scgd 	touch(mp);
280f3098750Schristos 	show_msgnum(args->obuf, mp, args->parent);
2818207b28aSchristos #ifdef MIME_SUPPORT
282f3098750Schristos 	if (args->mip == NULL)
283f3098750Schristos 		(void)mime_sendmessage(mp, args->obuf, args->igtab, NULL, NULL);
284f3098750Schristos 	else {
285f3098750Schristos 		*args->mip = mime_decode_open(mp);
286f3098750Schristos 		(void)mime_sendmessage(mp, args->obuf, args->igtab, NULL, *args->mip);
287f3098750Schristos 		mime_decode_close(*args->mip);
2888207b28aSchristos 	}
2898207b28aSchristos #else
290f3098750Schristos 	(void)sendmessage(mp, args->obuf, args->igtab, NULL, NULL);
2918207b28aSchristos #endif
292ca13337dSchristos 	sig_check();
293f3098750Schristos 	return 0;
29461f28255Scgd }
29561f28255Scgd 
29661f28255Scgd /*
29761f28255Scgd  * Respond to a broken pipe signal --
29861f28255Scgd  * probably caused by quitting more.
29961f28255Scgd  */
300f3098750Schristos static jmp_buf	pipestop;
301f3098750Schristos 
302ca286310Schristos /*ARGSUSED*/
3036818646aSjoerg __dead static void
cmd1_brokpipe(int signo __unused)304ca13337dSchristos cmd1_brokpipe(int signo __unused)
30561f28255Scgd {
306ca13337dSchristos 
30761f28255Scgd 	longjmp(pipestop, 1);
30861f28255Scgd }
30961f28255Scgd 
31061f28255Scgd /*
311f3098750Schristos  * Type out the messages requested.
312f3098750Schristos  */
313f3098750Schristos #ifndef MIME_SUPPORT
314f3098750Schristos # define type1(a,b,c)		legacy_type1(a,b)
315f3098750Schristos #endif
316f3098750Schristos static int
type1(int * msgvec,int doign,int mime_decode)317f3098750Schristos type1(int *msgvec, int doign, int mime_decode)
318f3098750Schristos {
319f3098750Schristos 	int recursive;
320f3098750Schristos 	int *ip;
321f3098750Schristos 	int msgCount;
322f3098750Schristos 	/*
323f3098750Schristos 	 * Some volatile variables so longjmp will get the current not
324f3098750Schristos 	 * starting values.  Note it is the variable that is volatile,
325f3098750Schristos 	 * not what it is pointing at!
326f3098750Schristos 	 */
327ca13337dSchristos 	FILE *volatile obuf;		/* avoid longjmp clobbering */
328*f49cbbddSchristos 	int * volatile mvec;
329ca13337dSchristos 	sig_t volatile oldsigpipe;	/* avoid longjmp clobbering? */
330f3098750Schristos #ifdef MIME_SUPPORT
331ca13337dSchristos 	struct mime_info *volatile mip;	/* avoid longjmp clobbering? */
332ca13337dSchristos 
333ca13337dSchristos 	mip = NULL;
334f3098750Schristos #endif
335f3098750Schristos 
336*f49cbbddSchristos 	mvec = msgvec;
337f3098750Schristos 	if ((obuf = last_registered_file(0)) == NULL)
338f3098750Schristos 		obuf = stdout;
339f3098750Schristos 
340ca13337dSchristos 	/*
341ca13337dSchristos 	 * Even without MIME_SUPPORT, we need to handle SIGPIPE here
342ca13337dSchristos 	 * or else the handler in execute() will grab things and our
343ca13337dSchristos 	 * exit code will never be seen.
344ca13337dSchristos 	 */
345ca13337dSchristos 	sig_check();
346ca13337dSchristos 	oldsigpipe = sig_signal(SIGPIPE, cmd1_brokpipe);
347f3098750Schristos 	if (setjmp(pipestop))
348f3098750Schristos 		goto close_pipe;
349f3098750Schristos 
350f3098750Schristos 	msgCount = get_msgCount();
351f3098750Schristos 
352f3098750Schristos 	recursive = do_recursion();
353*f49cbbddSchristos 	for (ip = mvec; *ip && ip - mvec < msgCount; ip++) {
354f3098750Schristos 		struct type1_core_args_s args;
355f3098750Schristos 		struct message *mp;
356f3098750Schristos 
357f3098750Schristos 		mp = get_message(*ip);
358f3098750Schristos 		dot = mp;
359f3098750Schristos 		args.obuf = obuf;
360f3098750Schristos 		args.parent = recursive ? mp : NULL;
361f3098750Schristos 		args.igtab = doign ? ignore : 0;
362f3098750Schristos #ifdef MIME_SUPPORT
363f3098750Schristos 		args.mip = mime_decode ? __UNVOLATILE(&mip) : NULL;
364f3098750Schristos #else
365f3098750Schristos 		args.mip = NULL;
366f3098750Schristos #endif
367f3098750Schristos 		(void)thread_recursion(mp, type1_core, &args);
368f3098750Schristos 	}
369f3098750Schristos close_pipe:
370ca13337dSchristos #ifdef MIME_SUPPORT
371f3098750Schristos 	if (mip != NULL) {
372ca13337dSchristos 		struct sigaction osa;
373ca13337dSchristos 		sigset_t oset;
374ca13337dSchristos 
375f3098750Schristos 		/*
376f3098750Schristos 		 * Ignore SIGPIPE so it can't cause a duplicate close.
377f3098750Schristos 		 */
378ca13337dSchristos 		(void)sig_ignore(SIGPIPE, &osa, &oset);
379f3098750Schristos 		mime_decode_close(mip);
380ca13337dSchristos 		(void)sig_restore(SIGPIPE, &osa, &oset);
381f3098750Schristos 	}
382f3098750Schristos #endif
383ca13337dSchristos 	(void)sig_signal(SIGPIPE, oldsigpipe);
384ca13337dSchristos 	sig_check();
385f3098750Schristos 	return 0;
386f3098750Schristos }
387f3098750Schristos 
388f3098750Schristos #ifdef MIME_SUPPORT
389f3098750Schristos static int
de_mime(void)390f3098750Schristos de_mime(void)
391f3098750Schristos {
392ca13337dSchristos 
393f3098750Schristos 	return value(ENAME_MIME_DECODE_MSG) != NULL;
394f3098750Schristos }
395f3098750Schristos 
396f3098750Schristos /*
397f3098750Schristos  * Identical to type(), but with opposite mime behavior.
398f3098750Schristos  */
399f3098750Schristos PUBLIC int
view(void * v)400f3098750Schristos view(void *v)
401f3098750Schristos {
402ca13337dSchristos 	int *msgvec;
403ca13337dSchristos 
404ca13337dSchristos 	msgvec = v;
405f3098750Schristos 	return type1(msgvec, 1, !de_mime());
406f3098750Schristos }
407f3098750Schristos 
408f3098750Schristos /*
409f3098750Schristos  * Identical to Type(), but with opposite mime behavior.
410f3098750Schristos  */
411f3098750Schristos PUBLIC int
View(void * v)412f3098750Schristos View(void *v)
413f3098750Schristos {
414ca13337dSchristos 	int *msgvec;
415f3098750Schristos 
416ca13337dSchristos 	msgvec = v;
417f3098750Schristos 	return type1(msgvec, 0, !de_mime());
418f3098750Schristos }
419f3098750Schristos #endif /* MIME_SUPPORT */
420f3098750Schristos 
421f3098750Schristos /*
422f3098750Schristos  * Type out messages, honor ignored fields.
423f3098750Schristos  */
424f3098750Schristos PUBLIC int
type(void * v)425f3098750Schristos type(void *v)
426f3098750Schristos {
427ca13337dSchristos 	int *msgvec;
428f3098750Schristos 
429ca13337dSchristos 	msgvec = v;
430f3098750Schristos 	return type1(msgvec, 1, de_mime());
431f3098750Schristos }
432f3098750Schristos 
433f3098750Schristos /*
434f3098750Schristos  * Type out messages, even printing ignored fields.
435f3098750Schristos  */
436f3098750Schristos PUBLIC int
Type(void * v)437f3098750Schristos Type(void *v)
438f3098750Schristos {
439ca13337dSchristos 	int *msgvec;
440f3098750Schristos 
441ca13337dSchristos 	msgvec = v;
442f3098750Schristos 	return type1(msgvec, 0, de_mime());
443f3098750Schristos }
444f3098750Schristos 
445f3098750Schristos /*
44685c81c58Schristos  * Pipe the current message buffer to a command.
44785c81c58Schristos  */
448f3098750Schristos PUBLIC int
pipecmd(void * v)44985c81c58Schristos pipecmd(void *v)
45085c81c58Schristos {
451ca13337dSchristos 	char *cmd;
452ca13337dSchristos 	FILE *volatile obuf;		/* void longjmp clobbering */
453a7879b44Schristos 	sig_t volatile oldsigpipe = sig_current(SIGPIPE);
454ca13337dSchristos 
455ca13337dSchristos 	cmd = v;
45685c81c58Schristos 	if (dot == NULL) {
45785c81c58Schristos 		warn("pipcmd: no current message");
45885c81c58Schristos 		return 1;
45985c81c58Schristos 	}
46085c81c58Schristos 
46185c81c58Schristos 	obuf = stdout;
46285c81c58Schristos 	if (setjmp(pipestop))
46385c81c58Schristos 		goto close_pipe;
46485c81c58Schristos 
465ca13337dSchristos 	sig_check();
4665942983dSchristos 	obuf = Popen(cmd, "we");
46785c81c58Schristos 	if (obuf == NULL) {
46885c81c58Schristos 		warn("pipecmd: Popen failed: %s", cmd);
46985c81c58Schristos 		return 1;
470ca13337dSchristos 	}
471ca13337dSchristos 
472ca13337dSchristos 	oldsigpipe = sig_signal(SIGPIPE, cmd1_brokpipe);
47385c81c58Schristos 
4748207b28aSchristos 	(void)sendmessage(dot, obuf, ignoreall, NULL, NULL);
47585c81c58Schristos  close_pipe:
476ca13337dSchristos 	sig_check();
47785c81c58Schristos 	if (obuf != stdout) {
478ca13337dSchristos 		struct sigaction osa;
479ca13337dSchristos 		sigset_t oset;
48085c81c58Schristos 		/*
48185c81c58Schristos 		 * Ignore SIGPIPE so it can't cause a duplicate close.
48285c81c58Schristos 		 */
483ca13337dSchristos 		(void)sig_ignore(SIGPIPE, &osa, &oset);
4848207b28aSchristos 		(void)Pclose(obuf);
485ca13337dSchristos 		(void)sig_restore(SIGPIPE, &osa, &oset);
48685c81c58Schristos 	}
487ca13337dSchristos 	(void)sig_signal(SIGPIPE, oldsigpipe);
488ca13337dSchristos 	sig_check();
48985c81c58Schristos 	return 0;
49085c81c58Schristos }
49185c81c58Schristos 
492f3098750Schristos struct top_core_args_s {
493f3098750Schristos 	int lineb;
494ca13337dSchristos 	size_t topl;
495f3098750Schristos 	struct message *parent;
496f3098750Schristos };
497f3098750Schristos static int
top_core(struct message * mp,void * v)498f3098750Schristos top_core(struct message *mp, void *v)
499f3098750Schristos {
500f3098750Schristos 	char buffer[LINESIZE];
501f3098750Schristos 	struct top_core_args_s *args;
502f3098750Schristos 	FILE *ibuf;
503ca13337dSchristos 	size_t lines;
504ca13337dSchristos 	size_t c;
505f3098750Schristos 
506f3098750Schristos 	args = v;
507f3098750Schristos 	touch(mp);
508f3098750Schristos 	if (!args->lineb)
509f3098750Schristos 		(void)printf("\n");
510f3098750Schristos 	show_msgnum(stdout, mp, args->parent);
511f3098750Schristos 	ibuf = setinput(mp);
512f3098750Schristos 	c = mp->m_lines;
513f3098750Schristos 	for (lines = 0; lines < c && lines <= args->topl; lines++) {
514ca13337dSchristos 		sig_check();
515ca13337dSchristos 		if (readline(ibuf, buffer, (int)sizeof(buffer), 0) < 0)
516f3098750Schristos 			break;
517f3098750Schristos 		(void)puts(buffer);
518f3098750Schristos 		args->lineb = blankline(buffer);
519f3098750Schristos 	}
520ca13337dSchristos 	sig_check();
521f3098750Schristos 	return 0;
522f3098750Schristos }
523f3098750Schristos 
52485c81c58Schristos /*
52561f28255Scgd  * Print the top so many lines of each desired message.
52661f28255Scgd  * The number of lines is taken from the variable "toplines"
52761f28255Scgd  * and defaults to 5.
52861f28255Scgd  */
529f3098750Schristos PUBLIC int
top(void * v)530b127ccccSwiz top(void *v)
53161f28255Scgd {
532f3098750Schristos 	struct top_core_args_s args;
533f3098750Schristos 	int recursive;
534f3098750Schristos 	int msgCount;
535ca13337dSchristos 	int *msgvec;
5367c81c8f3Slukem 	int *ip;
537f3098750Schristos 	int topl;
538f3098750Schristos 	char *valtop;
53961f28255Scgd 
540ca13337dSchristos 	msgvec = v;
54161f28255Scgd 	topl = 5;
542f3098750Schristos 	valtop = value(ENAME_TOPLINES);
543ab850155Swiz 	if (valtop != NULL) {
54461f28255Scgd 		topl = atoi(valtop);
54561f28255Scgd 		if (topl < 0 || topl > 10000)
54661f28255Scgd 			topl = 5;
54761f28255Scgd 	}
548f3098750Schristos 	args.topl = topl;
549f3098750Schristos 	args.lineb = 1;
550f3098750Schristos 	recursive = do_recursion();
551f3098750Schristos 	msgCount = get_msgCount();
55261f28255Scgd 	for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) {
553f3098750Schristos 		struct message *mp;
554f3098750Schristos 
555f3098750Schristos 		mp = get_message(*ip);
55661f28255Scgd 		dot = mp;
557f3098750Schristos 		args.parent = recursive ? mp : NULL;
558f3098750Schristos 		(void)thread_recursion(mp, top_core, &args);
55961f28255Scgd 	}
560f3098750Schristos 	return 0;
56161f28255Scgd }
56261f28255Scgd 
56361f28255Scgd /*
56461f28255Scgd  * Touch all the given messages so that they will
56561f28255Scgd  * get mboxed.
56661f28255Scgd  */
567f3098750Schristos PUBLIC int
stouch(void * v)568b127ccccSwiz stouch(void *v)
56961f28255Scgd {
570ca13337dSchristos 	int *msgvec;
5717c81c8f3Slukem 	int *ip;
57261f28255Scgd 
573ca13337dSchristos 	msgvec = v;
574ca13337dSchristos 	for (ip = msgvec; *ip != 0; ip++) {
575ca13337dSchristos 		sig_check();
576f3098750Schristos 		dot = set_m_flag(*ip, ~(MPRESERVE | MTOUCH), MTOUCH);
577ca13337dSchristos 	}
578f3098750Schristos 	return 0;
57961f28255Scgd }
58061f28255Scgd 
58161f28255Scgd /*
58261f28255Scgd  * Make sure all passed messages get mboxed.
58361f28255Scgd  */
584f3098750Schristos PUBLIC int
mboxit(void * v)585b127ccccSwiz mboxit(void *v)
58661f28255Scgd {
587ca13337dSchristos 	int *msgvec;
5887c81c8f3Slukem 	int *ip;
58961f28255Scgd 
590ca13337dSchristos 	msgvec = v;
591ca13337dSchristos 	for (ip = msgvec; *ip != 0; ip++) {
592ca13337dSchristos 		sig_check();
593f3098750Schristos 		dot = set_m_flag(*ip,
594f3098750Schristos 		    ~(MPRESERVE | MTOUCH | MBOX), MTOUCH | MBOX);
595ca13337dSchristos 	}
596f3098750Schristos 	return 0;
59761f28255Scgd }
59861f28255Scgd 
59961f28255Scgd /*
60061f28255Scgd  * List the folders the user currently has.
60161f28255Scgd  */
602ca286310Schristos /*ARGSUSED*/
603f3098750Schristos PUBLIC int
folders(void * v __unused)6048207b28aSchristos folders(void *v __unused)
60561f28255Scgd {
606254cb6fdSmikel 	char dirname[PATHSIZE];
607ece0fd5cSchristos 	const char *cmd;
60861f28255Scgd 
609f3098750Schristos 	if (getfold(dirname, sizeof(dirname)) < 0) {
610ca286310Schristos 		(void)printf("No value set for \"folder\"\n");
61161f28255Scgd 		return 1;
61261f28255Scgd 	}
613f3098750Schristos 	if ((cmd = value(ENAME_LISTER)) == NULL)
61461f28255Scgd 		cmd = "ls";
615ca13337dSchristos 	(void)run_command(cmd, NULL, -1, -1, dirname, NULL);
61661f28255Scgd 	return 0;
61761f28255Scgd }
61819d35cbcStls 
61919d35cbcStls /*
62019d35cbcStls  * Update the mail file with any new messages that have
62119d35cbcStls  * come in since we started reading mail.
62219d35cbcStls  */
623ca286310Schristos /*ARGSUSED*/
624f3098750Schristos PUBLIC int
inc(void * v __unused)6258207b28aSchristos inc(void *v __unused)
62619d35cbcStls {
627ca13337dSchristos 	int nmsg;
628ca13337dSchristos 	int mdot;
62919d35cbcStls 
63019d35cbcStls 	nmsg = incfile();
63119d35cbcStls 
63219d35cbcStls 	if (nmsg == 0) {
633ca286310Schristos 		(void)printf("No new mail.\n");
63419d35cbcStls 	} else if (nmsg > 0) {
635f3098750Schristos 		struct message *mp;
636f3098750Schristos 		mdot = newfileinfo(get_abs_msgCount() - nmsg);
637f3098750Schristos 		if ((mp = get_message(mdot)) != NULL)
638f3098750Schristos 			dot = mp;
63919d35cbcStls 	} else {
640ca286310Schristos 		(void)printf("\"inc\" command failed...\n");
64119d35cbcStls 	}
64219d35cbcStls 	return 0;
64319d35cbcStls }
644