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