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