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