From 5fd83771641d15c418f747bd343ba6738d3875f7 Mon Sep 17 00:00:00 2001 From: Cameron Katri Date: Sun, 9 May 2021 14:20:58 -0400 Subject: Import macOS userland adv_cmds-176 basic_cmds-55 bootstrap_cmds-116.100.1 developer_cmds-66 diskdev_cmds-667.40.1 doc_cmds-53.60.1 file_cmds-321.40.3 mail_cmds-35 misc_cmds-34 network_cmds-606.40.1 patch_cmds-17 remote_cmds-63 shell_cmds-216.60.1 system_cmds-880.60.2 text_cmds-106 --- mail_cmds/mail/fio.c | 475 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 475 insertions(+) create mode 100644 mail_cmds/mail/fio.c (limited to 'mail_cmds/mail/fio.c') diff --git a/mail_cmds/mail/fio.c b/mail_cmds/mail/fio.c new file mode 100644 index 0000000..6f59372 --- /dev/null +++ b/mail_cmds/mail/fio.c @@ -0,0 +1,475 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)fio.c 8.2 (Berkeley) 4/20/95"; +#endif +static const char rcsid[] = + "$FreeBSD: src/usr.bin/mail/fio.c,v 1.12 2002/06/30 05:25:06 obrien Exp $"; +#endif /* not lint */ + +#include + +#include "rcv.h" +#include +#include + +#include +#include +#include +#include "extern.h" + +/* + * Mail -- a mail program + * + * File I/O. + */ + +extern int wait_status; + +/* + * Set up the input pointers while copying the mail file into /tmp. + */ +void +setptr(ibuf, offset) + FILE *ibuf; + off_t offset; +{ + int c, count; + char *cp, *cp2; + struct message this; + FILE *mestmp; + int maybe, inhead; + char linebuf[LINESIZE], pathbuf[PATHSIZE]; + int omsgCount; + + /* Get temporary file. */ + (void)snprintf(pathbuf, sizeof(pathbuf), "%s/mail.XXXXXXXXXX", tmpdir); + if ((c = mkstemp(pathbuf)) == -1 || (mestmp = Fdopen(c, "r+")) == NULL) + err(1, "can't open %s", pathbuf); + (void)rm(pathbuf); + + if (offset == 0) { + msgCount = 0; + } else { + /* Seek into the file to get to the new messages */ + (void)fseeko(ibuf, offset, SEEK_SET); + /* + * We need to make "offset" a pointer to the end of + * the temp file that has the copy of the mail file. + * If any messages have been edited, this will be + * different from the offset into the mail file. + */ + (void)fseeko(otf, (off_t)0, SEEK_END); + offset = ftello(otf); + } + omsgCount = msgCount; + maybe = 1; + inhead = 0; + this.m_flag = MUSED|MNEW; + this.m_size = 0; + this.m_lines = 0; + this.m_block = 0; + this.m_offset = 0; + for (;;) { + if (fgets(linebuf, sizeof(linebuf), ibuf) == NULL) { + if (append(&this, mestmp)) + errx(1, "temporary file"); + makemessage(mestmp, omsgCount); + return; + } + count = strlen(linebuf); + /* + * Transforms lines ending in to just . + * This allows mail to be able to read Eudora mailboxes. + */ + if (count >= 2 && linebuf[count - 1] == '\n' && + linebuf[count - 2] == '\r') { + count--; + linebuf[count - 1] = '\n'; + } + + (void)fwrite(linebuf, sizeof(*linebuf), count, otf); + if (ferror(otf)) + errx(1, "/tmp"); + if (count) + linebuf[count - 1] = '\0'; + if (maybe && linebuf[0] == 'F' && ishead(linebuf)) { + msgCount++; + if (append(&this, mestmp)) + errx(1, "temporary file"); + this.m_flag = MUSED|MNEW; + this.m_size = 0; + this.m_lines = 0; + this.m_block = blockof(offset); + this.m_offset = boffsetof(offset); + inhead = 1; + } else if (linebuf[0] == 0) { + inhead = 0; + } else if (inhead) { + for (cp = linebuf, cp2 = "status";; cp++) { + if ((c = *cp2++) == '\0') { + while (isspace((unsigned char)*cp++)) + ; + if (cp[-1] != ':') + break; + while ((c = *cp++) != '\0') + if (c == 'R') + this.m_flag |= MREAD; + else if (c == 'O') + this.m_flag &= ~MNEW; + inhead = 0; + break; + } + if (*cp != c && *cp != toupper((unsigned char)c)) + break; + } + } + offset += count; + this.m_size += count; + this.m_lines++; + maybe = linebuf[0] == 0; + } +} + +/* + * Drop the passed line onto the passed output buffer. + * If a write error occurs, return -1, else the count of + * characters written, including the newline if requested. + */ +int +putline(obuf, linebuf, outlf) + FILE *obuf; + char *linebuf; + int outlf; +{ + int c; + + c = strlen(linebuf); + (void)fwrite(linebuf, sizeof(*linebuf), c, obuf); + if (outlf) { + fprintf(obuf, "\n"); + c++; + } + if (ferror(obuf)) + return (-1); + return (c); +} + +/* + * Read up a line from the specified input into the line + * buffer. Return the number of characters read. Do not + * include the newline (or carriage return) at the end. + */ +int +readline(ibuf, linebuf, linesize) + FILE *ibuf; + char *linebuf; + int linesize; +{ + int n; + + clearerr(ibuf); + if (fgets(linebuf, linesize, ibuf) == NULL) + return (-1); + n = strlen(linebuf); + if (n > 0 && linebuf[n - 1] == '\n') + linebuf[--n] = '\0'; + if (n > 0 && linebuf[n - 1] == '\r') + linebuf[--n] = '\0'; + return (n); +} + +/* + * Return a file buffer all ready to read up the + * passed message pointer. + */ +FILE * +setinput(mp) + struct message *mp; +{ + + (void)fflush(otf); + if (fseeko(itf, + positionof(mp->m_block, mp->m_offset), SEEK_SET) < 0) + err(1, "fseeko"); + return (itf); +} + +/* + * Take the data out of the passed ghost file and toss it into + * a dynamically allocated message structure. + */ +void +makemessage(f, omsgCount) + FILE *f; + int omsgCount; +{ + size_t size; + struct message *nmessage; + + size = (msgCount + 1) * sizeof(struct message); + nmessage = (struct message *)realloc(message, size); + if (nmessage == NULL) + errx(1, "Insufficient memory for %d messages\n", + msgCount); + if (omsgCount == 0 || message == NULL) + dot = nmessage; + else + dot = nmessage + (dot - message); + message = nmessage; + size -= (omsgCount + 1) * sizeof(struct message); + (void)fflush(f); + (void)lseek(fileno(f), (off_t)sizeof(*message), 0); + if (read(fileno(f), (char *)&message[omsgCount], size) != size) + errx(1, "Message temporary file corrupted"); + message[msgCount].m_size = 0; + message[msgCount].m_lines = 0; + (void)Fclose(f); +} + +/* + * Append the passed message descriptor onto the temp file. + * If the write fails, return 1, else 0 + */ +int +append(mp, f) + struct message *mp; + FILE *f; +{ + return (fwrite((char *)mp, sizeof(*mp), 1, f) != 1); +} + +/* + * Delete a file, but only if the file is a plain file. + */ +int +rm(name) + char *name; +{ + struct stat sb; + + if (stat(name, &sb) < 0) + return (-1); + if (!S_ISREG(sb.st_mode)) { + errno = EISDIR; + return (-1); + } + return (unlink(name)); +} + +static int sigdepth; /* depth of holdsigs() */ +static sigset_t nset, oset; +/* + * Hold signals SIGHUP, SIGINT, and SIGQUIT. + */ +void +holdsigs() +{ + + if (sigdepth++ == 0) { + (void)sigemptyset(&nset); + (void)sigaddset(&nset, SIGHUP); + (void)sigaddset(&nset, SIGINT); + (void)sigaddset(&nset, SIGQUIT); + (void)sigprocmask(SIG_BLOCK, &nset, &oset); + } +} + +/* + * Release signals SIGHUP, SIGINT, and SIGQUIT. + */ +void +relsesigs() +{ + + if (--sigdepth == 0) + (void)sigprocmask(SIG_SETMASK, &oset, NULL); +} + +/* + * Determine the size of the file possessed by + * the passed buffer. + */ +off_t +fsize(iob) + FILE *iob; +{ + struct stat sbuf; + + if (fstat(fileno(iob), &sbuf) < 0) + return (0); + return (sbuf.st_size); +} + +/* + * Evaluate the string given as a new mailbox name. + * Supported meta characters: + * % for my system mail box + * %user for user's system mail box + * # for previous file + * & invoker's mbox file + * +file file in folder directory + * any shell meta character + * Return the file name as a dynamic string. + */ +char * +expand(name) + char *name; +{ + char xname[PATHSIZE]; + char cmdbuf[PATHSIZE]; /* also used for file names */ + int pid, l; + char *cp, *sh; + int pivec[2]; + struct stat sbuf; + + /* + * The order of evaluation is "%" and "#" expand into constants. + * "&" can expand into "+". "+" can expand into shell meta characters. + * Shell meta characters expand into constants. + * This way, we make no recursive expansion. + */ + switch (*name) { + case '%': + findmail(name[1] ? name + 1 : myname, xname, sizeof(xname)); + return (savestr(xname)); + case '#': + if (name[1] != 0) + break; + if (prevfile[0] == 0) { + printf("No previous file\n"); + return (NULL); + } + return (savestr(prevfile)); + case '&': + if (name[1] == 0 && (name = value("MBOX")) == NULL) + name = "~/mbox"; + /* fall through */ + } + if (name[0] == '+' && getfold(cmdbuf, sizeof(cmdbuf)) >= 0) { + (void)snprintf(xname, sizeof(xname), "%s/%s", cmdbuf, name + 1); + name = savestr(xname); + } + /* catch the most common shell meta character */ + if (name[0] == '~' && homedir != NULL && + (name[1] == '/' || name[1] == '\0')) { + (void)snprintf(xname, sizeof(xname), "%s%s", homedir, name + 1); + name = savestr(xname); + } + if (!strpbrk(name, "~{[*?$`'\"\\")) + return (name); + if (pipe(pivec) < 0) { + warn("pipe"); + return (name); + } + (void)snprintf(cmdbuf, sizeof(cmdbuf), "echo %s", name); + if ((sh = value("SHELL")) == NULL) + sh = _PATH_BSHELL; + pid = start_command(sh, 0, -1, pivec[1], "-c", cmdbuf, NULL); + if (pid < 0) { + (void)close(pivec[0]); + (void)close(pivec[1]); + return (NULL); + } + (void)close(pivec[1]); + l = read(pivec[0], xname, BUFSIZ); + (void)close(pivec[0]); + if (wait_child(pid) < 0 && WIFSIGNALED(wait_status) && + WTERMSIG(wait_status) != SIGPIPE) { + fprintf(stderr, "\"%s\": Expansion failed.\n", name); + return (NULL); + } + if (l < 0) { + warn("read"); + return (NULL); + } + if (l == 0) { + fprintf(stderr, "\"%s\": No match.\n", name); + return (NULL); + } + if (l == BUFSIZ) { + fprintf(stderr, "\"%s\": Expansion buffer overflow.\n", name); + return (NULL); + } + xname[l] = '\0'; + for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--) + ; + cp[1] = '\0'; + if (strchr(xname, ' ') && stat(xname, &sbuf) < 0) { + fprintf(stderr, "\"%s\": Ambiguous.\n", name); + return (NULL); + } + return (savestr(xname)); +} + +/* + * Determine the current folder directory name. + */ +int +getfold(name, namelen) + char *name; + int namelen; +{ + char *folder; + int copylen; + + if ((folder = value("folder")) == NULL) + return (-1); + if (*folder == '/') + copylen = strlcpy(name, folder, namelen); + else + copylen = snprintf(name, namelen, "%s/%s", + homedir ? homedir : ".", folder); + return (copylen < 0 || copylen >= namelen ? (-1) : (0)); +} + +/* + * Return the name of the dead.letter file. + */ +char * +getdeadletter() +{ + char *cp; + + if ((cp = value("DEAD")) == NULL || (cp = expand(cp)) == NULL) + cp = expand("~/dead.letter"); + else if (*cp != '/') { + char buf[PATHSIZE]; + + (void)snprintf(buf, sizeof(buf), "~/%s", cp); + cp = expand(buf); + } + return (cp); +} -- cgit v1.2.3-56-ge451