#include "httpd.h" 
#include "http_config.h" 
#include "http_request.h" 
#include "http_protocol.h" 
#include "http_core.h" 
#include "http_main.h"
#include "http_log.h" 

/*
 * C version of chapter 4's Apache::NavBar
 */

/*
 * configure like so:
 * <Location /random/picture>
 * PictureDir /banners
 * SetHandler randpicture
 * </Location>
 */

module MODULE_VAR_EXPORT randpicture_module;

typedef struct {
    char *picture_dir;
} randpicture_dir_config;

static void *randpicture_create_dir_config(pool *p, char *path) 
{ 
    randpicture_dir_config *dcfg =  
        (randpicture_dir_config *)ap_pcalloc(p, sizeof(*dcfg)); 

    dcfg->picture_dir = NULL;

    return (void *)dcfg; 
} 

static const char *randpicture_dir_cmd(cmd_parms *parms, void *mconfig, const char *arg) 
{
    randpicture_dir_config *dcfg = (randpicture_dir_config *)mconfig;

    /* ensure trailing `/' so subrequest lookups can resolve relative paths */
    if (arg[strlen(arg) - 1] != '/') {
	dcfg->picture_dir = ap_pstrcat(parms->pool, arg, "/", NULL);
    }
    else {
	dcfg->picture_dir = ap_pstrdup(parms->pool, arg);
    }

    return NULL;
}

/* call srand() once per-child during child_init() */
static void randpicture_init(server_rec *s, pool *p)
{
    srand((unsigned)(getpid()));
}

/* borrowed from mod_rewrite */
static int randpicture_rand(int l, int h) 
{ 
    int i; 
    char buf[50]; 
 
    ap_snprintf(buf, sizeof(buf), "%.0f",  
                (((double)(rand()%RAND_MAX)/RAND_MAX)*(h-l))); 
    i = atoi(buf)+1; 
    if (i < l) i = l; 
    if (i > h) i = h; 
    return i; 
} 

/* invoke a subrequest to send the image file */
static int randpicture_send(request_rec *r, char *uri)
{
    request_rec *rr = ap_sub_req_lookup_uri(uri, r);
    int rc = OK;

    if (rr->status != HTTP_OK) {
	rc = rr->status;
	ap_destroy_sub_req(rr); 
	return rc;
    }

    r->content_type = rr->content_type;
    ap_send_http_header(r);
    if (r->header_only) {
	return OK;
    }
    rc = ap_run_sub_req(rr);
    ap_destroy_sub_req(rr); 

    return rc;
}

static int randpicture_handler(request_rec *r)
{
    randpicture_dir_config *dcfg = (randpicture_dir_config *)
	ap_get_module_config(r->per_dir_config, &randpicture_module);
    request_rec *subr;
    DIR *dirp;
    struct DIR_TYPE *dstruct;
    array_header *files;
    char *dname;
    int randval, rc;

    if (!dcfg->picture_dir) {
	ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r,
		      "no picture directory configured");
	return HTTP_INTERNAL_SERVER_ERROR;
    }

    subr = ap_sub_req_lookup_uri(dcfg->picture_dir, r); 
    if ((rc = subr->status) != HTTP_OK) { 
        ap_destroy_sub_req(subr); 
        return rc; 
    } 

    files = ap_make_array(subr->pool, 10, sizeof(char *));
    dname = subr->filename;

    if (!(dirp = ap_popendir(r->pool, dname))) {
	ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
		    "Can't open picture directory: %s", dname);
	return HTTP_FORBIDDEN;
    }

    /* read image uris into an array */
    while ((dstruct = readdir(dirp))) { 
	char *dname = dstruct->d_name;
	request_rec *rr = ap_sub_req_lookup_uri(dname, subr); 
	if (!rr->content_type) {
	    continue;
	}
	if (strncmp(rr->content_type, "image/", 6)) {
	    continue;
	}

	*(char **)ap_push_array(files) = ap_pstrdup(subr->pool, rr->uri);
	ap_destroy_sub_req(rr); 
    }

    /* send a random image from our list */
    randval = randpicture_rand(1, files->nelts-1);
    rc = randpicture_send(r, ((char **)files->elts)[randval]);
    ap_destroy_sub_req(subr); 

    return rc;
}

static command_rec randpicture_cmds[] = { 
    { 
	"PictureDir", randpicture_dir_cmd,
	NULL, OR_ALL, TAKE1, "a directory",
    }, 
    { NULL },
};

static const handler_rec randpicture_handlers[] = { 
    { "randpicture", randpicture_handler }, 
    { NULL }
};

module MODULE_VAR_EXPORT randpicture_module = {
    STANDARD_MODULE_STUFF, 
    NULL,                  /* module initializer                  */
    randpicture_create_dir_config, /* create per-dir    config structures */
    NULL,  /* merge  per-dir    config structures */
    NULL,                  /* create per-server config structures */
    NULL,                  /* merge  per-server config structures */
    randpicture_cmds,      /* table of config file commands       */
    randpicture_handlers,  /* [#8] MIME-typed-dispatched handlers */
    NULL,                  /* [#1] URI to filename translation    */
    NULL,                  /* [#4] validate user id from request  */
    NULL,                  /* [#5] check if the user is ok _here_ */
    NULL,                  /* [#3] check access by host address   */
    NULL,                  /* [#6] determine MIME type            */
    NULL,                  /* [#7] pre-run fixups                 */
    NULL,                  /* [#9] log a transaction              */
    NULL,                  /* [#2] header parser                  */
    randpicture_init,      /* child_init                          */
    NULL,                  /* child_exit                          */
    NULL                   /* [#0] post read-request              */
};

