/*
 * Copyright 1998-2002 Ben Smithurst <ben@smithurst.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * strip Received: (and other) headers from mail folders to save space.
 * used by ~/bin/rotatemail when archiving old mail.
 */

static const char rcsid[] =
	"$BCPS: src/mailutils/mail-strip.c,v 1.42 2003/01/19 19:18:25 ben Exp $";

#include "misc.h"

void usage(void);
int strip_file(FILE *, FILE *);
int strip_maildir(int, char *, FILE *);

int
main(int argc, char *argv[]) {
	if (getopt(argc, argv, "") != -1)
		usage();

	argv += optind;
	argc -= optind;

	signal(SIGTERM, signal_handler);
	signal(SIGINT, signal_handler);

	return (process(argv, strip_file, strip_maildir) ? 0 : 1);
}

int
strip_maildir(int reset, char *fn, FILE *in_fp) {
	FILE *out_fp;
	char *outfn;
	int e, ret;

	if ((outfn = strdup(fn)) == NULL)
		return (RET_ERROR);
	assert (strncmp(fn, "new/", 4) == 0 || strncmp(fn, "cur/", 4) == 0);
	memcpy(outfn, "tmp/", 4);

	if ((out_fp = fopen(outfn, "w")) == NULL) {
		e = errno;
		free(outfn);
		errno = e;
		return (RET_ERROR);
	}

	ret = strip_file(in_fp, out_fp);
	e = errno;

	if (ret == RET_CHANGE) {
		if (rename(outfn, fn) != 0) {
			ret = RET_ERROR;
			e = errno;
		} else
			ret = RET_NOCHANGE;
	}

	fclose(out_fp);
	free(outfn);
	errno = e;
	return (ret);
}

int
strip_file(FILE *fp, FILE *out) {
	int ignore, keep, header, retval, hdr_len;
	size_t len;
	char **pp, *line, *hdr_name;

	/*
	 * headers to keep. MUST be lowercase and MUST be sorted.
	 */
	char *keeplist[] = {
		"cc", "date", "from", "in-reply-to", "message-id",
		"mime-version", "references", "reply-to", "sender", "status",
		"subject", "to", "x-status", NULL
	};

	header = 1;
	ignore = 0;
	retval = RET_NOCHANGE;
	hdr_name = NULL;
	hdr_len = 0;

	while ((line = gl_getline(fp)) != NULL) {
		len = strlen(line);
		if (sig_count > 0) {
			warnx("strip_file: signal received, returning");
			free(hdr_name);
			return (RET_LOCALERROR);
		}

		chop(line, len);

		if (is_from(line, 1)) {
			header = 1;
			ignore = 0;
			fprintf(out, "%s\n", line);
			continue;
		}

		/* check for end of headers */
		if (*line == '\0') {
			header = 0;
			ignore = 0;
		}

		if (header && !isspace(*line)) {
			/*
			 * it's a new header (i.e., not a long one which
			 * has been folded). get the header name and
			 * deal with it later.
			 */
			char *colon;

			ignore = 0;
			colon = strchr(line, ':');
			if (colon == NULL) {
				/*
				 * probably not really headers. Originally,
				 * this would cause the program to abort,
				 * but some mailboxes do have lines
				 * starting with From_ which aren't the
				 * start of a new message.
				 */
				header = 0;
				fprintf(out, "%s\n", line);
				continue;
			} else {
				int i;

				/*
				 * If the already allocated space isn't
				 * large enough, free it and allocate
				 * space which is large enough.
				 */
				i = colon - line + 1;
				if (i > hdr_len) {
					free(hdr_name);
					hdr_name = malloc(i);
					if (hdr_name == NULL)
						return (RET_ERROR);
					hdr_len = i;
				}

				/* Do the actual copy. */
				i = 0;
				while (line + i < colon) {
					hdr_name[i] = tolower(line[i]);
					i++;
				}
				hdr_name[i] = '\0';
			}
		} else {
			/*
			 * it's either a subsequent line of a multiline
			 * header or it's in the body. print it,
			 * unless it's part of a header we're ignoring.
			 * (ignore === 0 in the body).
			 */
			if (!ignore)
				fprintf(out, "%s\n", line);
			continue;
		}

		/* check if it's a header we want to keep */
		keep = strncmp(hdr_name, "content-", 8) == 0;
		keep = keep || (strncmp(hdr_name, "x-spam-", 7) == 0);
		if (!keep) {
			int diff;
			for (pp = keeplist; *pp != NULL; pp++) {
				diff = strcmp(hdr_name, *pp);
				if (diff == 0) {
					/* header found in keeplist */
					keep = 1;
					break;
				} else if (diff < 0)
					/*
					 * header from list is greater
					 * than the header we're checking,
					 * so this header isn't in the list.
					 */
					break;
			}
		}

		if (keep)
			fprintf(out, "%s\n", line);
		else {
			ignore = 1;
			retval = RET_CHANGE;
		}
	}

	gl_destroy(fp);

	free(hdr_name);
	return (retval);
}

void
usage(void) {
	fprintf(stderr, "usage: mail-strip [file ...]\n");
	exit(EX_USAGE);
}


syntax highlighted by Code2HTML, v. 0.9.1