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