/*
 * $Id: 5da2c727529e92fd46c31c61e324622840b71eff $
 *
 * This file is part of nsmtp.
 *
 * Copyright (c) 2007, 2008 Niklas Olmes <niklas@noxa.de>
 *                          http://www.nevm.de/nsmtp/
 *                          NEVM-RIPE
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License Version 2
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

/*
 * NOTE:  This is very minimalistic implementation
 *        of a sendmail(1) compatibility interface.
 *
 *        One should really abandon the use of this
 *        or use a sendmail-to-SMTP wrapper like ssmtp.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <time.h>
#include <unistd.h>

#include "smtp.h"
#include "spool.h"
#include "check.h"
#include "alloc.h"
#include "ntu.h"

#define WORK_SPACE	10*1024	/* 10KB */
#define S_BCC		"Bcc: "

static const char rcsid[] = "$Id: 5da2c727529e92fd46c31c61e324622840b71eff $";

static SMTP_CTX *ctx;

static void usage(const char *) __attribute__((noreturn));

static void
usage(const char *str)
{

	(void)fprintf(stderr, "usage:\tsendmail [ -f envelope-from ] [ -r envelope-from ]\n"
	                      "\t[-oi] [-i] [recipient1 .. recipientN]\n"
	                      "accepted, but ignored: -o7, -o8, -B, -bm\n\n");
	(void)fprintf(stderr, "Copyright (c) 2007, 2008 Niklas Olmes <niklas@noxa.de>\n"
			      "                         http://www.nevm.de/nsmtp/\n"
			      "                         NEVM-RIPE\n"
			      "Licensed under the GNU GPL Version 2.\n\n");
	(void)fprintf(stderr, "%s\n", str);
	destroy_smtp_ctx(ctx);
	exit(EXIT_FAILURE);
}

int
main(int argc, char *argv[])
{
	char buf[4], host[64], domain[64], fqhost[64];
	char *data;
	int i, e, r, eflag, dflag;
	size_t allocd, len;

	ntu_seed();
	ctx = init_smtp_ctx();

	ctx->rcpts = nsm_calloc(1, sizeof(char *));
	ctx->rcpts[0] = NULL;
	eflag = 0;
	dflag = 0;
	r = 0;

	if (argc > 1) {
		for (i = 1; i < argc; i++) {
			if (strncmp(argv[i], "-f", 2) == 0 || strncmp(argv[i], "-r", 2) == 0) {
				/* envelope from */
				if (*(argv[i]+2) != '\0')
					ctx->from = nsm_strdup(argv[i]+2);
				else if (i+1 >= argc)
					usage("f and r need a parameter");
				else
					ctx->from = nsm_strdup(argv[++i]);
#if 0
			} else if (strcmp(argv[i], "-t") == 0) {
				eflag = 1;
#endif
			} else if (strcmp(argv[i], "-i") == 0 || strcmp(argv[i], "-oi") == 0) {
				dflag = 1;
			} else if (strcmp(argv[i], "-o7") == 0 || strcmp(argv[i], "-o8") == 0) {
				/* ignore 7/8 bit flags */
			} else if (strncmp(argv[i], "-B", 2) == 0) {
				/* ignore -B and parameter */
				if (*(argv[i]+2) != '\0')
					;
				else if (i+1 >= argc)
					usage("B needs a parameter (though ignored)");
				else
					++i;
			} else if (strcmp(argv[i], "-bm") == 0) {
				/* ignore */
			} else if (*(argv[i]) != '-') {
				/* recipient */
				ctx->rcpts = nsm_realloc(ctx->rcpts, (r+2) * sizeof(char *));
				ctx->rcpts[r] = nsm_strdup(argv[i]);
				ctx->rcpts[++r] = NULL;
			} else
				usage("unknown parameter");
		}
	}

	/*
	 * Read all that data from stdin...
	 */
	len = 0;
	allocd = 16384;
	data = nsm_malloc(allocd);
	while (len < MAX_SIZE - WORK_SPACE - 1 && fread(buf, 1, 1, stdin) == 1) {
		data[len++] = *buf;

		if (!dflag && len > 2 && data[len-3] == '\n' && data[len-2] == '.' && data[len-1] == '\n')
			break;

		if (len >= allocd) {
			allocd += 32768;
			data = nsm_realloc(data, allocd);
		}
	}

	if (len >= MAX_SIZE - WORK_SPACE - 1) {
		nsm_free(data);
		(void)fprintf(stderr, "mail data is too large, (%lu) >= (%d) chars\n", (unsigned long)len, MAX_SIZE - WORK_SPACE - 1);
		goto error_out;
	}

	data[len] = '\0';

	/*
	 * XXX/TODO: Parse mail header, extract Cc, Bcc, To, add to recipients
	 */
	ctx->data = data;
	ctx->size = len;

	/*
	 * Check all recipients and envelope from
	 */
	if (ctx->from == NULL)
		usage("no envelope from");
	if (ctx->rcpts == NULL || ctx->rcpts[0] == NULL)
		usage("no recipients");

	if ((e = check_mailaddress(ctx->from, 1)) > 0) {
		(void)fprintf(stderr, "check_mailaddress() for envelope from=<%s> failed with code (%d)\n", ctx->from, e);
		goto error_out;
	}

	for (i = 0; ctx->rcpts[i] != NULL; i++)
		if ((e = check_mailaddress(ctx->rcpts[i], 1)) > 0) {
			(void)fprintf(stderr, "check_mailaddress() for recipient=<%s> #(%d) failed with code (%d)\n", ctx->rcpts[i], i, e);
			goto error_out;
		}

	/*
	 * Everything in order, spool
	 */
	if (gethostname(host, sizeof(host)-1) != 0)
		*host = '\0';
	host[sizeof(host)-1] = '\0';
	if (getdomainname(domain, sizeof(domain)-1) != 0)
		*domain = '\0';
	domain[sizeof(domain)-1] = '\0';

	if (strstr(host, ".") != NULL || *domain == '\0')
		(void)snprintf(fqhost, sizeof(fqhost), "%s", host);
	else
		(void)snprintf(fqhost, sizeof(fqhost), "%s.%s", host, domain);

	(void)nsm_asprintf(&ctx->conn_id, "%d.%d", time(NULL), random() % 1000000 + 1);
	ctx->lmid = make_mid(ctx);
	(void)nsm_asprintf(&ctx->recvdinfo, "by %s (nsmtp/sendmail, from userid %d)\n\tid %s", fqhost, getuid(), ctx->lmid);

	if (spool("incoming", ctx) != 0) {
		(void)fprintf(stderr, "unable to spool() mail\n");
		goto error_out;
	}

	destroy_smtp_ctx(ctx);

	return EXIT_SUCCESS;

error_out:
	destroy_smtp_ctx(ctx);

	return EXIT_FAILURE;
}
