1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 * Copyright (c) 2016 by Delphix. All rights reserved.
26 */
27
28/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
29/*	  All Rights Reserved  	*/
30
31/*
32 * University Copyright- Copyright (c) 1982, 1986, 1988
33 * The Regents of the University of California
34 * All Rights Reserved
35 *
36 * University Acknowledgment- Portions of this document are derived from
37 * software developed by the University of California, Berkeley, and its
38 * contributors.
39 */
40
41#include "rcv.h"
42#ifndef preSVr4
43#include <locale.h>
44#endif
45
46/*
47 * mailx -- a modified version of a University of California at Berkeley
48 *	mail program
49 *
50 * Startup -- interface with user.
51 */
52
53static void		hdrstop(int);
54
55static jmp_buf	hdrjmp;
56
57const char *const version = "mailx version 5.0";
58
59/*
60 * Find out who the user is, copy their mail file (if exists) into
61 * /tmp/Rxxxxx and set up the message pointers.  Then, print out the
62 * message headers and read user commands.
63 *
64 * Command line syntax:
65 *	mailx [ -i ] [ -r address ] [ -h number ] [ -f [ name ] ]
66 * or:
67 *	mailx [ -i ] [ -r address ] [ -h number ] people ...
68 *
69 * and a bunch of other options.
70 */
71
72int
73main(int argc, char **argv)
74{
75	register char *ef;
76	register int argp;
77	int mustsend, f, goerr = 0;
78	void (*prevint)(int);
79	int loaded = 0;
80	struct termio tbuf;
81	struct termios tbufs;
82	int c;
83	char *cwd, *mf;
84
85	/*
86	 * Set up a reasonable environment.
87	 * Figure out whether we are being run interactively, set up
88	 * all the temporary files, buffer standard output, and so forth.
89	 */
90
91#ifndef preSVr4
92	(void)setlocale(LC_ALL, "");
93#endif
94#if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
95#define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
96#endif
97	(void) textdomain(TEXT_DOMAIN);
98
99#ifdef SIGCONT
100	sigset(SIGCONT, SIG_DFL);
101#endif
102	rpterr = 0;	/* initialize; set when we output to stderr */
103	progname = argv[0];
104	if (progname[strlen(progname) - 1] != 'x') {
105		assign("bsdcompat", "");
106	}
107	myegid = getegid();
108	myrgid = getgid();
109	myeuid = geteuid();
110	myruid = getuid();
111	mypid = getpid();
112	setgid(myrgid);
113	setuid(myruid);
114	inithost();
115	intty = isatty(0);
116	if (ioctl(1, TCGETS, &tbufs) < 0) {
117		if (ioctl(1, TCGETA, &tbuf)==0) {
118			outtty = 1;
119			baud = tbuf.c_cflag & CBAUD;
120		} else
121			baud = B9600;
122	} else {
123		outtty = 1;
124		baud = cfgetospeed(&tbufs);
125	}
126	image = -1;
127
128	/*
129	 * Now, determine how we are being used.
130	 * We successively pick off instances of -r, -h, -f, and -i.
131	 * If called as "rmail" we note this fact for letter sending.
132	 * If there is anything left, it is the base of the list
133	 * of users to mail to.  Argp will be set to point to the
134	 * first of these users.
135	 */
136
137	ef = NOSTR;
138	argp = -1;
139	mustsend = 0;
140	if (argc > 0 && **argv == 'r')
141		rmail++;
142	while ((c = getopt(argc, argv, "b:Bc:defFh:HiInNr:s:u:UtT:vV~")) != EOF)
143		switch (c) {
144		case 'e':
145			/*
146			 * exit status only
147			 */
148			exitflg++;
149			break;
150
151		case 'r':
152			/*
153			 * Next argument is address to be sent along
154			 * to the mailer.
155			 */
156			mustsend++;
157			rflag = optarg;
158			break;
159
160		case 'T':
161			/*
162			 * Next argument is temp file to write which
163			 * articles have been read/deleted for netnews.
164			 */
165			Tflag = optarg;
166			if ((f = creat(Tflag, TEMPPERM)) < 0) {
167				perror(Tflag);
168				exit(1);
169			}
170			close(f);
171			/* fall through for -I too */
172			/* FALLTHROUGH */
173
174		case 'I':
175			/*
176			 * print newsgroup in header summary
177			 */
178			newsflg++;
179			break;
180
181		case 'u':
182			/*
183			 * Next argument is person's mailbox to use.
184			 * Treated the same as "-f /var/mail/user".
185			 */
186			{
187			static char u[PATHSIZE];
188			snprintf(u, sizeof (u), "%s%s", maildir, optarg);
189			ef = u;
190			break;
191			}
192
193		case 'i':
194			/*
195			 * User wants to ignore interrupts.
196			 * Set the variable "ignore"
197			 */
198			assign("ignore", "");
199			break;
200
201		case 'U':
202			UnUUCP++;
203			break;
204
205		case 'd':
206			assign("debug", "");
207			break;
208
209		case 'h':
210			/*
211			 * Specified sequence number for network.
212			 * This is the number of "hops" made so
213			 * far (count of times message has been
214			 * forwarded) to help avoid infinite mail loops.
215			 */
216			mustsend++;
217			hflag = atoi(optarg);
218			if (hflag == 0) {
219				fprintf(stderr,
220				    gettext("-h needs non-zero number\n"));
221				goerr++;
222			}
223			break;
224
225		case 's':
226			/*
227			 * Give a subject field for sending from
228			 * non terminal
229			 */
230			mustsend++;
231			sflag = optarg;
232			break;
233
234		case 'c':	/* Cc: from command line */
235			mustsend++;
236			cflag = optarg;
237			break;
238
239		case 'b':	/* Bcc: from command line */
240			mustsend++;
241			bflag = optarg;
242			break;
243
244		case 'f':
245			/*
246			 * User is specifying file to "edit" with mailx,
247			 * as opposed to reading system mailbox.
248			 * If no argument is given after -f, we read their
249			 * $MBOX file or mbox in their home directory.
250			 */
251			ef = (argc == optind || *argv[optind] == '-')
252				? "" : argv[optind++];
253			if (*ef && *ef != '/' && *ef != '+')
254				cwd = getcwd(NOSTR, PATHSIZE);
255			break;
256
257		case 'F':
258			Fflag++;
259			mustsend++;
260			break;
261
262		case 'n':
263			/*
264			 * User doesn't want to source
265			 *	/etc/mail/mailx.rc
266			 */
267			nosrc++;
268			break;
269
270		case 'N':
271			/*
272			 * Avoid initial header printing.
273			 */
274			noheader++;
275			break;
276
277		case 'H':
278			/*
279			 * Print headers and exit
280			 */
281			Hflag++;
282			break;
283
284		case 'V':
285			puts(version);
286			return 0;
287
288		case '~':
289			/*
290			 * Permit tildas no matter where
291			 * the input is coming from.
292			 */
293			assign("escapeok", "");
294			break;
295
296		case 'v':
297			/*
298			 * Send mailer verbose flag
299			 */
300			assign("verbose", "");
301			break;
302
303		case 'B':
304			/*
305			 * Don't buffer output
306			 * (Line buffered is good enough)
307			 */
308			setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
309			setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
310			break;
311
312		case 't':
313			/*
314			 * Like sendmail -t, read headers from text
315			 */
316			tflag++;
317			mustsend++;
318			break;
319
320		case '?':
321		default:
322			goerr++;
323			break;
324		}
325
326	if (optind != argc)
327		argp = optind;
328
329	/*
330	 * Check for inconsistent arguments.
331	 */
332
333	if (newsflg && ef==NOSTR) {
334		fprintf(stderr, gettext("Need -f with -I flag\n"));
335		goerr++;
336	}
337	if (ef != NOSTR && argp != -1) {
338		fprintf(stderr,
339		    gettext("Cannot give -f and people to send to.\n"));
340		goerr++;
341	}
342	if (exitflg && (mustsend || argp != -1))
343		exit(1);	/* nonsense flags involving -e simply exit */
344	if (tflag && argp != -1) {
345		fprintf(stderr,
346		    gettext("Ignoring recipients on command line with -t\n"));
347		argp = -1;
348	} else if (!tflag && mustsend && argp == -1) {
349		fprintf(stderr,
350	    gettext("The flags you gave are used only when sending mail.\n"));
351		goerr++;
352	}
353	if (goerr) {
354		fprintf(stderr,
355gettext("Usage: %s -eiIUdFntBNHvV~ -T FILE -u USER -h hops -r address\n"),
356		    progname);
357		fprintf(stderr,
358		    gettext("\t\t-s SUBJECT -f FILE users\n"));
359		exit(1);
360	}
361	tinit();
362	input = stdin;
363	rcvmode = !tflag && argp == -1;
364	if (!nosrc)
365		load(MASTER);
366
367	if (!rcvmode) {
368		load(Getf("MAILRC"));
369		if (tflag)
370			tmail();
371		else
372			mail(&argv[argp]);
373		exit(senderr ? senderr : rpterr);
374	}
375
376	/*
377	 * Ok, we are reading mail.
378	 * Decide whether we are editing a mailbox or reading
379	 * the system mailbox, and open up the right stuff.
380	 *
381	 * Do this before sourcing the MAILRC, because there might be
382	 * a 'chdir' there that breaks the -f option.  But if the
383	 * file specified with -f is a folder name, go ahead and
384	 * source the MAILRC anyway so that "folder" will be defined.
385	 */
386
387	nstrcpy(origname, PATHSIZE, mailname);
388	editfile = mailname;
389
390	if (ef != NOSTR) {
391		if (ef == NOSTR || *ef == '\0' || *ef == '+') {
392			load(Getf("MAILRC"));
393			loaded++;
394		}
395		ef = *ef ? safeexpand(ef) : Getf("MBOX");
396		nstrcpy(origname, PATHSIZE, ef);
397		if (ef[0] != '/') {
398			if (cwd == NOSTR)
399				cwd = getcwd(NOSTR, PATHSIZE);
400			nstrcat(cwd, PATHSIZE, "/");
401			nstrcat(cwd, PATHSIZE, ef);
402			ef = cwd;
403		}
404		editfile = ef;
405		edit++;
406	}
407
408	if (setfile(editfile, edit) < 0)
409		exit(1);
410
411	if (!loaded)
412		load(Getf("MAILRC"));
413	if (msgCount > 0 && !noheader && value("header") != NOSTR) {
414		if (setjmp(hdrjmp) == 0) {
415			if ((prevint = sigset(SIGINT, SIG_IGN)) != SIG_IGN)
416				sigset(SIGINT, hdrstop);
417			announce();
418			fflush(stdout);
419			sigset(SIGINT, prevint);
420		}
421	}
422	if (Hflag || (!edit && msgCount == 0)) {
423		if (!Hflag) {
424			fprintf(stderr, gettext("No mail for %s\n"), myname);
425			Verhogen();
426		}
427		fflush(stdout);
428		exit(rpterr);
429	}
430	commands();
431	sigset(SIGHUP, SIG_IGN);
432	sigset(SIGINT, SIG_IGN);
433	sigset(SIGQUIT, SIG_IGN);
434	if (!outtty)
435		sigset(SIGPIPE, SIG_IGN);
436	if (edit)
437		edstop(0);
438	else {
439		quit(0);
440		Verhogen();
441	}
442	return (rpterr);
443}
444
445/*
446 * Interrupt printing of the headers.
447 */
448static void
449#ifdef	__cplusplus
450hdrstop(int)
451#else
452/* ARGSUSED */
453hdrstop(int s)
454#endif
455{
456
457	fflush(stdout);
458	fprintf(stderr, gettext("\nInterrupt\n"));
459# ifdef OLD_BSD_SIGS
460	sigrelse(SIGINT);
461# endif
462	longjmp(hdrjmp, 1);
463}
464