/*
** forw.c -- forward a message, or group of messages.
**
** This code is Copyright (c) 2002, by the authors of nmh.  See the
** COPYRIGHT file in the root directory of the nmh distribution for
** complete copyright information.
*/

#include <h/mh.h>
#include <fcntl.h>
#include <h/fmt_scan.h>
#include <h/tws.h>
#include <h/utils.h>
#include <unistd.h>
#include <locale.h>
#include <sysexits.h>

#define IFORMAT  "digest-issue-%s"
#define VFORMAT  "digest-volume-%s"

static struct swit switches[] = {
#define ANNOSW  0
	{ "annotate", 0 },
#define NANNOSW  1
	{ "noannotate", 2 },
#define EDITRSW  2
	{ "editor editor", 0 },
#define FORMSW  3
	{ "form formfile", 0 },
#define DGSTSW  4
	{ "digest list", 0 },
#define ISSUESW  5
	{ "issue number", 0 },
#define VOLUMSW  6
	{ "volume number", 0 },
#define WHATSW  7
	{ "whatnowproc program", 0 },
#define VERSIONSW  8
	{ "Version", 0 },
#define HELPSW  9
	{ "help", 0 },
#define BILDSW  10
	{ "build", 5 },  /* interface from mhe */
	{ NULL, 0 }
};

char *version=VERSION;

static char drft[BUFSIZ];
static struct msgs *mp = NULL;


/*
** static prototypes
*/
static void add_forw_hdr(char *);
static int build_form(char *, char *, int, int);


int
main(int argc, char **argv)
{
	int msgp = 0, anot = 0;
	int issue = 0, volume = 0;
	int in;
	int out, msgnum;
	char *cp, *cwd, *maildir;
	char *digest = NULL, *ed = NULL;
	char *folder = NULL;
	char *form = NULL, buf[BUFSIZ], value[10];
	char **argp, **arguments, *msgs[MAXARGS];
	char *fmtstr;
	int buildsw = 0;

	setlocale(LC_ALL, "");
	invo_name = mhbasename(argv[0]);

	/* read user profile/context */
	context_read();

	arguments = getarguments(invo_name, argc, argv, 1);
	argp = arguments;

	while ((cp = *argp++)) {
		if (*cp == '-') {
			switch (smatch(++cp, switches)) {
			case AMBIGSW:
				ambigsw(cp, switches);
				exit(EX_USAGE);
			case UNKWNSW:
				adios(EX_USAGE, NULL, "-%s unknown", cp);

			case HELPSW:
				snprintf(buf, sizeof(buf), "%s [+folder] [msgs] [switches]", invo_name);
				print_help(buf, switches, 1);
				exit(argc == 2 ? EX_OK : EX_USAGE);
			case VERSIONSW:
				print_version(invo_name);
				exit(argc == 2 ? EX_OK : EX_USAGE);

			case ANNOSW:
				anot++;
				continue;
			case NANNOSW:
				anot = 0;
				continue;

			case EDITRSW:
				if (!(ed = *argp++) || *ed == '-')
					adios(EX_USAGE, NULL, "missing argument to %s",
							argp[-2]);
				continue;

			case WHATSW:
				if (!(whatnowproc = *argp++) ||
						*whatnowproc == '-')
					adios(EX_USAGE, NULL, "missing argument to %s",
							argp[-2]);
				continue;

			case BILDSW:
				buildsw++;
				continue;

			case FORMSW:
				if (!(form = *argp++) || *form == '-')
					adios(EX_USAGE, NULL, "missing argument to %s",
							argp[-2]);
				continue;

			case DGSTSW:
				if (!(digest = *argp++) || *digest == '-')
					adios(EX_USAGE, NULL, "missing argument to %s",
							argp[-2]);
				continue;
			case ISSUESW:
				if (!(cp = *argp++) || *cp == '-')
					adios(EX_USAGE, NULL, "missing argument to %s",
							argp[-2]);
				if ((issue = atoi(cp)) < 1)
					adios(EX_USAGE, NULL, "bad argument %s %s",
							argp[-2], cp);
				continue;
			case VOLUMSW:
				if (!(cp = *argp++) || *cp == '-')
					adios(EX_USAGE, NULL, "missing argument to %s",
							argp[-2]);
				if ((volume = atoi(cp)) < 1)
					adios(EX_USAGE, NULL, "bad argument %s %s",
							argp[-2], cp);
				continue;
			}
		}
		if (*cp == '+' || *cp == '@') {
			if (folder)
				adios(EX_USAGE, NULL, "only one folder at a time!");
			else
				folder = mh_xstrdup(expandfol(cp));
		} else {
			msgs[msgp++] = cp;
		}
	}

	cwd = mh_xstrdup(pwd());
	strncpy(drft, buildsw ? toabsdir("draft") : m_draft(seq_beyond),
			sizeof(drft));
	/*
	** FIXME: (concerning MHE support (buildsw) only)
	** There's no check if the draft already exists. mmh has removed
	** this case by having the draft folder. I won't add code only to
	** handle this legacy issue for MHE. -- meillo@marmaro.de 2012-05
	*/

	/*
	** Forwarding a message.
	*/
	if (!msgp)
		msgs[msgp++] = seq_cur;
	if (!folder)
		folder = getcurfol();
	maildir = toabsdir(folder);

	if (chdir(maildir) == NOTOK)
		adios(EX_OSERR, maildir, "unable to change directory to");

	/* read folder and create message structure */
	if (!(mp = folder_read(folder)))
		adios(EX_IOERR, NULL, "unable to read folder %s", folder);

	/* check for empty folder */
	if (mp->nummsg == 0)
		adios(EX_DATAERR, NULL, "no messages in %s", folder);

	/* parse all the message ranges/sequences and set SELECTED */
	for (msgnum = 0; msgnum < msgp; msgnum++) {
		if (!m_convert(mp, msgs[msgnum])) {
			exit(EX_SOFTWARE);
		}
	}
	seq_setprev(mp);  /* set the previous sequence */

	if ((out = creat(drft, m_gmprot())) == NOTOK)
		adios(EX_CANTCREAT, drft, "unable to create");

	/* Open form (component) file. */
	if (digest) {
		if (issue == 0) {
			snprintf(buf, sizeof(buf), IFORMAT, digest);
			if (volume == 0 && (cp = context_find(buf))
					&& ((issue = atoi(cp)) < 0))
				issue = 0;
			issue++;
		}
		if (volume == 0) {
			snprintf(buf, sizeof(buf), VFORMAT, digest);
			if ((cp = context_find(buf)) == NULL ||
					(volume = atoi(cp)) <= 0)
				volume = 1;
		}
		if (!form)
			form = digestcomps;
		in = build_form(form, digest, volume, issue);
		cpydata(in, out, form, drft);
		close(in);
	} else {
		fmtstr = new_fs(form, forwcomps);
		if (write(out, fmtstr, strlen(fmtstr)) != (int)strlen(fmtstr)) {
			adios(EX_IOERR, drft, "error writing");
		}
	}
	close(out);

	add_forw_hdr(drft);

	if (digest) {
		snprintf(buf, sizeof(buf), IFORMAT, digest);
		snprintf(value, sizeof(value), "%d", issue);
		context_replace(buf, mh_xstrdup(value));
		snprintf(buf, sizeof(buf), VFORMAT, digest);
		snprintf(value, sizeof(value), "%d", volume);
		context_replace(buf, mh_xstrdup(value));
	}

	context_replace(curfolder, folder); /* update current folder */
	seq_setcur(mp, mp->lowsel);  /* update current message */
	seq_save(mp);  /* synchronize sequences */
	context_save();  /* save the context file */

	if (buildsw)
		exit(EX_OK);
	what_now(ed, NOUSE, drft, NULL, 0, mp,
		anot ? "Forwarded" : NULL, cwd);
	return EX_OSERR;
}


/*
** Create an attachment header for the to be forward messages.
*/
static void
add_forw_hdr(char *draft)
{
	int msgnum;
	char buf[BUFSIZ];
	char *vec[MAXARGS];
	int vecp = 0;

	vec[vecp++] = "anno";
	vec[vecp++] = "-append";
	vec[vecp++] = "-nodate";
	vec[vecp++] = draft;
	vec[vecp++] = "-comp";
	vec[vecp++] = attach_hdr;
	vec[vecp++] = "-text";
	snprintf(buf, sizeof buf, "+%s", mp->foldpath);
	for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
		if (!is_selected(mp, msgnum)) {
			continue;
		}
		if (strlen(buf) + 1 + strlen(m_name(msgnum)) + 1
				> sizeof buf) {
			adios(EX_DATAERR, NULL, "Attachment header line too long. "
					"Forward less messages.");
		}
		strcat(buf, " ");
		strcat(buf, m_name(msgnum));
	}
	vec[vecp++] = buf;
	vec[vecp] = NULL;
	if (execprog(*vec, vec) != 0) {
		advise(NULL, "unable to add attachment header");
	}
}


static int
build_form(char *form, char *digest, int volume, int issue)
{
	int in;
	int fmtsize;
	char *fmtstr;
	char *line, tmpfil[BUFSIZ];
	FILE *tmp;
	struct comp *cptr;
	struct format *fmt;
	int dat[5];
	char *cp = NULL;

	/* Get new format string */
	fmtstr = new_fs(form, NULL);
	fmtsize = strlen(fmtstr) + 256;

	/* Compile format string */
	fmt_compile(fmtstr, &fmt);

	FINDCOMP(cptr, "digest");
	if (cptr)
		cptr->c_text = digest;
	FINDCOMP(cptr, "date");
	if (cptr)
		cptr->c_text = mh_xstrdup(dtimenow());

	dat[0] = issue;
	dat[1] = volume;
	dat[2] = 0;
	dat[3] = fmtsize;
	dat[4] = 0;

	cp = m_mktemp2(NULL, invo_name, NULL, &tmp);
	if (cp == NULL) {
		adios(EX_CANTCREAT, "forw", "unable to create temporary file");
	}
	strncpy(tmpfil, cp, sizeof(tmpfil));
	unlink(tmpfil);
	if ((in = dup(fileno(tmp))) == NOTOK)
		adios(EX_OSERR, "dup", "unable to");

	line = mh_xcalloc(fmtsize, sizeof(char));
	fmt_scan(fmt, line, fmtsize, dat);
	fputs(line, tmp);
	mh_free0(&line);
	if (fclose(tmp))
		adios(EX_IOERR, tmpfil, "error writing");

	lseek(in, (off_t) 0, SEEK_SET);
	return in;
}
