1
0
Files
irix-657m-src/eoe/cmd/mailx/fio.c
2022-09-29 17:59:04 +03:00

699 lines
14 KiB
C

/*
* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#ifndef lint
static char *sccsid = "@(#)fio.c 5.3 (Berkeley) 9/5/85";
#endif /* !lint */
#include "glob.h"
#include <sys/stat.h>
#include <errno.h>
/*
* Mail -- a mail program
*
* File I/O.
*/
/*
* Set up the input pointers while copying the mail file into
* temp file.
*/
setptr(ibuf)
FILE *ibuf;
{
register int c;
register char *cp, *cp2;
register int len, lines, dlines;
u_long size;
off_t offset;
char linebuf[LINESIZE];
char wbuf[LINESIZE];
int maybe, mestmp, flag, inhead, isfrom;
struct message this;
extern char tempSet[];
extern char tempMesg[];
if ((mestmp = opentemp(tempSet)) < 0)
safe_exit(1);
msgCount = 0;
offset = 0;
size = 0L;
lines = 0;
dlines = 0;
isfrom = 0;
maybe = 1;
flag = MUSED|MNEW;
for (;;) {
if (fgets(linebuf, LINESIZE, ibuf) == NULL) {
this.m_flag = flag;
flag = MUSED|MNEW;
this.m_offset = local_offsetof(offset);
this.m_block = local_blockof(offset);
this.m_size = size;
this.m_lines = lines;
this.m_dlines = dlines;
if (append(&this, mestmp)) {
perror(tempSet);
safe_exit(1);
}
fclose(ibuf);
makemessage(mestmp);
close(mestmp);
return;
}
len = strlen(linebuf);
fputs(linebuf, otf);
cp = linebuf + (len - 1);
if (*cp == '\n')
*cp = 0;
if (ferror(otf)) {
perror(tempMesg);
safe_exit(1);
}
if (maybe && linebuf[0] == 'F' && (isfrom = ishead(linebuf))) {
msgCount++;
this.m_flag = flag;
flag = MUSED|MNEW;
inhead = 1;
this.m_block = local_blockof(offset);
this.m_offset = local_offsetof(offset);
this.m_size = size;
this.m_lines = lines;
this.m_dlines = dlines;
size = 0L;
lines = 0;
dlines = 0;
if (append(&this, mestmp)) {
perror(tempSet);
safe_exit(1);
}
}
if (linebuf[0] == 0)
inhead = 0;
if (inhead && (isfrom || isign(linebuf)))
dlines--;
isfrom = 0;
if (inhead && (cp = index(linebuf, ':'))) {
*cp = 0;
if (icequal(linebuf, "status")) {
++cp;
if (index(cp, 'R'))
flag |= MREAD;
if (index(cp, 'O'))
flag &= ~MNEW;
/* XXXrs nasty assumption here! */
inhead = 0;
}
}
offset += len;
size += (long) len;
lines++;
dlines++;
maybe = 0;
if (linebuf[0] == 0)
maybe = 1;
}
}
/*
* 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.
*/
putline(obuf, linebuf)
FILE *obuf;
char *linebuf;
{
register int c;
c = strlen(linebuf);
fputs(linebuf, obuf);
putc('\n', obuf);
if (ferror(obuf))
return(-1);
return(c+1);
}
/*
* Read up a line from the specified input into the line
* buffer. Return the number of characters read. Do not
* include the newline at the end.
*/
readline(ibuf, linebuf)
FILE *ibuf;
char *linebuf;
{
register int n;
clearerr(ibuf);
if (fgets(linebuf, LINESIZE, ibuf) == NULL)
return(0);
n = strlen(linebuf);
if (n >= 1 && linebuf[n-1] == '\n')
linebuf[n-1] = '\0';
return(n);
}
/*
* Return a file buffer all ready to read up the
* passed message pointer.
*/
FILE *
setinput(mp)
register struct message *mp;
{
off_t off;
extern char tempMesg[];
fflush(otf);
if (ferror(otf))
perror(tempMesg);
off = mp->m_block;
off <<= 12;
off += mp->m_offset;
if (fseek(itf, off, 0) < 0) {
perror("fseek");
panic("temporary file seek");
}
return(itf);
}
/*
* Take the data out of the passed ghost file and toss it into
* a dynamically allocated message structure.
*/
makemessage(f)
{
register struct message *m;
register char *mp;
register count;
mp = calloc((unsigned) (msgCount + 1), sizeof *m);
if (mp == NOSTR) {
printf("Insufficient memory for %d messages\n", msgCount);
safe_exit(1);
}
if (message != (struct message *) 0)
cfree((char *) message);
message = (struct message *) mp;
dot = message;
lseek(f, 0L, 0);
while (count = read(f, mp, BUFSIZ))
mp += count;
for (m = &message[0]; m < &message[msgCount]; m++) {
m->m_size = (m+1)->m_size;
m->m_lines = (m+1)->m_lines;
m->m_dlines = (m+1)->m_dlines;
m->m_flag = (m+1)->m_flag;
}
message[msgCount].m_size = 0L;
message[msgCount].m_lines = 0;
message[msgCount].m_dlines = 0;
}
/*
* Append the passed message descriptor onto the temp file.
* If the write fails, return 1, else 0
*/
append(mp, f)
struct message *mp;
{
if (write(f, (char *) mp, sizeof *mp) != sizeof *mp)
return(1);
return(0);
}
/*
* Delete a file, but only if the file is a plain file.
* const char * because stdio.h now declares the posix remove()
* but we want to check for a directory, so don't use that one...
*/
m_remove(const char *name)
{
struct stat statb;
extern int errno;
if (stat(name, &statb) < 0) {
if (debug)
printf("m_remove: cannot stat %s (%s)\n",
name, strerror(errno));
return(-1);
}
if ((statb.st_mode & S_IFMT) != S_IFREG) {
errno = EISDIR;
if (debug)
printf("m_remove: cannot delete %s (%s)\n",
name, strerror(errno));
return(-1);
}
return(unlink(name));
}
/*
* Terminate an editing session by attempting to write out the user's
* file from the temporary. Save any new stuff appended to the file.
*/
edstop()
{
int lcnt;
long ccnt;
register int gotcha, c;
register struct message *mp;
FILE *obuf, *ibuf, *readstat;
struct stat statb;
char tempname[30], *id;
extern char tempRoot[];
void (*sigs[3])();
if (readonly)
return;
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)) != NOSTR)
fprintf(readstat, "%s\n", id);
}
}
if (Tflag != NOSTR)
fclose(readstat);
if (!gotcha || Tflag != NOSTR)
goto done;
ibuf = NULL;
if (stat(editfile, &statb) >= 0 && statb.st_size > mailsize) {
strncpy(tempname, tempRoot, 30);
tempname[29] = '\0';
if((strlen(tempname) + 11) <= 29)
strcat(tempname, "/mboxXXXXXX");
mktemp(tempname);
if ((obuf = fopen(tempname, "w")) == NULL) {
perror(tempname);
relsesigs();
reset(0);
}
if ((ibuf = fopen(editfile, "r")) == NULL) {
perror(editfile);
fclose(obuf);
m_remove(tempname);
relsesigs();
reset(0);
}
fseek(ibuf, mailsize, 0);
while ((c = getc(ibuf)) != EOF)
putc(c, obuf);
fclose(ibuf);
fclose(obuf);
if ((ibuf = fopen(tempname, "r")) == NULL) {
perror(tempname);
m_remove(tempname);
relsesigs();
reset(0);
}
m_remove(tempname);
}
printf("\"%s\" ", editfile);
fflush(stdout);
if ((obuf = fopen(editfile, "r+")) == NULL) {
perror(editfile);
relsesigs();
reset(0);
}
fflush(obuf);
trunc(obuf);
c = 0;
for (mp = &message[0]; mp < &message[msgCount]; mp++) {
if ((mp->m_flag & MDELETED) != 0)
continue;
c++;
if (send_msg(mp, obuf, NO_SUPPRESS, &lcnt, &ccnt, 0) < 0) {
perror(editfile);
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)) {
perror(editfile);
relsesigs();
reset(0);
}
fclose(obuf);
if (gotcha && value("keep") == NOSTR) {
m_remove(editfile);
printf("removed\n");
}
else
printf("complete\n");
fflush(stdout);
done:
relsesigs();
}
static int sigdepth = 0; /* depth of holdsigs() */
static int omask = 0;
#ifndef VMUNIX
#if defined(SVR3) || defined(_SVR4_SOURCE)
static void (*washup)(); /* what was SIGHUP setting */
static void (*wasint)(); /* what was SIGINT setting */
static void (*wasquit)(); /* what was SIGQUIT setting */
#else
static int (*washup)(); /* what was SIGHUP setting */
static int (*wasint)(); /* what was SIGINT setting */
static int (*wasquit)(); /* what was SIGQUIT setting */
#endif
#endif /* !VMUNIX */
/*
* Hold signals SIGHUP - SIGQUIT.
*/
holdsigs()
{
register int i;
if (sigdepth++ == 0) {
#ifdef VMUNIX
omask = sigblock(sigmask(SIGHUP)|sigmask(SIGINT)|sigmask(SIGQUIT));
#else
washup = signal(SIGHUP, SIG_IGN);
wasint = signal(SIGINT, SIG_IGN);
wasquit= signal(SIGQUIT,SIG_IGN);
#endif /* VMUNIX */
}
}
/*
* Release signals SIGHUP - SIGQUIT
*/
relsesigs()
{
register int i;
if (--sigdepth == 0) {
#ifdef VMUNIX
sigsetmask(omask);
#else
signal(SIGHUP,washup);
signal(SIGINT,wasint);
signal(SIGQUIT,wasquit);
#endif
}
}
/*
* Open a temp file by creating, closing, unlinking, and
* reopening. Return the open file descriptor.
*/
opentemp(file)
char file[];
{
register int f;
if ((f = creat(file, 0600)) < 0) {
perror(file);
return(-1);
}
close(f);
if ((f = open(file, 2)) < 0) {
perror(file);
m_remove(file);
return(-1);
}
m_remove(file);
return(f);
}
/*
* Determine the size of the file possessed by
* the passed buffer.
*/
off_t
fsize(iob)
FILE *iob;
{
register int f;
struct stat sbuf;
f = fileno(iob);
if (fstat(f, &sbuf) < 0)
return(0);
return(sbuf.st_size);
}
/*
* Take a file name, possibly with shell meta characters
* in it and expand it by using "sh -c echo filename"
* Return the file name as a dynamic string.
*/
char *
expand(name)
char name[];
{
char xname[BUFSIZ];
char cmdbuf[BUFSIZ];
register int pid, l, rc;
register char *cp, *Shell;
int s, pivec[2];
void (*sigint)();
struct stat sbuf;
if ((name[0] == '+') && (value("folder") != NOSTR)) {
cp = expand(name + 1);
if (*cp != '/' && getfold(cmdbuf, BUFSIZ) >= 0) {
snprintf(xname, (ssize_t)BUFSIZ,
"%s/%s", cmdbuf, cp);
cp = savestr(xname);
}
return(cp);
}
if (!anyof(name, "~{[*?$`'\"\\ \t"))
return(name);
if (pipe(pivec) < 0) {
perror("pipe");
return(name);
}
if (strlen(name) > PATH_MAX) {
errno = ENAMETOOLONG;
perror(name);
goto err;
}
if (anyof(name, "\\"))
snprintf(cmdbuf, BUFSIZ, "echo '%s'", name);
else
snprintf(cmdbuf, BUFSIZ, "echo %s", name);
if ((pid = vfork()) == 0) {
sigchild();
Shell = value("SHELL");
if (Shell == NOSTR)
if (ismailx)
Shell = SHELL_XPG4;
else
Shell = SHELL;
close(pivec[0]);
close(1);
dup(pivec[1]);
close(pivec[1]);
close(2);
dup(1);
execl(Shell, Shell, "-c", cmdbuf, 0);
_exit(1);
}
if (pid == -1) {
perror("fork");
close(pivec[0]);
close(pivec[1]);
return(NOSTR);
}
close(pivec[1]);
l = read(pivec[0], xname, BUFSIZ);
close(pivec[0]);
while (wait(&s) != pid);
;
s &= 0377;
if (s != 0 && s != SIGPIPE) {
fprintf(stderr, "\"Echo\" failed\n");
goto err;
}
if (l < 0) {
perror("read");
goto err;
}
if (l == 0) {
fprintf(stderr, "\"%s\": No match\n", name);
goto err;
}
if (l == BUFSIZ) {
fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
goto err;
}
xname[l] = 0;
for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
;
*++cp = '\0';
if (!ismailx) {
if (any(' ', xname) && stat(xname, &sbuf) < 0) {
fprintf(stderr, "\"%s\": Ambiguous\n", name);
goto err;
}
}
return(savestr(xname));
err:
return(NOSTR);
}
/*
* XXX - This code will need to be changed to handle the general case
* of any output generated by the !command. The below code will just
* pass back the first BUFSIZ from the 'stdout' pipe generated by the
* forked process of "!command".
*
* Execute the "!command" by using "sh -c command"
* Return a read of BUFSIZ from the 'stdout' pipe generated by the results
* of an execution of the passed "!command".
*/
char *
expandbang(name)
char name[];
{
char xname[BUFSIZ];
char cmdbuf[BUFSIZ];
register int pid, l, rc;
register char *cp, *Shell;
int s, pivec[2];
void (*sigint)();
struct stat sbuf;
if ((*name == '!') && (*(name + 1) == '\0'))
goto err;
if (pipe(pivec) < 0) {
perror("pipe");
return(name);
}
snprintf(cmdbuf, BUFSIZ, "%s", (name + 1));
if ((pid = vfork()) == 0) {
sigchild();
Shell = value("SHELL");
if (Shell == NOSTR)
if (ismailx)
Shell = SHELL_XPG4;
else
Shell = SHELL;
close(pivec[0]);
close(1);
dup(pivec[1]);
close(pivec[1]);
close(2);
dup(1);
execl(Shell, Shell, "-c", cmdbuf, 0);
_exit(1);
}
if (pid == -1) {
perror("fork");
close(pivec[0]);
close(pivec[1]);
return(NOSTR);
}
close(pivec[1]);
l = read(pivec[0], xname, BUFSIZ);
close(pivec[0]);
while (wait(&s) != pid);
;
s &= 0377;
if (s != 0 && s != SIGPIPE) {
fprintf(stderr, "\"%s\" failed\n", name);
goto err;
}
if (l < 0) {
perror("read");
goto err;
}
if (l == 0) {
fprintf(stderr, "\"%s\": No match\n", name);
goto err;
}
if (l == BUFSIZ) {
fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
goto err;
}
xname[l] = 0;
for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
;
*++cp = '\0';
return(savestr(xname));
err:
return(NOSTR);
}
/*
* Determine the current folder directory name.
* Note: arg 'size' MUST be max size of arg 'name'.
*/
getfold(name, size)
char *name;
int size;
{
char *folder;
if ((folder = value("folder")) == NOSTR)
return(-1);
if ((folder = expand(folder)) == NOSTR)
return(-1);
if (*folder == '/') {
strncpy(name, folder, size);
name[size - 1]='\0';
} else
snprintf(name, size, "%s/%s", homedir, folder);
return(0);
}
/*
* A nicer version of Fdopen, which allows us to fclose
* without losing the open file.
*/
FILE *
Fdopen(fildes, mode)
char *mode;
{
register int f;
f = dup(fildes);
if (f < 0) {
perror("dup");
return(NULL);
}
return(fdopen(f, mode));
}