GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/mail/quit.c Lines: 0 267 0.0 %
Date: 2016-12-06 Branches: 0 232 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: quit.c,v 1.23 2016/07/19 06:43:27 deraadt Exp $	*/
2
/*	$NetBSD: quit.c,v 1.6 1996/12/28 07:11:07 tls Exp $	*/
3
4
/*
5
 * Copyright (c) 1980, 1993
6
 *	The Regents of the University of California.  All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. Neither the name of the University nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
#include "rcv.h"
34
#include <fcntl.h>
35
#include "extern.h"
36
37
/*
38
 * Rcv -- receive mail rationally.
39
 *
40
 * Termination processing.
41
 */
42
43
/*
44
 * The "quit" command.
45
 */
46
int
47
quitcmd(void *v)
48
{
49
	/*
50
	 * If we are sourcing, then return 1 so execute() can handle it.
51
	 * Otherwise, return -1 to abort command loop.
52
	 */
53
	if (sourcing)
54
		return(1);
55
	return(-1);
56
}
57
58
/*
59
 * Save all of the undetermined messages at the top of "mbox"
60
 * Save all untouched messages back in the system mailbox.
61
 * Remove the system mailbox, if none saved there.
62
 */
63
int
64
quit(void)
65
{
66
	int mcount, p, modify, autohold, anystat, holdbit, nohold;
67
	FILE *ibuf = NULL, *obuf, *fbuf, *rbuf, *abuf;
68
	struct message *mp;
69
	int c, fd;
70
	struct stat minfo;
71
	char *mbox, tempname[PATHSIZE];
72
73
	/*
74
	 * If we are read only, we can't do anything,
75
	 * so just return quickly.
76
	 */
77
	if (readonly)
78
		return(0);
79
80
	/*
81
	 * If editing (not reading system mail box), then do the work
82
	 * in edstop()
83
	 */
84
	if (edit)
85
		return(edstop());
86
87
	/*
88
	 * See if there any messages to save in mbox.  If no, we
89
	 * can save copying mbox to /tmp and back.
90
	 *
91
	 * Check also to see if any files need to be preserved.
92
	 * Delete all untouched messages to keep them out of mbox.
93
	 * If all the messages are to be preserved, just exit with
94
	 * a message.
95
	 */
96
	fbuf = Fopen(mailname, "r+");
97
	if (fbuf == NULL)
98
		goto newmail;
99
	if (flock(fileno(fbuf), LOCK_EX) == -1) {
100
		warn("Unable to lock mailbox");
101
		(void)Fclose(fbuf);
102
		return(-1);
103
	}
104
	if (!spool_lock()) {
105
		(void)Fclose(fbuf);
106
		return(-1);		/* lockspool printed the error for us */
107
	}
108
	rbuf = NULL;
109
	if (fstat(fileno(fbuf), &minfo) >= 0 && minfo.st_size > mailsize) {
110
		puts("New mail has arrived.");
111
		(void)snprintf(tempname, sizeof(tempname),
112
		    "%s/mail.RqXXXXXXXXXX", tmpdir);
113
		if ((fd = mkstemp(tempname)) == -1 ||
114
		    (rbuf = Fdopen(fd, "w")) == NULL)
115
			goto newmail;
116
#ifdef APPEND
117
		fseek(fbuf, (long)mailsize, SEEK_SET);
118
		while ((c = getc(fbuf)) != EOF)
119
			(void)putc(c, rbuf);
120
#else
121
		p = minfo.st_size - mailsize;
122
		while (p-- > 0) {
123
			c = getc(fbuf);
124
			if (c == EOF)
125
				goto newmail;
126
			(void)putc(c, rbuf);
127
		}
128
#endif
129
		(void)Fclose(rbuf);
130
		if ((rbuf = Fopen(tempname, "r")) == NULL)
131
			goto newmail;
132
		(void)rm(tempname);
133
	}
134
135
	/*
136
	 * Adjust the message flags in each message.
137
	 */
138
	anystat = 0;
139
	autohold = value("hold") != NULL;
140
	holdbit = autohold ? MPRESERVE : MBOX;
141
	nohold = MBOX|MSAVED|MDELETED|MPRESERVE;
142
	if (value("keepsave") != NULL)
143
		nohold &= ~MSAVED;
144
	for (mp = &message[0]; mp < &message[msgCount]; mp++) {
145
		if (mp->m_flag & MNEW) {
146
			mp->m_flag &= ~MNEW;
147
			mp->m_flag |= MSTATUS;
148
		}
149
		if (mp->m_flag & MSTATUS)
150
			anystat++;
151
		if ((mp->m_flag & MTOUCH) == 0)
152
			mp->m_flag |= MPRESERVE;
153
		if ((mp->m_flag & nohold) == 0)
154
			mp->m_flag |= holdbit;
155
	}
156
	modify = 0;
157
	for (c = 0, p = 0, mp = &message[0]; mp < &message[msgCount]; mp++) {
158
		if (mp->m_flag & MBOX)
159
			c++;
160
		if (mp->m_flag & MPRESERVE)
161
			p++;
162
		if (mp->m_flag & MODIFY)
163
			modify++;
164
	}
165
	if (p == msgCount && !modify && !anystat) {
166
		printf("Held %d message%s in %s\n",
167
			p, p == 1 ? "" : "s", mailname);
168
		(void)Fclose(fbuf);
169
		spool_unlock();
170
		return(0);
171
	}
172
	if (c == 0) {
173
		if (p != 0) {
174
			writeback(rbuf);
175
			(void)Fclose(fbuf);
176
			spool_unlock();
177
			return(0);
178
		}
179
		goto cream;
180
	}
181
182
	/*
183
	 * Create another temporary file and copy user's mbox file
184
	 * darin.  If there is no mbox, copy nothing.
185
	 * If he has specified "append" don't copy his mailbox,
186
	 * just copy saveable entries at the end.
187
	 */
188
	mbox = expand("&");
189
	mcount = c;
190
	if (value("append") == NULL) {
191
		int fdx;
192
193
		(void)snprintf(tempname, sizeof(tempname),
194
		    "%s/mail.RmXXXXXXXXXX", tmpdir);
195
		if ((fd = mkstemp(tempname)) == -1 ||
196
		    (obuf = Fdopen(fd, "w")) == NULL) {
197
			warn("%s", tempname);
198
			(void)Fclose(fbuf);
199
			spool_unlock();
200
			return(-1);
201
		}
202
		if ((ibuf = Fopen(tempname, "r")) == NULL) {
203
			warn("%s", tempname);
204
			(void)rm(tempname);
205
			(void)Fclose(obuf);
206
			(void)Fclose(fbuf);
207
			spool_unlock();
208
			return(-1);
209
		}
210
		(void)rm(tempname);
211
		if ((abuf = Fopen(mbox, "r")) != NULL) {
212
			while ((c = getc(abuf)) != EOF)
213
				(void)putc(c, obuf);
214
			(void)Fclose(abuf);
215
		}
216
		if (ferror(obuf)) {
217
			warn("%s", tempname);
218
			(void)Fclose(ibuf);
219
			(void)Fclose(obuf);
220
			(void)Fclose(fbuf);
221
			spool_unlock();
222
			return(-1);
223
		}
224
		(void)Fclose(obuf);
225
		if ((fdx = open(mbox, O_CREAT | O_TRUNC | O_WRONLY, 0600)) != -1)
226
			close(fdx);
227
		if ((obuf = Fopen(mbox, "r+")) == NULL) {
228
			warn("%s", mbox);
229
			(void)Fclose(ibuf);
230
			(void)Fclose(fbuf);
231
			spool_unlock();
232
			return(-1);
233
		}
234
	} else {
235
		if ((obuf = Fopen(mbox, "a")) == NULL) {
236
			warn("%s", mbox);
237
			(void)Fclose(fbuf);
238
			spool_unlock();
239
			return(-1);
240
		}
241
		fchmod(fileno(obuf), 0600);
242
	}
243
	for (mp = &message[0]; mp < &message[msgCount]; mp++)
244
		if (mp->m_flag & MBOX)
245
			if (sendmessage(mp, obuf, saveignore, NULL) < 0) {
246
				warn("%s", mbox);
247
				(void)Fclose(ibuf);
248
				(void)Fclose(obuf);
249
				(void)Fclose(fbuf);
250
				spool_unlock();
251
				return(-1);
252
			}
253
254
	/*
255
	 * Copy the user's old mbox contents back
256
	 * to the end of the stuff we just saved.
257
	 * If we are appending, this is unnecessary.
258
	 */
259
	if (value("append") == NULL) {
260
		rewind(ibuf);
261
		c = getc(ibuf);
262
		while (c != EOF) {
263
			(void)putc(c, obuf);
264
			if (ferror(obuf))
265
				break;
266
			c = getc(ibuf);
267
		}
268
		(void)Fclose(ibuf);
269
		fflush(obuf);
270
	}
271
	trunc(obuf);
272
	if (ferror(obuf)) {
273
		warn("%s", mbox);
274
		(void)Fclose(obuf);
275
		(void)Fclose(fbuf);
276
		spool_unlock();
277
		return(-1);
278
	}
279
	(void)Fclose(obuf);
280
	if (mcount == 1)
281
		puts("Saved 1 message in mbox");
282
	else
283
		printf("Saved %d messages in mbox\n", mcount);
284
285
	/*
286
	 * Now we are ready to copy back preserved files to
287
	 * the system mailbox, if any were requested.
288
	 */
289
	if (p != 0) {
290
		writeback(rbuf);
291
		(void)Fclose(fbuf);
292
		spool_unlock();
293
		return(0);
294
	}
295
296
	/*
297
	 * Finally, remove his /var/mail file.
298
	 * If new mail has arrived, copy it back.
299
	 */
300
cream:
301
	if (rbuf != NULL) {
302
		abuf = Fopen(mailname, "r+");
303
		if (abuf == NULL)
304
			goto newmail;
305
		while ((c = getc(rbuf)) != EOF)
306
			(void)putc(c, abuf);
307
		(void)Fclose(rbuf);
308
		trunc(abuf);
309
		(void)Fclose(abuf);
310
		alter(mailname);
311
		(void)Fclose(fbuf);
312
		spool_unlock();
313
		return(0);
314
	}
315
	demail();
316
	(void)Fclose(fbuf);
317
	spool_unlock();
318
	return(0);
319
320
newmail:
321
	puts("Thou hast new mail.");
322
	if (fbuf != NULL) {
323
		(void)Fclose(fbuf);
324
		spool_unlock();
325
	}
326
	return(0);
327
}
328
329
/*
330
 * Preserve all the appropriate messages back in the system
331
 * mailbox, and print a nice message indicated how many were
332
 * saved.  On any error, just return -1.  Else return 0.
333
 * Incorporate the any new mail that we found.
334
 */
335
int
336
writeback(FILE *res)
337
{
338
	struct message *mp;
339
	int p, c;
340
	FILE *obuf;
341
342
	p = 0;
343
	if ((obuf = Fopen(mailname, "r+")) == NULL) {
344
		warn("%s", mailname);
345
		return(-1);
346
	}
347
#ifndef APPEND
348
	if (res != NULL)
349
		while ((c = getc(res)) != EOF)
350
			(void)putc(c, obuf);
351
#endif
352
	for (mp = &message[0]; mp < &message[msgCount]; mp++)
353
		if ((mp->m_flag&MPRESERVE)||(mp->m_flag&MTOUCH)==0) {
354
			p++;
355
			if (sendmessage(mp, obuf, NULL, NULL) < 0) {
356
				warn("%s", mailname);
357
				(void)Fclose(obuf);
358
				return(-1);
359
			}
360
		}
361
#ifdef APPEND
362
	if (res != NULL)
363
		while ((c = getc(res)) != EOF)
364
			(void)putc(c, obuf);
365
#endif
366
	fflush(obuf);
367
	trunc(obuf);
368
	if (ferror(obuf)) {
369
		warn("%s", mailname);
370
		(void)Fclose(obuf);
371
		return(-1);
372
	}
373
	if (res != NULL)
374
		(void)Fclose(res);
375
	(void)Fclose(obuf);
376
	alter(mailname);
377
	if (p == 1)
378
		printf("Held 1 message in %s\n", mailname);
379
	else
380
		printf("Held %d messages in %s\n", p, mailname);
381
	return(0);
382
}
383
384
/*
385
 * Terminate an editing session by attempting to write out the user's
386
 * file from the temporary.  Save any new stuff appended to the file.
387
 */
388
int
389
edstop(void)
390
{
391
	int gotcha, c;
392
	struct message *mp;
393
	FILE *obuf, *ibuf;
394
	struct stat statb;
395
	char tempname[PATHSIZE];
396
397
	if (readonly)
398
		return(0);
399
	holdsigs();
400
	for (mp = &message[0], gotcha = 0; mp < &message[msgCount]; mp++) {
401
		if (mp->m_flag & MNEW) {
402
			mp->m_flag &= ~MNEW;
403
			mp->m_flag |= MSTATUS;
404
		}
405
		if (mp->m_flag & (MODIFY|MDELETED|MSTATUS))
406
			gotcha++;
407
	}
408
	if (!gotcha)
409
		goto done;
410
	ibuf = NULL;
411
	if (stat(mailname, &statb) >= 0 && statb.st_size > mailsize) {
412
		int fd;
413
414
		(void)snprintf(tempname, sizeof(tempname), "%s/mbox.XXXXXXXXXX",
415
		    tmpdir);
416
		if ((fd = mkstemp(tempname)) == -1 ||
417
		    (obuf = Fdopen(fd, "w")) == NULL) {
418
			warn("%s", tempname);
419
			if (fd != -1)
420
				close(fd);
421
			relsesigs();
422
			return(-1);
423
		}
424
		if ((ibuf = Fopen(mailname, "r")) == NULL) {
425
			warn("%s", mailname);
426
			(void)Fclose(obuf);
427
			(void)rm(tempname);
428
			relsesigs();
429
			return(-1);
430
		}
431
		fseek(ibuf, (long)mailsize, SEEK_SET);
432
		while ((c = getc(ibuf)) != EOF)
433
			(void)putc(c, obuf);
434
		(void)Fclose(ibuf);
435
		(void)Fclose(obuf);
436
		if ((ibuf = Fopen(tempname, "r")) == NULL) {
437
			warn("%s", tempname);
438
			(void)rm(tempname);
439
			relsesigs();
440
			return(-1);
441
		}
442
		(void)rm(tempname);
443
	}
444
	printf("\"%s\" ", mailname);
445
	fflush(stdout);
446
	if ((obuf = Fopen(mailname, "r+")) == NULL) {
447
		warn("%s", mailname);
448
		relsesigs();
449
		return(-1);
450
	}
451
	trunc(obuf);
452
	c = 0;
453
	for (mp = &message[0]; mp < &message[msgCount]; mp++) {
454
		if ((mp->m_flag & MDELETED) != 0)
455
			continue;
456
		c++;
457
		if (sendmessage(mp, obuf, NULL, NULL) < 0) {
458
			warn("%s", mailname);
459
			relsesigs();
460
			return(-1);
461
		}
462
	}
463
	gotcha = (c == 0 && ibuf == NULL);
464
	if (ibuf != NULL) {
465
		while ((c = getc(ibuf)) != EOF)
466
			(void)putc(c, obuf);
467
		(void)Fclose(ibuf);
468
	}
469
	fflush(obuf);
470
	if (ferror(obuf)) {
471
		warn("%s", mailname);
472
		relsesigs();
473
		return(-1);
474
	}
475
	(void)Fclose(obuf);
476
	if (gotcha) {
477
		(void)rm(mailname);
478
		puts("removed");
479
	} else
480
		puts("complete");
481
	fflush(stdout);
482
483
done:
484
	relsesigs();
485
	return(0);
486
}