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, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23/*	  All Rights Reserved  	*/
24
25
26/*
27 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
28 * Use is subject to license terms.
29 */
30
31#pragma ident	"%Z%%M%	%I%	%E% SMI"
32
33#include "mail.h"
34/*
35 *	Print mail entries
36 */
37void
38printmail()
39{
40	static char pn[] = "printmail";
41	int	flg, curlet, showlet, k, print, aret, stret, rc;
42	int	nsmbox = 0;	/* 1 ==> mailbox is in non-standard place */
43	int	sav_j = -1;
44	char	*p, *getarg();
45	struct	stat stbuf;
46	struct	stat *stbufp;
47	int ttyf = isatty(1) ? TTY : ORDINARY;
48	char	readbuf[LSIZE];	/* holds user's response in interactive mode */
49	char	*resp;
50	gid_t	savedegid;
51
52	stbufp = &stbuf;
53
54	/*
55	 *	create working directory mbox name
56	 */
57	if ((hmbox = malloc(strlen(home) + strlen(mbox) + 1)) == NULL) {
58		errmsg(E_MBOX, "");
59		return;
60	}
61	cat(hmbox, home, mbox);
62
63	/*
64	 *	If we are not using an alternate mailfile, then get
65	 *	the $MAIL value and build the filename for the mailfile.
66	 *	If $MAIL is set, but is NOT the 'standard' place, then
67	 *	use it but set flgf to circumvent :saved processing.
68	 */
69	if (!flgf) {
70		if ((p = malloc(strlen(maildir) + strlen(my_name) + 1))
71								== NULL) {
72			errmsg(E_MEM, "");
73			return;
74		}
75		cat(p, maildir, my_name);
76		if (((mailfile = getenv("MAIL")) == NULL) ||
77		    (strlen(mailfile) == 0)) {
78			/* $MAIL not set, use standard path to mailfile */
79			mailfile = p;
80		} else {
81			if (strcmp(mailfile, p) != 0) {
82			    flgf = 1;
83			    nsmbox = 1;
84			    Dout(pn, 0, "$MAIL ('%s') != standard path\n",
85				mailfile);
86			    Dout("", 0, "\tSetting flgf to 1.\n");
87			}
88			free(p);
89		}
90	}
91
92	/*
93	 *	Get ACCESS and MODIFICATION times of mailfile BEFORE we
94	 *	use it. This allows us to put them back when we are
95	 *	done. If we didn't, the shell would think NEW mail had
96	 *	arrived since the file times would have changed.
97	 */
98	stret = CERROR;
99	if (access(mailfile, A_EXIST) == A_OK) {
100		if ((stret = stat(mailfile, stbufp)) != A_OK) {
101			errmsg(E_FILE, "Cannot stat mailfile");
102			return;
103		}
104		mf_gid = stbufp->st_gid;
105		mf_uid = stbufp->st_uid;
106		utimep->actime = stbufp->st_atime;
107		utimep->modtime = stbufp->st_mtime;
108		file_size = stbufp->st_size;
109	}
110
111	/* Open the file as the real gid */
112	savedegid = getegid();
113	(void) setegid(getgid());
114	malf = fopen(mailfile, "r");
115	(void) setegid(savedegid);
116	/*
117	 *	stat succeeded, but we cannot access the mailfile
118	 */
119	if (stret == CSUCCESS && malf == NULL) {
120		char buf[MAXFILENAME+50];
121		(void) snprintf(buf, sizeof (buf),
122		    "Invalid permissions on %s", mailfile);
123		errmsg(E_PERM, buf);
124		return;
125	} else
126	/*
127	 *	using an alternate mailfile, but we failed on access
128	 */
129	if (!nsmbox && flgf && (malf == NULL)) {
130		errmsg(E_FILE, "Cannot open mailfile");
131		return;
132	}
133	/*
134	 *	we failed to access OR the file is empty
135	 */
136	else if ((malf == NULL) || (stbuf.st_size == 0)) {
137		if (!flge && !flgE) {
138			printf("No mail.\n");
139		}
140		error = E_FLGE;
141		Dout(pn, 0, "error set to %d\n", error);
142		return;
143	}
144	if (flge)
145		return;
146
147	if (flgE) {
148		if (utimep->modtime < utimep->actime) {
149			error = E_FLGE_OM;
150			Dout(pn, 0, "error set to %d\n", error);
151		}
152		return;
153	}
154	/*
155	 *	Secure the mailfile to guarantee integrity
156	 */
157	lock(my_name);
158
159	/*
160	 *	copy mail to temp file and mark each letter in the
161	 *	let array --- mailfile is still locked !!!
162	 */
163	mktmp();
164	copymt(malf, tmpf);
165	onlet = nlet;
166	fclose(malf);
167	fclose(tmpf);
168	unlock();	/* All done, OK to unlock now */
169	tmpf = doopen(lettmp, "r+", E_TMP);
170	changed = 0;
171	print = 1;
172	curlet = 0;
173	while (curlet < nlet) {
174		/*
175		 *	reverse order ?
176		 */
177		showlet = flgr ? curlet : nlet - curlet - 1;
178
179		if (setjmp(sjbuf) == 0 && print != 0) {
180				/* -h says to print the headers first */
181				if (flgh) {
182					gethead(showlet, 0);
183					flgh = 0;	/* Only once */
184					/* set letter # to invalid # */
185					curlet--;
186					showlet =
187					    flgr ? curlet : nlet - curlet - 1;
188				} else {
189					if (showlet != sav_j) {
190						/* Looking at new message. */
191						/* Reset flag to override */
192						/* non-display of binary */
193						/* contents */
194						sav_j = showlet;
195						pflg = 0;
196						Pflg = flgP;
197					}
198					copylet(showlet, stdout, ttyf);
199				}
200		}
201
202		/*
203		 *	print only
204		 */
205		if (flgp) {
206			curlet++;
207			continue;
208		}
209		/*
210		 *	Interactive
211		 */
212		interactive = 1;
213		setjmp(sjbuf);
214		stat(mailfile, stbufp);
215		if (stbufp->st_size != file_size) {
216			/*
217			 *	New mail has arrived, load it
218			 */
219			k = nlet;
220			lock(my_name);
221			malf = doopen(mailfile, "r", E_FILE);
222			fclose(tmpf);
223			tmpf = doopen(lettmp, "a", E_TMP);
224			fseek(malf, let[nlet].adr, 0);
225			copymt(malf, tmpf);
226			file_size = stbufp->st_size;
227			fclose(malf);
228			fclose(tmpf);
229			unlock();
230			tmpf = doopen(lettmp, "r+", E_TMP);
231			if (++k < nlet)
232				printf("New mail loaded into letters %d - %d\n",
233				    k, nlet);
234			else
235				printf("New mail loaded into letter %d\n",
236				    nlet);
237		}
238
239		/* read the command */
240		printf("? ");
241		fflush(stdout);
242		fflush(stderr);
243		if (fgets(readbuf, sizeof (readbuf), stdin) == NULL) break;
244		resp = readbuf;
245		while (*resp == ' ' || *resp == '\t') resp++;
246		print = 1;
247		Dout(pn, 0, "resp = '%s'\n", resp);
248		if ((rc = atoi(resp)) != 0) {
249			if (!validmsg(rc)) print = 0;
250			else curlet = flgr ? rc - 1 : nlet - rc;
251		} else switch (resp[0]) {
252			default:
253				printf("Usage:\n");
254			/*
255			 *	help
256			 */
257			case '?':
258				print = 0;
259				for (rc = 0; help[rc]; rc++)
260					printf("%s", help[rc]);
261				break;
262			/*
263			 *	print message number of current message
264			 */
265			case '#':
266				print = 0;
267				if ((showlet == nlet) || (showlet < 0)) {
268					printf("No message selected yet.\n");
269				} else {
270					printf("Current message number is %d\n",
271					    showlet+1);
272				}
273				break;
274			/*
275			 *	headers
276			 */
277			case 'h':
278				print = 0;
279				if (resp[2] != 'd' &&
280				    resp[2] != 'a' &&
281				    (rc = getnumbr(resp+1)) > 0) {
282					showlet = rc - 1;
283					curlet = flgr ? rc - 1 : nlet - rc- 1;
284				}
285				if (rc == -1 && resp[2] != 'a' &&
286				    resp[2] != 'd')
287					break;
288				if (resp[2] == 'a') rc = 1;
289				else if (resp[2] == 'd') rc = 2;
290					else rc = 0;
291
292/*
293 *				if (!validmsg(showlet)) break;
294 */
295				gethead(showlet, rc);
296				break;
297			/*
298			 *	skip entry
299			 */
300			case '+':
301			case 'n':
302			case '\n':
303				curlet++;
304				break;
305			case 'P':
306				Pflg++;
307				break;
308			case 'p':
309				pflg++;
310				break;
311			case 'x':
312				changed = 0;
313			case 'q':
314				goto donep;
315			/*
316			 *	Previous entry
317			 */
318			case '^':
319			case '-':
320				if (--curlet < 0) curlet = 0;
321				break;
322			/*
323			 *	Save in file without header
324			 */
325			case 'y':
326			case 'w':
327			/*
328			 *	Save mail with header
329			 */
330			case 's':
331				print = 0;
332				if (!validmsg(curlet)) break;
333				if (resp[1] == '\n' || resp[1] == '\0') {
334					cat(resp+1, hmbox, "");
335				} else if (resp[1] != ' ') {
336					printf("Invalid command\n");
337					break;
338				}
339				umask(umsave);
340				flg = 0;
341				if (getarg(lfil, resp + 1) == NULL) {
342					cat(resp + 1, hmbox, "");
343				}
344				malf = (FILE *)NULL;
345				p = resp + 1;
346				while ((p = getarg(lfil, p)) != NULL) {
347					if (flg) {
348					    fprintf(stderr,
349						"%s: File '%s' skipped\n",
350						program, lfil);
351					    continue;
352					}
353					malf = NULL;
354					if ((aret = legal(lfil))) {
355						malf = fopen(lfil, "a");
356					}
357					if ((malf == NULL) || (aret == 0)) {
358					    fprintf(stderr,
359						"%s: Cannot append to %s\n",
360						program, lfil);
361					    flg++;
362					} else if (aret == 2) {
363						chown(lfil, my_euid, my_gid);
364					}
365					if (!flg &&
366					    copylet(showlet, malf, resp[0] ==
367					    's'? ORDINARY: ZAP) == FALSE) {
368						fprintf(stderr,
369					    "%s: Cannot save mail to '%s'\n",
370						    program, lfil);
371						flg++;
372					} else
373						Dout(pn, 0, "!saved\n");
374					if (malf != (FILE *)NULL) {
375						fclose(malf);
376					}
377				}
378				umask(7);
379				if (!flg) {
380					setletr(showlet, resp[0]);
381					print = 1;
382					curlet++;
383				}
384				break;
385			/*
386			 *	Reply to a letter
387			 */
388			case 'r':
389				print = 0;
390				if (!validmsg(curlet)) break;
391				replying = 1;
392				for (k = 1; resp[k] == ' ' || resp[k] == '\t';
393				    ++k);
394				resp[strlen(resp)-1] = '\0';
395				(void) strlcpy(m_sendto, resp+k,
396				    sizeof (m_sendto));
397				goback(showlet);
398				replying = 0;
399				setletr(showlet, resp[0]);
400				break;
401			/*
402			 *	Undelete
403			 */
404			case 'u':
405				print = 0;
406				if ((k = getnumbr(resp+1)) <= 0) k = showlet;
407				else k--;
408				if (!validmsg(k)) break;
409				setletr(k, ' ');
410				break;
411			/*
412			 *	Mail letter to someone else
413			 */
414			case 'm':
415				{
416				reciplist list;
417				print = 0;
418				if (!validmsg(curlet)) break;
419				new_reciplist(&list);
420				flg = 0;
421				k = 0;
422				if (substr(resp, " -") != -1 ||
423					substr(resp, "\t-") != -1) {
424					printf("Only users may be specified\n");
425					break;
426				}
427				p = resp + 1;
428				while ((p = getarg(lfil, p)) != NULL) {
429					char *env;
430					if (lfil[0] == '$') {
431						if (!(env = getenv(&lfil[1]))) {
432							fprintf(stderr,
433				"%s: %s has no value or is not exported.\n",
434							    program, lfil);
435							flg++;
436						} else
437							add_recip(&list, env,
438							    FALSE);
439						k++;
440					} else if (lfil[0] != '\0') {
441						add_recip(&list, lfil, FALSE);
442						k++;
443					}
444				}
445				(void) strlcpy(Rpath, my_name, sizeof (Rpath));
446				sending = TRUE;
447				flg += sendlist(&list, showlet, 0);
448				sending = FALSE;
449				if (k) {
450					if (!flg) {
451						setletr(showlet, 'm');
452						print = 1;
453						curlet++;
454					}
455				} else
456					printf("Invalid command\n");
457				del_reciplist(&list);
458				break;
459				}
460			/*
461			 *	Read new letters
462			 */
463			case 'a':
464				if (onlet == nlet) {
465					printf("No new mail\n");
466					print = 0;
467					break;
468				}
469				curlet = 0;
470				print = 1;
471				break;
472			/*
473			 *	Escape to shell
474			 */
475			case '!':
476				systm(resp + 1);
477				printf("!\n");
478				print = 0;
479				break;
480			/*
481			 *	Delete an entry
482			 */
483			case 'd':
484				print = 0;
485				k = 0;
486				if (strncmp("dq", resp, 2) != SAME &&
487					strncmp("dp", resp, 2) != SAME)
488					if ((k = getnumbr(resp+1)) == -1) break;
489				if (k == 0) {
490					k = showlet;
491					if (!validmsg(curlet)) break;
492					print = 1;
493					curlet++;
494				} else	k--;
495
496				setletr(k, 'd');
497				if (resp[1] == 'p') print = 1;
498				else if (resp[1] == 'q') goto donep;
499				break;
500		}
501	}
502	/*
503	 *	Copy updated mailfile back
504	 */
505donep:
506	if (changed) {
507		copyback();
508		stamp();
509	}
510}
511