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