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