diff usr/src/cmd/mailx/cmd1.c @ 0:c9caec207d52 b86

Initial porting based on b86
author Koji Uno <koji.uno@sun.com>
date Tue, 02 Jun 2009 18:56:50 +0900
parents
children 1a15d5aaf794
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mailx/cmd1.c	Tue Jun 02 18:56:50 2009 +0900
@@ -0,0 +1,624 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2001 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
+/*	  All Rights Reserved  	*/
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+#pragma ident	"@(#)cmd1.c	1.26	05/06/13 SMI"
+
+#include "rcv.h"
+#include <locale.h>
+
+/*
+ * mailx -- a modified version of a University of California at Berkeley
+ *	mail program
+ *
+ * User commands.
+ */
+
+static char	*dispname(char *hdr);
+static void	print(register struct message *mp, FILE *obuf, int doign);
+static int	type1(int *msgvec, int doign, int page);
+static int	topputs(const char *line, FILE *obuf);
+
+void	brokpipe(int sig);
+jmp_buf	pipestop;
+
+/*
+ * Print the current active headings.
+ * Don't change dot if invoker didn't give an argument.
+ */
+
+static int curscreen = 0, oldscreensize = 0;
+
+int
+headers(int *msgvec)
+{
+	register int n, mesg, flag;
+	register struct message *mp;
+	int size;
+
+	size = screensize();
+	n = msgvec[0];
+	if (n != 0)
+		curscreen = (n-1)/size;
+	if (curscreen < 0)
+		curscreen = 0;
+	mp = &message[curscreen * size];
+	if (mp >= &message[msgCount])
+		mp = &message[msgCount - size];
+	if (mp < &message[0])
+		mp = &message[0];
+	flag = 0;
+	mesg = mp - &message[0];
+	if (dot != &message[n-1])
+		dot = mp;
+	if (Hflag)
+		mp = message;
+	for (; mp < &message[msgCount]; mp++) {
+		mesg++;
+		if (mp->m_flag & MDELETED)
+			continue;
+		if (flag++ >= size && !Hflag)
+			break;
+		printhead(mesg);
+		sreset();
+	}
+	if (flag == 0) {
+		printf(gettext("No more mail.\n"));
+		return (1);
+	}
+	return (0);
+}
+
+/*
+ * Scroll to the next/previous screen
+ */
+
+int
+scroll(char arg[])
+{
+	register int s, size;
+	int cur[1];
+
+	cur[0] = 0;
+	size = screensize();
+	s = curscreen;
+	switch (*arg) {
+	case 0:
+	case '+':
+		s++;
+		if (s * size > msgCount) {
+			printf(gettext("On last screenful of messages\n"));
+			return (0);
+		}
+		curscreen = s;
+		break;
+
+	case '-':
+		if (--s < 0) {
+			printf(gettext("On first screenful of messages\n"));
+			return (0);
+		}
+		curscreen = s;
+		break;
+
+	default:
+		printf(gettext("Unrecognized scrolling command \"%s\"\n"), arg);
+		return (1);
+	}
+	return (headers(cur));
+}
+
+/*
+ * Compute what the screen size should be.
+ * We use the following algorithm:
+ *	If user specifies with screen option, use that.
+ *	If baud rate < 1200, use  5
+ *	If baud rate = 1200, use 10
+ *	If baud rate > 1200, use 20
+ */
+int
+screensize(void)
+{
+	register char *cp;
+	register int newscreensize, tmp;
+#ifdef	TIOCGWINSZ
+	struct winsize ws;
+#endif
+
+	if ((cp = value("screen")) != NOSTR && (tmp = atoi(cp)) > 0)
+		newscreensize = tmp;
+	else if (baud < B1200)
+		newscreensize = 5;
+	else if (baud == B1200)
+		newscreensize = 10;
+#ifdef	TIOCGWINSZ
+	else if (ioctl(fileno(stdout), TIOCGWINSZ, &ws) == 0 && ws.ws_row > 4)
+		newscreensize = ws.ws_row - 4;
+#endif
+	else
+		newscreensize = 20;
+	/* renormalize the value of curscreen */
+	if (newscreensize != oldscreensize) {
+		curscreen = curscreen * oldscreensize / newscreensize;
+		oldscreensize = newscreensize;
+	}
+	return (newscreensize);
+}
+
+/*
+ * Print out the headlines for each message
+ * in the passed message list.
+ */
+
+int
+from(int *msgvec)
+{
+	register int *ip;
+
+	for (ip = msgvec; *ip != NULL; ip++) {
+		printhead(*ip);
+		sreset();
+	}
+	if (--ip >= msgvec)
+		dot = &message[*ip - 1];
+	return (0);
+}
+
+/*
+ * Print out the header of a specific message.
+ * This is a slight improvement to the standard one.
+ */
+
+void
+printhead(int mesg)
+{
+	struct message *mp;
+	FILE *ibuf;
+	char headline[LINESIZE], *subjline, dispc, curind;
+	char *fromline;
+	char pbuf[LINESIZE];
+	char name[LINESIZE];
+	struct headline hl;
+	register char *cp;
+	int showto;
+
+	mp = &message[mesg-1];
+	ibuf = setinput(mp);
+	readline(ibuf, headline);
+	if ((subjline = hfield("subject", mp, addone)) == NOSTR &&
+	    (subjline = hfield("subj", mp, addone)) == NOSTR &&
+	    (subjline = hfield("message-status", mp, addone)) == NOSTR)
+		subjline = "";
+
+	curind = (!Hflag && dot == mp) ? '>' : ' ';
+	dispc = ' ';
+	showto = 0;
+	if ((mp->m_flag & (MREAD|MNEW)) == (MREAD|MNEW))
+		dispc = 'R';
+	if (!(int)value("bsdcompat") && (mp->m_flag & (MREAD|MNEW)) == MREAD)
+		dispc = 'O';
+	if ((mp->m_flag & (MREAD|MNEW)) == MNEW)
+		dispc = 'N';
+	if ((mp->m_flag & (MREAD|MNEW)) == 0)
+		dispc = 'U';
+	if (mp->m_flag & MSAVED)
+		if ((int)value("bsdcompat"))
+			dispc = '*';
+		else
+			dispc = 'S';
+	if (mp->m_flag & MPRESERVE)
+		if ((int)value("bsdcompat"))
+			dispc = 'P';
+		else
+			dispc = 'H';
+	if (mp->m_flag & MBOX)
+		dispc = 'M';
+	parse(headline, &hl, pbuf);
+	if (hl.l_date == NOSTR)
+		hl.l_date = "<Unknown date>";
+
+	/*
+	 * Netnews interface?
+	 */
+
+	if (newsflg) {
+		if ((fromline = hfield("newsgroups", mp, addone)) == NOSTR &&
+		    (fromline = hfield("article-id", mp, addone)) == NOSTR)
+			fromline = "<>";
+		else
+			for (cp = fromline; *cp; cp++) { /* limit length */
+				if (any(*cp, " ,\n")) {
+					*cp = '\0';
+					break;
+				}
+			}
+	/*
+	 * else regular.
+	 */
+
+	} else {
+		fromline = nameof(mp);
+		if (value("showto") &&
+		    samebody(myname, skin(fromline), FALSE) &&
+		    (cp = hfield("to", mp, addto))) {
+			showto = 1;
+			yankword(cp, fromline = name, sizeof (name),
+				docomma(cp));
+		}
+		if (value("showname"))
+			fromline = dispname(fromline);
+		else
+			fromline = skin(fromline);
+	}
+	printf("%c%c%3d ", curind, dispc, mesg);
+	if ((int)value("showfull")) {
+		if (showto)
+			printf("To %-15s ", fromline);
+		else
+			printf("%-18s ", fromline);
+	} else {
+		if (showto)
+			printf("To %-15.15s ", fromline);
+		else
+			printf("%-18.18s ", fromline);
+	}
+	if (mp->m_text) {
+		printf("%16.16s %4ld/%-5ld %-.25s\n",
+			hl.l_date, mp->m_lines, mp->m_size, subjline);
+	} else {
+		printf("%16.16s binary/%-5ld %-.25s\n", hl.l_date, mp->m_size,
+		    subjline);
+	}
+}
+
+/*
+ * Return the full name from an RFC-822 header line
+ * or the last two (or one) component of the address.
+ */
+
+static char *
+dispname(char *hdr)
+{
+	char *cp, *cp2;
+
+	if (hdr == 0)
+		return (0);
+	if (((cp = strchr(hdr, '<')) != 0) && (cp > hdr)) {
+		*cp = 0;
+		if ((*hdr == '"') && ((cp = strrchr(++hdr, '"')) != 0))
+			*cp = 0;
+		return (hdr);
+	} else if ((cp = strchr(hdr, '(')) != 0) {
+		hdr = ++cp;
+		if ((cp = strchr(hdr, '+')) != 0)
+			*cp = 0;
+		if ((cp = strrchr(hdr, ')')) != 0)
+			*cp = 0;
+		return (hdr);
+	}
+	cp = skin(hdr);
+	if ((cp2 = strrchr(cp, '!')) != 0) {
+		while (cp2 >= cp && *--cp2 != '!');
+		cp = ++cp2;
+	}
+	return (cp);
+}
+
+/*
+ * Print out the value of dot.
+ */
+
+int
+pdot(void)
+{
+	printf("%d\n", dot - &message[0] + 1);
+	return (0);
+}
+
+/*
+ * Print out all the possible commands.
+ */
+
+int
+pcmdlist(void)
+{
+	register const struct cmd *cp;
+	register int cc;
+
+	printf("Commands are:\n");
+	for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) {
+		cc += strlen(cp->c_name) + 2;
+		if (cc > 72) {
+			printf("\n");
+			cc = strlen(cp->c_name) + 2;
+		}
+		if ((cp+1)->c_name != NOSTR)
+			printf("%s, ", cp->c_name);
+		else
+			printf("%s\n", cp->c_name);
+	}
+	return (0);
+}
+
+/*
+ * Paginate messages, honor ignored fields.
+ */
+int
+more(int *msgvec)
+{
+	return (type1(msgvec, 1, 1));
+}
+
+/*
+ * Paginate messages, even printing ignored fields.
+ */
+int
+More(int *msgvec)
+{
+
+	return (type1(msgvec, 0, 1));
+}
+
+/*
+ * Type out messages, honor ignored fields.
+ */
+int
+type(int *msgvec)
+{
+
+	return (type1(msgvec, 1, 0));
+}
+
+/*
+ * Type out messages, even printing ignored fields.
+ */
+int
+Type(int *msgvec)
+{
+
+	return (type1(msgvec, 0, 0));
+}
+
+/*
+ * Type out the messages requested.
+ */
+static int
+type1(int *msgvec, int doign, int page)
+{
+	int *ip;
+	register struct message *mp;
+	register int mesg;
+	register char *cp;
+	long nlines;
+	FILE *obuf;
+	void (*sigint)(int), (*sigpipe)(int);
+	int setsigs = 0;
+
+	obuf = stdout;
+	if (setjmp(pipestop)) {
+		if (obuf != stdout) {
+			pipef = NULL;
+			npclose(obuf);
+		}
+		goto ret0;
+	}
+	if (intty && outtty && (page || (cp = value("crt")) != NOSTR)) {
+		if (!page) {
+			nlines = 0;
+			for (ip = msgvec, nlines = 0;
+			    *ip && ip-msgvec < msgCount; ip++)
+				nlines += message[*ip - 1].m_lines;
+		}
+		if (page ||
+		    nlines > (*cp == '\0' ? screensize() - 2 : atoi(cp))) {
+			obuf = npopen(MORE, "w");
+			if (obuf == NULL) {
+				perror(MORE);
+				obuf = stdout;
+			} else {
+				pipef = obuf;
+				sigint = sigset(SIGINT, SIG_IGN);
+				sigpipe = sigset(SIGPIPE, brokpipe);
+				setsigs++;
+			}
+		}
+	}
+	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
+		mesg = *ip;
+		touch(mesg);
+		mp = &message[mesg-1];
+		dot = mp;
+		print(mp, obuf, doign);
+	}
+	if (obuf != stdout) {
+		pipef = NULL;
+		npclose(obuf);
+	}
+ret0:
+	if (setsigs) {
+		sigset(SIGPIPE, sigpipe);
+		sigset(SIGINT, sigint);
+	}
+	return (0);
+}
+
+/*
+ * Respond to a broken pipe signal --
+ * probably caused by user quitting more.
+ */
+void
+#ifdef	__cplusplus
+brokpipe(int)
+#else
+/* ARGSUSED */
+brokpipe(int s)
+#endif
+{
+#ifdef OLD_BSD_SIGS
+	sigrelse(SIGPIPE);
+#endif
+	longjmp(pipestop, 1);
+}
+
+/*
+ * Print the indicated message on standard output.
+ */
+
+static void
+print(register struct message *mp, FILE *obuf, int doign)
+{
+
+	if (value("quiet") == NOSTR && (!doign || !isign("message", 0)))
+		fprintf(obuf, "Message %2d:\n", mp - &message[0] + 1);
+	touch(mp - &message[0] + 1);
+	if (mp->m_text) {
+		(void) msend(mp, obuf, doign ? M_IGNORE : 0, fputs);
+	} else {
+		fprintf(obuf, "\n%s\n", gettext(binmsg));
+	}
+}
+
+/*
+ * Print the top so many lines of each desired message.
+ * The number of lines is taken from the variable "toplines"
+ * and defaults to 5.
+ */
+
+static	long	top_linecount, top_maxlines, top_lineb;
+static	jmp_buf	top_buf;
+
+int
+top(int *msgvec)
+{
+	register int *ip;
+	register struct message *mp;
+	register int mesg;
+	char *valtop;
+
+	top_maxlines = 5;
+	valtop = value("toplines");
+	if (valtop != NOSTR) {
+		top_maxlines = atoi(valtop);
+		if (top_maxlines < 0 || top_maxlines > 10000)
+			top_maxlines = 5;
+	}
+	top_lineb = 1;
+	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
+		mesg = *ip;
+		touch(mesg);
+		mp = &message[mesg-1];
+		dot = mp;
+		if (value("quiet") == NOSTR)
+			printf("Message %2d:\n", mesg);
+		if (!top_lineb)
+			printf("\n");
+		top_linecount = 0;
+		if (setjmp(top_buf) == 0) {
+			if (mp->m_text) {
+				(void) msend(mp, stdout, M_IGNORE, topputs);
+			} else {
+				printf("\n%s\n", gettext(binmsg));
+			}
+		}
+	}
+	return (0);
+}
+
+int
+topputs(const char *line, FILE *obuf)
+{
+	if (top_linecount++ >= top_maxlines)
+		longjmp(top_buf, 1);
+	top_lineb = blankline(line);
+	return (fputs(line, obuf));
+}
+
+/*
+ * Touch all the given messages so that they will
+ * get mboxed.
+ */
+
+int
+stouch(int msgvec[])
+{
+	register int *ip;
+
+	for (ip = msgvec; *ip != 0; ip++) {
+		dot = &message[*ip-1];
+		dot->m_flag |= MTOUCH;
+		dot->m_flag &= ~MPRESERVE;
+	}
+	return (0);
+}
+
+/*
+ * Make sure all passed messages get mboxed.
+ */
+
+int
+mboxit(int msgvec[])
+{
+	register int *ip;
+
+	for (ip = msgvec; *ip != 0; ip++) {
+		dot = &message[*ip-1];
+		dot->m_flag |= MTOUCH|MBOX;
+		dot->m_flag &= ~MPRESERVE;
+	}
+	return (0);
+}
+
+/*
+ * List the folders the user currently has.
+ */
+int
+folders(char **arglist)
+{
+	char dirname[BUFSIZ], cmd[BUFSIZ];
+
+	if (getfold(dirname) < 0) {
+		printf(gettext("No value set for \"folder\"\n"));
+		return (-1);
+	}
+	if (*arglist) {
+		nstrcat(dirname, sizeof (dirname), "/");
+		nstrcat(dirname, sizeof (dirname), *arglist);
+	}
+	snprintf(cmd, sizeof (cmd), "%s %s", LS, dirname);
+	return (system(cmd));
+}