/*
 * Apache Web Server Module Reveal:
 *
 * Author: Matthew W. Coan (Fri Feb  4 13:30:18 EST 2005)  
 * Copywright (C) 2005
 *
 */

#include "httpd.h"
#include "http_config.h"
#include "http_protocol.h"

typedef struct {
   char * szDir;
   char * szTag;
} SPerDir;

typedef struct {
   char * szServer;
   char * szTag;
} SPerServer;

extern module reveal_module;

static void RevealInit(server_rec * pServer, pool * pPool) {
   SPerServer * pPerServer = get_module_config(pServer->module_config,
                                               &reveal_module);

   fprintf(stderr, "Init : host=%s port=%d server=%s tag=%s\n",
           pServer->server_hostname, pServer->port, pPerServer->szServer,
           pPerServer->szTag);

}

static void * RevealCreateServer(pool * pPool, server_rec * pServer) {
   SPerServer * pPerServer = palloc(pPool, sizeof(*pPerServer));
   const char * szServer;
   char szPort[20];

   if(pServer->server_hostname)
      szServer = pServer->server_hostname;
   else
      szServer = "(none)";
  
   sprintf(szPort, "%d", pServer->port);
   pPerServer->szTag = NULL;
   pPerServer->szServer = pstrcat(pPool, szServer, ":", szPort, NULL);

   fprintf(stderr, "CreateServer: server=%s\n", szServer);

   return pPerServer;

}

static void * RevealMergeServer(pool * pPool, SPerServer * pBase,
                                SPerServer * pNew) {
   char p1[20], p2[20];
   SPerServer * pMerged = palloc(pPool, sizeof(*pMerged));

   fprintf(stderr, "MergeServer : pBase: server=%s tag=%s pNew: server=%s"
                   " tag=%s\n", pBase->szServer, pBase->szTag,
                   pNew->szServer, pNew->szTag);

   pMerged->szServer = pstrcat(pPool, pBase->szServer, "+",
                               pNew->szServer, NULL);
   pMerged->szTag = pstrcat(pPool, pBase->szTag, "+", pNew->szTag, NULL);

   return pMerged;

}

static void * RevealCreateDir(pool * pPool, char * szDir) {
   SPerDir * pPerDir = palloc(pPool, sizeof(*pPerDir));

   if(!szDir)
      szDir = "(none)";
   
   fprintf(stderr, "CreateDir: dir=%s\n", szDir);

   pPerDir->szDir = pstrdup(pPool, szDir);
   pPerDir->szTag = NULL;

   return pPerDir;

}

static void * RevealMergeDir(pool * pPool, SPerDir * pBase, SPerDir * pNew) {
   SPerDir * pMerged = palloc(pPool, sizeof(*pMerged));

   fprintf(stderr, "MergeDir : pBase: dir=%s tag=\"%s\" "
           "pNew: dir=%s tag=\"%s\"\n", pBase->szDir, pBase->szTag,
           pNew->szDir, pNew->szTag);

   pMerged->szDir = pstrcat(pPool, pBase->szDir, "+", pNew->szDir, NULL);
   pMerged->szTag = pstrcat(pPool, pBase->szTag, "+", pNew->szTag, NULL);

   return pMerged;

}

static void ShowRequestStuff(request_rec * pReq) {
   SPerDir * pPerDir = NULL;
   SPerServer * pPerServer;
   SPerDir none = { "(null)", "(null)" };
   SPerDir noconf = { "(no per-dir config)", "(no per-dir config)"};

   if(pReq->per_dir_config) {
      pPerDir = get_module_config(pReq->per_dir_config,
                &reveal_module);
   }

   pPerServer = get_module_config(pReq->server->module_config,
                &reveal_module);

   if(!pReq->per_dir_config)
      pPerDir = &noconf;
   else if(!pPerDir)
      pPerDir = &none;

   if(pPerServer) {
      fprintf(stderr, "server=%s tag=%s dir=%s tag=%s\n",
              pPerServer->szServer, pPerServer->szTag, 
              pPerDir->szDir, pPerDir->szTag);
   }
   else {
      fprintf(stderr, "dir=%s tag=%s\n",
              pPerDir->szDir, pPerDir->szTag);
   }

}

static int RevealTranslate(request_rec * pReq) {
   fprintf(stderr, "Translate : uri=%s\n", pReq->uri);
   ShowRequestStuff(pReq);
   fprintf(stderr, "Done\n");
   return DECLINED;
}

static int RevealCheckUserID(request_rec * pReq) {
   fprintf(stderr, "CheckUserID : \n");
   ShowRequestStuff(pReq);
   fprintf(stderr, "Done\n");
   return DECLINED;
}

static int RevealCheckAuth(request_rec * pReq) {
   fprintf(stderr, "CheckAuth : \n");
   ShowRequestStuff(pReq);
   fprintf(stderr, "Done\n");
   return DECLINED;
}

static int RevealCheckAccess(request_rec * pReq) {
   fprintf(stderr, "CheckAccess : \n");
   ShowRequestStuff(pReq);
   fprintf(stderr, "Done\n");
   return DECLINED;
}

static int RevealTypeChecker(request_rec * pReq) {
   fprintf(stderr, "TypeChecker : \n");
   ShowRequestStuff(pReq);
   fprintf(stderr, "Done\n");
   return DECLINED;
}

static int RevealFixups(request_rec * pReq) {
   fprintf(stderr, "Fixups : \n");
   ShowRequestStuff(pReq);
   fprintf(stderr, "Done\n");
   return DECLINED;
}

static int RevealLogger(request_rec * pReq) {
   fprintf(stderr, "Logger : \n");
   ShowRequestStuff(pReq);
   fprintf(stderr, "Done\n");
   return DECLINED;
}

static char * RevealTag(cmd_parms * cmd, SPerDir * pPerDir, char * arg) {
   SPerServer * pPerServer = get_module_config(cmd->server->module_config, 
                                               &reveal_module);

   fprintf(stderr, "Name : tag=%s server=%s tag=%s\n", arg,
           pPerServer->szServer, pPerServer->szTag);

   if(pPerServer->szTag)
      pPerServer->szTag = pstrcat(cmd->pool, pPerServer->szTag,
                                  "-", arg, NULL);
   else
      pPerServer->szTag = pstrdup(cmd->pool, arg);

   return NULL;

}

static char * RevealServerTag(cmd_parms * cmd, SPerDir * pPerDir, char * arg) {
   SPerServer * pPerServer = get_module_config(cmd->server->module_config,
                                               &reveal_module);

   fprintf(stderr, "Command : tag=%s server=%s tag=%s\n", arg,
           pPerServer->szServer, pPerServer->szTag);

   if(pPerServer->szTag)
      pPerServer->szTag = pstrcat(cmd->pool, pPerServer->szTag,
                                  "-", arg, NULL);
   else
      pPerServer->szTag = pstrdup(cmd->pool, arg);

   return NULL;

}


static command_rec aCommands[] = {
   { "RevealTag", RevealTag, NULL, ACCESS_CONF | OR_ALL, TAKE1, 
     "a tag for this section" },
   { "RevealServerTag", RevealServerTag, NULL, RSRC_CONF, TAKE1,
     "a tag for this server" },
   { NULL }
};

static void TShow(request_rec * pReq, 
                  const char * szHead, 
                  const char * szItem) {
   if(!szHead)
      szHead = "(null)";
   if(!szItem)
      szItem = "(null)";
   rprintf(pReq, "<TR><TH>%s<TD>%s\n", szHead, szItem);
}

static void TShowN(request_rec * pReq, 
                   const char * szHead, 
                   int nItem) {
   if(!szHead) 
      szHead = "(null)";
   rprintf(pReq, "<TR><TH>%s<TD>%d\n", szHead, nItem);
}

static int RevealHandler(request_rec * pReq) {
   SPerDir * pPerDir;
   SPerServer * pPerServer;
   SPerDir none = { "(null)", "(null)" };

   if(pReq->per_dir_config) 
      pPerDir = get_module_config(pReq->per_dir_config,
                &reveal_module);
   else 
      pPerDir = &none;

   pPerServer = get_module_config(pReq->server->module_config,
                &reveal_module);

fprintf(stderr, "RevealHandler\n");

   pReq->content_type = "text/html";
   send_http_header(pReq);

   rputs("<CENTER><H1>Revelation of ", pReq);
   rputs(pReq->uri, pReq);
   rputs("</H1></CENTER><HR>\n", pReq);
   rputs("<TABLE>\n", pReq); 
   TShow(pReq, "URI", pReq->uri);
   TShow(pReq, "Filename", pReq->filename);
   TShow(pReq, "Server name", pReq->server->server_hostname);
   TShowN(pReq, "Server port", pReq->server->port);
   TShow(pReq, "Server config", pPerServer->szServer);
   TShow(pReq, "Server config", pPerServer->szTag);
   TShow(pReq, "Directory config", pPerDir->szDir);
   TShow(pReq, "Directory config", pPerDir->szTag);
   rputs("</TABLE>\n", pReq);

fprintf(stderr, "Done\n");

   return OK;
}

static handler_rec aHandlers[] = {
   { "reveal", RevealHandler },
   { NULL }
};

module reveal_module = {
   STANDARD_MODULE_STUFF,
   RevealInit,			/* initializer */
   RevealCreateDir,		/* dir config creater */
   RevealMergeDir,		/* dir merger --- default is to override */
   RevealCreateServer,		/* server config */
   RevealMergeServer,		/* merge server configs */
   aCommands,			/* command table */
   aHandlers,			/* handlers */
   RevealTranslate,		/* filename transation */
   RevealCheckUserID,		/* check_user_id */
   RevealCheckAuth,		/* check auth */
   RevealCheckAccess,		/* check access */
   RevealTypeChecker,		/* type_checker */
   RevealFixups,		/* fixups */
   RevealLogger			/* logger */
};
