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