/* * Incorporate any new mail that has arrived since we first * started reading mail. */ int incfile(void) { off_t newsize; int omsgCount = msgCount; FILE *ibuf; ibuf = Fopen(mailname, "r"); if (ibuf == NULL) return (-1); holdsigs(); newsize = fsize(ibuf); if (newsize == 0) return (-1); /* mail box is now empty??? */ if (newsize < mailsize) return (-1); /* mail box has shrunk??? */ if (newsize == mailsize) return (0); /* no new mail */ setptr(ibuf, mailsize); setmsize(msgCount); mailsize = ftello(ibuf); (void)Fclose(ibuf); relsesigs(); return (msgCount - omsgCount); }
/* * Wait for a specific child to die. */ int wait_command(int pid) { register struct child* cp = findchild(pid); int status = -1; holdsigs(); while (waitpid(pid, &status, 0) == -1 && errno == EINTR); relsesigs(); delchild(cp); return status; }
int fileclose(FILE* fp) { int r; struct file* p; struct file** pp; if (fp == 0 || fp == stdin) return 0; if (fp == stdout || fp == stderr) return fflush(fp); r = 0; for (pp = &state.files;; pp = &p->link) { if (!(p = *pp)) { fclose(fp); return 0; } if (p->fp == fp) { r = p->pid; *pp = p->link; free(p); break; } } if (r) { holdsigs(); fclose(fp); signal(SIGPIPE, SIG_IGN); r = wait_command(r); signal(SIGPIPE, SIG_DFL); relsesigs(); } else r = fclose(fp); return r; }
/* * Terminate an editing session by attempting to write out the user's * file from the temporary. Save any new stuff appended to the file. */ int edstop( int noremove /* don't allow the file to be removed, trunc instead */ ) { register int gotcha, c; register struct message *mp; FILE *obuf, *ibuf, *tbuf = 0, *readstat; struct stat statb; char tempname[STSIZ], *id; int tmpfd = -1; if (readonly) return (0); holdsigs(); if (Tflag != NOSTR) { if ((readstat = fopen(Tflag, "w")) == NULL) Tflag = NOSTR; } for (mp = &message[0], gotcha = 0; mp < &message[msgCount]; mp++) { if (mp->m_flag & MNEW) { mp->m_flag &= ~MNEW; mp->m_flag |= MSTATUS; } if (mp->m_flag & (MODIFY|MDELETED|MSTATUS)) gotcha++; if (Tflag != NOSTR && (mp->m_flag & (MREAD|MDELETED)) != 0) { if ((id = hfield("article-id", mp, addone)) != NOSTR) fprintf(readstat, "%s\n", id); } } if (Tflag != NOSTR) fclose(readstat); if (!gotcha || Tflag != NOSTR) goto done; if ((ibuf = fopen(editfile, "r+")) == NULL) { perror(editfile); relsesigs(); longjmp(srbuf, 1); } lock(ibuf, "r+", 1); if (fstat(fileno(ibuf), &statb) >= 0 && statb.st_size > mailsize) { nstrcpy(tempname, STSIZ, "/tmp/mboxXXXXXX"); if ((tmpfd = mkstemp(tempname)) == -1) { perror(tempname); fclose(ibuf); relsesigs(); longjmp(srbuf, 1); } if ((obuf = fdopen(tmpfd, "w")) == NULL) { perror(tempname); fclose(ibuf); removefile(tempname); relsesigs(); (void) close(tmpfd); longjmp(srbuf, 1); } fseek(ibuf, mailsize, 0); while ((c = getc(ibuf)) != EOF) putc(c, obuf); fclose(obuf); if ((tbuf = fopen(tempname, "r")) == NULL) { perror(tempname); fclose(ibuf); removefile(tempname); relsesigs(); longjmp(srbuf, 1); } removefile(tempname); } if ((obuf = fopen(editfile, "r+")) == NULL) { if ((obuf = fopen(editfile, "w")) == NULL) { perror(editfile); fclose(ibuf); if (tbuf) fclose(tbuf); relsesigs(); longjmp(srbuf, 1); } } printf("\"%s\" ", editfile); flush(); c = 0; for (mp = &message[0]; mp < &message[msgCount]; mp++) { if ((mp->m_flag & MDELETED) != 0) continue; c++; if (msend(mp, obuf, 0, fputs) < 0) { perror(editfile); fclose(ibuf); fclose(obuf); if (tbuf) fclose(tbuf); relsesigs(); longjmp(srbuf, 1); } } gotcha = (c == 0 && tbuf == NULL); if (tbuf != NULL) { while ((c = getc(tbuf)) != EOF) putc(c, obuf); fclose(tbuf); } fflush(obuf); if (fferror(obuf)) { perror(editfile); fclose(ibuf); fclose(obuf); relsesigs(); longjmp(srbuf, 1); } if (gotcha && !noremove && (value("keep") == NOSTR)) { removefile(editfile); printf(gettext("removed.\n")); } else printf(gettext("updated.\n")); fclose(ibuf); trunc(obuf); fclose(obuf); flush(); done: relsesigs(); return (1); }
/* * Terminate an editing session by attempting to write out the user's * file from the temporary. Save any new stuff appended to the file. */ static void edstop(void) { int gotcha, c; struct message *mp; FILE *obuf, *ibuf, *readstat; struct stat statb; char tempname[PATHSIZE]; if (readonly) return; holdsigs(); if (Tflag != NULL) { if ((readstat = Fopen(Tflag, "w")) == NULL) Tflag = NULL; } for (mp = &message[0], gotcha = 0; mp < &message[msgCount]; mp++) { if (mp->m_flag & MNEW) { mp->m_flag &= ~MNEW; mp->m_flag |= MSTATUS; } if (mp->m_flag & (MODIFY|MDELETED|MSTATUS)) gotcha++; if (Tflag != NULL && (mp->m_flag & (MREAD|MDELETED)) != 0) { char *id; if ((id = hfield("article-id", mp)) != NULL) fprintf(readstat, "%s\n", id); } } if (Tflag != NULL) Fclose(readstat); if (!gotcha || Tflag != NULL) goto done; ibuf = NULL; if (stat(mailname, &statb) >= 0 && statb.st_size > mailsize) { int fd; snprintf(tempname, sizeof(tempname), "%s/mbox.XXXXXXXXXX", tmpdir); if ((fd = mkstemp(tempname)) == -1 || (obuf = Fdopen(fd, "w")) == NULL) { warn("%s", tempname); relsesigs(); reset(0); } if ((ibuf = Fopen(mailname, "r")) == NULL) { warn("%s", mailname); Fclose(obuf); rm(tempname); relsesigs(); reset(0); } fseeko(ibuf, mailsize, SEEK_SET); while ((c = getc(ibuf)) != EOF) putc(c, obuf); Fclose(ibuf); Fclose(obuf); if ((ibuf = Fopen(tempname, "r")) == NULL) { warn("%s", tempname); rm(tempname); relsesigs(); reset(0); } rm(tempname); } printf("\"%s\" ", mailname); fflush(stdout); if ((obuf = Fopen(mailname, "r+")) == NULL) { warn("%s", mailname); relsesigs(); reset(0); } trunc(obuf); c = 0; for (mp = &message[0]; mp < &message[msgCount]; mp++) { if ((mp->m_flag & MDELETED) != 0) continue; c++; if (sendmessage(mp, obuf, NULL, NULL) < 0) { warnx("%s", mailname); relsesigs(); reset(0); } } gotcha = (c == 0 && ibuf == NULL); if (ibuf != NULL) { while ((c = getc(ibuf)) != EOF) putc(c, obuf); Fclose(ibuf); } fflush(obuf); if (ferror(obuf)) { warn("%s", mailname); relsesigs(); reset(0); } Fclose(obuf); if (gotcha) { rm(mailname); printf("removed\n"); } else printf("complete\n"); fflush(stdout); done: relsesigs(); }
/* * Set up editing on the given file name. * If the first character of name is %, we are considered to be * editing the file, otherwise we are reading our mail which has * signficance for mbox and so forth. * * If the -e option is being passed to mail, this function has a * tri-state return code: -1 on error, 0 on no mail, 1 if there is * mail. */ int setfile(char *name) { FILE *ibuf; int checkmode, i, fd; struct stat stb; char isedit = *name != '%' || getuserid(myname) != getuid(); char *who = name[1] ? name + 1 : myname; char tempname[PATHSIZE]; static int shudclob; checkmode = value("checkmode") != NULL; if ((name = expand(name)) == NULL) return (-1); if ((ibuf = Fopen(name, "r")) == NULL) { if (!isedit && errno == ENOENT) goto nomail; warn("%s", name); return (-1); } if (fstat(fileno(ibuf), &stb) < 0) { warn("fstat"); (void)Fclose(ibuf); return (-1); } if (S_ISDIR(stb.st_mode) || !S_ISREG(stb.st_mode)) { (void)Fclose(ibuf); errno = S_ISDIR(stb.st_mode) ? EISDIR : EINVAL; warn("%s", name); return (-1); } /* * Looks like all will be well. We must now relinquish our * hold on the current set of stuff. Must hold signals * while we are reading the new file, else we will ruin * the message[] data structure. */ holdsigs(); if (shudclob) quit(); /* * Copy the messages into /tmp * and set pointers. */ readonly = 0; if ((i = open(name, 1)) < 0) readonly++; else (void)close(i); if (shudclob) { (void)fclose(itf); (void)fclose(otf); } shudclob = 1; edit = isedit; strlcpy(prevfile, mailname, sizeof(prevfile)); if (name != mailname) strlcpy(mailname, name, sizeof(mailname)); mailsize = fsize(ibuf); (void)snprintf(tempname, sizeof(tempname), "%s/mail.RxXXXXXXXXXX", tmpdir); if ((fd = mkstemp(tempname)) == -1 || (otf = fdopen(fd, "w")) == NULL) err(1, "%s", tempname); (void)fcntl(fileno(otf), F_SETFD, 1); if ((itf = fopen(tempname, "r")) == NULL) err(1, "%s", tempname); (void)fcntl(fileno(itf), F_SETFD, 1); (void)rm(tempname); setptr(ibuf, 0); setmsize(msgCount); /* * New mail may have arrived while we were reading * the mail file, so reset mailsize to be where * we really are in the file... */ mailsize = ftello(ibuf); (void)Fclose(ibuf); relsesigs(); sawcom = 0; if ((checkmode || !edit) && msgCount == 0) { nomail: if (!checkmode) { fprintf(stderr, "No mail for %s\n", who); return (-1); } else return (0); } return (checkmode ? 1 : 0); }
/* * Terminate an editing session by attempting to write out the user's * file from the temporary. Save any new stuff appended to the file. */ int edstop(void) { int gotcha, c; struct message *mp; FILE *obuf, *ibuf; struct stat statb; char tempname[PATHSIZE]; if (readonly) return(0); holdsigs(); for (mp = &message[0], gotcha = 0; mp < &message[msgCount]; mp++) { if (mp->m_flag & MNEW) { mp->m_flag &= ~MNEW; mp->m_flag |= MSTATUS; } if (mp->m_flag & (MODIFY|MDELETED|MSTATUS)) gotcha++; } if (!gotcha) goto done; ibuf = NULL; if (stat(mailname, &statb) >= 0 && statb.st_size > mailsize) { int fd; (void)snprintf(tempname, sizeof(tempname), "%s/mbox.XXXXXXXXXX", tmpdir); if ((fd = mkstemp(tempname)) == -1 || (obuf = Fdopen(fd, "w")) == NULL) { warn("%s", tempname); if (fd != -1) close(fd); relsesigs(); return(-1); } if ((ibuf = Fopen(mailname, "r")) == NULL) { warn("%s", mailname); (void)Fclose(obuf); (void)rm(tempname); relsesigs(); return(-1); } fseek(ibuf, (long)mailsize, SEEK_SET); while ((c = getc(ibuf)) != EOF) (void)putc(c, obuf); (void)Fclose(ibuf); (void)Fclose(obuf); if ((ibuf = Fopen(tempname, "r")) == NULL) { warn("%s", tempname); (void)rm(tempname); relsesigs(); return(-1); } (void)rm(tempname); } printf("\"%s\" ", mailname); fflush(stdout); if ((obuf = Fopen(mailname, "r+")) == NULL) { warn("%s", mailname); relsesigs(); return(-1); } trunc(obuf); c = 0; for (mp = &message[0]; mp < &message[msgCount]; mp++) { if ((mp->m_flag & MDELETED) != 0) continue; c++; if (sendmessage(mp, obuf, NULL, NULL) < 0) { warn("%s", mailname); relsesigs(); return(-1); } } gotcha = (c == 0 && ibuf == NULL); if (ibuf != NULL) { while ((c = getc(ibuf)) != EOF) (void)putc(c, obuf); (void)Fclose(ibuf); } fflush(obuf); if (ferror(obuf)) { warn("%s", mailname); relsesigs(); return(-1); } (void)Fclose(obuf); if (gotcha) { (void)rm(mailname); puts("removed"); } else puts("complete"); fflush(stdout); done: relsesigs(); return(0); }