#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <pwd.h>
#include <sys/types.h>
#include <sys/file.h>
#include <unistd.h>
#include <syslog.h>

#include "indexer.h"
#include "formatting.h"

void
html_error(int code, char *why)
{
    int err = errno;

    syslog(LOG_ERR, "%m");

    printf("HTTP/1.0 %03d %s\r\n", code, why);
    puts("content-type: text/html\r\n"
           "\r\n"
         "<HTML>\n"
	 "<HEAD><TITLE>Aaaaiieee!</TITLE></HEAD>\n"
	 "<BODY BGCOLOR=black>\n"
         "<CENTER><FONT COLOR=RED>OH, NO!<BR>");
    if (code == 503)
	puts(strerror(err));
    else
	puts(why);
    puts("</FONT></CENTER>\n"
         "</BODY></HTML>");
    exit(1);
}


struct passwd *user;
char *bbspath  = "";
char *bbsroot  = "";

int fillin      = 0;
int printenv    = 0;
int preview     = 0;
int help        = 0;
char *text      = 0;
char *script    = 0;
char *siteowner = 0;
char *name      = 0;
char *email     = 0;
char *website   = 0;
char *url       = 0;


static void
putbody(FILE *f)
{
    int rows;
    char *p;

    fputs("<DIV CLASS=\"postwindow\">\n", f);

    if (fillin) {
	fprintf(f, "<p>Please enter your name, email or website,\n");
	fprintf(f, "and some text.</p>\n");
    }

    fprintf(f, "<!-- preview = %d, |text| = %d -->\n", preview,
		    text ? strlen(text) : 0);

    if ( preview && text && (strlen(text) > 1) ) {
	fputs("<DIV CLASS=\"previewbox\">\n", f);
	format(f, text, FM_BLOCKED);
	fputs("</DIV>\n"
	      "<HR>\n", f);
	rows=10;
    }
    else {
	rows=24;
    }

    fprintf(f, "<FORM METHOD=POST ACTION=\"%s\">\n", script);
    fprintf(f, "<INPUT TYPE=HIDDEN NAME=url VALUE=\"%s\">\n", url);
    fprintf(f, "<DIV align=left CLASS=\"Name\">Name"
	       "<INPUT TYPE=TEXT NAME=\"name\" SIZE=40 MAXLENGTH=180"
	       " VALUE=\"%s\">\n", name ? name : "");
    if (fillin && !name)
	fprintf(f, " <font CLASS=alert>Please enter your name</font>\n");
    fprintf(f, "<br><DIV align=left CLASS=\"Email\">Email"
	       "<INPUT TYPE=TEXT NAME=\"email\" SIZE=40 MAXLENGTH=180"
	       " VALUE=\"%s\">\n", email ? email : "");
    if (fillin && !email)
	fprintf(f, " <font CLASS=alert>Please enter your email address</font>\n");
    fprintf(f, "<br><DIV align=left CLASS=\"URL\">Website "
	       "<INPUT TYPE=TEXT NAME=\"website\" SIZE=40 MAXLENGTH=180"
	       " VALUE=\"%s\">\n", website ? website : "");
    if (fillin && !email)
	fprintf(f, " <font CLASS=alert>Please enter your website</font>\n");

    if (fillin && !text)
	fprintf(f, "<br><p CLASS=alert>Please enter a message</p>\n");
    fprintf(f, "<br><DIV CLASS=\"inputbox\">\n"
	       "<FONT BGCOLOR=silver>\n"
	       "<TEXTAREA NAME=_text ROWS=%d COLS=80 WRAP=SOFT>\n",rows);

    if (text)
	for (p=text; *p; ++p)
	    if (*p == '&')
		fprintf(f, "&amp;");
	    else
		fputc(*p, f);
    
    fputs("</TEXTAREA></FONT></DIV>\n", f);

    fputs("<DIV ALIGN=LEFT CLASS=\"controls\">\n", f);

    if (preview)
	fprintf(f, "<INPUT TYPE=HIDDEN NAME=preview VALUE=Preview>\n");
    fprintf(f, "<INPUT TYPE=SUBMIT NAME=preview VALUE=Preview>\n"
	       "<INPUT TYPE=SUBMIT NAME=post VALUE=Post>\n"
	       "<INPUT TYPE=SUBMIT NAME=cancel VALUE=Cancel>\n");

    if (help)
	fprintf(f, "<INPUT TYPE=HIDDEN NAME=help VALUE=\"Show\">\n");
    fprintf(f, "<INPUT TYPE=SUBMIT NAME=help VALUE=\"%s\">\n",
		help ? "Hide Help" : "Show Help");

    fputs("</DIV>\n"
	  "</FORM>\n", f);

    if (help)
	fputs("<DIV CLASS=\"helpbox\" ALIGN=LEFT><HR>\n"
	      " *text* <b>boldfaces</b> text; \n"
	      " _text_ <i>italicizes</i> text; \n"
	      " a blank line starts a new paragraph\n"
	      "</DIV>", f);
}


int
comment(char *from, char *email, char *website, char *text, char *article)
{
    struct article *art;
    int len = strlen(article);
    char *base = strrchr(article, '/');
    FILE *out;
    time_t now;
    struct tm *tm, *today;
    int buildflags = PG_ARCHIVE;

    if ( (art = openart(article)) == 0) {
	syslog(LOG_ERR, "openart(%s): %m", article);
	return 0;
    }
    else if (art->comments_ok == 0) {
	syslog(LOG_INFO, "comment_ok is FALSE");
	freeart(art);
	return 0;
    }

    if ( (out = fopen(art->cmtfile, "a")) == 0) {
	syslog(LOG_ERR, "cannot open [%s]: %m", art->cmtfile);
	return 0;
    }
    flock(fileno(out), LOCK_EX);

    fprintf(out, "<DIV CLASS=\"comment\">\n");
    if (art->comments > 0)
	fputs(fmt.commentsep, out);
    format(out, text, FM_BLOCKED);
    fprintf(out, "</DIV>\n");
    fprintf(out, "<DIV CLASS=\"commentsig\">\n");

    if (email || website) {
	if (website) {
	    if (strncasecmp(website, "http://", 7) == 0)
		fprintf(out, "<a href=\"%s\">%s</a>\n", website, from);
	    else
		fprintf(out, "<a href=\"http://%s\">%s</a>\n", website, from);
	}
	else
	    fprintf(out, "<a href=\"mailto:%s\">%s</a>\n", email, from);
    }
    else
	fprintf(out, "%s ", from);

    time(&now);
    fputs(ctime(&now), out);
    fprintf(out, "</DIV>\n");
    fflush(out);

    art->comments++;

    tm = localtime( &(art->timeofday) );
    today = localtime( &now );

    if ( (tm->tm_year == today->tm_year) && (tm->tm_mon == today->tm_mon) )
	buildflags |= (PG_HOME|PG_POST);

    writectl(art);
    writehtml(art);

    generate(tm,bbspath,0,buildflags);

    flock(fileno(out), LOCK_UN);
    fclose(out);

    return 1;
}


static char *
xgetenv(char *e)
{
    char *p = getenv(e);


    if (p && strlen(p)) {
	while (isspace(*p) && *p)
	    ++p;
	return (*p) ? p : 0;
    }
    return 0;
}

main(int argc, char **argv, char **envp)
{
    FILE *theme;
    char *themfile;
    char *bbsdir = "/";
    register c;
    char *p;

    static char *item[] = { "WWW_text", "WWW_name", "WWW_email", "WWW_website",
                            "WWW_preview", "WWW_url", "WWW_help", 0 };

    openlog("comment", LOG_PID, LOG_NEWS);

    fillin = 0;
    opterr = 0;
    while ( (c = getopt(argc, argv, "d:eu:A:S:")) != EOF) {
	switch (c) {
	case 'S':
	    script = optarg;
	    break;
	case 'A':
	    siteowner = optarg;
	    break;
	case 'd':
	    bbsdir = optarg;
	    break;
	case 'u':
	    siteowner = optarg;
	    break; 
	case 'e':
	    printenv=1;
	    break;
	}
    }

    bbsroot = malloc(strlen(bbsdir)+2);
    strcpy(bbsroot, bbsdir);
    if (bbsroot[0] && bbsroot[strlen(bbsroot)-1] != '/')
	strcat(bbsroot, "/");

    stash("weblog",bbsroot);
    stash("_ROOT", bbsroot);

    if ( (bbsdir[0] == '/') && (bbsdir[1] == '~') ) {
	char *r = strchr(bbsdir+2, '/');

	siteowner = bbsdir+2;

	if (r) {
	    *r++ = 0;
	    bbsdir = r;
	}
	else
	    bbsdir = "";
    }

    if ( siteowner) {
	if ( (user = getpwnam(siteowner)) == 0 )
	    html_error(500, "User does not exist");

	if (user->pw_uid == 0 || user->pw_gid == 0)
	    html_error(500, "User cannot be root");

	bbspath = malloc(strlen(user->pw_dir) +
			 strlen(PATH_USERDIR) +
			 strlen(bbsdir) + 4);

	if (bbspath == 0)
	    html_error(503, "Out of memory!");

	if (setgid(user->pw_gid) || setuid(user->pw_uid))
	    html_error(503, "Privilege confusion");

	sprintf(bbspath, "%s/%s/%s", user->pw_dir, PATH_USERDIR, bbsdir);
    }
    else {
	bbspath = malloc(strlen(PATH_WWWDIR) + strlen(bbsdir) + 3);
	if (bbspath == 0)
	    html_error(503, "Out of memory!");

	sprintf(bbspath, "%s/%s", PATH_WWWDIR, bbsdir);
    }

    if (chdir(bbspath) != 0)
	html_error(503, bbspath);

    readconfig(bbspath);

    if (!script)
	script = getenv("SCRIPT_NAME");
    if (!script)
	script = "/bin/false";

    if ( siteowner == 0 && (siteowner = getenv("REMOTE_USER")) == 0)
	html_error(500, "I don't know who you are!");

    uncgi();

    text    = xgetenv("WWW_text");
    name    = xgetenv("WWW_name");
    email   = xgetenv("WWW_email");
    website = xgetenv("WWW_website");

    preview = getenv("WWW_preview") != 0;
    url     = getenv("WWW_url");
    if ( (p = getenv("WWW_help")) != 0 && strncasecmp(p, "Show", 4) == 0)
	help = 1;

    if (url == 0)
	html_error(500, "Nothing to comment to?");

    if (getenv("WWW_post")) {
	if (text && name && (email||website) ) {

	    if ( comment(name,email,website,text,url) ) {
		printf("HTTP/1.0 307 Ok\r\n"
		       "Location: %s%s\n"
		       "\n", bbsroot, url);
		exit(0);
	    }
	    syslog(LOG_ERR, "Oops#1");
	}
	else
	    fillin = 1;
	/* complain about missing items */
    }
    else if (getenv("WWW_cancel")) {
	printf("HTTP/1.0 307 Ok\n"
	       "Location: %s\n"
	       "\n", bbsroot);
	exit(0);
    }


    if ( (themfile = alloca(strlen(bbspath) + 20)) == 0 )
	html_error(503, "Out of memory!");

    printf("Content-Type: text/html; charset=iso-8859-1\r\n"
	   "Connection: close\r\n"
	   "Server: %s\r\n"
	   "Cache-Control: no-cache\r\n"
	   "\r\n", script);

    stash("_DOCUMENT", script);
    stash("_USER", siteowner);

    sprintf(themfile, "%s/post.theme", bbspath);
    process(themfile, putbody, 1, stdout);

    if (printenv) {
	int i;
	puts("<!-- WWW_vars:");
	for (i=0; item[i]; i++)
	    printf("%s=\"%s\"\n", item[i], getenv(item[i]));
	puts("  -->");
	puts("<!-- ENV:");
	for (i=0; envp[i]; i++)
	    puts(envp[i]);
	puts("  -->");
    }

    exit(0);
}