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