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

1625 lines
30 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 = "@(#)collect.c 5.2 (Berkeley) 6/21/85";
#endif /* !lint */
/*
* Mail -- a mail program
*
* Collect input from standard input, handling
* ~ escapes.
*/
#include "glob.h"
#include <sys/stat.h>
#include <ctype.h>
#include <termio.h>
#include <errno.h>
/*
* Read a message from standard output and return a read file to it
* or NULL on error.
*/
/*
* The following hokiness with global variables is so that on
* receipt of an interrupt signal, the partial message can be salted
* away on dead.letter. The output file must be available to flush,
* and the input to read. Several open files could be saved all through
* Mail if stdio allowed simultaneous read/write access.
*/
#if defined(SVR3) || defined(_SVR4_SOURCE)
static void (*savesig)(); /* Previous SIGINT value */
static void (*savehup)(); /* Previous SIGHUP value */
#ifdef VMUNIX
static void (*savecont)(); /* Previous SIGCONT value */
#endif /* VMUNIX */
#else
static int (*savesig)(); /* Previous SIGINT value */
static int (*savehup)(); /* Previous SIGHUP value */
#ifdef VMUNIX
static int (*savecont)(); /* Previous SIGCONT value */
#endif /* VMUNIX */
#endif /* SVR3 || _SVR4_SOURCE */
static FILE *newi; /* File for saving away */
static FILE *newo; /* Output side of same */
static int hf; /* Ignore interrups */
static int hadintr; /* Have seen one SIGINT so far */
static jmp_buf coljmp; /* To get back to work */
void collrub(int);
void resetsigs(FILE *, FILE *);
FILE *
collect(hp)
struct header *hp;
{
FILE *ibuf, *fbuf, *obuf;
int lc, cc, escape, eof, frtn;
register int c, t;
char linebuf[LINESIZE], *cp;
extern char tempMail[];
void collintsig(), collhupsig(), intack(), collcont();
char getsub;
struct tcmd *tcom;
int i;
noreset++;
ibuf = obuf = NULL;
if (value("ignore") != NOSTR)
hf = 1;
else
hf = 0;
hadintr = 0;
#ifdef VMUNIX
if ((savesig = sigset(SIGINT, SIG_IGN)) != SIG_IGN)
sigset(SIGINT, hf ? intack : collrub), sigblock(sigmask(SIGINT));
if ((savehup = sigset(SIGHUP, SIG_IGN)) != SIG_IGN)
sigset(SIGHUP, collrub), sigblock(sigmask(SIGHUP));
savecont = sigset(SIGCONT, collcont);
#else /* !VMUNIX */
savesig = signal(SIGINT, SIG_IGN);
savehup = signal(SIGHUP, SIG_IGN);
#endif /* VMUNIX */
newi = NULL;
newo = NULL;
if ((obuf = fopen(tempMail, "w")) == NULL) {
perror(tempMail);
resetsigs(ibuf, obuf);
return(NULL);
}
newo = obuf;
if ((ibuf = fopen(tempMail, "r")) == NULL) {
perror(tempMail);
newo = NULL;
fclose(obuf);
resetsigs(ibuf, obuf);
return(NULL);
}
newi = ibuf;
m_remove(tempMail);
/*
* If we are going to prompt for a subject,
* refrain from printing the new line after
* the headers.
*/
t = (GALLHDR|GNL)&~GBCC;
getsub = 0;
if (intty && sflag == NOSTR &&
hp->h_subject == NOSTR &&
((value("ask") || value("asksub")) ||
/* The default is "ask" and "asksub" */
(!value("ask") && !value("asksub"))))
{
t &= ~GNL;
getsub++;
}
if (value("noask") || value("noasksub")) {
t = (GALLHDR|GNL)&~GBCC;
getsub = 0;
}
if (hp->h_seq != 0) {
puthead(hp, stdout, t);
fflush(stdout);
}
escape = ESCAPE;
if ((cp = value("escape")) != NOSTR)
escape = *cp;
eof = 0;
for (;;) {
#ifdef VMUNIX
int omask = sigblock(0) &~ (sigmask(SIGINT)|sigmask(SIGHUP));
#endif
setjmp(coljmp);
#ifdef VMUNIX
sigsetmask(omask);
#else /* !VMUNIX */
if (savesig != SIG_IGN) {
if(hf) /* work around compiler bug; can't use ? : . 3/89 */
signal(SIGINT, intack);
else
signal(SIGINT, collintsig);
}
if (savehup != SIG_IGN)
signal(SIGHUP, collhupsig);
#endif /* VMUNIX */
fflush(stdout);
if (getsub) {
grabh(hp, GSUBJECT);
getsub = 0;
continue;
}
for (i=0; i<LINESIZE; i++)
linebuf[i] = 0;
if (readline(stdin, linebuf) <= 0) {
if (intty && value("ignoreeof") != NOSTR) {
if (++eof > 35)
break;
printf("Use \".\" to terminate letter\n");
continue;
}
break;
}
eof = 0;
hadintr = 0;
if (intty && equal(".", linebuf) &&
(value("dot") != NOSTR || value("ignoreeof") != NOSTR))
break;
if (linebuf[0] != escape || rflag != NOSTR) {
if ((t = putline(obuf, linebuf)) < 0) {
resetsigs(ibuf, obuf);
return(NULL);
}
continue;
}
if ((linebuf[0] == escape) && (linebuf[1] == escape)) {
if (putline(obuf, &linebuf[1]) < 0) {
resetsigs(ibuf, obuf);
return(NULL);
}
}
else if (linebuf[1] == '.') {
frtn = 0;
goto eofl;
}
else {
tcom = tlex(&linebuf[1], &cp);
if (tcom == TNONE)
printf("Unknown command: \"%s\"\n",
&linebuf[1]);
else {
switch(tcom->tc_argtype) {
case TNOARG:
frtn = (*tcom->tc_func)(0);
break;
case TSTR:
frtn = (*tcom->tc_func)(cp);
break;
case THDR:
frtn = (*tcom->tc_func)(hp);
break;
case TBUF:
frtn = (*tcom->tc_func)(&ibuf, &obuf);
break;
case THDRSTR:
frtn = (*tcom->tc_func)(hp, cp);
break;
case TBUFSTR:
frtn = (*tcom->tc_func)(&ibuf, &obuf,
cp);
break;
case TBUFHDR:
frtn = (*tcom->tc_func)(&ibuf, &obuf,
hp);
break;
}
if (frtn)
return(NULL);
}
}
}
eofl:
/*
* Don't use the .signature feature for X/Open's mailx
*/
if (ismailx)
goto nodotsignature;
{
char xsigned[PATHSIZE];
char xsigned2[PATHSIZE];
struct name *names;
int remote;
/*
* Signature search:
* 1. If no '!' in "to" field try ~/.lsignature
* otherwise try ~/.rsignature.
* 2. If no such file, try ~/.signature (also
* used by netnews).
*/
strncpy(xsigned, homedir, PATHSIZE);
xsigned[PATHSIZE - 1] = '\0';
strncpy(xsigned2,homedir, PATHSIZE);
xsigned2[PATHSIZE - 1] = '\0';
remote = 0;
if (0 != hp->h_to) {
names = usermap(extract(hp->h_to));
while (names != NULL) {
if (strchr(names->n_name,'!')
|| strchr(names->n_name,'@')) {
remote++;
break;
}
names = names->n_flink;
}
strcat(xsigned, ((remote != 0) ?
"/.rsignature" : "/.lsignature"));
}
strcat(xsigned2,"/.signature");
if (((fbuf = fopen(xsigned, "r")) != NULL) ||
((fbuf = fopen(xsigned2, "r")) != NULL)) {
fflush(stdout);
fflush(stderr);
lc = 0;
cc = 0;
while (readline(fbuf, linebuf) > 0) {
lc++;
if ((t = putline(obuf, linebuf)) < 0) {
fclose(fbuf);
resetsigs(ibuf, obuf);
return(NULL);
}
cc += t;
}
fclose(fbuf);
}
}
nodotsignature:
fclose(obuf);
rewind(ibuf);
sigset(SIGINT, savesig);
sigset(SIGHUP, savehup);
#ifdef VMUNIX
sigset(SIGCONT, savecont);
sigsetmask(0);
#endif /* VMUNIX */
noreset = 0;
return(ibuf);
}
void
resetsigs(FILE *ibuf, FILE *obuf)
{
if (ibuf != NULL)
fclose(ibuf);
if (obuf != NULL)
fclose(obuf);
sigset(SIGINT, savesig);
sigset(SIGHUP, savehup);
#ifdef VMUNIX
sigset(SIGCONT, savecont);
sigsetmask(0);
#endif /* VMUNIX */
noreset = 0;
return;
}
esctocmd(str)
char *str;
{
execute(str, 1);
printf("(continue)\n");
return(0);
}
tintr()
{
hadintr++;
collrub(SIGINT);
safe_exit(1);
}
/*
* Grab the "usual" headers and any others that are now in use.
*/
grabhdrs(hp)
struct header *hp;
{
if (!intty || !outtty)
printf("~h: no can do!?\n");
else {
grabh(hp, GTO|GCC|GBCC|GSUBJECT|hp->h_optusedmask);
printf("(continue)\n");
}
return(0);
}
/*
* Grab all the headers.
*/
graballhdrs(hp)
struct header *hp;
{
if (!intty || !outtty)
printf("~H: no can do!?\n");
else {
grabh(hp, GREGHDR);
printf("(continue)\n");
}
return(0);
}
/*
* Add to the In-Reply-To list.
*/
addirt(hp, str)
struct header *hp;
char *str;
{
if (notempty(str)) {
hp->h_inreplyto = addto(hp->h_inreplyto, str);
hp->h_optusedmask |= GIRT;
}
hp->h_seq++;
return(0);
}
/*
* Add to the Keywords list.
*/
addkey(hp, str)
struct header *hp;
char *str;
{
if (notempty(str)) {
hp->h_keywords = addto(hp->h_keywords, str);
hp->h_optusedmask |= GKEY;
}
hp->h_seq++;
return(0);
}
/*
* Add to the To list.
*/
addt(hp, str)
struct header *hp;
char *str;
{
hp->h_to = addto(hp->h_to, str);
hp->h_seq++;
return(0);
}
/*
* Set the Subject list.
*/
setsubj(hp, str)
struct header *hp;
char *str;
{
while (isspace(*str))
str++;
hp->h_subject = savestr(str);
hp->h_seq++;
return(0);
}
/*
* Add to the cc list.
*/
addcc(hp, str)
struct header *hp;
char *str;
{
hp->h_cc = addto(hp->h_cc, str);
hp->h_seq++;
return(0);
}
/*
* Add to the bcc list.
*/
addbcc(hp, str)
struct header *hp;
char *str;
{
hp->h_bcc = addto(hp->h_bcc, str);
hp->h_seq++;
return(0);
}
/*
* Set the Comments line.
*/
setcomments(hp, str)
struct header *hp;
char *str;
{
while (isspace(*str))
str++;
if (*str != '\0')
hp->h_optusedmask |= GCOM;
else
hp->h_optusedmask &= ~GCOM;
hp->h_comments = savestr(str);
hp->h_seq++;
return(0);
}
/*
* Insert the value of the named variable: 'sign', followed by a newline
* character, into the text of the message. If the string is 'unset' or
* NULL, the message will not be changed.
*/
insert_sign(ibufp, obufp)
FILE **ibufp, **obufp;
{
return(insert_val(ibufp, obufp, "sign"));
}
/*
* Insert the value of the named variable: 'Sign', followed by a newline
* character, into the text of the message. If the string is 'unset' or
* NULL, the message will not be changed.
*/
insert_Sign(ibufp, obufp)
FILE **ibufp, **obufp;
{
return(insert_val(ibufp, obufp, "Sign"));
}
/*
* Insert the value of the named variable, followed by a newline character,
* into the text of the message. If the string is 'unset' or NULL, the
* message will not be changed.
*/
insert_val(ibufp, obufp, str)
FILE **ibufp, **obufp;
char *str;
{
int i;
char *cp, *cp1, linebuf[LINESIZE];
if (*str == '\0') {
/* nothing to insert, just leave */
return(0);
}
#ifdef DANCDEBUG
fprintf(stderr, "insert_val: str=%x %x %x %x %x %x\n",
*str, *(str+1), *(str+2), *(str+3), *(str+4), *(str+5));
#endif
/*
* Strip off leading blanks
*/
cp1 = str;
while (isspace(*cp1))
cp1++;
#ifdef DANCDEBUG
fprintf(stderr, "insert_val: *(cp1+0-->cp1+6)=%x %x %x %x %x %x %x\n",
*cp1, *(cp1+1), *(cp1+2), *(cp1+3), *(cp1+4), *(cp1+5), *(cp1+6));
#endif
if ((*cp1 == 0) || (cp = value(cp1)) == NOSTR) {
/* nothing to insert, just leave */
return(0);
}
/*
* This code to test "*cp" for zero seems redundant, but
* needs to be done. There are cases where the above return
* from 'value()' has 'cp' being non-zero where the first character
* of the sttring pointed to by 'cp' is zero.
*/
if (*cp == '\0') {
/* nothing to insert, just leave */
return(0);
}
#ifdef DANCDEBUG
fprintf(stderr, "insert_val: value returned: *(cp+0-->cp+19)=\n");
fprintf(stderr,
"%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n",
*(cp+0), *(cp+1), *(cp+2), *(cp+3), *(cp+4), *(cp+5),
*(cp+6), *(cp+7), *(cp+8), *(cp+9), *(cp+10), *(cp+11),
*(cp+12), *(cp+13), *(cp+14), *(cp+15), *(cp+16), *(cp+17),
*(cp+18), *(cp+19));
#endif
for (i=0; i<LINESIZE; i++)
linebuf[i] = 0;
/*
* Convert the passed string characters: "\t" and "\n"
* to one character: '\t' and '\n', respectively.
*/
cp1 = cp;
for (i=0; i<strlen(cp); i++) {
switch(*cp1) {
case '\\':
if ((cp1+2) <= (cp + strlen(cp))) {
if (*(cp1+1) == '\\')
cp1++;
if (*(cp1+1) == 't') {
linebuf[i] = '\t';
cp1 += 2;
break;
}
if (*(cp1+1) == 'n') {
linebuf[i] = '\n';
cp1 += 2;
break;
}
}
linebuf[i] = *cp1++;
break;
default:
linebuf[i] = *cp1++;
}
}
if (putline(*obufp, linebuf) < 0) {
resetsigs(*ibufp, *obufp);
return(1);
}
return(0);
}
/*
* Read deadletter into message.
*/
getdead(ibufp, obufp)
FILE **ibufp, **obufp;
{
return(getfile(ibufp, obufp, deadletter));
}
/*
* Read file into message
*/
getfile(ibufp, obufp, str)
FILE **ibufp, **obufp;
char *str;
{
register int lc, cc, t, lcc;
char *cp, linebuf[LINESIZE];
FILE *fbuf;
int i;
cp = str;
while (isspace(*cp))
cp++;
if (*cp == '\0') {
printf("Interpolate what file?\n");
return(0);
}
if (*cp == '!') {
cp = expandbang(cp);
if (cp == NOSTR)
return(0);
if (strlen(cp) == 0)
return(0);
cc = 0;
lc = 0;
while (*cp) {
lcc = 0;
for (i=0; i<LINESIZE; i++) {
if ((*cp == '\n') || (*cp == '\0')) {
linebuf[i] = '\0';
cp++;
lc++;
if ((t=putline(*obufp, linebuf)) < 0) {
resetsigs(*ibufp, *obufp);
return(1);
}
lcc = 0;
cc += t;
if (*(cp - 1) == '\0')
cp--;
break;
} else {
linebuf[i] = *cp++;
lcc++;
}
}
if (lcc) {
linebuf[LINESIZE - 1] = '\0';
lc++;
if ((t=putline(*obufp, linebuf)) < 0) {
resetsigs(*ibufp, *obufp);
return(1);
}
lcc = 0;
cc += t;
}
}
fflush(*obufp);
printf("\"%s\" ", str+1);
printf("%ld/%ld\n", lc, cc);
fflush(stdout);
return(0);
} else
cp = expand(cp);
if (cp == NOSTR)
return(0);
if (isdir(cp)) {
printf("%s: directory\n", cp);
return(0);
}
if ((fbuf = fopen(cp, "r")) == NULL) {
printf("%s: %s\n", cp, strerror(errno));
return(0);
}
printf("\"%s\" ", cp);
fflush(stdout);
lc = 0;
cc = 0;
while (readline(fbuf, linebuf) > 0) {
lc++;
if ((t = putline(*obufp, linebuf)) < 0) {
fclose(fbuf);
resetsigs(*ibufp, *obufp);
return(1);
}
cc += t;
}
fclose(fbuf);
printf("%d/%d\n", lc, cc);
return(0);
}
/*
* Add to the References list.
*/
addref(hp, str)
struct header *hp;
char *str;
{
if (notempty(str)) {
hp->h_references = addto(hp->h_references, str);
hp->h_optusedmask |= GREF;
}
hp->h_seq++;
return(0);
}
/*
* Add to Reply-to header field.
*/
addreplyto(hp, str)
struct header *hp;
char *str;
{
if (notempty(str)) {
hp->h_replyto = addto(hp->h_replyto, str);
hp->h_optusedmask |= GRT;
}
hp->h_seq++;
return(0);
}
/*
* Set the Return-Receipt-To header field.
*/
addrtnrcpt(hp, str)
struct header *hp;
char *str;
{
if (notempty(str)) {
hp->h_rtnrcpt = addto(hp->h_rtnrcpt, str);
hp->h_optusedmask |= GRR;
}
else if (hp->h_rtnrcpt == NOSTR) {
hp->h_rtnrcpt = addto(hp->h_rtnrcpt, myname);
hp->h_optusedmask |= GRR;
hp->h_seq++;
printf("Return receipt to \"%s\" added.\n", myname);
}
else {
hp->h_rtnrcpt = NOSTR;
hp->h_optusedmask &= ~GRR;
hp->h_seq++;
printf("Return receipt removed.\n");
}
printf("(continue)\n");
return(0);
}
/*
* Write the message on a file.
*/
putfile(ibufp, obufp, str)
FILE **ibufp, **obufp;
char *str;
{
char *cp;
extern char tempMail[];
cp = str;
while (isspace(*cp))
cp++;
if (*cp == '\0') {
fprintf(stderr, "Write what file!?\n");
return(0);
}
if ((cp = expand(cp)) == NOSTR)
return(0);
fflush(*obufp);
if (ferror(*obufp)) {
perror(tempMail);
return(0);
}
rewind(*ibufp);
exwrite(cp, *ibufp, 1);
return(0);
}
/*
* Interpolate the named messages with shift, if we
* are in receiving mail mode. Does the
* standard list processing garbage.
*/
fFgetmessage(ibufp, obufp, str, cmdfF)
FILE **ibufp, **obufp;
char *str;
char *cmdfF;
{
char *cp;
if (!rcvmode) {
printf("No messages to send from!?!\n");
return(0);
}
cp = str;
while (isspace(*cp))
cp++;
if (forward(cp, *obufp, cmdfF) < 0) {
resetsigs(*ibufp, *obufp);
return(1);
}
printf("(continue)\n");
return(0);
}
fgetmessage(ibufp, obufp, str)
FILE **ibufp, **obufp;
char *str;
{
return(fFgetmessage(ibufp, obufp, str, "f"));
}
Fgetmessage(ibufp, obufp, str)
FILE **ibufp, **obufp;
char *str;
{
return(fFgetmessage(ibufp, obufp, str, "F"));
}
/*
* Interpolate the named messages without shift, if we
* are in receiving mail mode. Does the
* standard list processing garbage.
*/
mMgetmessage(ibufp, obufp, str, cmdmM)
FILE **ibufp, **obufp;
char *str;
char *cmdmM;
{
char *cp;
if (!rcvmode) {
printf("No messages to send from!?!\n");
return(0);
}
cp = str;
while (isspace(*cp))
cp++;
if (forward(cp, *obufp, cmdmM) < 0) {
resetsigs(*ibufp, *obufp);
return(1);
}
printf("(continue)\n");
return(0);
}
Mgetmessage(ibufp, obufp, str)
FILE **ibufp, **obufp;
char *str;
{
return(mMgetmessage(ibufp, obufp, str, "M"));
}
mgetmessage(ibufp, obufp, str)
FILE **ibufp, **obufp;
char *str;
{
return(mMgetmessage(ibufp, obufp, str, "m"));
}
/*
* Print the help file.
*/
helpme()
{
register int t;
FILE *fbuf;
char *cp;
if (ismailx)
cp = TXHELPFILE;
else
cp = THELPFILE;
if ((fbuf = fopen(cp, "r")) == NULL) {
perror(cp);
return(0);
}
t = getc(fbuf);
while (t != -1) {
putchar(t);
t = getc(fbuf);
}
fclose(fbuf);
printf("(continue)\n");
return(0);
}
/*
* Print out the current state of the
* message without altering anything.
*/
printmessage(ibufp, obufp, hp)
FILE **ibufp, **obufp;
struct header *hp;
{
register int t;
extern char tempMail[];
fflush(*obufp);
if (ferror(*obufp)) {
perror(tempMail);
return(0);
}
rewind(*ibufp);
{
FILE * pbuf;
extern jmp_buf pipestop;
extern void brokpipe();
int nwcols;
char *cp;
pbuf = stdout;
if (setjmp(pipestop)) {
if (pbuf != stdout)
pclose(pbuf);
sigset(SIGPIPE, SIG_DFL);
return(0);
}
if (intty && outtty) {
nwcols = getwincols();
if (getheadlen(hp, nwcols)
+ gettextlen(*ibufp, nwcols) + 2
> getwinlines(0)) {
if (!ismailx)
cp = MORE;
else {
cp = value("PAGER");
if (cp == NULL || *cp == '\0')
cp = MORE;
}
pbuf = popen(cp, "w");
if (pbuf == NULL) {
perror(cp);
pbuf = stdout;
} else
sigset(SIGPIPE, brokpipe);
}
}
fprintf(pbuf, "-------\nMessage contains:\n");
puthead(hp, pbuf, GALLHDR|GNL);
t = getc(*ibufp);
while (t != EOF) {
putc(t, pbuf);
t = getc(*ibufp);
}
if (pbuf != stdout)
pclose(pbuf);
}
printf("(continue)\n");
return(0);
}
/*
* Pipe message through command.
* Collect output as new message.
*/
pipemessage(ibufp, obufp, str)
FILE **ibufp, **obufp;
char *str;
{
*obufp = mespipe(*ibufp, *obufp, str);
newo = *obufp;
*ibufp = newi;
newi = *ibufp;
printf("(continue)\n");
return(0);
}
/*
* Edit the current message body only using EDITOR.
*/
eeditmsgbody(ibufp, obufp, hp)
FILE **ibufp, **obufp;
{
if ((*obufp = mesedit(*ibufp, *obufp, hp, 'e', 0)) == NULL) {
resetsigs(*ibufp, *obufp);
return(1);
}
newo = *obufp;
*ibufp = newi;
printf("(continue)\n");
return(0);
}
/*
* Edit the current message body only using VISUAL.
*/
veditmsgbody(ibufp, obufp, hp)
FILE **ibufp, **obufp;
{
if ((*obufp = mesedit(*ibufp, *obufp, hp, 'v', 0)) == NULL) {
resetsigs(*ibufp, *obufp);
return(1);
}
newo = *obufp;
*ibufp = newi;
printf("(continue)\n");
return(0);
}
/*
* Edit the complete message including the headers using EDITOR.
*/
eeditmsg(ibufp, obufp, hp)
FILE **ibufp, **obufp;
struct header *hp;
{
if ((*obufp = mesedit(*ibufp, *obufp, hp, 'e', 1)) == NULL) {
resetsigs(*ibufp, *obufp);
return(1);
}
newo = *obufp;
*ibufp = newi;
printf("(continue)\n");
return(0);
}
/*
* Edit the complete message including the headers using VISUAL.
*/
veditmsg(ibufp, obufp, hp)
FILE **ibufp, **obufp;
struct header *hp;
{
if ((*obufp = mesedit(*ibufp, *obufp, hp, 'v', 1)) == NULL) {
resetsigs(*ibufp, *obufp);
return(1);
}
newo = *obufp;
*ibufp = newi;
printf("(continue)\n");
return(0);
}
/*
* Set the Encrypt field.
*/
setencrypt(hp, str)
struct header *hp;
char *str;
{
while (isspace(*str))
str++;
if (*str != '\0')
hp->h_optusedmask |= GEN;
else
hp->h_optusedmask &= ~GEN;
hp->h_encrypt = savestr(str);
hp->h_seq++;
return(0);
}
notempty(str)
char *str;
{
while(isspace(*str))
str++;
return(*str != '\0');
}
/*
* Write a file, ex-like if f set.
*/
exwrite(name, ibuf, f)
char name[];
FILE *ibuf;
{
register FILE *of;
register int c;
long cc;
int lc;
char *type;
struct stat junk;
if (f) {
printf("\"%s\" ", name);
fflush(stdout);
}
type = "w";
if (stat(name, &junk) >= 0 && (junk.st_mode & S_IFMT) == S_IFREG) {
if (!ismailx) {
/*
* The file exists and we are running 'Mail'. So,
* to preserve backward compatibilty we will now
* error terminate.
*/
if (!f)
fprintf(stderr, "%s: ", name);
fprintf(stderr, "File exists\n");
return(-1);
}
/*
* The file exists and we are running 'mailx'. So, the
* spec says that if the file exists, then we should append
* this message to the existing file.
*/
type = "a+";
}
if ((of = fopen(name, type)) == NULL) {
perror("");
return(-1);
}
lc = 0;
cc = 0;
while ((c = getc(ibuf)) != EOF) {
cc++;
if (c == '\n')
lc++;
putc(c, of);
if (ferror(of)) {
perror(name);
fclose(of);
return(-1);
}
}
fclose(of);
printf("%d/%ld\n", lc, cc);
fflush(stdout);
return(0);
}
/*
* Edit the message being collected on ibuf and obuf.
* Write the message out onto some poorly-named temp file
* and point an editor at it.
*
* On return, make the edit file the new temp file.
*/
FILE *
mesedit(ibuf, obuf, hp, cmd, dohdr)
FILE *ibuf, *obuf;
struct header *hp;
int cmd, dohdr;
{
int pid, s;
FILE *fbuf;
register int t;
#if defined(SVR3) || defined(_SVR4_SOURCE)
void (*sig)(), (*scont)(), signull();
#else
int (*sig)(), (*scont)(), signull();
#endif
struct stat sbuf;
extern char tempEdit[], tempMail[];
register char *edit;
char *Shell;
sig = sigset(SIGINT, SIG_IGN);
#ifdef VMUNIX
scont = sigset(SIGCONT, signull);
#endif /* VMUNIX */
/* create a temp file */
if (stat(tempEdit, &sbuf) >= 0) {
printf("%s: file exists\n", tempEdit);
goto out;
}
close(creat(tempEdit, 0600));
if ((fbuf = fopen(tempEdit, "w")) == NULL) {
perror(tempEdit);
goto out;
}
if (dohdr) {
if ((hp->h_subject == NOSTR) && sflag)
hp->h_subject = sflag;
/* write all current headers into the temp file */
puthead(hp, fbuf, GSUBJECT|GALLHDR|GSEP);
}
/* write out the message body collected so far */
fflush(obuf);
if (ferror(obuf)) {
perror(tempMail);
fclose(fbuf);
m_remove(tempEdit);
goto out;
}
rewind(ibuf);
t = getc(ibuf);
while (t != EOF) {
putc(t, fbuf);
t = getc(ibuf);
}
fflush(fbuf);
if (ferror(fbuf)) {
perror(tempEdit);
m_remove(tempEdit);
goto fix;
}
fclose(fbuf);
/* fork an editor on the message */
if (((edit = value(cmd == 'e' ? "EDITOR" : "VISUAL")) == NOSTR) ||
*edit == 0)
{
edit = cmd == 'e' ? EDITOR : VISUAL;
}
if (*edit != '/')
edit = cmd == 'e' ? EDITOR : VISUAL;
pid = fork();
if (pid == 0) {
/* CHILD - exec the editor. */
sigchild();
if (sig != SIG_IGN)
sigsys(SIGINT, SIG_DFL);
execl(edit, edit, tempEdit, 0);
if (!ismailx) {
perror(edit);
_exit(1);
} else {
if (errno == ENOEXEC) {
/* CHILD - exec the editor. */
sigchild();
if (sig != SIG_IGN)
sigsys(SIGINT, SIG_DFL);
Shell = SHELL_XPG4;
execl(Shell, Shell, "-c", edit, 0);
perror(edit);
_exit(1);
}
}
}
if (pid == -1) {
/* ERROR - issue warning and get out. */
perror("fork");
m_remove(tempEdit);
goto out;
}
/* PARENT - wait for the child (editor) to complete. */
while (wait(&s) != pid)
;
/* Check the results. */
if ((s & 0377) != 0) {
printf("Fatal error in \"%s\"\n", edit);
m_remove(tempEdit);
goto out;
}
/* If necessary, extract the headers from the resulting file. */
if (dohdr && extracthead(hp, tempEdit) < 0) {
perror(tempEdit);
m_remove(tempEdit);
goto out;
}
/* Switch files */
if ((fbuf = fopen(tempEdit, "a")) == NULL) {
perror(tempEdit);
m_remove(tempEdit);
goto out;
}
if ((ibuf = fopen(tempEdit, "r")) == NULL) {
perror(tempEdit);
fclose(fbuf);
m_remove(tempEdit);
goto out;
}
m_remove(tempEdit);
fclose(obuf);
fclose(newi);
obuf = fbuf;
goto out;
fix:
perror(tempEdit);
out:
#ifdef VMUNIX
sigset(SIGCONT, scont);
#endif /* VMUNIX */
sigset(SIGINT, sig);
newi = ibuf;
return(obuf);
}
/*
* Pipe the message through the command.
* Old message is on stdin of command;
* New message collected from stdout.
* Sh -c must return 0 to accept the new message.
*/
FILE *
mespipe(ibuf, obuf, cmd)
FILE *ibuf, *obuf;
char cmd[];
{
register FILE *ni, *no;
int pid, s;
#if defined(SVR3) || defined(_SVR4_SOURCE)
void (*savesig)();
#else
int (*savesig)();
#endif
char *Shell;
extern char tempEdit[], tempMail[];
newi = ibuf;
if ((no = fopen(tempEdit, "w")) == NULL) {
perror(tempEdit);
return(obuf);
}
if ((ni = fopen(tempEdit, "r")) == NULL) {
perror(tempEdit);
fclose(no);
m_remove(tempEdit);
return(obuf);
}
m_remove(tempEdit);
savesig = sigset(SIGINT, SIG_IGN);
fflush(obuf);
if (ferror(obuf)) {
perror(tempMail);
fclose(ni);
fclose(no);
m_remove(tempEdit);
return(obuf);
}
rewind(ibuf);
if (((Shell = value("SHELL")) == NULL) || (Shell[0] == '\0'))
Shell = "/bin/sh";
if ((pid = fork()) == -1) {
perror("fork");
goto err;
}
if (pid == 0) {
/*
* stdin = current message.
* stdout = new message.
*/
sigchild();
close(0);
dup(fileno(ibuf));
close(1);
dup(fileno(no));
for (s = 4; s < 15; s++)
close(s);
execl(Shell, Shell, "-c", cmd, 0);
perror(Shell);
_exit(1);
}
while (wait(&s) != pid)
;
if (s != 0 || pid == -1) {
fprintf(stderr, "\"%s\" failed!?\n", cmd);
goto err;
}
if (fsize(ni) == 0) {
fprintf(stderr, "No bytes from \"%s\" !?\n", cmd);
goto err;
}
/*
* Take new files.
*/
newi = ni;
fclose(ibuf);
fclose(obuf);
sigset(SIGINT, savesig);
return(no);
err:
fclose(no);
fclose(ni);
sigset(SIGINT, savesig);
return(obuf);
}
/*
* Interpolate the named messages into the current
* message, preceding each line with a tab or user-defined
* string.
*
* Return a count of the number of characters now in
* the message, or -1 if an error is encountered writing
* the message temporary. The flag argument is 'm' if we
* should shift over and 'f' if not.
*/
forward(ms, obuf, f)
char ms[];
FILE *obuf;
char *f;
{
register int *msgvec, *ip;
int lcnt;
long ccnt;
extern char tempMail[];
int suppresstype;
msgvec = (int *) salloc((msgCount+1) * sizeof *msgvec);
if (msgvec == (int *) NOSTR)
return(0);
if (getmsglist(ms, msgvec, 0) < 0)
return(0);
if (*msgvec == NULL) {
*msgvec = first(0, MMNORM);
if (*msgvec == NULL) {
printf("No appropriate messages\n");
return(0);
}
msgvec[1] = NULL;
}
printf("Interpolating:");
for (ip = msgvec; *ip != NULL; ip++) {
touch(*ip);
printf(" %d", *ip);
if (!ismailx) {
if (*f == 'm') {
if (transmit(&message[*ip-1], obuf) < 0L) {
perror(tempMail);
return(-1);
}
} else
if (send_msg(&message[*ip-1], obuf,
NO_SUPPRESS, &lcnt, &ccnt, 0) < 0)
{
perror(tempMail);
return(-1);
}
} else {
if ((*f == 'm') || (*f == 'f'))
suppresstype = SUPPRESS_IGN;
else
suppresstype = NO_SUPPRESS;
if (send_msg(&message[*ip-1], obuf,
suppresstype, &lcnt, &ccnt, f) < 0) {
perror(tempMail);
return(-1);
}
}
}
printf("\n");
return(0);
}
/*
* Send message described by the passed pointer to the
* passed output buffer. Insert a tab or user-defined
* character in front of each line. Return a count of
* the characters sent, or -1 on error.
*/
long
transmit(mailp, obuf)
struct message *mailp;
FILE *obuf;
{
register struct message *mp;
register int ch;
char *istr;
u_long c, n;
int bol;
FILE *ibuf;
if (ismailx) {
if ((istr = value("indentprefix")) == NOSTR)
istr = "\t";
} else {
if ((istr = value("mprefix")) == NOSTR)
istr = "\t";
}
mp = mailp;
ibuf = setinput(mp);
c = mp->m_size;
n = c;
bol = 1;
while (c-- > 0L) {
if (bol) {
bol = 0;
fprintf(obuf, "%s", istr);
n++;
if (ferror(obuf)) {
perror("transmit");
return(-1L);
}
}
ch = getc(ibuf);
if (ch == '\n')
bol++;
putc(ch, obuf);
if (ferror(obuf)) {
perror("transmit");
return(-1L);
}
}
return(n);
}
/*
* Print (continue) when continued after ^Z.
*/
void
collcont(s)
{
printf("(continue)\n");
fflush(stdout);
}
/*
* On interrupt, go here to save the partial
* message on ~/dead.letter.
* Then restore signals and execute the normal
* signal routine. We only come here if signals
* were previously set anyway.
*/
#ifndef VMUNIX
void
collintsig()
{
signal(SIGINT, SIG_IGN);
collrub(SIGINT);
}
void
collhupsig()
{
signal(SIGHUP, SIG_IGN);
collrub(SIGHUP);
}
#endif /* !VMUNIX */
void
collrub(s)
{
register FILE *dbuf;
register int c;
if (s == SIGINT && hadintr == 0) {
hadintr++;
fflush(stdout);
fprintf(stderr, "\n(Interrupt -- one more to kill letter)\n");
longjmp(coljmp, 1);
}
fclose(newo);
rewind(newi);
if (s == SIGINT && value("nosave") != NOSTR || fsize(newi) == 0)
goto done;
if ((dbuf = fopen(deadletter, "w")) == NULL)
goto done;
chmod(deadletter, 0600);
while ((c = getc(newi)) != EOF)
putc(c, dbuf);
fclose(dbuf);
done:
fclose(newi);
sigset(SIGINT, savesig);
sigset(SIGHUP, savehup);
#ifdef VMUNIX
sigset(SIGCONT, savecont);
#endif /* VMUNIX */
if (rcvmode) {
if (s == SIGHUP)
hangup(SIGHUP);
else
stop(s);
}
else
safe_exit(1);
}
/*
* Acknowledge an interrupt signal from the tty by typing an @
*/
void
intack(s)
{
puts("@");
fflush(stdout);
clearerr(stdin);
if (hf)
longjmp(coljmp, 1);
}
/*
* Add a string to the end of a header entry field.
*/
char *
addto(hf, news)
char hf[], news[];
{
register char *cp, *cp2, *linebuf;
for (cp = news; isspace(*cp); cp++)
;
if (*cp == '\0')
return(hf);
if (hf == NOSTR)
hf = cp = "";
linebuf = salloc(strlen(hf) + strlen(news) + 2);
cp2 = linebuf;
*cp2 = '\0';
if (hf != cp) {
for (cp = hf; isspace(*cp); cp++)
;
for (cp2 = linebuf; *cp;)
*cp2++ = *cp++;
}
for (cp = news; isspace(*cp); cp++)
;
if ((cp2 != linebuf) && (*cp != '\0'))
*cp2++ = ',';
while (*cp != '\0') {
if (isspace(*cp)) {
for (; isspace(*cp); cp++);
*cp2++ = ',';
}
*cp2++ = *cp++;
}
*cp2 = '\0';
return(linebuf);
}