collect.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 1998 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* University Copyright- Copyright (c) 1982, 1986, 1988
* The Regents of the University of California
* All Rights Reserved
*
* University Acknowledgment- Portions of this document are derived from
* software developed by the University of California, Berkeley, and its
* contributors.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* mailx -- a modified version of a University of California at Berkeley
* mail program
*
* Collect input from standard input, handling
* ~ escapes.
*/
#include "rcv.h"
#include <locale.h>
#ifdef SIGCONT
static void collcont(int);
#endif
static void collrub(int s);
static void intack(int);
static void xhalt(void);
/*
* 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
*/
static void (*savesig)(int); /* Previous SIGINT value */
static void (*savehup)(int); /* Previous SIGHUP value */
#ifdef SIGCONT
static void (*savecont)(int); /* Previous SIGCONT value */
#endif
static int ignintr; /* Ignore interrups */
static int hadintr; /* Have seen one SIGINT so far */
FILE *
{
register int c, t;
int hdrs;
char *iprompt;
int inhead;
int fd = -1;
noreset++;
goto err;
}
goto err;
}
hadintr = 1;
inhead = 1;
# ifdef VMUNIX
# else VMUNIX
# ifdef OLD_BSD_SIGS
# else
sigemptyset(&mask);
}
sigemptyset(&mask);
}
# endif
# endif VMUNIX
#ifdef SIGCONT
#endif
/*
* refrain from printing a newline after
* the headers (since some people mind).
*/
}
}
}
t = GMASK;
hdrs = 0;
if (hdrs)
t &= ~GNL;
}
}
goto err;
eof = 0;
}
hadintr = 0;
for (;;) {
# ifdef VMUNIX
# else
# ifndef OLD_BSD_SIGS
# endif
# endif
# ifdef VMUNIX
# else VMUNIX
# ifdef OLD_BSD_SIGS
# else
# endif
# endif VMUNIX
flush();
if (hdrs) {
hdrs = 0;
continue;
}
if (++eof > 35)
break;
"Use \".\" to terminate letter\n"));
continue;
}
break;
}
eof = 0;
hadintr = 0;
break;
/*
* If -t, scan text for headers.
*/
if (tflag) {
char *cp2;
if (!inhead) {
goto werr;
continue;
}
if (linebuf[0] == '\n') {
/* got blank line after header, ignore it */
inhead = 0;
continue;
}
/* got non-header line, save it */
inhead = 0;
goto writeit;
}
if (hasnulls)
for (;;) {
if (!isspace(c) || c == '\n')
break;
break;
cp2++)
;
(unsigned)LINESIZE-2)
break;
cp--;
*cp++ = ' ';
}
cp--;
*++cp = 0;
}
else
continue;
}
goto werr;
continue;
}
/*
* On double escape, just send the single one.
*/
goto werr;
continue;
}
if (hasnulls)
c = linebuf[1];
switch (c) {
default:
/*
* Otherwise, it's an error.
*/
break;
case 'a':
case 'A':
/*
* autograph; sign the letter.
*/
if (*cp)
if (*cp)
}
}
break;
case 'i':
/*
* insert string
*/
;
if (*cp)
if (*cp)
if (*cp)
}
}
break;
case '!':
/*
* Shell escape, send the balance of the
* line to sh -c.
*/
break;
case ':':
case '_':
/*
* Escape to command mode, but be nice!
*/
break;
case '.':
/*
* Simulate end of file on input.
*/
goto eofl;
case 'q':
case 'Q':
/*
* Force a quit of sending mail.
* Act like an interrupt happened.
*/
hadintr++;
exit(1);
/* NOTREACHED */
case 'x':
xhalt();
break; /* not reached */
case 'h':
/*
* Grab a bunch of headers.
*/
break;
}
break;
case 't':
/*
* Add to the To list.
*/
break;
case 's':
/*
* Set the Subject list.
*/
cp++;
break;
case 'c':
/*
* Add to the CC list.
*/
break;
case 'b':
/*
* Add stuff to blind carbon copies list.
*/
break;
case 'R':
receipt_flg = 1;
break;
case 'd':
/* FALLTHROUGH */
case '<':
case 'r': {
int ispip;
/*
* Invoke a file:
* Search for the file name,
* then open it and copy the contents to obuf.
*
* if name begins with '!', read from a command
*/
cp++;
if (*cp == '\0') {
break;
}
if (*cp=='!') {
/* take input from a command */
ispip = 1;
perror("");
break;
}
} else {
ispip = 0;
break;
break;
}
break;
}
}
flush();
if (t == '\n')
lc++;
if (ispip) {
} else
goto werr;
}
cc++;
}
if (ispip) {
} else
break;
}
case 'w':
/*
* Write the message on a file.
*/
cp++;
if (*cp == '\0') {
break;
}
break;
break;
case 'm':
case 'M':
case 'f':
case 'F':
/*
* Interpolate the named messages, if we
* are in receiving mail mode. Does the
* standard list processing garbage.
* If ~f or ~F is given, we don't shift over.
*/
if (!rcvmode) {
"No messages to send from!?!\n"));
break;
}
cp++;
goto werr;
break;
case '?':
break;
}
while (t != -1) {
putchar(t);
}
break;
case 'p': {
/*
* Print out the current state of the
* message without altering anything.
*/
int nlines;
extern void brokpipe(int);
goto ret0;
nlines =
/* 7 for hdr lines */
if (t == '\n')
if (--nlines <= 0)
break;
}
if (nlines <= 0) {
} else {
}
}
}
ret0:
}
break;
}
case '^':
case '|':
/*
* Pipe message through command.
* Collect output as new message.
*/
break;
case 'v':
case 'e':
/*
* Edit the current message.
* 'e' means to use EDITOR
* 'v' means to use VISUAL
*/
goto err;
break;
}
}
eofl:
}
resetsigs(0);
noreset = 0;
return(ibuf);
werr:
/*
* Write error occurred on tmp file, save partial
* message in dead.letter.
*/
char *deadletter;
} else
}
err:
resetsigs(0);
noreset = 0;
return(NULL);
}
static void
{
if (resethup)
#ifdef SIGCONT
# ifdef preSVr4
# else
{
}
# endif
#endif
}
/*
* Write a file ex-like.
*/
static int
{
return(-1);
}
if (pi) {
}
if (pi) {
}
return(0);
}
void
{
register int c;
cc++;
lc++;
perror("");
return;
}
}
if (addnl) {
lc++;
cc++;
}
perror("");
return;
}
}
/*
* 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.
*/
static FILE *
{
register int t;
void (*sigint)(int);
#ifdef SIGCONT
void (*sigcont)(int);
#endif
register char *edit;
int fd = -1;
goto out;
}
goto out;
}
goto out;
}
*edit == '\0')
/*
*/
perror("fork");
goto out;
}
if (pid == 0) {
char *Shell;
sigchild();
/*
* If execlp fails, "edit" might really be a complete
* shell command, not a simple pathname. Try using
* the shell to run it.
*/
_exit(1);
}
#ifdef SIGCONT
#endif
;
#ifdef SIGCONT
#endif
/*
* Now switch to new file.
*/
goto out;
}
/* save the old headers, in case they are accidentally deleted */
else
}
/* if we didn't see any headers, restore the original headers */
"(Deleted headers restored to original values)\n"));
}
goto out;
}
goto out;
}
}
out:
return(newo);
}
/*
* 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.
*/
static FILE *
{
int s;
void (*sigint)(int);
char *Shell;
int fd = -1;
return(obuf);
}
return(obuf);
}
perror("fork");
goto err;
}
if (pid == 0) {
/*
* stdin = current message.
* stdout = new message.
*/
sigchild();
close(0);
close(1);
for (s = 4; s < 15; s++)
close(s);
_exit(1);
}
;
goto err;
}
goto err;
}
/*
* Take new files.
*/
return(no);
err:
return(obuf);
}
static char *indentprefix; /* used instead of tab by tabputs */
/*
* Interpolate the named messages into the current
* message, preceding each line with a tab.
* 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.
*/
static int
{
return(0);
return(0);
return(0);
}
}
if (tolower(f) == 'm')
return(-1);
}
}
return(-1);
}
printf("\n");
return(0);
}
static int
{
if (indentprefix)
/* Don't create lines with only a tab on them */
else if (line[0] != '\n')
}
/*
* Print (continue) when continued after ^Z.
*/
#ifdef SIGCONT
static void
#ifdef __cplusplus
collcont(int)
#else
/* ARGSUSED */
collcont(int s)
#endif
{
}
#endif /* SIGCONT */
/*
* 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.
*/
static void
collrub(int s)
{
register char *deadletter;
# ifdef OLD_BSD_SIGS
if (s == SIGHUP)
# endif
hadintr++;
gettext("\n(Interrupt -- one more to kill letter)\n"));
# ifdef OLD_BSD_SIGS
sigrelse(s);
# endif
}
goto done;
goto done;
}
done:
resetsigs(1);
if (rcvmode) {
if (s == SIGHUP)
hangup(s);
else
stop(s);
}
else
exit(1);
}
/*
* Acknowledge an interrupt signal from the tty by typing an @
*/
static void
#ifdef __cplusplus
intack(int)
#else
/* ARGSUSED */
intack(int s)
#endif
{
puts("@");
}
/* Read line from stdin, noting any NULL characters.
Return the number of characters read. Note that the buffer
passed must be 1 larger than "size" for the trailing NUL byte.
*/
int
{
register int i, ch;
if ( ch == '\0' )
*hasnulls = 1;
}
line[i] = '\0';
return(i);
}
void
#ifdef __cplusplus
savedead(int)
#else
/* ARGSUSED */
savedead(int s)
#endif
{
exit(1);
/* NOTREACHED */
}
/*
* Add a list of addresses to the end of a header entry field.
*/
char *
{
}
return hf;
}
/*
* Add a string to the end of a header entry field.
*/
char *
{
if (*news == '\0')
return(hf);
*cp2++ = ' ';
;
while (*cp != '\0')
*cp2 = '\0';
return(linebuf);
}
static int
{
register int i;
if (!hf)
return(0);
i++;
return(i);
}
/*
* Add a non-standard header to the end of the non-standard headers.
*/
static char **
{
register char *linebuf;
else
return(ohf);
}
return(hf);
}
static void
{
while (*cp) {
if (*cp == '\\') {
switch (*(cp+1)) {
case 'n':
cp++;
break;
case 't':
cp++;
break;
default:
}
} else {
}
cp++;
}
}
static void
xhalt(void)
{
if (rcvmode)
stop(0);
exit(1);
/* NOTREACHED */
}
/*
* Strip the nulls from a buffer of length n
*/
static int
{
register int i, j;
for (i = 0; i < nread; i++)
if (linebuf[i] == '\0')
break;
for (j = i; j < nread; j++)
if (linebuf[j] != '\0')
linebuf[i] = '\0';
return(i);
}