#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <time.h>
#include <string.h>

/* MailDir Delivery Agent -- David DeSimone <fox@rsn.hp.com> */

/*
 * This program delivers a single message into a maildir-format directory. 
 * This is a directory with three sub-directories named "tmp", "new", and
 * "cur".  For more information about this format and its advantages, see
 *
 *        http://www.qmail.org/qmail-manual-html/man5/maildir.html
 *
 * This program works best as a delivery agent call either directly from your
 * .forward file, or from your .procmailrc.
 *
 *   ~/.forward:
 *       |"/home/user/bin/maildir /home/user/Mail/incoming"
 *
 *   ~/.procmailrc:
 *       :0
 *       | /home/user/bin/maildir incoming
 *
 * In this case, the "incoming" directory must already exist, as must the new,
 * cur, and tmp directories underneath it.  They will not be created for you,
 * and the mail delivery will fail.
 *
 * This program takes great pains to not lose any mail.  If it runs into a
 * problem, it will return exit status 75, which is a signal to the calling
 * program that the operation has failed temporarily.  If the calling program
 * is sendmail (as in the .forward usage), that means the mail will sit in the
 * queue until it can be delivered on the next retry.  If the calling program
 * is procmail, my experience has been that the delivery rule will simply fail,
 * and the mail will be stored in your $DEFAULT mailbox.  I'm not sure how to
 * change this behavior of procmail.
 *
 * Hope this program is useful for somebody.  It has worked flawlessly for me. 
 * for several months now.  If you have any questions or enhancements, please
 * let me know about them.
 *                                                             -- Fox
 */

int  main( int argc, char **argv )
{
    pid_t  pid;
    char  hostname[64];
    int  count = 0;
    int  len;
    int  file;
    char  buffer[1024];
    char  filename[1024];

    if (argc != 2)
    {
	fputs("Usage:  maildir {maildir-path}\n", stderr);
	return (75);
    }

    alarm(24 * 3600);

    gethostname(hostname, 64);
    pid = getpid();

    if (chdir(argv[1]))
    {
	perror(argv[1]);
	return (75);
    }

    while (++count < 1000)
    {
	sprintf(filename, "tmp/%d.%d.%s", (int)time(NULL), pid, hostname);

	if ((file = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0600)) == -1)
	{
	    if (errno != EINTR && errno != EEXIST)
	    {
		perror(filename);
		return (75);
	    }
	}
	else
	{
	    break;
	}

	sleep(2);
    }

    if (file == -1)
    {
	fputs("Could not create a mail file\n", stderr);
	return (75);
    }

    while (fgets(buffer, 1024, stdin))  /* Strip From_ line, if present */
    {
	if (strncmp(buffer, "From ", 5))
	{
	    len = strlen(buffer);

	    if (write(file, buffer, len) != len)
	    {
		perror(filename);
		close(file);
		unlink(filename);
		return (75);
	    }

	    break;
	}
    }

    while (!feof (stdin))	/* Copy mail message */
    {
	while (len = fread(buffer, 1, 1024, stdin))
	{
	    if (write(file, buffer, len) != len)
	    {
		perror(filename);
		close(file);
		unlink(filename);
		return (75);
	    }
	}
    }

    if (close(file))
    {
	perror(filename);
	unlink(filename);
	return (75);
    }

    strcpy(buffer, filename);

    strncpy(buffer, "new", 3);

    if (rename(filename, buffer))
    {
	perror(buffer);
	unlink(filename);
	return (75);
    }

    return (0);
}
