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