diff options
| author | Sam Varshavchik | 2013-08-19 16:39:41 -0400 | 
|---|---|---|
| committer | Sam Varshavchik | 2013-08-25 14:43:51 -0400 | 
| commit | 9c45d9ad13fdf439d44d7443ae75da15ea0223ed (patch) | |
| tree | 7a81a04cb51efb078ee350859a64be2ebc6b8813 /rfc2045/reformime.c | |
| parent | a9520698b770168d1f33d6301463bb70a19655ec (diff) | |
| download | courier-libs-9c45d9ad13fdf439d44d7443ae75da15ea0223ed.tar.bz2 | |
Initial checkin
Imported from subversion report, converted to git. Updated all paths in
scripts and makefiles, reflecting the new directory hierarchy.
Diffstat (limited to 'rfc2045/reformime.c')
| -rw-r--r-- | rfc2045/reformime.c | 1228 | 
1 files changed, 1228 insertions, 0 deletions
| diff --git a/rfc2045/reformime.c b/rfc2045/reformime.c new file mode 100644 index 0000000..26396cb --- /dev/null +++ b/rfc2045/reformime.c @@ -0,0 +1,1228 @@ +/* +** Copyright 1998 - 2011 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	<langinfo.h> + +#if	HAVE_STRINGS_H +#include	<strings.h> +#endif + +#if	HAVE_LOCALE_H +#include	<locale.h> +#endif + +#include	<stdlib.h> +#include	<ctype.h> +#include	<pwd.h> +#include	<fcntl.h> +#include	<signal.h> +#include	"rfc2045.h" +#include	"rfc822/rfc822.h" +#include	"rfc822/rfc2047.h" +#include	"rfc2045charset.h" +#include	"unicode/unicode.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 + +extern int rfc2045_in_reformime; + +static const char *defchset; + + +void rfc2045_error(const char *errmsg) +{ +	fprintf(stderr, "reformime: %s\n", errmsg); +	exit(1); +} + +static void do_print_structure(struct rfc2045 *p, struct rfc2045id *id, void *ptr) +{ +	p=p; +	ptr=p; + +	while (id) +	{ +		printf("%d%c", id->idnum, id->next ? '.':'\n'); +		id=id->next; +	} +} + +static int decode_to_file(const char *p, size_t n, void *ptr) +{ +FILE	*fp=(FILE *)ptr; + +	while (n) +	{ +		--n; +		if (putc((int)(unsigned char)*p++, fp) == EOF) +		{ +			perror("write"); +			exit(1); +		} +	} +	return (0); +} + +void usage() +{ +	fprintf(stderr, "Usage: reformime [options]\n"); +	fprintf(stderr, "    -d - parse a delivery status notification.\n"); +	fprintf(stderr, "    -e - extract contents of MIME section.\n"); +	fprintf(stderr, "    -x - extract MIME section to a file.\n"); +	fprintf(stderr, "    -X - pipe MIME section to a program.\n"); +	fprintf(stderr, "    -i - show MIME info.\n"); +	fprintf(stderr, "    -s n.n.n.n[,n.n.n.n]* - specify MIME section(s).\n"); +	fprintf(stderr, "    -r - rewrite message, filling in missing MIME headers.\n"); +	fprintf(stderr, "    -r7 - also convert 8bit/raw encoding to quoted-printable, if possible.\n"); +	fprintf(stderr, "    -r8 - also convert quoted-printable encoding to 8bit, if possible.\n"); +	fprintf(stderr, "    -c charset - default charset for rewriting, -o, and -O.\n"); +	fprintf(stderr, "    -m [file] [file]... - create a MIME message digest.\n"); +	fprintf(stderr, "    -h \"header\" - decode RFC 2047-encoded header.\n"); +	fprintf(stderr, "    -o \"header\" - encode unstructured header using RFC 2047.\n"); +	fprintf(stderr, "    -O \"header\" - encode address list header using RFC 2047.\n"); + +	exit(1); +} + +static char *tempname(const char *tempdir) +{ +char	pidbuf[NUMBUFSIZE], timebuf[NUMBUFSIZE], hostnamebuf[256]; +static unsigned counter=0; +time_t	t; +char	*p; + +	libmail_str_pid_t(getpid(), pidbuf); +	time(&t); +	libmail_str_time_t(t, timebuf); +	hostnamebuf[sizeof(hostnamebuf)-1]=0; +	if (gethostname(hostnamebuf, sizeof(hostnamebuf))) +		hostnamebuf[0]=0; +	p=malloc(strlen(tempdir)+strlen(pidbuf)+strlen(timebuf)+ +		strlen(hostnamebuf)+100); +	if (!p)	return (0); +	sprintf(p, "%s/%s.%s-%u.%s", tempdir, timebuf, pidbuf, counter++, +		hostnamebuf); +	return (p); +} + +struct rfc2045 *read_message() +{ +char	buf[BUFSIZ]; +struct	rfc2045 *p=rfc2045_alloc_ac(); +FILE	*tempfp=0; +int	l; + +	if (fseek(stdin, 0L, SEEK_END) < 0 || +		fseek(stdin, 0L, SEEK_SET) < 0)	/* Pipe, save to temp file */ +	{ +		tempfp=tmpfile(); +	} + +	while ((l=fread(buf, 1, sizeof(buf), stdin)) > 0) +	{ + +		rfc2045_parse(p, buf, l); +		if (tempfp && fwrite(buf, l, 1, tempfp) != 1) +		{ +			perror("fwrite"); +			exit(1); +		} +	} +	rfc2045_parse_partial(p); + +	if (tempfp)	/* Replace stdin */ +	{ +		dup2(fileno(tempfp), 0); +		fclose(tempfp); +	} +	return (p); +} + +void print_structure(struct rfc2045 *p) +{ +	rfc2045_decode(p, &do_print_structure, 0); +} + +static void notfound(const char *p) +{ +	fprintf(stderr, "reformime: MIME section %s not found.\n", p); +	exit(1); +} + +static void do_print_info(struct rfc2045 *s) +{ +const char *content_type, *transfer_encoding, *charset; +off_t start, end, body; +char *content_name; +off_t nlines, nbodylines; +const char *p; + +char *disposition_name, *disposition_filename; + +	rfc2045_mimeinfo(s, &content_type, &transfer_encoding, &charset); +	rfc2045_mimepos(s, &start, &end, &body, &nlines, &nbodylines); + +	if (rfc2231_udecodeType(s, "name", NULL, &content_name) < 0) +	{ +		perror("malloc"); +		exit(1); +	} + +	printf("content-type: %s\n", content_type); +	if (*content_name) +	{ +		printf("content-name: %s\n", content_name); +	} +	free(content_name); + +	printf("content-transfer-encoding: %s\n", transfer_encoding); +	printf("charset: %s\n", charset); +	if (s->content_disposition && *s->content_disposition) +		printf("content-disposition: %s\n", s->content_disposition); + +	if ((rfc2231_udecodeDisposition(s, "name", NULL, &disposition_name) < 0 +	     && (disposition_name=strdup("")) == NULL) +	    || +	    (rfc2231_udecodeDisposition(s, "filename", NULL, +					&disposition_filename) < 0 +	     && (disposition_filename=strdup("")) == NULL)) +	{ +		perror("malloc"); +		exit(1); +	} + +	if (*disposition_name) +		printf("content-disposition-name: %s\n", disposition_name); + +	free(disposition_name); + +	if (*disposition_filename) +	{ +		printf("content-disposition-filename: %s\n", +		       disposition_filename); +	} +	free(disposition_filename); + +	if (*(p=rfc2045_content_id(s))) +		printf("content-id: <%s>\n", p); +	if (*(p=rfc2045_content_description(s))) +	{ +		char *s=rfc822_display_hdrvalue_tobuf("content-description", +						      p, +						      defchset, +						      NULL, +						      NULL); + +		if (!s) +		{ +			perror("rfc2047_decode_unicode"); +			exit(1); +		} +		printf("content-description: %s\n", s); +		free(s); +	} +	if (*(p=rfc2045_content_language(s))) +		printf("content-language: %s\n", p); +	if (*(p=rfc2045_content_md5(s))) +		printf("content-md5: %s\n", p); + +	printf("starting-pos: %lu\n", (unsigned long)start); +	printf("starting-pos-body: %lu\n", (unsigned long)body); +	printf("ending-pos: %lu\n", (unsigned long)end); +	printf("line-count: %lu\n", (unsigned long)nlines); +	printf("body-line-count: %lu\n", (unsigned long)nbodylines); +} + +static void do_print_info_multiple(struct rfc2045 *p, struct rfc2045id *id, +		void *ptr) +{ +	printf("section: "); +	do_print_structure(p, id, ptr); +	do_print_info(p); +	printf("\n"); +} + +void print_info(struct rfc2045 *p, const char *mimesection) +{ +struct	rfc2045 *s; + +	if (mimesection) +	{ +		s=rfc2045_find(p, mimesection); +		if (!s) +			notfound(mimesection); +		printf("section: %s\n", mimesection); +		do_print_info(s); +		return; +	} +	rfc2045_decode(p, &do_print_info_multiple, 0); +} + +static void do_print_section(struct rfc2045 *s, FILE *fp) +{ +off_t start, end, body; +off_t nlines; +off_t nbodylines; + +	rfc2045_mimepos(s, &start, &end, &body, &nlines, &nbodylines); + +	if (fseek(stdin, body, SEEK_SET) == -1) +	{ +		perror("fseek"); +		exit(1); +	} + +	rfc2045_cdecode_start(s, &decode_to_file, fp); +	while (body < end) +	{ +	char	buf[BUFSIZ]; +	size_t	n=sizeof(buf); + +		if ((off_t)n > end-body)	n=end-body; +		n=fread(buf, 1, n, stdin); +		if (n == 0) +		{ +			perror("fread"); +			exit(1); +		} +		rfc2045_cdecode(s, buf, n); +		body += n; +	} +	rfc2045_cdecode_end(s); +} + +void print_decode(struct rfc2045 *p, const char *mimesection) +{ +struct	rfc2045 *s; + +	if (!mimesection) +		usage(); + +	s=rfc2045_find(p, mimesection); +	if (!s) +		notfound(mimesection); + +	do_print_section(s, stdout); +} + +void rewrite(struct rfc2045 *p, int rwmode) +{ +	struct rfc2045src *src; + +	rfc2045_ac_check(p, rwmode); + +	src=rfc2045src_init_fd(fileno(stdin)); + +	if (src == NULL || rfc2045_rewrite(p, src, fileno(stdout), +		"reformime (" RFC2045PKG " " RFC2045VER ")")) +	{ +		perror("reformime"); +		exit(1); +	} +	rfc2045src_deinit(src); +} + +static char *get_suitable_filename(struct rfc2045 *r, const char *pfix, +	int ignore_filename) +{ +char *disposition_name; +char *disposition_filename; +char	*filename_buf; +char *content_name; +char	*p, *q; +char	*dyn_disp_name=0; + +const char *disposition_filename_s; + +	if (rfc2231_udecodeDisposition(r, "name", NULL, &disposition_name) < 0) +		disposition_name=NULL; + +	if (rfc2231_udecodeDisposition(r, "filename", NULL, +				       &disposition_filename) < 0) +		disposition_filename=NULL; + +	if (rfc2231_udecodeType(r, "name", NULL, +				&content_name) < 0) +		content_name=NULL; + +	disposition_filename_s=disposition_filename; + +	if (!disposition_filename_s || !*disposition_filename_s) +		disposition_filename_s=disposition_name; +	if (!disposition_filename_s || !*disposition_filename_s) +		disposition_filename_s=content_name; + +	filename_buf=strdup(disposition_filename_s ? disposition_filename_s:""); + +	if (!filename_buf) +	{ +		perror("strdup"); +		exit(1); +	} + +	if (content_name)		free(content_name); +	if (disposition_name)		free(disposition_name); +	if (disposition_filename)	free(disposition_filename); + +	if (strlen(filename_buf) > 32) +	{ +		p=filename_buf; +		q=filename_buf + strlen(filename_buf)-32; +		while ( (*p++ = *q++) != 0) +			; +	} + +	/* Strip leading/trailing spaces */ + +	p=filename_buf; +	while (*p && isspace((int)(unsigned char)*p)) +		++p; + +	q=filename_buf; +	while ((*q=*p) != 0) +	{ +		++p; +		++q; +	} + +	for (p=q=filename_buf; *p; p++) +		if (!isspace((int)(unsigned char)*p)) +			q=p+1; +	*q=0; + +	disposition_filename_s=filename_buf; + +	if (ignore_filename) +	{ +	char	numbuf[NUMBUFSIZE]; +	static size_t counter=0; +	const char *p=libmail_str_size_t(++counter, numbuf); + +		dyn_disp_name=malloc(strlen(disposition_filename_s) +			+ strlen(p)+2); +		if (!dyn_disp_name) +		{ +			perror("malloc"); +			exit(1); +		} +		disposition_filename_s=strcat(strcat(strcpy( +			dyn_disp_name, p), "-"), +			disposition_filename_s); +	} +	else if (!disposition_filename_s || !*disposition_filename_s) +	{ +		dyn_disp_name=tempname("."); +		disposition_filename_s=dyn_disp_name+2;	/* Skip over ./ */ +	} + +	p=malloc((pfix ? strlen(pfix):0)+strlen(disposition_filename_s)+1); +	if (!p) +	{ +		perror("malloc"); +		exit(1); +	} +	*p=0; +	if (pfix)	strcpy(p, pfix); +	q=p+strlen(p); +	for (strcpy(q, disposition_filename_s); *q; q++) +		if (!isalnum(*q) && *q != '.' && *q != '-') +			*q='_'; + +	if (dyn_disp_name)	free(dyn_disp_name); + +	if (!pfix) +	{ +        const char *content_type_s; +        const char *content_transfer_encoding_s; +        const char *charset_s; +	int c; +	static char filenamebuf[256]; +	char	*t; +	FILE	*tty; + +		if ((tty=fopen("/dev/tty", "r+")) == 0) +		{ +			perror("/dev/tty"); +			exit(1); +		} + +		rfc2045_mimeinfo(r, &content_type_s, +			&content_transfer_encoding_s, &charset_s); + +		fprintf (tty, "Extract %s? ", content_type_s); +		fflush(tty); +		c=getc(tty); +		if (c != '\n' && c != EOF) +		{ +		int	cc; + +			while ((cc=getc(tty)) != '\n' && cc != EOF) +				; +		} +		if (c != 'y' && c != 'Y') +		{ +			free(p); +			fclose(tty); +			free(filename_buf); +			return (0); +		} +		fprintf (tty, "Filename [%s]: ", p); +		if (fgets(filenamebuf, sizeof(filenamebuf)-1, tty) == NULL) +			filenamebuf[0]=0; + +		fclose(tty); +		t=strchr(filenamebuf, '\n'); +		if (t)	*t=0; +		else +		{ +			fprintf(stderr, "Filename too long.\n"); +			exit(1); +		} +		if (filenamebuf[0]) +		{ +			free(p); +			p=strdup(filenamebuf); +			if (!p) +			{ +				perror("malloc"); +				exit(1); +			} +		} +	} +	free(filename_buf); +	return (p); +} + +static void extract_file(struct rfc2045 *p, +	const char *filename, int argc, char **argv) +{ +char	*f; +FILE	*fp; +int	ignore=0; + +	for (;;) +	{ +	int	fd; + +		f=get_suitable_filename(p, filename, ignore); +		if (!f)	return; + +		fd=open(f, O_WRONLY|O_CREAT|O_EXCL, 0666); +		if (fd < 0) +		{ +			if (errno == EEXIST) +			{ +				printf("%s exists.\n", f); +				free(f); +				ignore=1; +				continue; +			} + +			perror(f); +			exit(1); +		} +		fp=fdopen(fd, "w"); +		if (!fp) +		{ +			perror("fdopen"); +			exit(1); +		} +		break; +	} + +	do_print_section(p, fp); +	if (fflush(fp) || ferror(fp)) +	{ +		perror("write"); +		exit(1); +	} +	fclose(fp); +	free(f); +} + +static void extract_pipe(struct rfc2045 *p, +	const char *filename, +	int argc, char **argv) +{ +char	*f=get_suitable_filename(p, "FILENAME=", 0); +int	pipefd[2]; +pid_t	pid, p2; +FILE	*fp; +int	waitstat; + +	if (argc == 0) +	{ +		fprintf(stderr, "reformime: Invalid -X option.\n"); +		exit(1); +	} + +	if (pipe(pipefd)) +	{ +		perror("pipe"); +		exit(1); +	} + +	if ((fp=fdopen(pipefd[1], "w")) == 0) +	{ +		perror("fdopen"); +		exit(1); +	} + +	while ((pid=fork()) == -1) +	{ +		sleep(2); +	} + +	if (pid == 0) +	{ +        const char *content_type_s; +        const char *content_transfer_encoding_s; +        const char *charset_s; + +		if (!f)	f="FILENAME=attachment.dat"; +		putenv(f); +		rfc2045_mimeinfo(p, &content_type_s, +			&content_transfer_encoding_s, &charset_s); +		f=malloc(strlen(content_type_s) +			+sizeof("CONTENT_TYPE=")); +		if (!f) +		{ +			perror("malloc"); +			exit(1); +		} +		strcat(strcpy(f, "CONTENT_TYPE="), content_type_s); +		putenv(f); +		dup2(pipefd[0], 0); +		close(pipefd[0]); +		close(pipefd[1]); +		execv(argv[0], argv); +		perror("exec"); +		_exit(1); +	} +	close(pipefd[0]); +	signal(SIGPIPE, SIG_IGN); +	do_print_section(p, fp); +	signal(SIGPIPE, SIG_DFL); +	fclose(fp); +	close(pipefd[1]); + +	while ((p2=wait(&waitstat)) != pid && p2 != -1) +		; +	free(f); + +	if ((p2 == pid) && WIFEXITED(waitstat)) +	{ +		if (WEXITSTATUS(waitstat) != 0) +		{ +			fprintf(stderr, "reformime: %s exited with status %d.\n", +				argv[0], WEXITSTATUS(waitstat)); +			exit(WEXITSTATUS(waitstat) + 20); +		} +	} +} + +static void extract_section(struct rfc2045 *top_rfcp, const char *mimesection, +	const char *extract_filename, int argc, char **argv, +	void	(*extract_func)(struct rfc2045 *, const char *, +		int, char **)) +{ +	if (mimesection) +	{ +		top_rfcp=rfc2045_find(top_rfcp, mimesection); +		if (!mimesection) +			notfound(mimesection); +		if (top_rfcp->firstpart) +		{ +			fprintf(stderr, "reformime: MIME section %s is a compound section.\n", mimesection); +			exit(1); +		} +		(*extract_func)(top_rfcp, extract_filename, argc, argv); +		return; +	} + +	/* Recursive */ + +	if (top_rfcp->firstpart) +	{ +		for (top_rfcp=top_rfcp->firstpart; top_rfcp; +			top_rfcp=top_rfcp->next) +			extract_section(top_rfcp, mimesection, +				extract_filename, argc, argv, extract_func); +		return; +	} + +	if (!top_rfcp->isdummy) +		(*extract_func)(top_rfcp, extract_filename, argc, argv); +} + +static void print_dsn_recip(char *addr, char *action) +{ +char *p, *q; + +	if (!action || !addr) +	{ +		if (action)	free(action); +		if (addr)	free(addr); +		return; +	} + +	for (p=action; *p; ++p) +		*p=tolower((int)(unsigned char)*p); + +	for (p=addr; *p && isspace((int)(unsigned char)*p); ++p) +		; + +	if (strncasecmp(p, "rfc822;", 7)) +	{ +		free(action); +		free(addr); +		return; +	} +	for (q=action; *q && isspace((int)(unsigned char)*q); ++q) +		; +	p += 7; +	while (*p && isspace((int)(unsigned char)*p)) +		++p; +	printf("%s %s\n", q, p); +	free(action); +	free(addr); +} + +static void dsn(struct rfc2045 *p, int do_orig) +{ +const char *content_type_s; +const char *content_transfer_encoding_s; +const char *charset_s; +off_t start_pos, end_pos, start_body; +off_t dummy; +const char *q; +char	buf[BUFSIZ]; +unsigned i; +int	ch; +char *recip; +char *action; +char *orecip; + +	rfc2045_mimeinfo(p, &content_type_s, &content_transfer_encoding_s, +		&charset_s); +	if (strcasecmp(content_type_s, "multipart/report") || +		(q=rfc2045_getattr(p->content_type_attr, "report-type")) == 0 || +		strcasecmp(q, "delivery-status") || +		!p->firstpart || !p->firstpart->next || +		!p->firstpart->next->next) +		_exit(1); +	p=p->firstpart->next->next; +	rfc2045_mimeinfo(p, &content_type_s, &content_transfer_encoding_s, +		&charset_s); +	rfc2045_mimepos(p, &start_pos, &end_pos, &start_body, &dummy, &dummy); +	if (strcasecmp(content_type_s, "message/delivery-status") || +		fseek(stdin, start_body, SEEK_SET) == -1) +		_exit(1); + +	i=0; +	recip=0; +	orecip=0; +	action=0; +	while (start_body < end_pos) +	{ +		if ((ch=getchar()) == EOF)	break; +		++start_body; +		if (i < sizeof(buf)-1) +			buf[i++]= ch; +		if (ch != '\n')	continue; +		ch=getchar(); +		if (ch != EOF)	ungetc(ch, stdin); +		if (ch != '\n' && isspace((int)(unsigned char)ch)) +			continue; +		buf[i-1]=0; +		if (buf[0] == 0) +		{ +			if (orecip) +			{ +				if (recip)	free(recip); +				recip=orecip; +				orecip=0; +			} +			print_dsn_recip(recip, action); +			recip=0; +			action=0; +		} +		if (strncasecmp(buf, "Final-Recipient:", 16) == 0 && +			recip == 0) +		{ +			recip=strdup(buf+16); +			if (!recip) +			{ +				perror("strdup"); +				exit(2); +			} +		} +		if (strncasecmp(buf, "Original-Recipient:", 19) == 0 && +			orecip == 0 && do_orig) +		{ +			orecip=strdup(buf+19); +			if (!orecip) +			{ +				perror("strdup"); +				exit(2); +			} +		} +		if (strncasecmp(buf, "Action:", 7) == 0 && action == 0) +		{ +			action=strdup(buf+7); +			if (!action) +			{ +				perror("strdup"); +				exit(2); +			} +		} +		i=0; +	} +	if (orecip) +	{ +		if (recip)	free(recip); +		recip=orecip; +		orecip=0; +	} +	print_dsn_recip(recip, action); +} + +static void mimedigest1(int, char **); +static char mimebuf[BUFSIZ]; + +static void mimedigest(int argc, char **argv) +{ +char	*p; +struct filelist { struct filelist *next; char *fn; } *first=0, *last=0; +unsigned pcnt=0; +char	**l; + +	if (argc > 0) +	{ +		mimedigest1(argc, argv); +		return; +	} + +	while (fgets(mimebuf, sizeof(mimebuf), stdin)) +	{ +	struct	filelist *q; + +		if ((p=strchr(mimebuf, '\n')) != 0)	*p=0; +		q=malloc(sizeof(struct filelist)); +		if (!q || !(q->fn=strdup(mimebuf))) +		{ +			perror("malloc"); +			exit(1); +		} + +		if (last)	last->next=q; +		else	first=q; +		last=q; +		q->next=0; +		++pcnt; +	} +	if (pcnt == 0)	return; + +	if ( (l=malloc(sizeof (char *) * pcnt)) == 0) +	{ +		perror("malloc"); +	} +	pcnt=0; + +	for (last=first; last; last=last->next) +		l[pcnt++]=last->fn; + +	mimedigest1(pcnt, l); +} + +static void mimedigest1(int argc, char **argv) +{ +time_t	t; +char	boundarybuf[200]; +unsigned boundarycnt=0; +int	i; +FILE	*fp; + +	time (&t); + +	/* Search for a suitable boundary */ + +	do +	{ +	int	l; + +		sprintf(boundarybuf, "reformime_%lu_%u", +			(unsigned long)t, ++boundarycnt); + +		l=strlen(boundarybuf); + +		for (i=0; i<argc; i++) +		{ +		int	err=0; + +			if ((fp=fopen(argv[i], "r")) == 0) +			{ +				perror(argv[i]); +				exit(1); +			} + +			while (fgets(mimebuf, sizeof(mimebuf), fp)) +			{ +				if (mimebuf[0] != '-' || mimebuf[1] != '-') +					continue; + +				if (strncasecmp(mimebuf+2, boundarybuf, l) == 0) +				{ +					err=1; +					break; +				} +			} +			fclose(fp); +			if (err)	break; +		} +	} while (i < argc); +		 +	printf("Mime-Version:1.0\n" +		"Content-Type: multipart/digest; boundary=\"%s\"\n\n%s", +			boundarybuf, RFC2045MIMEMSG); + +	for (i=0; i<argc; i++) +	{ +		if ((fp=fopen(argv[i], "r")) == 0) +		{ +			perror(argv[i]); +			exit(1); +		} + +		printf("\n--%s\nContent-Type: message/rfc822\n\n", +			boundarybuf); + +		while (fgets(mimebuf, sizeof(mimebuf), fp)) +			printf("%s", mimebuf); +		fclose(fp); +	} + +	printf("\n--%s--\n", boundarybuf); +} + +static void display_decoded_header(const char *ptr, size_t cnt, void *dummy) +{ +	if (cnt == 0) +		putchar('\n'); +	else +		fwrite(ptr, cnt, 1, stdout); +} + +static int doconvtoutf8_stdout(const char *ptr, size_t n, void *dummy) +{ +	if (fwrite(ptr, n, 1, stdout) != 1) +		return -1; + +	return 0; +} + +static int main2(const char *mimecharset, int argc, char **argv) +{ +int	argn; +char	optc; +char	*optarg; +char	*mimesection=0; +char	*section=0; +int	doinfo=0, dodecode=0, dorewrite=0, dodsn=0, domimedigest=0; +int	dodecodehdr=0, dodecodeaddrhdr=0, doencodemime=0, doencodemimehdr=0; + +char	*decode_header=""; +struct	rfc2045 *p; +int	rwmode=0; +int     convtoutf8=0; +int	dovalidate=0; +void	(*do_extract)(struct rfc2045 *, const char *, int, char **)=0; +const char *extract_filename=0; +int rc=0; + + +	rfc2045_in_reformime=1; + +	for (argn=1; argn<argc; ) +	{ +		if (argv[argn][0] != '-')	break; +		optarg=0; +		optc=argv[argn][1]; +		if (optc && argv[argn][2])	optarg=argv[argn]+2; +		++argn; +		switch	(optc)	{ +		case 'c': +			if (!optarg && argn < argc) +				optarg=argv[argn++]; +			if (optarg && *optarg) +			{ +				char *p=libmail_u_convert_tobuf("", +								optarg, +								libmail_u_ucs4_native, +								NULL); + +				if (!p) +				{ +					fprintf(stderr, "Unknown charset: %s\n", +						optarg); +					exit(1); +				} +				free(p); +				mimecharset=optarg; +			} +			break; + +		case 's': +			if (!optarg && argn < argc) +				optarg=argv[argn++]; +			if (optarg && *optarg)	section=strdup(optarg); +			break; +		case 'i': +			doinfo=1; +			break; +		case 'e': +			dodecode=1; +			break; +		case 'r': +			dorewrite=1; +			if (optarg && *optarg == '7') +				rwmode=RFC2045_RW_7BIT; +			if (optarg && *optarg == '8') +				rwmode=RFC2045_RW_8BIT; +			break; +		case 'm': +			domimedigest=1; +			break; +		case 'd': +			dodsn=1; +			break; +		case 'D': +			dodsn=2; +			break; +		case 'x': +			do_extract=extract_file; +			if (optarg) +				extract_filename=optarg; +			break; +		case 'X': +			do_extract=extract_pipe; +			break; +		case 'V': +			dovalidate=1; +			break; +		case 'h': +			if (!optarg && argn < argc) +				optarg=argv[argn++]; +			if (optarg) +			{ +				decode_header=optarg; +			} +			dodecodehdr=1; +			break; +		case 'H': +			if (!optarg && argn < argc) +				optarg=argv[argn++]; +			if (optarg) +			{ +				decode_header=optarg; +			} +			dodecodeaddrhdr=1; +			break; +		case 'o': +			if (!optarg && argn < argc) +				optarg=argv[argn++]; +			if (optarg) +			{ +				decode_header=optarg; +			} +			doencodemime=1; +			break; +		case 'O': +			if (!optarg && argn < argc) +				optarg=argv[argn++]; +			if (optarg) +			{ +				decode_header=optarg; +			} +			doencodemimehdr=1; +			break; +		case 'u': +			convtoutf8=1; +			break; +		default: +			usage(); +		} +	} + +	defchset=mimecharset; + +	rfc2045_setdefaultcharset(defchset); + +	if (domimedigest) +	{ +		mimedigest(argc-argn, argv+argn); +		return (0); +	} +	else if (dodecodehdr) +	{ +		if (rfc822_display_hdrvalue("Subject", +					    decode_header, +					    mimecharset, +					    display_decoded_header, +					    NULL, +					    NULL) < 0) +		{ +			perror("rfc822_display_hdrvalue"); +			return (1); +		} + +		printf("\n"); +		return (0); +	} +	else if (dodecodeaddrhdr) +	{ +		if (rfc822_display_hdrvalue("To", +					    decode_header, +					    mimecharset, +					    display_decoded_header, +					    NULL, +					    NULL) < 0) +		{ +			perror("rfc822_display_hdrvalue"); +			return (1); +		} + +		printf("\n"); +		return (0); +	} + +	if (doencodemime) +	{ +		char *s=rfc2047_encode_str(decode_header, mimecharset, +					   rfc2047_qp_allow_any); + +		if (s) +		{ +			printf("%s\n", s); +			free(s); +		} +		return (0); +	} +	if (doencodemimehdr) +	{ +		struct rfc822t *t=rfc822t_alloc_new(decode_header, NULL, NULL); +		struct rfc822a *a=t ? rfc822a_alloc(t):NULL; +		char *s; + +		if (a && (s=rfc2047_encode_header_addr(a, mimecharset)) != NULL) +		{ +			printf("%s\n", s); +			free(s); +		} + +		if (a) rfc822a_free(a); +		if (t) rfc822t_free(t); +		return (0); +	} + +	p=read_message(); + +	if (doinfo) +	{ +		mimesection = section ? strtok(section, ","):NULL; +		do { +			print_info(p, mimesection); +			if (do_extract) +				extract_section(p, mimesection, +						extract_filename, argc-argn, +						argv+argn, do_extract); +			if (mimesection) +				mimesection = strtok(NULL,","); +		} while (mimesection != NULL); +	} +	else if (dodecode) +	{ +		mimesection = strtok(section,","); +		do { +			print_decode(p, mimesection); +			mimesection = strtok(NULL,","); +		} while (mimesection != NULL); +	} +	else if (dorewrite) +		rewrite(p, rwmode); +	else if (dodsn) +		dsn(p, dodsn == 2); +	else if (do_extract) +	{ +		mimesection = strtok(section,","); +		do { +			extract_section(p, mimesection, extract_filename, +					argc-argn, argv+argn, do_extract); +			mimesection = strtok(NULL,","); +		} while (mimesection != NULL); +	} +	else if (dovalidate) +	{ +		rc=1; + +		if (p->rfcviolation & RFC2045_ERR2COMPLEX) +			printf("ERROR: MIME complexity.\n"); +		else if (p->rfcviolation & RFC2045_ERRBADBOUNDARY) +			printf("ERROR: Ambiguous  MIME boundary delimiters.\n"); +		else rc=0; + +	} +	else if (convtoutf8) +	{ +		struct rfc2045src *src; +		struct rfc2045_decodemsgtoutf8_cb cb; + +		memset(&cb, 0, sizeof(cb)); + +		cb.output_func=doconvtoutf8_stdout; +		cb.arg=NULL; + +		src=rfc2045src_init_fd(0); + +		if (src) +		{ +			rfc2045_decodemsgtoutf8(src, p, &cb); +			rfc2045src_deinit(src); +		} +	} +	else +		print_structure(p); +	rfc2045_free(p); +	exit(rc); +	return (rc); +} + +int main(int argc, char **argv) +{ +	int	rc; + +	rc=main2(unicode_default_chset(), argc, argv); +	return rc; +} | 
