/*
 * 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.
 */

/*
 * Splits a mbox into its individual messages.
 */

#include "misc.h"

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

int split_maildir(int, char *, FILE *);
int split_file(FILE *, FILE *);
void usage(void);

char *prefix, *suffix;
int fflag;

int
main(int argc, char *argv[]) {
	int ch;

	/* defaults */
	prefix = "%n-";
	suffix = "";
	fflag = 0;

	while ((ch = getopt(argc, argv, "fp:s:")) != -1)
		switch (ch) {
		case 'f':
			fflag = 1;
			break;
		case 'p':
			prefix = optarg;
			break;
		case 's':
			suffix = optarg;
			break;
		default:
			usage();
			/* NOTREACHED */
		}

	argc -= optind;
	argv += optind;

	return (process(argv, split_file, split_maildir) ? 0 : 1);
}

int
split_maildir(int reset, char *fn, FILE *in_fp) {

	if (reset)
		warnx("useless on Maildir %s", curfile);

	return (RET_NOCHANGE);
}

/*
 * Expands the given prefix, number and suffix into `buf', which has
 * room for `size' characters including NUL. %N in prefix or suffix
 * expands to the value of `curfile', %n to the last part of `curfile'
 * (i.e. from the character after the last slash onwards, or the entire
 * string if it doesn't contain any slashes.)
 */
int
fn_expand(char *buf, int size, char *prefix, char *suffix, int num) {
	char numbuf[32];
	char *b, *p;
	int len, i;
	int plen, slen, nlen, nblen, numlen;

	snprintf(numbuf, sizeof numbuf, "%06d", num);
	numlen = strlen(numbuf);

	plen = strlen(prefix);
	slen = strlen(suffix);
	nlen = strlen(curfile);
	if ((b = strrchr(curfile, '/')) == NULL) {
		b = curfile;
		nblen = nlen;
	} else {
		b++;
		nblen = strlen(b);
	}

	/* Do the expansion */
	len = 0;
	for (i = 0; i < 3; i++) {
		/* Second time through the loop, just copy the number */
		if (i == 1) {
			if (len + numlen >= size)
				return (0);

			strcpy(buf + len, numbuf);
			len += numlen;
			continue;
		}

		/*
		 * First time through (i == 0), process the prefix, otherwise
		 * (must be third time) process suffix.
		 */
		for (p = (i ? suffix : prefix); *p != '\0'; p++)
			switch (*p) {
			case '%':
				switch (*++p) {
				case 'n':
					if (len + nblen >= size)
						return (0);
					strcpy(buf + len, b);
					len += nblen;
					break;
				case 'N':
					if (len + nlen >= size)
						return (0);
					strcpy(buf + len, curfile);
					len += nlen;
					break;
				case '\0':
					p--; /* So that for() loop sees \0 */
					/* FALLTHROUGH */
				case '%':
					if (len + 1 >= size)
						return (0);
					buf[len++] = '%';
					break;
				default:
					if (len + 2 >= size)
						return (0);
					buf[len++] = '%';
					buf[len++] = *p;
					break;
				}
				break;
			default:
				if (len + numlen >= size)
					return (0);
				buf[len++] = *p;
				break;
			}
	}
	buf[len] = '\0';

	return (1);
}

int
split_file(FILE *in, FILE *junk) {
	FILE *out;
	char *line, filename[MAXPATHLEN];
	int e, fd, from_line, num;
	size_t len;
	mode_t mask;

	/* Set a restrictive umask since files containing mail are created */
	mask = umask(077);

	num = 0;
	from_line = 0;
	out = NULL;

	while ((line = gl_getline(in)) != NULL) {
		len = strlen(line);
		chop(line, len);

		if (is_from(line, 1)) {
			num++;
			from_line = 1;
			if (out) {
				fclose(out);
				out = NULL;
			}

			/*
			 * build the new filename, increase num until
			 * a unique name is found.
			 */
			for (;;) {
				/* Do expansion */
				if (!fn_expand(filename, sizeof filename,
				  prefix, suffix, num))
				{
					warnx("fn_expand failed");
					umask(mask);
					return (RET_LOCALERROR);
				}

				/* Attempt to create file */
				fd = open(filename, O_WRONLY|O_CREAT|O_EXCL,
				  0600);
				if (fd >= 0)
					break;

				/* EEXIST is ok, anything else isn't. */
				if (errno != EEXIST) {
					e = errno;
					umask(mask);
					errno = e;
					return (RET_ERROR);
				}

				/* Protect against overflow. */
				if (num == INT_MAX) {
					warnx("couldn't get unique name");
					umask(mask);
					return (RET_LOCALERROR);
				}

				num++;
			}

			if ((out = fdopen(fd, "w")) == NULL) {
				e = errno;
				umask(mask);
				errno = e;
				return (RET_ERROR);
			}
		} else
			from_line = 0;

		if (out && (fflag || !from_line))
			fprintf(out, "%s\n", line);
	}

	gl_destroy(in);

	if (out != NULL)
		fclose(out);

	umask(mask);
	return (RET_NOCHANGE);
}

void
usage(void) {
	fprintf(stderr, "usage: mail-split [-f] [-p prefix] [-s suffix]\n"
			"       [files ...]\n");
	exit(EX_USAGE);
}


syntax highlighted by Code2HTML, v. 0.9.1