/*
 * Jsafecat - Store messages in maildir directories, skip empty ones.
 * (C)opyleft 2006-2008 by Frank DENIS (Jedi/Sector One).
 * Public domain.
 */

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

#define MINIMUM_SIZE 10

static int preline = 0;

void usage(void) {
    puts("\nUsage: jsafecat [--preline] <tmp dir> <new dir>\n");
    exit(EXIT_FAILURE);
}

char *get_filename(void)
{
    char hostname[256] = "hostname";
    char *filename;
    size_t sizeof_filename = PATH_MAX;
    struct timeval tp;
    
    if (gettimeofday(&tp, NULL) != 0) {
        return NULL;
    }
    if ((filename = malloc(sizeof_filename)) == NULL) {
        return NULL;
    }
    (void) gethostname(hostname, sizeof hostname);
    snprintf(filename, sizeof_filename, "%ld.M%ldP%lu.%s",
             tp.tv_sec, tp.tv_usec, (unsigned long) getpid(), hostname);
    
    return filename;
}

int cat_stdin_into_file(const char *file)
{
    FILE *fp;
    int c;
    const char *ev;
    size_t size = (size_t) 0U;
    
    if ((fp = fopen(file, "wb")) == NULL) {
        perror("fopen()");
        return -1;
    }
    if (preline != 0) {
        if ((ev = getenv("UFLINE")) != NULL) {
            fputs(ev, fp);
        }
        if ((ev = getenv("RPLINE")) != NULL) {
            fputs(ev, fp);
        }
        if ((ev = getenv("DTLINE")) != NULL) {
            fputs(ev, fp);
        }
    }
    while ((c = getchar()) != EOF) {
        fputc(c, fp);   
        size++;
    }
    if (fclose(fp) != 0) {
        perror("fclose()");
        return -1;
    }    
    if (size < MINIMUM_SIZE) {
        unlink(file);
        return 1;
    }
    return 0;
}

int main(int argc, char *argv[])
{
    const char *filename;
    char *tmp_filename, *new_filename;
    size_t sizeof_tmp_filename, sizeof_new_filename;
    const char *tmp_dir, *new_dir;
    size_t strlen_filename;
    int ret;
    
    if (argc < 3) {
        usage();
    } else if (argc == 4 && strcmp(argv[1], "--preline") == 0) {
        preline++;
        argv++;
    } else if (argc > 4) {
	usage();
    }
    if ((filename = get_filename()) == NULL) {
        perror("get_filename()");
        return 1;
    }
    tmp_dir = argv[1];
    new_dir = argv[2];
    strlen_filename = strlen(filename);
    sizeof_tmp_filename = strlen(tmp_dir) + 1U + strlen(filename) + 1U;
    sizeof_new_filename = strlen(new_dir) + 1U + strlen(filename) + 1U;    
    if ((tmp_filename = malloc(sizeof_tmp_filename)) == NULL ||
        (new_filename = malloc(sizeof_new_filename)) == NULL) {
        perror("malloc()");
        return 1;
    }
    snprintf(tmp_filename, sizeof_tmp_filename, "%s/%s", tmp_dir, filename);
    snprintf(new_filename, sizeof_new_filename, "%s/%s", new_dir, filename);
    ret = cat_stdin_into_file(tmp_filename);
    if (ret < 0) {
        perror("cat_stdin_into_file()");
        return 2;
    }
    if (ret > 0) {
        return 0;
    }
    if (rename(tmp_filename, new_filename) != 0) {
        perror("rename()");
        return 4;
    }
    return 0;
}
