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