quit.c revision 1.12
1/* $NetBSD: quit.c,v 1.12 2001/02/05 02:07:53 christos 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 39static char sccsid[] = "@(#)quit.c 8.2 (Berkeley) 4/28/95"; 40#else 41__RCSID("$NetBSD: quit.c,v 1.12 2001/02/05 02:07:53 christos 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 54extern char *tmpdir; 55extern char *tempQuit, *tempResid; 56 57/* 58 * The "quit" command. 59 */ 60int 61quitcmd(v) 62 void *v; 63{ 64 /* 65 * If we are sourcing, then return 1 so execute() can handle it. 66 * Otherwise, return -1 to abort command loop. 67 */ 68 if (sourcing) 69 return 1; 70 return -1; 71} 72 73/* 74 * Save all of the undetermined messages at the top of "mbox" 75 * Save all untouched messages back in the system mailbox. 76 * Remove the system mailbox, if none saved there. 77 */ 78void 79quit() 80{ 81 int mcount, p, modify, autohold, anystat, holdbit, nohold; 82 FILE *ibuf = NULL, *obuf, *fbuf, *rbuf, *readstat = NULL, *abuf; 83 struct message *mp; 84 int c; 85 struct stat minfo; 86 char *mbox; 87 88#ifdef __GNUC__ 89 obuf = NULL; /* XXX gcc -Wuninitialized */ 90#endif 91 92 /* 93 * If we are read only, we can't do anything, 94 * so just return quickly. 95 */ 96 if (readonly) 97 return; 98 /* 99 * If editing (not reading system mail box), then do the work 100 * in edstop() 101 */ 102 if (edit) { 103 edstop(); 104 return; 105 } 106 107 /* 108 * See if there any messages to save in mbox. If no, we 109 * can save copying mbox to /tmp and back. 110 * 111 * Check also to see if any files need to be preserved. 112 * Delete all untouched messages to keep them out of mbox. 113 * If all the messages are to be preserved, just exit with 114 * a message. 115 */ 116 117 fbuf = Fopen(mailname, "r"); 118 if (fbuf == NULL) 119 goto newmail; 120 if (flock(fileno(fbuf), LOCK_EX) == -1) { 121nolock: 122 perror("Unable to lock mailbox"); 123 Fclose(fbuf); 124 return; 125 } 126 if (dot_lock(mailname, 1, stdout, ".") == -1) 127 goto nolock; 128 rbuf = NULL; 129 if (fstat(fileno(fbuf), &minfo) >= 0 && minfo.st_size > mailsize) { 130 printf("New mail has arrived.\n"); 131 rbuf = Fopen(tempResid, "w"); 132 if (rbuf == NULL || fbuf == NULL) 133 goto newmail; 134#ifdef APPEND 135 fseek(fbuf, (long)mailsize, 0); 136 while ((c = getc(fbuf)) != EOF) 137 (void) putc(c, rbuf); 138#else 139 p = minfo.st_size - mailsize; 140 while (p-- > 0) { 141 c = getc(fbuf); 142 if (c == EOF) 143 goto newmail; 144 (void) putc(c, rbuf); 145 } 146#endif 147 (void) fflush(rbuf); 148 if (ferror(rbuf)) { 149 perror(tempResid); 150 Fclose(rbuf); 151 Fclose(fbuf); 152 dot_unlock(mailname); 153 return; 154 } 155 Fclose(rbuf); 156 if ((rbuf = Fopen(tempResid, "r")) == NULL) 157 goto newmail; 158 rm(tempResid); 159 } 160 161 /* 162 * Adjust the message flags in each message. 163 */ 164 165 anystat = 0; 166 autohold = value("hold") != NOSTR; 167 holdbit = autohold ? MPRESERVE : MBOX; 168 nohold = MBOX|MSAVED|MDELETED|MPRESERVE; 169 if (value("keepsave") != NOSTR) 170 nohold &= ~MSAVED; 171 for (mp = &message[0]; mp < &message[msgCount]; mp++) { 172 if (mp->m_flag & MNEW) { 173 mp->m_flag &= ~MNEW; 174 mp->m_flag |= MSTATUS; 175 } 176 if (mp->m_flag & MSTATUS) 177 anystat++; 178 if ((mp->m_flag & MTOUCH) == 0) 179 mp->m_flag |= MPRESERVE; 180 if ((mp->m_flag & nohold) == 0) 181 mp->m_flag |= holdbit; 182 } 183 modify = 0; 184 if (Tflag != NOSTR) { 185 if ((readstat = Fopen(Tflag, "w")) == NULL) 186 Tflag = NOSTR; 187 } 188 for (c = 0, p = 0, mp = &message[0]; mp < &message[msgCount]; mp++) { 189 if (mp->m_flag & MBOX) 190 c++; 191 if (mp->m_flag & MPRESERVE) 192 p++; 193 if (mp->m_flag & MODIFY) 194 modify++; 195 if (Tflag != NOSTR && (mp->m_flag & (MREAD|MDELETED)) != 0) { 196 char *id; 197 198 if ((id = hfield("article-id", mp)) != NOSTR) 199 fprintf(readstat, "%s\n", id); 200 } 201 } 202 if (Tflag != NOSTR) 203 Fclose(readstat); 204 if (p == msgCount && !modify && !anystat) { 205 printf("Held %d message%s in %s\n", 206 p, p == 1 ? "" : "s", mailname); 207 Fclose(fbuf); 208 dot_unlock(mailname); 209 return; 210 } 211 if (c == 0) { 212 if (p != 0) { 213 writeback(rbuf); 214 Fclose(fbuf); 215 dot_unlock(mailname); 216 return; 217 } 218 goto cream; 219 } 220 221 /* 222 * Create another temporary file and copy user's mbox file 223 * darin. If there is no mbox, copy nothing. 224 * If he has specified "append" don't copy his mailbox, 225 * just copy saveable entries at the end. 226 */ 227 228 mbox = expand("&"); 229 mcount = c; 230 if (value("append") == NOSTR) { 231 if ((obuf = Fopen(tempQuit, "w")) == NULL) { 232 perror(tempQuit); 233 Fclose(fbuf); 234 dot_unlock(mailname); 235 return; 236 } 237 if ((ibuf = Fopen(tempQuit, "r")) == NULL) { 238 perror(tempQuit); 239 rm(tempQuit); 240 Fclose(obuf); 241 Fclose(fbuf); 242 dot_unlock(mailname); 243 return; 244 } 245 rm(tempQuit); 246 if ((abuf = Fopen(mbox, "r")) != NULL) { 247 while ((c = getc(abuf)) != EOF) 248 (void) putc(c, obuf); 249 Fclose(abuf); 250 } 251 if (ferror(obuf)) { 252 perror(tempQuit); 253 Fclose(ibuf); 254 Fclose(obuf); 255 Fclose(fbuf); 256 dot_unlock(mailname); 257 return; 258 } 259 Fclose(obuf); 260 close(creat(mbox, 0600)); 261 if ((obuf = Fopen(mbox, "r+")) == NULL) { 262 perror(mbox); 263 Fclose(ibuf); 264 Fclose(fbuf); 265 dot_unlock(mailname); 266 return; 267 } 268 } 269 else { 270 if ((obuf = Fopen(mbox, "a")) == NULL) { 271 perror(mbox); 272 Fclose(fbuf); 273 dot_unlock(mailname); 274 return; 275 } 276 fchmod(fileno(obuf), 0600); 277 } 278 for (mp = &message[0]; mp < &message[msgCount]; mp++) 279 if (mp->m_flag & MBOX) 280 if (sendmessage(mp, obuf, saveignore, NOSTR) < 0) { 281 perror(mbox); 282 Fclose(ibuf); 283 Fclose(obuf); 284 Fclose(fbuf); 285 dot_unlock(mailname); 286 return; 287 } 288 289 /* 290 * Copy the user's old mbox contents back 291 * to the end of the stuff we just saved. 292 * If we are appending, this is unnecessary. 293 */ 294 295 if (value("append") == NOSTR) { 296 rewind(ibuf); 297 c = getc(ibuf); 298 while (c != EOF) { 299 (void) putc(c, obuf); 300 if (ferror(obuf)) 301 break; 302 c = getc(ibuf); 303 } 304 Fclose(ibuf); 305 } 306 fflush(obuf); 307 if (!ferror(obuf)) 308 trunc(obuf); /* XXX or should we truncate? */ 309 if (ferror(obuf)) { 310 perror(mbox); 311 Fclose(obuf); 312 Fclose(fbuf); 313 dot_unlock(mailname); 314 return; 315 } 316 Fclose(obuf); 317 if (mcount == 1) 318 printf("Saved 1 message in mbox\n"); 319 else 320 printf("Saved %d messages in mbox\n", mcount); 321 322 /* 323 * Now we are ready to copy back preserved files to 324 * the system mailbox, if any were requested. 325 */ 326 327 if (p != 0) { 328 writeback(rbuf); 329 Fclose(fbuf); 330 dot_unlock(mailname); 331 return; 332 } 333 334 /* 335 * Finally, remove his /usr/mail file. 336 * If new mail has arrived, copy it back. 337 */ 338 339cream: 340 if (rbuf != NULL) { 341 abuf = Fopen(mailname, "r+"); 342 if (abuf == NULL) 343 goto newmail; 344 while ((c = getc(rbuf)) != EOF) 345 (void) putc(c, abuf); 346 (void) fflush(abuf); 347 if (ferror(abuf)) { 348 perror(mailname); 349 Fclose(abuf); 350 Fclose(fbuf); 351 dot_unlock(mailname); 352 return; 353 } 354 Fclose(rbuf); 355 trunc(abuf); 356 Fclose(abuf); 357 alter(mailname); 358 Fclose(fbuf); 359 dot_unlock(mailname); 360 return; 361 } 362 demail(); 363 Fclose(fbuf); 364 dot_unlock(mailname); 365 return; 366 367newmail: 368 printf("Thou hast new mail.\n"); 369 if (fbuf != NULL) { 370 Fclose(fbuf); 371 dot_unlock(mailname); 372 } 373} 374 375/* 376 * Preserve all the appropriate messages back in the system 377 * mailbox, and print a nice message indicated how many were 378 * saved. On any error, just return -1. Else return 0. 379 * Incorporate the any new mail that we found. 380 */ 381int 382writeback(res) 383 FILE *res; 384{ 385 struct message *mp; 386 int p, c; 387 FILE *obuf; 388 389 p = 0; 390 if ((obuf = Fopen(mailname, "r+")) == NULL) { 391 perror(mailname); 392 return(-1); 393 } 394#ifndef APPEND 395 if (res != NULL) { 396 while ((c = getc(res)) != EOF) 397 (void) putc(c, obuf); 398 (void) fflush(obuf); 399 if (ferror(obuf)) { 400 perror(mailname); 401 Fclose(obuf); 402 return(-1); 403 } 404 } 405#endif 406 for (mp = &message[0]; mp < &message[msgCount]; mp++) 407 if ((mp->m_flag&MPRESERVE)||(mp->m_flag&MTOUCH)==0) { 408 p++; 409 if (sendmessage(mp, obuf, (struct ignoretab *)0, NOSTR) < 0) { 410 perror(mailname); 411 Fclose(obuf); 412 return(-1); 413 } 414 } 415#ifdef APPEND 416 if (res != NULL) 417 while ((c = getc(res)) != EOF) 418 (void) putc(c, obuf); 419#endif 420 fflush(obuf); 421 if (!ferror(obuf)) 422 trunc(obuf); /* XXX or should we truncate? */ 423 if (ferror(obuf)) { 424 perror(mailname); 425 Fclose(obuf); 426 return(-1); 427 } 428 if (res != NULL) 429 Fclose(res); 430 Fclose(obuf); 431 alter(mailname); 432 if (p == 1) 433 printf("Held 1 message in %s\n", mailname); 434 else 435 printf("Held %d messages in %s\n", p, mailname); 436 return(0); 437} 438 439/* 440 * Terminate an editing session by attempting to write out the user's 441 * file from the temporary. Save any new stuff appended to the file. 442 */ 443void 444edstop() 445{ 446 int gotcha, c; 447 struct message *mp; 448 FILE *obuf, *ibuf, *readstat = NULL; 449 struct stat statb; 450 char *tempname; 451 452 if (readonly) 453 return; 454 holdsigs(); 455 if (Tflag != NOSTR) { 456 if ((readstat = Fopen(Tflag, "w")) == NULL) 457 Tflag = NOSTR; 458 } 459 for (mp = &message[0], gotcha = 0; mp < &message[msgCount]; mp++) { 460 if (mp->m_flag & MNEW) { 461 mp->m_flag &= ~MNEW; 462 mp->m_flag |= MSTATUS; 463 } 464 if (mp->m_flag & (MODIFY|MDELETED|MSTATUS)) 465 gotcha++; 466 if (Tflag != NOSTR && (mp->m_flag & (MREAD|MDELETED)) != 0) { 467 char *id; 468 469 if ((id = hfield("article-id", mp)) != NOSTR) 470 fprintf(readstat, "%s\n", id); 471 } 472 } 473 if (Tflag != NOSTR) 474 Fclose(readstat); 475 if (!gotcha || Tflag != NOSTR) 476 goto done; 477 ibuf = NULL; 478 if (stat(mailname, &statb) >= 0 && statb.st_size > mailsize) { 479 tempname = tempnam(tmpdir, "mbox"); 480 481 if ((obuf = Fopen(tempname, "w")) == NULL) { 482 perror(tempname); 483 relsesigs(); 484 reset(0); 485 } 486 if ((ibuf = Fopen(mailname, "r")) == NULL) { 487 perror(mailname); 488 Fclose(obuf); 489 rm(tempname); 490 relsesigs(); 491 reset(0); 492 } 493 fseek(ibuf, (long)mailsize, 0); 494 while ((c = getc(ibuf)) != EOF) 495 (void) putc(c, obuf); 496 (void) fflush(obuf); 497 if (ferror(obuf)) { 498 perror(tempname); 499 Fclose(obuf); 500 Fclose(ibuf); 501 rm(tempname); 502 relsesigs(); 503 reset(0); 504 } 505 Fclose(ibuf); 506 Fclose(obuf); 507 if ((ibuf = Fopen(tempname, "r")) == NULL) { 508 perror(tempname); 509 rm(tempname); 510 relsesigs(); 511 reset(0); 512 } 513 rm(tempname); 514 free(tempname); 515 } 516 printf("\"%s\" ", mailname); 517 fflush(stdout); 518 if ((obuf = Fopen(mailname, "r+")) == NULL) { 519 perror(mailname); 520 relsesigs(); 521 reset(0); 522 } 523 trunc(obuf); 524 c = 0; 525 for (mp = &message[0]; mp < &message[msgCount]; mp++) { 526 if ((mp->m_flag & MDELETED) != 0) 527 continue; 528 c++; 529 if (sendmessage(mp, obuf, (struct ignoretab *) NULL, NOSTR) < 0) { 530 perror(mailname); 531 relsesigs(); 532 reset(0); 533 } 534 } 535 gotcha = (c == 0 && ibuf == NULL); 536 if (ibuf != NULL) { 537 while ((c = getc(ibuf)) != EOF) 538 (void) putc(c, obuf); 539 Fclose(ibuf); 540 } 541 fflush(obuf); 542 if (ferror(obuf)) { 543 perror(mailname); 544 relsesigs(); 545 reset(0); 546 } 547 Fclose(obuf); 548 if (gotcha) { 549 rm(mailname); 550 printf("removed\n"); 551 } else 552 printf("complete\n"); 553 fflush(stdout); 554 555done: 556 relsesigs(); 557} 558