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