xref: /illumos-gate/usr/src/cmd/mailx/quit.c (revision 6e6545bfaed3bab9ce836ee82d1abd8f2edba89a)
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  * Copyright (c) 2016 by Delphix. All rights reserved.
26  */
27 
28 /*
29  * University Copyright- Copyright (c) 1982, 1986, 1988
30  * The Regents of the University of California
31  * All Rights Reserved
32  *
33  * University Acknowledgment- Portions of this document are derived from
34  * software developed by the University of California, Berkeley, and its
35  * contributors.
36  */
37 
38 #pragma ident	"%Z%%M%	%I%	%E% SMI"
39 
40 #include "rcv.h"
41 #include <locale.h>
42 
43 /*
44  * mailx -- a modified version of a University of California at Berkeley
45  *	mail program
46  *
47  * Rcv -- receive mail rationally.
48  *
49  * Termination processing.
50  */
51 
52 static void		writeback(int noremove);
53 
54 #define PRIV(x)		setgid(myegid), (x), setgid(myrgid);
55 
56 /*
57  * Save all of the undetermined messages at the top of "mbox"
58  * Save all untouched messages back in the system mailbox.
59  * Remove the system mailbox, if none saved there.
60  */
61 
62 void
63 quit(
64     int noremove	/* don't remove system mailbox, trunc it instead */
65 )
66 {
67 	int mcount, p, modify, autohold, anystat, holdbit, nohold, fd;
68 	FILE *ibuf, *obuf, *fbuf, *readstat;
69 	register struct message *mp;
70 	register int c;
71 	char *id;
72 	int appending;
73 	char *mbox = Getf("MBOX");
74 
75 	/*
76 	 * If we are read only, we can't do anything,
77 	 * so just return quickly.
78 	 */
79 
80 	mcount = 0;
81 	if (readonly)
82 		return;
83 	/*
84 	 * See if there any messages to save in mbox.  If no, we
85 	 * can save copying mbox to /tmp and back.
86 	 *
87 	 * Check also to see if any files need to be preserved.
88 	 * Delete all untouched messages to keep them out of mbox.
89 	 * If all the messages are to be preserved, just exit with
90 	 * a message.
91 	 *
92 	 * If the luser has sent mail to himself, refuse to do
93 	 * anything with the mailbox, unless mail locking works.
94 	 */
95 
96 #ifndef CANLOCK
97 	if (selfsent) {
98 		printf(gettext("You have new mail.\n"));
99 		return;
100 	}
101 #endif
102 
103 	/*
104 	 * Adjust the message flags in each message.
105 	 */
106 
107 	anystat = 0;
108 	autohold = value("hold") != NOSTR;
109 	appending = value("append") != NOSTR;
110 	holdbit = autohold ? MPRESERVE : MBOX;
111 	nohold = MBOXED|MBOX|MSAVED|MDELETED|MPRESERVE;
112 	if (value("keepsave") != NOSTR)
113 		nohold &= ~MSAVED;
114 	for (mp = &message[0]; mp < &message[msgCount]; mp++) {
115 		if (mp->m_flag & MNEW) {
116 			receipt(mp);
117 			mp->m_flag &= ~MNEW;
118 			mp->m_flag |= MSTATUS;
119 		}
120 		if (mp->m_flag & MSTATUS)
121 			anystat++;
122 		if ((mp->m_flag & MTOUCH) == 0)
123 			mp->m_flag |= MPRESERVE;
124 		if ((mp->m_flag & nohold) == 0)
125 			mp->m_flag |= holdbit;
126 	}
127 	modify = 0;
128 	if (Tflag != NOSTR) {
129 		if ((readstat = fopen(Tflag, "w")) == NULL)
130 			Tflag = NOSTR;
131 	}
132 	for (c = 0, p = 0, mp = &message[0]; mp < &message[msgCount]; mp++) {
133 		if (mp->m_flag & MBOX)
134 			c++;
135 		if (mp->m_flag & MPRESERVE)
136 			p++;
137 		if (mp->m_flag & MODIFY)
138 			modify++;
139 		if (Tflag != NOSTR && (mp->m_flag & (MREAD|MDELETED)) != 0) {
140 			id = hfield("message-id", mp, addone);
141 			if (id != NOSTR)
142 				fprintf(readstat, "%s\n", id);
143 			else {
144 				id = hfield("article-id", mp, addone);
145 				if (id != NOSTR)
146 					fprintf(readstat, "%s\n", id);
147 			}
148 		}
149 	}
150 	if (Tflag != NOSTR)
151 		fclose(readstat);
152 	if (p == msgCount && !modify && !anystat) {
153 		if (p == 1)
154 			printf(gettext("Held 1 message in %s\n"), mailname);
155 		else
156 			printf(gettext("Held %d messages in %s\n"), p,
157 			    mailname);
158 		return;
159 	}
160 	if (c == 0) {
161 		writeback(noremove);
162 		return;
163 	}
164 
165 	/*
166 	 * Create another temporary file and copy user's mbox file
167 	 * therein.  If there is no mbox, copy nothing.
168 	 * If they have specified "append" don't copy the mailbox,
169 	 * just copy saveable entries at the end.
170 	 */
171 
172 	mcount = c;
173 	if (!appending) {
174 		if ((fd = open(tempQuit, O_RDWR|O_CREAT|O_EXCL, 0600)) < 0 ||
175 		(obuf = fdopen(fd, "w")) == NULL) {
176 			perror(tempQuit);
177 			return;
178 		}
179 		if ((ibuf = fopen(tempQuit, "r")) == NULL) {
180 			perror(tempQuit);
181 			removefile(tempQuit);
182 			fclose(obuf);
183 			return;
184 		}
185 		removefile(tempQuit);
186 		if ((fbuf = fopen(mbox, "r")) != NULL) {
187 			while ((c = getc(fbuf)) != EOF)
188 				putc(c, obuf);
189 			fclose(fbuf);
190 		}
191 		fflush(obuf);
192 		if (fferror(obuf)) {
193 			perror(tempQuit);
194 			fclose(ibuf);
195 			fclose(obuf);
196 			return;
197 		}
198 		fclose(obuf);
199 		if ((fd = open(mbox, O_RDWR|O_CREAT|O_TRUNC, MBOXPERM)) < 0 ||
200 		    (obuf = fdopen(fd, "r+")) == NULL) {
201 			perror(mbox);
202 			fclose(ibuf);
203 			return;
204 		}
205 		if (issysmbox)
206 			touchlock();
207 	} else {	/* we are appending */
208 		if ((fd = open(mbox, O_RDWR|O_CREAT, MBOXPERM)) < 0 ||
209 		    (obuf = fdopen(fd, "a")) == NULL) {
210 			perror(mbox);
211 			return;
212 		}
213 	}
214 	for (mp = &message[0]; mp < &message[msgCount]; mp++)
215 		if (mp->m_flag & MBOX) {
216 			if (msend(mp, obuf, (int)value("alwaysignore") ?
217 			    M_IGNORE|M_SAVING : M_SAVING, fputs) < 0) {
218 				perror(mbox);
219 				if (!appending)
220 					fclose(ibuf);
221 				fclose(obuf);
222 				return;
223 			}
224 			mp->m_flag &= ~MBOX;
225 			mp->m_flag |= MBOXED;
226 			if (issysmbox)
227 				touchlock();
228 		}
229 
230 	/*
231 	 * Copy the user's old mbox contents back
232 	 * to the end of the stuff we just saved.
233 	 * If we are appending, this is unnecessary.
234 	 */
235 
236 	if (!appending) {
237 		rewind(ibuf);
238 		c = getc(ibuf);
239 		while (c != EOF) {
240 			putc(c, obuf);
241 			if (ferror(obuf))
242 				break;
243 			c = getc(ibuf);
244 		}
245 		fclose(ibuf);
246 		fflush(obuf);
247 	}
248 	trunc(obuf);
249 	if (fferror(obuf)) {
250 		perror(mbox);
251 		fclose(obuf);
252 		return;
253 	}
254 	fclose(obuf);
255 	if (mcount == 1)
256 		printf(gettext("Saved 1 message in %s\n"), mbox);
257 	else
258 		printf(gettext("Saved %d messages in %s\n"), mcount, mbox);
259 
260 	/*
261 	 * Now we are ready to copy back preserved files to
262 	 * the system mailbox, if any were requested.
263 	 */
264 	writeback(noremove);
265 }
266 
267 /*
268  * Preserve all the appropriate messages back in the system
269  * mailbox, and print a nice message indicating how many were
270  * saved.  Incorporate any new mail that we found.
271  */
272 static void
273 writeback(int noremove)
274 {
275 	register struct message *mp;
276 	register int p, c;
277 	struct stat st;
278 	FILE *obuf = 0, *fbuf = 0, *rbuf = 0;
279 	void (*fhup)(int), (*fint)(int), (*fquit)(int);
280 	int fd = -1;
281 
282 	fhup = sigset(SIGHUP, SIG_IGN);
283 	fint = sigset(SIGINT, SIG_IGN);
284 	fquit = sigset(SIGQUIT, SIG_IGN);
285 
286 	if (issysmbox)
287 		lockmail();
288 	if ((fbuf = fopen(mailname, "r+")) == NULL) {
289 		perror(mailname);
290 		goto die;
291 	}
292 	if (!issysmbox)
293 		lock(fbuf, "r+", 1);
294 	fstat(fileno(fbuf), &st);
295 	if (st.st_size > mailsize) {
296 		printf(gettext("New mail has arrived.\n"));
297 		snprintf(tempResid, PATHSIZE, "%s/:saved/%s", maildir, myname);
298 		PRIV(rbuf = fopen(tempResid, "w+"));
299 		if (rbuf == NULL) {
300 			snprintf(tempResid, PATHSIZE, "/tmp/Rq%-ld", mypid);
301 			fd = open(tempResid,O_RDWR|O_CREAT|O_EXCL, 0600);
302 			PRIV(rbuf = fdopen(fd, "w+"));
303 			if (rbuf == NULL) {
304 				snprintf(tempResid, PATHSIZE,
305 					"%s/:saved/%s", maildir,
306 				    myname);
307 				perror(tempResid);
308 				fclose(fbuf);
309 				goto die;
310 			}
311 		}
312 #ifdef APPEND
313 		fseek(fbuf, mailsize, 0);
314 		while ((c = getc(fbuf)) != EOF)
315 			putc(c, rbuf);
316 #else
317 		p = st.st_size - mailsize;
318 		while (p-- > 0) {
319 			c = getc(fbuf);
320 			if (c == EOF) {
321 				perror(mailname);
322 				fclose(fbuf);
323 				goto die;
324 			}
325 			putc(c, rbuf);
326 		}
327 #endif
328 		fclose(fbuf);
329 		fseek(rbuf, 0L, 0);
330 		if (issysmbox)
331 			touchlock();
332 	}
333 
334 	if ((obuf = fopen(mailname, "r+")) == NULL) {
335 		perror(mailname);
336 		goto die;
337 	}
338 #ifndef APPEND
339 	if (rbuf != NULL)
340 		while ((c = getc(rbuf)) != EOF)
341 			putc(c, obuf);
342 #endif
343 	p = 0;
344 	for (mp = &message[0]; mp < &message[msgCount]; mp++)
345 		if ((mp->m_flag&MPRESERVE)||(mp->m_flag&MTOUCH)==0) {
346 			p++;
347 			if (msend(mp, obuf, 0, fputs) < 0) {
348 				perror(mailname);
349 				goto die;
350 			}
351 			if (issysmbox)
352 				touchlock();
353 		}
354 #ifdef APPEND
355 	if (rbuf != NULL)
356 		while ((c = getc(rbuf)) != EOF)
357 			putc(c, obuf);
358 #endif
359 	fflush(obuf);
360 	trunc(obuf);
361 	if (fferror(obuf)) {
362 		perror(mailname);
363 		goto die;
364 	}
365 	alter(mailname);
366 	if (p) {
367 		if (p == 1)
368 			printf(gettext("Held 1 message in %s\n"), mailname);
369 		else
370 			printf(gettext("Held %d messages in %s\n"), p,
371 			    mailname);
372 	}
373 
374 	if (!noremove && (fsize(obuf) == 0) && (value("keep") == NOSTR)) {
375 		if (stat(mailname, &st) >= 0)
376 			PRIV(delempty(st.st_mode, mailname));
377 	}
378 
379 die:
380 	if (rbuf) {
381 		fclose(rbuf);
382 		PRIV(removefile(tempResid));
383 	}
384 	if (obuf)
385 		fclose(obuf);
386 	if (issysmbox)
387 		unlockmail();
388 	sigset(SIGHUP, fhup);
389 	sigset(SIGINT, fint);
390 	sigset(SIGQUIT, fquit);
391 }
392 
393 void
394 lockmail(void)
395 {
396     PRIV(maillock(lockname,10));
397 }
398 
399 void
400 unlockmail(void)
401 {
402     PRIV(mailunlock());
403 }
404