xref: /netbsd-src/usr.bin/mail/quit.c (revision 4fe1ef32f37334167b71a62286b21da7d9542909)
1*4fe1ef32Schristos /*	$NetBSD: quit.c,v 1.29 2017/11/09 20:27:50 christos Exp $	*/
288b833a7Schristos 
361f28255Scgd /*
42cb5542fSderaadt  * Copyright (c) 1980, 1993
52cb5542fSderaadt  *	The Regents of the University of California.  All rights reserved.
661f28255Scgd  *
761f28255Scgd  * Redistribution and use in source and binary forms, with or without
861f28255Scgd  * modification, are permitted provided that the following conditions
961f28255Scgd  * are met:
1061f28255Scgd  * 1. Redistributions of source code must retain the above copyright
1161f28255Scgd  *    notice, this list of conditions and the following disclaimer.
1261f28255Scgd  * 2. Redistributions in binary form must reproduce the above copyright
1361f28255Scgd  *    notice, this list of conditions and the following disclaimer in the
1461f28255Scgd  *    documentation and/or other materials provided with the distribution.
1589aaa1bbSagc  * 3. Neither the name of the University nor the names of its contributors
1661f28255Scgd  *    may be used to endorse or promote products derived from this software
1761f28255Scgd  *    without specific prior written permission.
1861f28255Scgd  *
1961f28255Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2061f28255Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2161f28255Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2261f28255Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2361f28255Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2461f28255Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2561f28255Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2661f28255Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2761f28255Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2861f28255Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2961f28255Scgd  * SUCH DAMAGE.
3061f28255Scgd  */
3161f28255Scgd 
327c81c8f3Slukem #include <sys/cdefs.h>
3361f28255Scgd #ifndef lint
3488b833a7Schristos #if 0
3519d35cbcStls static char sccsid[] = "@(#)quit.c	8.2 (Berkeley) 4/28/95";
3688b833a7Schristos #else
37*4fe1ef32Schristos __RCSID("$NetBSD: quit.c,v 1.29 2017/11/09 20:27:50 christos Exp $");
3888b833a7Schristos #endif
3961f28255Scgd #endif /* not lint */
4061f28255Scgd 
4161f28255Scgd #include "rcv.h"
422cb5542fSderaadt #include "extern.h"
43f3098750Schristos #include "thread.h"
44ca13337dSchristos #include "sig.h"
4561f28255Scgd 
4661f28255Scgd /*
4761f28255Scgd  * Rcv -- receive mail rationally.
4861f28255Scgd  *
4961f28255Scgd  * Termination processing.
5061f28255Scgd  */
5161f28255Scgd 
5261f28255Scgd /*
5361f28255Scgd  * The "quit" command.
5461f28255Scgd  */
55ca286310Schristos /*ARGSUSED*/
56f3098750Schristos PUBLIC int
quitcmd(void * v __unused)578207b28aSchristos quitcmd(void *v __unused)
5861f28255Scgd {
5961f28255Scgd 	/*
6061f28255Scgd 	 * If we are sourcing, then return 1 so execute() can handle it.
6161f28255Scgd 	 * Otherwise, return -1 to abort command loop.
6261f28255Scgd 	 */
6361f28255Scgd 	if (sourcing)
6461f28255Scgd 		return 1;
6561f28255Scgd 	return -1;
6661f28255Scgd }
6761f28255Scgd 
6861f28255Scgd /*
69f3098750Schristos  * Preserve all the appropriate messages back in the system
70f3098750Schristos  * mailbox, and print a nice message indicated how many were
71f3098750Schristos  * saved.  On any error, just return -1.  Else return 0.
72f3098750Schristos  * Incorporate the any new mail that we found.
73f3098750Schristos  */
74f3098750Schristos static int
writeback(FILE * res)75f3098750Schristos writeback(FILE *res)
76f3098750Schristos {
77f3098750Schristos 	struct message *mp;
78f3098750Schristos 	int p, c;
79f3098750Schristos 	FILE *obuf;
80f3098750Schristos 
81f3098750Schristos 	p = 0;
82*4fe1ef32Schristos 	if ((obuf = Fopen(mailname, "ref+")) == NULL) {
83f3098750Schristos 		warn("%s", mailname);
84f3098750Schristos 		return -1;
85f3098750Schristos 	}
86f3098750Schristos #ifndef APPEND
87f3098750Schristos 	if (res != NULL) {
88f3098750Schristos 		while ((c = getc(res)) != EOF)
89f3098750Schristos 			(void)putc(c, obuf);
90f3098750Schristos 		(void)fflush(obuf);
91f3098750Schristos 		if (ferror(obuf)) {
92f3098750Schristos 			warn("%s", mailname);
93f3098750Schristos 			(void)Fclose(obuf);
94f3098750Schristos 			return -1;
95f3098750Schristos 		}
96f3098750Schristos 	}
97f3098750Schristos #endif
98f3098750Schristos 	for (mp = get_message(1); mp; mp = next_message(mp))
99f3098750Schristos 		if ((mp->m_flag & MPRESERVE) || (mp->m_flag & MTOUCH)==0) {
100f3098750Schristos 			p++;
101f3098750Schristos 			if (sendmessage(mp, obuf, NULL, NULL, NULL) < 0) {
102f3098750Schristos 				warn("%s", mailname);
103f3098750Schristos 				(void)Fclose(obuf);
104f3098750Schristos 				return -1;
105f3098750Schristos 			}
106f3098750Schristos 		}
107f3098750Schristos #ifdef APPEND
108f3098750Schristos 	if (res != NULL)
109f3098750Schristos 		while ((c = getc(res)) != EOF)
110f3098750Schristos 			(void)putc(c, obuf);
111f3098750Schristos #endif
112f3098750Schristos 	(void)fflush(obuf);
113f3098750Schristos 	if (!ferror(obuf))
114f3098750Schristos 		trunc(obuf);	/* XXX or should we truncate? */
115f3098750Schristos 	if (ferror(obuf)) {
116f3098750Schristos 		warn("%s", mailname);
117f3098750Schristos 		(void)Fclose(obuf);
118f3098750Schristos 		return -1;
119f3098750Schristos 	}
120f3098750Schristos 	if (res != NULL)
121f3098750Schristos 		(void)Fclose(res);
122f3098750Schristos 	(void)Fclose(obuf);
123f3098750Schristos 	alter(mailname);
124f3098750Schristos 	if (p == 1)
125f3098750Schristos 		(void)printf("Held 1 message in %s\n", mailname);
126f3098750Schristos 	else
127f3098750Schristos 		(void)printf("Held %d messages in %s\n", p, mailname);
128f3098750Schristos 	return 0;
129f3098750Schristos }
130f3098750Schristos 
131f3098750Schristos /*
132f3098750Schristos  * Terminate an editing session by attempting to write out the user's
133f3098750Schristos  * file from the temporary.  Save any new stuff appended to the file.
134f3098750Schristos  */
135f3098750Schristos static void
edstop(jmp_buf jmpbuf)136ca13337dSchristos edstop(jmp_buf jmpbuf)
137f3098750Schristos {
138f3098750Schristos 	int gotcha, c;
139f3098750Schristos 	struct message *mp;
140ca13337dSchristos 	FILE *obuf;
141ca13337dSchristos 	FILE *ibuf;
142ca13337dSchristos 	FILE *readstat;
143f3098750Schristos 	struct stat statb;
144f3098750Schristos 	char tempname[PATHSIZE];
145f3098750Schristos 	int fd;
146f3098750Schristos 
147ca13337dSchristos 	sig_check();
148f3098750Schristos 	if (readonly)
149f3098750Schristos 		return;
150ca13337dSchristos 
151ca13337dSchristos 	readstat = NULL;
152f3098750Schristos 	if (Tflag != NULL) {
153*4fe1ef32Schristos 		if ((readstat = Fopen(Tflag, "wef")) == NULL)
154f3098750Schristos 			Tflag = NULL;
155f3098750Schristos 	}
156f3098750Schristos 	for (mp = get_message(1), gotcha = 0; mp; mp = next_message(mp)) {
157f3098750Schristos 		if (mp->m_flag & MNEW) {
158f3098750Schristos 			mp->m_flag &= ~MNEW;
159f3098750Schristos 			mp->m_flag |= MSTATUS;
160f3098750Schristos 		}
161f3098750Schristos 		if (mp->m_flag & (MMODIFY|MDELETED|MSTATUS))
162f3098750Schristos 			gotcha++;
163f3098750Schristos 		if (Tflag != NULL && (mp->m_flag & (MREAD|MDELETED)) != 0) {
164f3098750Schristos 			char *id;
165f3098750Schristos 
166f3098750Schristos 			if ((id = hfield("article-id", mp)) != NULL)
167f3098750Schristos 				(void)fprintf(readstat, "%s\n", id);
168f3098750Schristos 		}
169f3098750Schristos 	}
170f3098750Schristos 	if (Tflag != NULL)
171f3098750Schristos 		(void)Fclose(readstat);
172f3098750Schristos 	if (!gotcha || Tflag != NULL)
173f3098750Schristos 		goto done;
174f3098750Schristos 	ibuf = NULL;
175f3098750Schristos 	if (stat(mailname, &statb) >= 0 && statb.st_size > mailsize) {
176f3098750Schristos 		(void)snprintf(tempname, sizeof(tempname),
177f3098750Schristos 		    "%s/mbox.XXXXXXXXXX", tmpdir);
178f3098750Schristos 		if ((fd = mkstemp(tempname)) == -1 ||
179*4fe1ef32Schristos 		    (obuf = Fdopen(fd, "wef")) == NULL) {
180f3098750Schristos 			warn("%s", tempname);
181f3098750Schristos 			if (fd != -1)
182f3098750Schristos 				(void)close(fd);
183ca13337dSchristos 			sig_release();
184ca13337dSchristos 			longjmp(jmpbuf, -11);
185f3098750Schristos 		}
186*4fe1ef32Schristos 		if ((ibuf = Fopen(mailname, "ref")) == NULL) {
187f3098750Schristos 			warn("%s", mailname);
188f3098750Schristos 			(void)Fclose(obuf);
189f3098750Schristos 			(void)rm(tempname);
190ca13337dSchristos 			sig_release();
191ca13337dSchristos 			longjmp(jmpbuf, -1);
192f3098750Schristos 		}
193f3098750Schristos 		(void)fseek(ibuf, (long)mailsize, 0);
194f3098750Schristos 		while ((c = getc(ibuf)) != EOF)
195f3098750Schristos 			(void)putc(c, obuf);
196f3098750Schristos 		(void)fflush(obuf);
197f3098750Schristos 		if (ferror(obuf)) {
198f3098750Schristos 			warn("%s", tempname);
199f3098750Schristos 			(void)Fclose(obuf);
200f3098750Schristos 			(void)Fclose(ibuf);
201f3098750Schristos 			(void)rm(tempname);
202ca13337dSchristos 			sig_release();
203ca13337dSchristos 			longjmp(jmpbuf, -1);
204f3098750Schristos 		}
205f3098750Schristos 		(void)Fclose(ibuf);
206f3098750Schristos 		(void)Fclose(obuf);
207*4fe1ef32Schristos 		if ((ibuf = Fopen(tempname, "ref")) == NULL) {
208f3098750Schristos 			warn("%s", tempname);
209f3098750Schristos 			(void)rm(tempname);
210ca13337dSchristos 			sig_release();
211ca13337dSchristos 			longjmp(jmpbuf, -1);
212f3098750Schristos 		}
213f3098750Schristos 		(void)rm(tempname);
214f3098750Schristos 	}
215f3098750Schristos 	(void)printf("\"%s\" ", mailname);
216f3098750Schristos 	(void)fflush(stdout);
217*4fe1ef32Schristos 	if ((obuf = Fopen(mailname, "ref+")) == NULL) {
218f3098750Schristos 		warn("%s", mailname);
219ca13337dSchristos 		sig_release();
220ca13337dSchristos 		longjmp(jmpbuf, -1);
221f3098750Schristos 	}
222f3098750Schristos 	trunc(obuf);
223f3098750Schristos 	c = 0;
224f3098750Schristos 	for (mp = get_message(1); mp; mp = next_message(mp)) {
225f3098750Schristos 		if ((mp->m_flag & MDELETED) != 0)
226f3098750Schristos 			continue;
227f3098750Schristos 		c++;
228f3098750Schristos 		if (sendmessage(mp, obuf, NULL, NULL, NULL) < 0) {
229f3098750Schristos 			warn("%s", mailname);
230ca13337dSchristos 			sig_release();
231ca13337dSchristos 			longjmp(jmpbuf, -1);
232f3098750Schristos 		}
233f3098750Schristos 	}
234f3098750Schristos 	gotcha = (c == 0 && ibuf == NULL);
235f3098750Schristos 	if (ibuf != NULL) {
236f3098750Schristos 		while ((c = getc(ibuf)) != EOF)
237f3098750Schristos 			(void)putc(c, obuf);
238f3098750Schristos 		(void)Fclose(ibuf);
239f3098750Schristos 	}
240f3098750Schristos 	(void)fflush(obuf);
241f3098750Schristos 	if (ferror(obuf)) {
242f3098750Schristos 		warn("%s", mailname);
243ca13337dSchristos 		sig_release();
244ca13337dSchristos 		longjmp(jmpbuf, -1);
245f3098750Schristos 	}
246f3098750Schristos 	(void)Fclose(obuf);
247f3098750Schristos 	if (gotcha) {
248f3098750Schristos 		(void)rm(mailname);
249f3098750Schristos 		(void)printf("removed\n");
250f3098750Schristos 	} else
251f3098750Schristos 		(void)printf("complete\n");
252f3098750Schristos 	(void)fflush(stdout);
253f3098750Schristos 
254f3098750Schristos done:
255ca13337dSchristos 	sig_release();
256ca13337dSchristos 	sig_check();
257f3098750Schristos }
258f3098750Schristos 
259f3098750Schristos /*
26061f28255Scgd  * Save all of the undetermined messages at the top of "mbox"
26161f28255Scgd  * Save all untouched messages back in the system mailbox.
26261f28255Scgd  * Remove the system mailbox, if none saved there.
26361f28255Scgd  */
264f3098750Schristos PUBLIC void
quit(jmp_buf jmpbuf)265ca13337dSchristos quit(jmp_buf jmpbuf)
26661f28255Scgd {
26761f28255Scgd 	int mcount, p, modify, autohold, anystat, holdbit, nohold;
268ca13337dSchristos 	_Bool append;
269ca13337dSchristos 	FILE *ibuf, *obuf, *fbuf, *rbuf, *readstat, *abuf;
2707c81c8f3Slukem 	struct message *mp;
27169047878Swiz 	int c, fd;
27261f28255Scgd 	struct stat minfo;
273ece0fd5cSchristos 	const char *mbox;
2744361c515Swiz 	char tempname[PATHSIZE];
27561f28255Scgd 
276ca13337dSchristos #ifdef __GNUC__		/* XXX gcc -Wuninitialized */
277ca13337dSchristos 	ibuf = NULL;
278ca13337dSchristos 	readstat = NULL;
279a444ae60Sbad #endif
28061f28255Scgd 	/*
28161f28255Scgd 	 * If we are read only, we can't do anything,
28261f28255Scgd 	 * so just return quickly.
28361f28255Scgd 	 */
28461f28255Scgd 	if (readonly)
28561f28255Scgd 		return;
286f3098750Schristos 
287f3098750Schristos #ifdef THREAD_SUPPORT
288f3098750Schristos 	(void)showtagscmd(NULL);	/* make sure we see tagged messages */
289f3098750Schristos 	(void)unthreadcmd(NULL);
290f3098750Schristos #endif
29161f28255Scgd 	/*
29261f28255Scgd 	 * If editing (not reading system mail box), then do the work
29361f28255Scgd 	 * in edstop()
29461f28255Scgd 	 */
29561f28255Scgd 	if (edit) {
296ca13337dSchristos 		edstop(jmpbuf);
29761f28255Scgd 		return;
29861f28255Scgd 	}
29961f28255Scgd 
30061f28255Scgd 	/*
30161f28255Scgd 	 * See if there any messages to save in mbox.  If no, we
30261f28255Scgd 	 * can save copying mbox to /tmp and back.
30361f28255Scgd 	 *
30461f28255Scgd 	 * Check also to see if any files need to be preserved.
30561f28255Scgd 	 * Delete all untouched messages to keep them out of mbox.
30661f28255Scgd 	 * If all the messages are to be preserved, just exit with
30761f28255Scgd 	 * a message.
30861f28255Scgd 	 */
30961f28255Scgd 
310*4fe1ef32Schristos 	fbuf = Fopen(mailname, "ref");
31161f28255Scgd 	if (fbuf == NULL)
31261f28255Scgd 		goto newmail;
31388b833a7Schristos 	if (flock(fileno(fbuf), LOCK_EX) == -1) {
31488b833a7Schristos nolock:
31569047878Swiz 		warn("Unable to lock mailbox");
316ca286310Schristos 		(void)Fclose(fbuf);
31788b833a7Schristos 		return;
31888b833a7Schristos 	}
31988b833a7Schristos 	if (dot_lock(mailname, 1, stdout, ".") == -1)
32088b833a7Schristos 		goto nolock;
32161f28255Scgd 	rbuf = NULL;
32261f28255Scgd 	if (fstat(fileno(fbuf), &minfo) >= 0 && minfo.st_size > mailsize) {
323ca286310Schristos 		(void)printf("New mail has arrived.\n");
3249c3d74c3Swiz 		(void)snprintf(tempname, sizeof(tempname),
3259c3d74c3Swiz 		    "%s/mail.RqXXXXXXXXXX", tmpdir);
3269c3d74c3Swiz 		if ((fd = mkstemp(tempname)) == -1 ||
327*4fe1ef32Schristos 		    (rbuf = Fdopen(fd, "wef")) == NULL) {
3289c3d74c3Swiz 		    	if (fd != -1)
329ca286310Schristos 				(void)close(fd);
33061f28255Scgd 			goto newmail;
3319c3d74c3Swiz 		}
33261f28255Scgd #ifdef APPEND
333ca286310Schristos 		(void)fseek(fbuf, (long)mailsize, 0);
33461f28255Scgd 		while ((c = getc(fbuf)) != EOF)
33561f28255Scgd 			(void)putc(c, rbuf);
33661f28255Scgd #else
33761f28255Scgd 		p = minfo.st_size - mailsize;
33861f28255Scgd 		while (p-- > 0) {
33961f28255Scgd 			c = getc(fbuf);
34061f28255Scgd 			if (c == EOF)
34161f28255Scgd 				goto newmail;
34261f28255Scgd 			(void)putc(c, rbuf);
34361f28255Scgd 		}
34461f28255Scgd #endif
3452f2497e5Sbad 		(void)fflush(rbuf);
3462f2497e5Sbad 		if (ferror(rbuf)) {
3479c3d74c3Swiz 			warn("%s", tempname);
348ca286310Schristos 			(void)Fclose(rbuf);
349ca286310Schristos 			(void)Fclose(fbuf);
3502f2497e5Sbad 			dot_unlock(mailname);
3512f2497e5Sbad 			return;
3522f2497e5Sbad 		}
353ca286310Schristos 		(void)Fclose(rbuf);
354*4fe1ef32Schristos 		if ((rbuf = Fopen(tempname, "ref")) == NULL)
35561f28255Scgd 			goto newmail;
356ca286310Schristos 		(void)rm(tempname);
35761f28255Scgd 	}
35861f28255Scgd 
35961f28255Scgd 	/*
36061f28255Scgd 	 * Adjust the message flags in each message.
36161f28255Scgd 	 */
36261f28255Scgd 
36361f28255Scgd 	anystat = 0;
364f3098750Schristos 	autohold = value(ENAME_HOLD) != NULL;
36561f28255Scgd 	holdbit = autohold ? MPRESERVE : MBOX;
36661f28255Scgd 	nohold = MBOX|MSAVED|MDELETED|MPRESERVE;
367f3098750Schristos 	if (value(ENAME_KEEPSAVE) != NULL)
36861f28255Scgd 		nohold &= ~MSAVED;
369f3098750Schristos 	for (mp = get_message(1); mp; mp = next_message(mp)) {
37061f28255Scgd 		if (mp->m_flag & MNEW) {
37161f28255Scgd 			mp->m_flag &= ~MNEW;
37261f28255Scgd 			mp->m_flag |= MSTATUS;
37361f28255Scgd 		}
37461f28255Scgd 		if (mp->m_flag & MSTATUS)
37561f28255Scgd 			anystat++;
37661f28255Scgd 		if ((mp->m_flag & MTOUCH) == 0)
37761f28255Scgd 			mp->m_flag |= MPRESERVE;
37861f28255Scgd 		if ((mp->m_flag & nohold) == 0)
37961f28255Scgd 			mp->m_flag |= holdbit;
38061f28255Scgd 	}
38161f28255Scgd 	modify = 0;
382ab850155Swiz 	if (Tflag != NULL) {
383*4fe1ef32Schristos 		if ((readstat = Fopen(Tflag, "wef")) == NULL)
384ab850155Swiz 			Tflag = NULL;
38561f28255Scgd 	}
386f3098750Schristos 	for (c = 0, p = 0, mp = get_message(1); mp; mp = next_message(mp)) {
38761f28255Scgd 		if (mp->m_flag & MBOX)
38861f28255Scgd 			c++;
38961f28255Scgd 		if (mp->m_flag & MPRESERVE)
39061f28255Scgd 			p++;
391f3098750Schristos 		if (mp->m_flag & MMODIFY)
39261f28255Scgd 			modify++;
393ab850155Swiz 		if (Tflag != NULL && (mp->m_flag & (MREAD|MDELETED)) != 0) {
39461f28255Scgd 			char *id;
39561f28255Scgd 
396ab850155Swiz 			if ((id = hfield("article-id", mp)) != NULL)
397ca286310Schristos 				(void)fprintf(readstat, "%s\n", id);
39861f28255Scgd 		}
39961f28255Scgd 	}
400ab850155Swiz 	if (Tflag != NULL)
401ca286310Schristos 		(void)Fclose(readstat);
402f3098750Schristos 	if (p == get_msgCount() && !modify && !anystat) {
403ca286310Schristos 		(void)printf("Held %d message%s in %s\n",
40461f28255Scgd 			p, p == 1 ? "" : "s", mailname);
405ca286310Schristos 		(void)Fclose(fbuf);
40688b833a7Schristos 		dot_unlock(mailname);
40761f28255Scgd 		return;
40861f28255Scgd 	}
40961f28255Scgd 	if (c == 0) {
41061f28255Scgd 		if (p != 0) {
411ca286310Schristos 			(void)writeback(rbuf);
412ca286310Schristos 			(void)Fclose(fbuf);
41388b833a7Schristos 			dot_unlock(mailname);
41461f28255Scgd 			return;
41561f28255Scgd 		}
41661f28255Scgd 		goto cream;
41761f28255Scgd 	}
41861f28255Scgd 
41961f28255Scgd 	/*
42061f28255Scgd 	 * Create another temporary file and copy user's mbox file
42161f28255Scgd 	 * darin.  If there is no mbox, copy nothing.
42261f28255Scgd 	 * If he has specified "append" don't copy his mailbox,
42361f28255Scgd 	 * just copy saveable entries at the end.
42461f28255Scgd 	 */
42561f28255Scgd 
42661f28255Scgd 	mbox = expand("&");
42761f28255Scgd 	mcount = c;
428ca13337dSchristos 	append = value(ENAME_APPEND) != NULL;
429ca13337dSchristos 	if (!append) {
4304361c515Swiz 		(void)snprintf(tempname, sizeof(tempname),
4314361c515Swiz 		    "%s/mail.RmXXXXXXXXXX", tmpdir);
4324361c515Swiz 		if ((fd = mkstemp(tempname)) == -1 ||
433*4fe1ef32Schristos 		    (obuf = Fdopen(fd, "wef")) == NULL) {
4344361c515Swiz 			warn("%s", tempname);
43569047878Swiz 			if (fd != -1)
436ca286310Schristos 				(void)close(fd);
437ca286310Schristos 			(void)Fclose(fbuf);
43888b833a7Schristos 			dot_unlock(mailname);
43961f28255Scgd 			return;
44061f28255Scgd 		}
441*4fe1ef32Schristos 		if ((ibuf = Fopen(tempname, "ref")) == NULL) {
4424361c515Swiz 			warn("%s", tempname);
443ca286310Schristos 			(void)rm(tempname);
444ca286310Schristos 			(void)Fclose(obuf);
445ca286310Schristos 			(void)Fclose(fbuf);
44688b833a7Schristos 			dot_unlock(mailname);
44761f28255Scgd 			return;
44861f28255Scgd 		}
449ca286310Schristos 		(void)rm(tempname);
450*4fe1ef32Schristos 		if ((abuf = Fopen(mbox, "ref")) != NULL) {
45161f28255Scgd 			while ((c = getc(abuf)) != EOF)
45261f28255Scgd 				(void)putc(c, obuf);
453ca286310Schristos 			(void)Fclose(abuf);
45461f28255Scgd 		}
45561f28255Scgd 		if (ferror(obuf)) {
4564361c515Swiz 			warn("%s", tempname);
457ca286310Schristos 			(void)Fclose(ibuf);
458ca286310Schristos 			(void)Fclose(obuf);
459ca286310Schristos 			(void)Fclose(fbuf);
46088b833a7Schristos 			dot_unlock(mailname);
46161f28255Scgd 			return;
46261f28255Scgd 		}
463ca286310Schristos 		(void)Fclose(obuf);
4644871d79cSchristos 		if ((fd = creat(mbox, 0600)) != -1)
46585576ae0Schristos 			(void)close(fd);
466*4fe1ef32Schristos 		if ((obuf = Fopen(mbox, "ref+")) == NULL) {
46769047878Swiz 			warn("%s", mbox);
468ca286310Schristos 			(void)Fclose(ibuf);
469ca286310Schristos 			(void)Fclose(fbuf);
47088b833a7Schristos 			dot_unlock(mailname);
47161f28255Scgd 			return;
47261f28255Scgd 		}
47361f28255Scgd 	}
47488b833a7Schristos 	else {
475*4fe1ef32Schristos 		if ((obuf = Fopen(mbox, "aef")) == NULL) {
47669047878Swiz 			warn("%s", mbox);
477ca286310Schristos 			(void)Fclose(fbuf);
47888b833a7Schristos 			dot_unlock(mailname);
47961f28255Scgd 			return;
48061f28255Scgd 		}
481ca286310Schristos 		(void)fchmod(fileno(obuf), 0600);
48261f28255Scgd 	}
483f3098750Schristos 	for (mp = get_message(1); mp; mp = next_message(mp))
48461f28255Scgd 		if (mp->m_flag & MBOX)
4858207b28aSchristos 			if (sendmessage(mp, obuf, saveignore, NULL, NULL) < 0) {
48669047878Swiz 				warn("%s", mbox);
487ca13337dSchristos 				if (!append)
488ca286310Schristos 					(void)Fclose(ibuf);
489ca286310Schristos 				(void)Fclose(obuf);
490ca286310Schristos 				(void)Fclose(fbuf);
49188b833a7Schristos 				dot_unlock(mailname);
49261f28255Scgd 				return;
49361f28255Scgd 			}
49461f28255Scgd 
49561f28255Scgd 	/*
49661f28255Scgd 	 * Copy the user's old mbox contents back
49761f28255Scgd 	 * to the end of the stuff we just saved.
49861f28255Scgd 	 * If we are appending, this is unnecessary.
49961f28255Scgd 	 */
50061f28255Scgd 
501ca13337dSchristos 	if (!append) {
50261f28255Scgd 		rewind(ibuf);
50361f28255Scgd 		c = getc(ibuf);
50461f28255Scgd 		while (c != EOF) {
50561f28255Scgd 			(void)putc(c, obuf);
50661f28255Scgd 			if (ferror(obuf))
50761f28255Scgd 				break;
50861f28255Scgd 			c = getc(ibuf);
50961f28255Scgd 		}
510ca286310Schristos 		(void)Fclose(ibuf);
51161f28255Scgd 	}
512ca286310Schristos 	(void)fflush(obuf);
5132f2497e5Sbad 	if (!ferror(obuf))
5142f2497e5Sbad 		trunc(obuf);	/* XXX or should we truncate? */
51561f28255Scgd 	if (ferror(obuf)) {
51669047878Swiz 		warn("%s", mbox);
517ca286310Schristos 		(void)Fclose(obuf);
518ca286310Schristos 		(void)Fclose(fbuf);
51988b833a7Schristos 		dot_unlock(mailname);
52061f28255Scgd 		return;
52161f28255Scgd 	}
522ca286310Schristos 	(void)Fclose(obuf);
52361f28255Scgd 	if (mcount == 1)
524ca286310Schristos 		(void)printf("Saved 1 message in mbox\n");
52561f28255Scgd 	else
526ca286310Schristos 		(void)printf("Saved %d messages in mbox\n", mcount);
52761f28255Scgd 
52861f28255Scgd 	/*
52961f28255Scgd 	 * Now we are ready to copy back preserved files to
53061f28255Scgd 	 * the system mailbox, if any were requested.
53161f28255Scgd 	 */
53261f28255Scgd 
53361f28255Scgd 	if (p != 0) {
534ca286310Schristos 		(void)writeback(rbuf);
535ca286310Schristos 		(void)Fclose(fbuf);
53688b833a7Schristos 		dot_unlock(mailname);
53761f28255Scgd 		return;
53861f28255Scgd 	}
53961f28255Scgd 
54061f28255Scgd 	/*
54169047878Swiz 	 * Finally, remove his /var/mail file.
54261f28255Scgd 	 * If new mail has arrived, copy it back.
54361f28255Scgd 	 */
54461f28255Scgd 
54561f28255Scgd cream:
54661f28255Scgd 	if (rbuf != NULL) {
547*4fe1ef32Schristos 		abuf = Fopen(mailname, "ref+");
54861f28255Scgd 		if (abuf == NULL)
54961f28255Scgd 			goto newmail;
55061f28255Scgd 		while ((c = getc(rbuf)) != EOF)
55161f28255Scgd 			(void)putc(c, abuf);
5522f2497e5Sbad 		(void)fflush(abuf);
553d78ba354Sbad 		if (ferror(abuf)) {
55469047878Swiz 			warn("%s", mailname);
555ca286310Schristos 			(void)Fclose(abuf);
556ca286310Schristos 			(void)Fclose(fbuf);
5572f2497e5Sbad 			dot_unlock(mailname);
5582f2497e5Sbad 			return;
5592f2497e5Sbad 		}
560ca286310Schristos 		(void)Fclose(rbuf);
56161f28255Scgd 		trunc(abuf);
562ca286310Schristos 		(void)Fclose(abuf);
56361f28255Scgd 		alter(mailname);
564ca286310Schristos 		(void)Fclose(fbuf);
56588b833a7Schristos 		dot_unlock(mailname);
56661f28255Scgd 		return;
56761f28255Scgd 	}
56861f28255Scgd 	demail();
569ca286310Schristos 	(void)Fclose(fbuf);
57088b833a7Schristos 	dot_unlock(mailname);
57161f28255Scgd 	return;
57261f28255Scgd 
57361f28255Scgd newmail:
574ca286310Schristos 	(void)printf("Thou hast new mail.\n");
57588b833a7Schristos 	if (fbuf != NULL) {
576ca286310Schristos 		(void)Fclose(fbuf);
57788b833a7Schristos 		dot_unlock(mailname);
57888b833a7Schristos 	}
57961f28255Scgd }
580