Merge commit 'b1e7e97d3b60469b243b3b2e22c7d8cbd11c7c90'
[unleashed.git] / usr / src / cmd / mailx / main.c
blobf9819ca4a0a12c3fb5a3b169ccd9059e8dd018e8
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
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.
28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
29 /* All Rights Reserved */
32 * University Copyright- Copyright (c) 1982, 1986, 1988
33 * The Regents of the University of California
34 * All Rights Reserved
36 * University Acknowledgment- Portions of this document are derived from
37 * software developed by the University of California, Berkeley, and its
38 * contributors.
41 #include "rcv.h"
42 #ifndef preSVr4
43 #include <locale.h>
44 #endif
47 * mailx -- a modified version of a University of California at Berkeley
48 * mail program
50 * Startup -- interface with user.
53 static void hdrstop(int);
55 static jmp_buf hdrjmp;
57 const char *const version = "mailx version 5.0";
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.
64 * Command line syntax:
65 * mailx [ -i ] [ -r address ] [ -h number ] [ -f [ name ] ]
66 * or:
67 * mailx [ -i ] [ -r address ] [ -h number ] people ...
69 * and a bunch of other options.
72 int
73 main(int argc, char **argv)
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;
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.
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);
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", "");
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);
126 image = -1;
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.
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':
146 * exit status only
148 exitflg++;
149 break;
151 case 'r':
153 * Next argument is address to be sent along
154 * to the mailer.
156 mustsend++;
157 rflag = optarg;
158 break;
160 case 'T':
162 * Next argument is temp file to write which
163 * articles have been read/deleted for netnews.
165 Tflag = optarg;
166 if ((f = creat(Tflag, TEMPPERM)) < 0) {
167 perror(Tflag);
168 exit(1);
170 close(f);
171 /* fall through for -I too */
172 /* FALLTHROUGH */
174 case 'I':
176 * print newsgroup in header summary
178 newsflg++;
179 break;
181 case 'u':
183 * Next argument is person's mailbox to use.
184 * Treated the same as "-f /var/mail/user".
187 static char u[PATHSIZE];
188 snprintf(u, sizeof (u), "%s%s", maildir, optarg);
189 ef = u;
190 break;
193 case 'i':
195 * User wants to ignore interrupts.
196 * Set the variable "ignore"
198 assign("ignore", "");
199 break;
201 case 'U':
202 UnUUCP++;
203 break;
205 case 'd':
206 assign("debug", "");
207 break;
209 case 'h':
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.
216 mustsend++;
217 hflag = atoi(optarg);
218 if (hflag == 0) {
219 fprintf(stderr,
220 gettext("-h needs non-zero number\n"));
221 goerr++;
223 break;
225 case 's':
227 * Give a subject field for sending from
228 * non terminal
230 mustsend++;
231 sflag = optarg;
232 break;
234 case 'c': /* Cc: from command line */
235 mustsend++;
236 cflag = optarg;
237 break;
239 case 'b': /* Bcc: from command line */
240 mustsend++;
241 bflag = optarg;
242 break;
244 case 'f':
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.
251 ef = (argc == optind || *argv[optind] == '-')
252 ? "" : argv[optind++];
253 if (*ef && *ef != '/' && *ef != '+')
254 cwd = getcwd(NOSTR, PATHSIZE);
255 break;
257 case 'F':
258 Fflag++;
259 mustsend++;
260 break;
262 case 'n':
264 * User doesn't want to source
265 * /etc/mail/mailx.rc
267 nosrc++;
268 break;
270 case 'N':
272 * Avoid initial header printing.
274 noheader++;
275 break;
277 case 'H':
279 * Print headers and exit
281 Hflag++;
282 break;
284 case 'V':
285 puts(version);
286 return 0;
288 case '~':
290 * Permit tildas no matter where
291 * the input is coming from.
293 assign("escapeok", "");
294 break;
296 case 'v':
298 * Send mailer verbose flag
300 assign("verbose", "");
301 break;
303 case 'B':
305 * Don't buffer output
306 * (Line buffered is good enough)
308 setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
309 setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
310 break;
312 case 't':
314 * Like sendmail -t, read headers from text
316 tflag++;
317 mustsend++;
318 break;
320 case '?':
321 default:
322 goerr++;
323 break;
326 if (optind != argc)
327 argp = optind;
330 * Check for inconsistent arguments.
333 if (newsflg && ef==NOSTR) {
334 fprintf(stderr, gettext("Need -f with -I flag\n"));
335 goerr++;
337 if (ef != NOSTR && argp != -1) {
338 fprintf(stderr,
339 gettext("Cannot give -f and people to send to.\n"));
340 goerr++;
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++;
353 if (goerr) {
354 fprintf(stderr,
355 gettext("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);
361 tinit();
362 input = stdin;
363 rcvmode = !tflag && argp == -1;
364 if (!nosrc)
365 load(MASTER);
367 if (!rcvmode) {
368 load(Getf("MAILRC"));
369 if (tflag)
370 tmail();
371 else
372 mail(&argv[argp]);
373 exit(senderr ? senderr : rpterr);
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.
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.
387 nstrcpy(origname, PATHSIZE, mailname);
388 editfile = mailname;
390 if (ef != NOSTR) {
391 if (ef == NOSTR || *ef == '\0' || *ef == '+') {
392 load(Getf("MAILRC"));
393 loaded++;
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;
404 editfile = ef;
405 edit++;
408 if (setfile(editfile, edit) < 0)
409 exit(1);
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);
422 if (Hflag || (!edit && msgCount == 0)) {
423 if (!Hflag) {
424 fprintf(stderr, gettext("No mail for %s\n"), myname);
425 Verhogen();
427 fflush(stdout);
428 exit(rpterr);
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();
442 return (rpterr);
446 * Interrupt printing of the headers.
448 static void
449 #ifdef __cplusplus
450 hdrstop(int)
451 #else
452 /* ARGSUSED */
453 hdrstop(int s)
454 #endif
457 fflush(stdout);
458 fprintf(stderr, gettext("\nInterrupt\n"));
459 # ifdef OLD_BSD_SIGS
460 sigrelse(SIGINT);
461 # endif
462 longjmp(hdrjmp, 1);