/*
 * Author: Giam Teck Choon <choon@choon.net>
 *
 * Version: 0.03
 *
 * Description: greetdelay is a program to introduce a small delay before an SMTP
 *              greeting. It also enforce RFC 2821's recommendation that SMTP
 *              clients not send any commands before receiving the greeting
 *              message.
 *
 *              If RELAYCLIENT is set in environment variable, greetdelay will be skipped.
 *              Set environment variable GREETDELAY to any numberic value greater than 0
 *              to enable greetdelay to wait for the set value before executing other program.
 *
 *              If SMTP clients send any commands during the greet delay period,
 *              "554 smtp protocol violation (#5.5.1)" will be responsed with
 *              "premature input on stdin" will be printed in stderr and exit with exit code 111.
 *
 * Disclaimer: Use this program at your own risk! I am not responsible for any damages caused.
 *             You have been warned!
 *
 * Compile: gcc -O -o greetdelay greetdelay.c
 * Usage:   tcpserver -R -h 0 smtp greetdelay qmail-smtpd
 *
 * Code references: http://linux.die.net/man/3/fd_set
 *                  greetdelay-0.03 by Matthew R. Dempsky (http://alkemio.org/software/greetdelay/index.html)
 *
 * ChangeLog:
 * 08 Sep 2009: Fix the description.
 * 03 Sep 2009: Release 0.02 to fix wait delay by checking stdin first.
 * 02 Sep 2009: Initial release 0.01.
 */

#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

int main(int argc, char *argv[]) {
	fd_set rfds;
	struct timeval tv;
	int retval, greetdelay;
	unsigned long pid;
	const char *ip;
	const char *tmp;

	if (argc < 2) {
		fputs("usage: greetdelay program [arguments]\n", stderr);
		return 111;
	}

	pid = (unsigned long)getpid();

	/* check for environment variable GREETDELAY */
	if (
	    (tmp = getenv("GREETDELAY")) == 0 ||
	    (greetdelay = strtoul(tmp, (char**)&tmp, 10)) == 0 ||
	    *tmp != 0
	)
		greetdelay = 0;

	/* get IP from environment variable TCPREMOTEIP */
	if (getenv("TCPREMOTEIP") != 0) {
		ip = getenv("TCPREMOTEIP");
	} else {
		ip = "";
	}

	/* If environment variable RELAYCLIENT is not set then we start greetdelay or otherwise bypass greetdelay totally */
	if (getenv("RELAYCLIENT") == 0 && greetdelay > 0) {
		/* Watch stdin (fd 0) to see when it has input. */
		FD_ZERO(&rfds);
		FD_SET(0, &rfds);
		/* Wait up to greetdelay seconds. */
		tv.tv_sec = greetdelay;
		tv.tv_usec = 0;
		retval = select(1, &rfds, NULL, NULL, &tv);
		/* Don't rely on the value of tv now! */
		/* FD_ISSET(0, &rfds) will be true. */
		if (retval && FD_ISSET(0, &rfds)) {
			fprintf(stderr,"greetdelay: %s pid %lu: premature input on stdin\n",ip,pid);
			printf("554 smtp protocol violation (#5.5.1)\r\n");
			return 111;
		}
		fprintf(stderr,"greetdelay: %s pid %lu: ok\n",ip,pid);
	}
	execvp(argv[1], argv+1);
	fprintf(stderr,"greetdelay: %s pid %lu: unable to run %s: %s\n",ip,pid,argv[1],strerror(errno));
	return 111;
}
