diff options
Diffstat (limited to 'rfc2045/makemime.c')
| -rw-r--r-- | rfc2045/makemime.c | 1111 | 
1 files changed, 1111 insertions, 0 deletions
| diff --git a/rfc2045/makemime.c b/rfc2045/makemime.c new file mode 100644 index 0000000..e535556 --- /dev/null +++ b/rfc2045/makemime.c @@ -0,0 +1,1111 @@ +/* +** Copyright 2000-2010 Double Precision, Inc.  See COPYING for +** distribution information. +*/ + +#if	HAVE_CONFIG_H +#include "rfc2045_config.h" +#endif +#include	<sys/types.h> +#include	<sys/stat.h> +#include	<time.h> +#include	<stdio.h> +#include	<errno.h> +#include	<string.h> +#include	<signal.h> +#if	HAVE_STRINGS_H +#include	<strings.h> +#endif +#if	HAVE_UNISTD_H +#include	<unistd.h> +#endif +#include	<stdlib.h> +#include	<ctype.h> +#include	<pwd.h> +#include	<fcntl.h> +#include	<signal.h> +#include	"rfc822/encode.h" +#include	"rfc2045.h" +#include	"rfc2045charset.h" +#if HAVE_UNISTD_H +#include	<unistd.h> +#endif +#if HAVE_SYS_WAIT_H +#include	<sys/wait.h> +#endif +#include	"numlib/numlib.h" + +#if     HAS_GETHOSTNAME +#else +int gethostname(const char *, size_t); +#endif + + +struct arg_list { +	struct arg_list *next; +	char *arg; +	} ; + +/****************************************************************************** + +Check if a file is a regular file. + +******************************************************************************/ + +static int isreg(int fd) +{ +	struct stat st; +	if (fstat(fd, &st)) +	{ +		perror("fstat"); +		exit(1); +	} +	return S_ISREG(st.st_mode); +} + +/****************************************************************************** + +Determine the file descriptor wanted, if any. + +******************************************************************************/ + +static int fd_wanted(const char *filename, const char *mode) +{ +	if (strcmp(filename, "-") == 0)		/* stdin or stdout */ +		return strcmp(mode, "r") ? 1:0; +	if (*filename == '&') +		return atoi(filename+1);	/* file descriptor */ +	return -1;				/* or a file */ +} + +/****************************************************************************** + +Open some file or a pipe for reading and writing. + +******************************************************************************/ + +static FILE *openfile_or_pipe(const char *filename, const char *mode) +{ +int	fd, fd_to_dup = fd_wanted(filename, mode); +FILE	*fp; + +	if (fd_to_dup == 0) +		return stdin; + +	if (fd_to_dup >= 0) +		fd = dup(fd_to_dup); +	else +		fd=open(filename, (strcmp(mode, "r") ? +			O_WRONLY|O_CREAT|O_TRUNC:O_RDONLY), 0666); + +	if (fd < 0) +	{ +		perror(filename); +		exit(1); +	} +	fp=fdopen(fd, mode); +	if (!fp) +	{ +		perror("fdopen"); +		exit(1); +	} +	return (fp); +} + +/****************************************************************************** + +Open some file.  If we get a pipe, open a temporary file, and drain pipe's +contents into it. + +******************************************************************************/ + +static FILE *openfile(const char *filename) +{ +FILE	*fp=openfile_or_pipe(filename, "r"); +int	fd=fileno(fp); + +	if (!isreg(fd))	/* Must be a pipe */ +	{ +	FILE *t=tmpfile(); +	int	c; + +		if (!t) +		{ +			perror("tmpfile"); +			exit(1); +		} + +		while ((c=getc(fp)) != EOF) +			putc(c, t); +		if (ferror(fp) || fflush(t) +			|| ferror(t) || fseek(t, 0L, SEEK_SET) == -1) +		{ +			perror("write"); +			exit(1); +		} +		fclose(fp); +		fp=t; +	} +	else +	{ +	off_t	orig_pos = lseek(fd, 0L, SEEK_CUR); + +		if (orig_pos == -1 || +			fseek(fp, orig_pos, SEEK_SET) == -1) +		{ +			perror("fseek"); +			exit(1); +		} +	} +	return (fp); +} + +/****************************************************************************** + +Build argv/argc from a file. + +******************************************************************************/ + +static void read_args(int *argcp, char ***argvp, const char *file) +{ +FILE	*fp=openfile_or_pipe(file, "r"); +struct arg_list *argfirst=0, *arglast=0, *argp; +char	buffer[BUFSIZ]; +char	*p; +int	c; + +	*argcp=0; +	while (fgets(buffer, sizeof(buffer), fp) != 0) +	{ +	const	char *q; + +		if ((p=strchr(buffer, '\n')) != 0) +			*p=0; +		else while ((c=getc(fp)) != '\n' && c != EOF) +			;	/* Just dump the excess */ + +		/* Skip the filler. */ + +		q=buffer; +		while (*q && isspace((int)(unsigned char)*q)) +			++q; +		if (!*q)	continue; +		if (*q == '#')	continue; +		if (strcmp(buffer, "-") == 0) +		{ +			if (isreg(fileno(fp))) +			{ +				long orig_pos = ftell(fp); +				if (orig_pos == -1 || +					lseek(fileno(fp), orig_pos, SEEK_SET) == -1) +				{ +					perror("seek"); +					exit(1); +				} +			} +			break; +		} + +		argp=(struct arg_list *)malloc(sizeof(struct arg_list)+1+ +			strlen(q)); +		if (!argp) +		{ +			perror("malloc"); +			exit(1); +		} +		if (arglast) +			arglast->next=argp; +		else +			argfirst=argp; +		arglast=argp; +		++*argcp; +		argp->next=0; +		argp->arg=strcpy((char *)(argp+1), q); +	} + +	if ((*argvp=malloc(sizeof (char *) * (*argcp+1))) == 0) +	{ +		perror("malloc"); +		exit(1); +	} +	c=0; +	for (argp=argfirst; argp; argp=argp->next) +	{ +		(*argvp)[c]= argp->arg; +		++c; +	} +	(*argvp)[c]=0; +} + +static void usage() +{ +	fprintf(stderr, +"Usage:\n" +"  makemime -c type [-o file] [-e encoding] [-C charset] [-N name] \\\n" +"                   [-a \"Header: Contents\"] file\n" +"           -m [ type ] [-o file] [-e encoding] [-a \"Header: Contents\"] file\n" +"           -j [-o file] file1 file2\n" +"           @file\n" +"\n" +"   file:  filename    - read or write from filename\n" +"          -           - read or write from stdin or stdout\n" +"          &n          - read or write from file descriptor n\n" +"          \\( opts \\)  - read from child process, that generates [ opts ]\n" +		"\n"); + +	fprintf(stderr, +"Options:\n" +"\n" +"  -c type         - create a new MIME section from \"file\" with this\n" +"                    Content-Type: (default is application/octet-stream).\n" +"  -C charset      - MIME charset of a new text/plain section.\n" +		"  -N name         - MIME content name of the new mime section.\n"); + +	fprintf(stderr, +"  -m [ type ]     - create a multipart mime section from \"file\" of this\n" +"                    Content-Type: (default is multipart/mixed).\n" +"  -e encoding     - use the given encoding (7bit, 8bit, quoted-printable,\n" +"                    or base64), instead of guessing.  Omit \"-e\" and use\n" +"                    -c auto to set Content-Type: to text/plain or\n" +		"                    application/octet-stream based on picked encoding.\n"); + +	fprintf(stderr, +"  -j file1 file2  - join mime section file2 to multipart section file1.\n" +"  -o file         - write ther result to file, instead of stdout (not\n" +"                    allowed in child processes).\n" +"  -a header       - prepend an additional header to the output.\n" +"\n" +"  @file - read all of the above options from file, one option or\n" +"          value on each line.\n" +	); +	exit (0); +} + +/****************************************************************************** + +The arguments are parsed into the following structure, as a tree. + +******************************************************************************/ +struct mimestruct { + +	/* +	** One or two input files.  We initialize either file or child, +	** depending on the source being a file, or a child process. +	** Later, we open a file pointer in either case. +	*/ + +	const char *inputfile1, *inputfile2; +	struct mimestruct *inputchild1, *inputchild2; +	FILE *inputfp1, *inputfp2; +	pid_t	child1, child2; + +	/* Output file.  Defaults to "-", stdout */ + +	const char *outputfile; +	FILE	*outputfp; + +		/* The handler and open functions */ + +	void (*handler_func)(struct mimestruct *); +	void (*open_func)(struct mimestruct *); + +		/* The new mime type, and encoding (-e) */ +	const char *mimetype; +	const char *mimeencoding; +	const char *textplaincharset; +	const char *contentname; + +		/* A list of -a headers */ +	struct arg_list *a_first, *a_last; +	} ; + +static void createsimplemime(struct mimestruct *); +static void createmultipartmime(struct mimestruct *); +static void joinmultipart(struct mimestruct *); + +static void opencreatesimplemime(struct mimestruct *); +static void opencreatemultipartmime(struct mimestruct *); +static void openjoinmultipart(struct mimestruct *); + +/****************************************************************************** + +Recursively build the mimestruct tree. + +******************************************************************************/ + +struct mimestruct *parseargs(int *argcp, char ***argvp) +{ +struct mimestruct *m=malloc(sizeof(struct mimestruct)); +int argc= *argcp; +char **argv= *argvp; + +	if (!m) +	{ +		perror("malloc"); +		exit(1); +	} +	memset(m, 0, sizeof(*m)); + +	if (argc == 0 || argv[0][0] != '-')	usage(); + +	if (strncmp(argv[0], "-c", 2) == 0) +	{ +		m->handler_func= &createsimplemime; +		m->open_func= &opencreatesimplemime; +		if (argv[0][2]) +		{ +			m->mimetype=argv[0]+2; +			--argc; +			++argv; +		} +		else +		{ +			--argc; +			++argv; +			if (argc && argv[0][0] != '-' && argv[0][0] != ')') +			{ +				m->mimetype=argv[0]; +				--argc; +				++argv; +			} +			else +				m->mimetype="application/octet-stream"; +		} + +		while (isspace((int)(unsigned char)*m->mimetype)) +			++m->mimetype; +	} +	else if (strncmp(argv[0], "-m", 2) == 0) +	{ +		m->handler_func= &createmultipartmime; +		m->open_func= &opencreatemultipartmime; +		if (argv[0][2]) +		{ +			m->mimetype=argv[0]+2; +			--argc; +			++argv; +		} +		else +		{ +			--argc; +			++argv; +			if (argc && argv[0][0] != '-' && argv[0][0] != ')') +			{ +				m->mimetype=argv[0]; +				--argc; +				++argv; +			} +			else +				m->mimetype="multipart/mixed"; +		} +		while (isspace((int)(unsigned char)*m->mimetype)) +			++m->mimetype; +	} +	else if (strncmp(argv[0], "-j", 2) == 0) +	{ +	const char *filename; + +		m->handler_func= &joinmultipart; +		m->open_func= &openjoinmultipart; +		if (argv[0][2]) +		{ +			filename=argv[0]+2; +			--argc; +			++argv; +		} +		else +		{ +			--argc; +			++argv; +			if (argc == 0)	usage(); +			filename=argv[0]; +			--argc; +			++argv; +		} + +		while (isspace((int)(unsigned char)*filename)) +			++filename; + +		if (strcmp(filename, "(") == 0) +		{ +			m->inputchild2=parseargs(&argc, &argv); +			if (argc == 0 || strcmp(argv[0], ")")) +				usage(); +			--argc; +			++argv; +		} +		else +			m->inputfile2=filename; +	} +	else +		usage(); + +	/* Handle common options */ + +	while (argc) +	{ +		if (strncmp(argv[0], "-o", 2) == 0) +		{ +		const char *f=argv[0]+2; + +			++argv; +			--argc; +			if (*f == 0) +			{ +				if (!argc)	usage(); +				f=argv[0]; +				++argv; +				--argc; +			} +			while (isspace((int)(unsigned char)*f)) +				++f; +			m->outputfile=f; +			continue; +		} + +		if (strncmp(argv[0], "-C", 2) == 0) +		{ +			char *f=argv[0]+2; + +			++argv; +			--argc; + + +			if (*f == 0) +			{ +				if (!argc)	usage(); +				f=argv[0]; +				++argv; +				--argc; +			} +			while (isspace((int)(unsigned char)*f)) +				++f; +			m->textplaincharset=f; +			continue; +		} + +		if (strncmp(argv[0], "-N", 2) == 0) +		{ +			char *f=argv[0]+2; + +			++argv; +			--argc; + + +			if (*f == 0) +			{ +				if (!argc)	usage(); +				f=argv[0]; +				++argv; +				--argc; +			} +			while (isspace((int)(unsigned char)*f)) +				++f; +			m->contentname=f; +			continue; +		} + +		if (strncmp(argv[0], "-e", 2) == 0) +		{ +		char *f=argv[0]+2, *q; + +			++argv; +			--argc; + +			if (*f == 0) +			{ +				if (!argc)	usage(); +				f=argv[0]; +				++argv; +				--argc; +			} + +			for (q=f; *q; q++) +				*q=tolower((int)(unsigned char)*q); + +			while (isspace((int)(unsigned char)*f)) +				++f; + +			if (strcmp(f, "7bit") && strcmp(f, "8bit") && +				strcmp(f, "quoted-printable") && +				strcmp(f, "base64")) +				usage(); + +			m->mimeencoding=f; +			continue; +		} + +		if (strncmp(argv[0], "-a", 2) == 0) +		{ +		char *f=argv[0]+2; +		struct arg_list *a; + +			++argv; +			--argc; + +			if (*f == 0) +			{ +				if (!argc)	usage(); +				f=argv[0]; +				++argv; +				--argc; +			} + +			while (isspace((int)(unsigned char)*f)) +				++f; + +			a=malloc(sizeof(struct arg_list)); +			if (!a) +			{ +				perror("malloc"); +				exit(1); +			} +			if (m->a_last) +				m->a_last->next=a; +			else	m->a_first=a; +			m->a_last=a; +			a->arg=f; +			a->next=0; +			continue; +		} +		break; +	} + +	/* We must now have the input file argument */ + +	if (!argc)	usage(); + +	if (strcmp(argv[0], "(") == 0) +	{ +		--argc; +		++argv; +		m->inputchild1=parseargs(&argc, &argv); +		if (argc == 0 || strcmp(argv[0], ")")) +			usage(); +		--argc; +		++argv; +	} +	else +	{ +		m->inputfile1=argv[0]; +		--argc; +		++argv; +	} + +	*argcp=argc; +	*argvp=argv; +	return (m); +} + +/****************************************************************************** + +After we're done, terminate with a zero exit code if all child processes also +terminated with a zero exit code.  Otherwise, terminate with a non-zero exit +code thus propagating any child's non-zero exit code to parent. + +******************************************************************************/ + +static void goodexit(struct mimestruct *m, int exitcode) +{ +	if (m->outputfp && (fflush(m->outputfp) || ferror(m->outputfp))) +	{ +		perror("makemime"); +		exit(1); +	} + +	/* +	** Drain any leftover input, so that the child doesn't get +	** a SIGPIPE. +	*/ + +	while (m->inputfp1 && !feof(m->inputfp1) && !ferror(m->inputfp1)) +		getc(m->inputfp1); + +	while (m->inputfp2 && !feof(m->inputfp2) && !ferror(m->inputfp2)) +		getc(m->inputfp2); + +	if (m->inputfp1) +	{ +		if (ferror(m->inputfp1)) +		{ +			perror("makemime"); +			exitcode=1; +		} + +		fclose(m->inputfp1); +	} +	if (m->inputfp2) +	{ +		if (ferror(m->inputfp2)) +		{ +			perror("makemime"); +			exitcode=1; +		} + +		fclose(m->inputfp2); +	} + +	while (m->child1 > 0 && m->child2 > 0) +	{ +	int	waitstat; +	pid_t	p=wait(&waitstat); + +		if (p <= 0 && errno == ECHILD)	break; + +		if (p == m->child1) +			m->child1=0; +		else if (p == m->child2) +			m->child2=0; +		else	continue; +		if (waitstat)	exitcode=1; +	} +	exit(exitcode); +} + +int main(int argc, char **argv) +{ +struct	mimestruct *m; + +	signal(SIGCHLD, SIG_DFL); +	if (argc > 1 && argv[1][0] == '@') +		read_args(&argc, &argv, argv[1]+1); +	else if (argc > 1) +	{ +		--argc; +		++argv; +	} + +	m=parseargs(&argc, &argv); +	if (argc)	usage();	/* Some arguments left */ + +	(*m->open_func)(m); +	(*m->handler_func)(m); +	goodexit(m, 0); +	return (0); +} + +static int encode_outfp(const char *p, size_t n, void *vp) +{ +	if (fwrite(p, n, 1, *(FILE **)vp) != 1) +		return -1; +	return 0; +} + +static int do_printRfc2231Attr(const char *param, +			       const char *value, +			       void *voidArg) +{ +	fprintf( ((struct mimestruct *)voidArg)->outputfp, +		 ";\n  %s=%s", param, value); +	return 0; +} + +static void createsimplemime(struct mimestruct *m) +{ +struct	arg_list *a; +struct libmail_encode_info encode_info; +const char *orig_charset=m->textplaincharset; + +	/* Determine encoding by reading the file, as follows: +	** +	** Default to 7bit.  Use 8bit if high-ascii bytes found.  Use +	** quoted printable if lines more than 200 characters found. +	** Use base64 if a null byte is found. +	*/ + +	if (m->mimeencoding == 0) +	{ +		long	orig_pos=ftell(m->inputfp1); +		int	binaryflag; + +		if (orig_pos == -1) +		{ +			perror("ftell"); +			goodexit(m, 1); +		} + +		m->mimeencoding=libmail_encode_autodetect_fpoff(m->inputfp1, +								0, +								0, -1, +								&binaryflag); + +		if (ferror(m->inputfp1) +			|| fseek(m->inputfp1, orig_pos, SEEK_SET)<0) +		{ +			perror("fseek"); +			goodexit(m, 1); +		} + +		if (strcmp(m->mimetype, "auto") == 0) +			m->mimetype=binaryflag +				? (orig_charset=0, +				   "application/octet-stream"):"text/plain"; +	} + +	for (a=m->a_first; a; a=a->next) +		fprintf(m->outputfp, "%s\n", a->arg); + +	fprintf(m->outputfp, "Content-Type: %s", m->mimetype); +	if (orig_charset && *orig_charset) +	{ +		const char *c; + +		fprintf(m->outputfp, "; charset=\""); +		for (c=orig_charset; *c; c++) +		{ +			if (*c != '"' && *c != '\\') +				putc(*c, m->outputfp); +		} +		fprintf(m->outputfp, "\""); +	} + +	if (m->contentname && *m->contentname) +	{ +		const char *chset=m->textplaincharset ? m->textplaincharset +			: "iso-8859-1"; + +		rfc2231_attrCreate("name", m->contentname, chset, NULL, +				   do_printRfc2231Attr, m); +	} + +	fprintf(m->outputfp, "\nContent-Transfer-Encoding: %s\n\n", +		m->mimeencoding); + +	libmail_encode_start(&encode_info, m->mimeencoding, +			     &encode_outfp, +			     &m->outputfp); +	{ +		char input_buf[BUFSIZ]; +		int n; + +		while ((n=fread(input_buf, 1, sizeof(input_buf), +				m->inputfp1)) > 0) +		{ +			if ( libmail_encode(&encode_info, input_buf, n)) +				break; +		} + +		libmail_encode_end(&encode_info); +	} +} + +/****************************************************************************** + +Satisfy paranoia by making sure that the MIME boundary we picked does not +appear in the contents of the bounded section. + +******************************************************************************/ + +static int tryboundary(struct mimestruct *m, FILE *f, const char *bbuf) +{ +char	buf[BUFSIZ]; +char	*p; +int	l=strlen(bbuf); +int	c; +long	orig_pos=ftell(f); + +	if (orig_pos == -1) +	{ +		perror("ftell"); +		goodexit(m, 1); +	} + +	while ((p=fgets(buf, sizeof(buf), f)) != 0) +	{ +		if (p[0] == '-' && p[1] == '-' && +			strncmp(p+2, bbuf, l) == 0) +			break; + +		if ((p=strchr(buf, '\n')) != 0) +			*p=0; +		else while ((c=getc(f)) != EOF && c != '\n') +			; +	} + +	if (ferror(f) || fseek(f, orig_pos, SEEK_SET)<0) +	{ +		perror("fseek"); +		goodexit(m, 1); +	} + +	return (p ? 1:0); +} + +/****************************************************************************** + +Create a MIME boundary for some content. + +******************************************************************************/ + +static const char *mkboundary(struct mimestruct *m, FILE *f) +{ +pid_t	pid=getpid(); +time_t	t; +static unsigned n=0; +static char bbuf[NUMBUFSIZE*4]; +char	buf[NUMBUFSIZE]; + +	time(&t); + +	do +	{ +		strcpy(bbuf, "=_"); +		strcat(bbuf, libmail_str_size_t(++n, buf)); +		strcat(bbuf, "_"); +		strcat(bbuf, libmail_str_time_t(t, buf)); +		strcat(bbuf, "_"); +		strcat(bbuf, libmail_str_pid_t(pid, buf)); +	} while (tryboundary(m, f, bbuf)); +	return (bbuf); +} + +static void createmultipartmime(struct mimestruct *m) +{ +const char *b=mkboundary(m, m->inputfp1); +struct arg_list *a; +int	c; + +	if (m->mimeencoding == 0) +		m->mimeencoding="8bit"; + +	for (a=m->a_first; a; a=a->next) +		fprintf(m->outputfp, "%s\n", a->arg); +	fprintf(m->outputfp, "Content-Type: %s; boundary=\"%s\"\n" +			"Content-Transfer-Encoding: %s\n\n" +			RFC2045MIMEMSG +			"\n--%s\n", +		m->mimetype, b, +		m->mimeencoding, +		b); +	while ((c=getc(m->inputfp1)) != EOF) +		putc(c, m->outputfp); +	fprintf(m->outputfp, "\n--%s--\n", b); +} + +static void joinmultipart(struct mimestruct *m) +{ +const char *new_boundary; +char	*old_boundary=0; +int	old_boundary_len=0; +char	buffer[BUFSIZ]; +char	*p; +int	c; + +	do +	{ +		new_boundary=mkboundary(m, m->inputfp1); +	} while (tryboundary(m, m->inputfp2, new_boundary)); + +	/* Copy the header */ + +	for (;;) +	{ +		if (fgets(buffer, sizeof(buffer), m->inputfp2) == 0) +		{ +			buffer[0]=0; +			break; +		} + +		if (strcmp(buffer, "\r\n") == 0 || +		    buffer[0] == '\n' || strncmp(buffer, "--", 2) == 0) +			break; + +		if (strncasecmp(buffer, "content-type:", 13)) +		{ +			fprintf(m->outputfp, "%s", buffer); +			if ((p=strchr(buffer, '\n')) != 0)	continue; +			while ((c=getc(m->inputfp2)) != EOF && c != '\n') +				putc(c, m->outputfp); +			continue; +		} + +		if ((p=strchr(buffer, '\n')) == 0) +			while ((c=getc(m->inputfp2)) != EOF && c != '\n') +				; + +		p=strchr(buffer+13, ';'); +		if (p)	*p=0; +		fprintf(m->outputfp, "Content-Type:%s; boundary=\"%s\"\n", +			buffer+13, new_boundary); + +		for (;;) +		{ +			c=getc(m->inputfp2); +			if (c != EOF)	ungetc(c, m->inputfp2); +			if (c == '\n' || !isspace((int)(unsigned char)c)) +				break; +			while ((c=getc(m->inputfp2)) != EOF && c != '\n') +				; +		} +	} + +	do +	{ +		if (strncmp(buffer, "--", 2) == 0) +		{ +			if (old_boundary == 0) +			{ +				old_boundary=malloc(strlen(buffer)+1); +				if (!old_boundary) +				{ +					perror("malloc"); +					exit(1); +				} +				strcpy(old_boundary, buffer); +				if ((p=strchr(old_boundary, '\n')) != 0) +				{ +					if (p > old_boundary && p[-1] == '\r') +						--p; +					*p=0; +				} +				p=old_boundary+strlen(old_boundary); +				if (p >= old_boundary+4 && +					strcmp(p-2, "--") == 0) +					p[-2]=0; +				old_boundary_len=strlen(old_boundary); +			} + + +			if (strncasecmp(buffer, old_boundary, +				old_boundary_len) == 0) +			{ +				if ((p=strchr(buffer, '\n')) != 0) +					*p=0; +				else while ((c=getc(m->inputfp2)) != '\n' +					&& c != EOF) +					; + +				c=strlen(buffer); +				if (c > 0 && buffer[c-1] == '\r') +					buffer[--c]=0; + +				if (c >= 4 && strcmp(buffer+(c-2), "--") == 0) +					break; +				fprintf(m->outputfp, "--%s\n", +					new_boundary); +				continue; +			} +		} +		fprintf(m->outputfp, "%s", buffer); +		if ((p=strchr(buffer, '\n')) == 0) +			while ((c=getc(m->inputfp2)) != '\n' && c != EOF) +				; +	} while (fgets(buffer, sizeof(buffer), m->inputfp2) != 0); + +	fprintf(m->outputfp, "--%s\n", new_boundary); + +	while ((c=getc(m->inputfp1)) != EOF) +		putc(c, m->outputfp); + +	fprintf(m->outputfp, "\n--%s--\n", new_boundary); +	goodexit(m, 0); +} + +/****************************************************************************** + +Open input from a child process + +******************************************************************************/ + +static FILE *openchild(struct mimestruct *parent, struct mimestruct *child, +	pid_t	*pidptr, +	int usescratch) +{ +int	pipefd[2]; +char	buf[NUMBUFSIZE]; +char	buf2[NUMBUFSIZE+1]; +FILE	*fp; + +	if (pipe(pipefd) < 0) +	{ +		perror("pipe"); +		exit(1); +	} + +	*pidptr=fork(); + +	if (*pidptr < 0) +	{ +		perror("fork"); +		exit(1); +	} + +	if (*pidptr == 0) +	{ +		/* Duplicate pipe on stdout */ + +		close(pipefd[0]); +		dup2(pipefd[1], 1); +		close(pipefd[1]); + +		/* Close any input files opened by parent */ + +		if (parent->inputfp1)	fclose(parent->inputfp1); +		if (parent->inputfp2)	fclose(parent->inputfp2); + +		/* Open, then execute the child process */ + +		(*child->open_func)(child); +		(*child->handler_func)(child); +		goodexit(child, 0); +	} +	close(pipefd[1]); + +	/* +	** Open the pipe by calling openfile(), automatically creating +	** the scratch file, if necessary. +	*/ + +	buf[0]='&'; +	strcpy(buf+1, libmail_str_size_t(pipefd[0], buf2)); + +	fp= usescratch ? openfile(buf):openfile_or_pipe(buf, "r"); +	close(pipefd[0]);	/* fd was duped by openfile */ +	return (fp); +} + +static void openoutput(struct mimestruct *m) +{ +	if (!m->outputfile) +		m->outputfile="-"; + +	m->outputfp= openfile_or_pipe(m->outputfile, "w"); +} + +static void openjoinmultipart(struct mimestruct *m) +{ +	/* number two is the multipart section */ +	if (m->inputchild2) +		m->inputfp2=openchild(m, m->inputchild2, &m->child2, 1); +	else +		m->inputfp2=openfile(m->inputfile2); + + +	if (m->inputchild1) +		m->inputfp1=openchild(m, m->inputchild1, &m->child1, 1); +	else +		m->inputfp1=openfile(m->inputfile1); +	openoutput(m); +} + +static void opencreatesimplemime(struct mimestruct *m) +{ +	if (m->inputchild1) +		m->inputfp1=openchild(m, m->inputchild1, &m->child1, +			m->mimeencoding ? 0:1); +	else +		m->inputfp1= m->mimeencoding +			? openfile_or_pipe(m->inputfile1, "r") +			: openfile(m->inputfile1); +	openoutput(m); +} + +static void opencreatemultipartmime(struct mimestruct *m) +{ +	if (m->inputchild1) +		m->inputfp1=openchild(m, m->inputchild1, &m->child1, 1); +	else +		m->inputfp1=openfile_or_pipe(m->inputfile1, "r"); +	openoutput(m); +} + | 
