#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 6's Apache::DayLimit
 */

/*
 * configure like so:
 * <Location />
 * ReqDay Friday Saturday
 * </Location>
 */
 
module MODULE_VAR_EXPORT daylimit_module;

typedef struct {
    array_header *days;
    int configured;
} daylimit_dir_config;

static const char day_snames[7][4] = 
{ 
    "sun", "mon", "tue", "wed", "thu", "fri", "sat" 
}; 

static const char *day_names[7] = 
{
    "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
};

static void *daylimit_create_dir_config(pool *p, char *path)  
{  
    daylimit_dir_config *dcfg =   
        (daylimit_dir_config *)ap_pcalloc(p, sizeof(*dcfg));  
 
    dcfg->days = ap_make_array(p, 7, sizeof(char *));
    dcfg->configured = 0;

    return (void *)dcfg;  
}

static const char *daylimit_reqday_cmd(cmd_parms *parms, void *mconfig, const char *arg) 
{
    daylimit_dir_config *dcfg = (daylimit_dir_config *)mconfig;
    int i, dayok=0;

    /* lowercase the day string */
    ap_str_tolower((char *)arg);

    /* sanity check */
    for (i=0; i<7; i++) {
	if (strncmp(day_snames[i], arg, 3) == 0) {
	    dayok = 1;
	    break;
	}
    }

    if (!dayok) {
	return ap_pstrcat(parms->pool, "`", arg, "' is not a valid day", NULL);
    }

    *(char **)ap_push_array(dcfg->days) = ap_pstrdup(parms->pool, arg); 
    dcfg->configured = 1;

    return NULL;
}

static int daylimit_handler(request_rec *r)
{
    daylimit_dir_config *dcfg = 
	(daylimit_dir_config *)ap_get_module_config(r->per_dir_config, &daylimit_module);
    struct tm *tm = localtime(&r->request_time); 
    char *today = day_snames[tm->tm_wday];
    char **reqdays = (char **)dcfg->days->elts;
    int i;

    if (!dcfg->configured) {
	return DECLINED;
    }

    for (i=0; i<dcfg->days->nelts; i++) {
	if (strncmp(today, reqdays[i], 3) == 0) {
	    return OK;
	}
    }

    ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r, 
		  "Access forbidden on day %s", day_names[tm->tm_wday]);

    return HTTP_FORBIDDEN;
}

static command_rec daylimit_cmds[] = {  
    {  
        "ReqDay", daylimit_reqday_cmd, 
        NULL, OR_ALL, ITERATE, "a list of days", 
    },  
    { NULL }, 
}; 

module MODULE_VAR_EXPORT daylimit_module = {
    STANDARD_MODULE_STUFF, 
    NULL,                  /* module initializer                  */
    daylimit_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 */
    daylimit_cmds,         /* table of config file commands       */
    NULL,                  /* [#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_ */
    daylimit_handler,      /* [#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                  */
    NULL,                  /* child_init                          */
    NULL,                  /* child_exit                          */
    NULL                   /* [#0] post read-request              */
};

