/* N O T E S - to be removed before release
executable
l:\projects\libwww\www\linemode\pics\windows\windebug\wwwpics.exe
working dir
l:\projects\libwww\www\library\implementation\windows\windebug
args

dlls
l:\projects\libwww\www\pics\implementation\windows\windebug\wwwpics.dll

switch to HTStrMatch
*/

#include <stdio.h>
#include <string.h>
#include "WWWLib.h"
#include "WWWApp.h"
#include "WWWFile.h"
#include "HTHeader.h"
#include "CSLApp.h"
#include "CSParse.h"
#include "CSLUtils.h"
#include "CSLL.h"
#include "CSUser.h"
#include "CSUserSt.h"
#include "CSUsrLst.h"

/* ReqParms - list of pending HTRequests and their callbacks an' stuff */
typedef struct {
    HTRequest * pReq;
    enum {reqState_NEW, reqState_PROT_REQ, reqState_BUREAU_START, 
	  reqState_BUREAU_MIDDLE, reqState_BUREAU_DONE, 
	  reqState_BUREAU_ERR} reqState;

    CSDisposition_criteria criteria;/* if the criteria are met */
    CSDisposition_callback * pCallback;	/*  call pCallback */
    CSError_t disposition;	/*   with */
    CSLabel_t * pCSLabel;	/*   all */
    CSUser_t * pCSUser;		/*   these */
    void * pVoid;		/*   parameters */
    HTParentAnchor * anchor;
    HTFormat outputFormat;
    HTStream * outputStream;
    HTMethod method;
    } ReqParms_t;

ReqParms_t DefaultReqParms = {0, reqState_NEW, CSApp_neverCall, 
			      0, CSError_APP, 0, 0, 0};

/* handy strings */

PRIVATE char * S_mimeLabel = "PICS-Label";
PRIVATE char * S_machRead = "application/x-pics-machine-readable";
PRIVATE char * S_label = "application/pics-label";
PRIVATE char * S_user = "application/x-pics-user";
PRIVATE char * S_URLList = "application/x-url-list";
PRIVATE HTList * ListWithHeaderGenerator = NULL;

/* LoadURLToConverter - load a URL and set the output to go to converter.
                        Useful for loading user list and profiles. */
PRIVATE BOOL LoadURLToConverter(const char * url, const char * relatedName, 
				const char * type, HTConverter * converter, 
				const char * errMessage)
{
    BOOL ret;
    char * fullURL;
    HTRequest * pRequest;
    HTParentAnchor * pParentAnchor;
    HTList * conversions = HTList_new();

    pRequest = HTRequest_new();
    fullURL = HTParse(url, relatedName, PARSE_ALL);
    pParentAnchor = (HTParentAnchor *) HTAnchor_findAddress(fullURL);
    HTRequest_setPreemptive(pRequest, YES);
    if (converter) {
        HTConversion_add(conversions, type, "*/*", converter, 1.0, 0.0, 0.0);
	HTRequest_setConversion(pRequest, conversions, YES);
    }
    if ((ret = HTLoadAnchor((HTAnchor *) pParentAnchor, pRequest)) != YES)
        HTPrint("PICS: Can't access %s.\n", errMessage);
    if (converter)
        HTConversion_deleteAll(conversions);
    else
        HTList_delete(conversions);
    HTRequest_delete(pRequest);
    HT_FREE(fullURL);
    return ret;
}

/* This should be in CSUserList, but that would require 
   that LoadURLToConverter and S_URLList be PUBLIC and 
   added to some header, which one? */
PUBLIC BOOL CSUserList_load(char * url, char * relatedName)
{
    return LoadURLToConverter(url, relatedName, S_URLList, CSUserLists, 
			      "PICS user list");
}

/* L O A D E D U S E R */
/* LoadedUsers is a list of all the users who have 
   had their descritpion files loaded */
typedef struct {
    CSUser_t * pCSUser;
    char *     url;
} CSLoadedUser_t;
PRIVATE HTList * LoadedUsers = 0;

PRIVATE CSLoadedUser_t * CSLoadedUser_new(CSUser_t * pCSUser, char * url)
{
    CSLoadedUser_t * pCSLoadedUser;
    if ((pCSLoadedUser = (CSLoadedUser_t *)HT_MALLOC(sizeof(CSLoadedUser_t))) == NULL)
        HT_OUTOFMEM("CSLoadedUser_t");
    pCSLoadedUser->pCSUser = pCSUser;
    pCSLoadedUser->url = 0;
    StrAllocCopy(pCSLoadedUser->url, url);
    return pCSLoadedUser;
}

PRIVATE void CSLoadedUser_delete(CSLoadedUser_t * pCSLoadedUser)
{
    CSUser_free(pCSLoadedUser->pCSUser);
    HT_FREE(pCSLoadedUser->url);
    HT_FREE(pCSLoadedUser);
}

PRIVATE CSLoadedUser_t * CSLoadedUser_findUser(CSUser_t * pCSUser)
{
    HTList * cur = LoadedUsers;
    CSLoadedUser_t * pCSLoadedUser;
    while ((pCSLoadedUser = (CSLoadedUser_t *) HTList_nextObject(cur))) {
        if (pCSLoadedUser->pCSUser ==  pCSUser)
            return pCSLoadedUser;
    }
    return 0;
}

PRIVATE CSLoadedUser_t * CSLoadedUser_findName(char * name)
{
    HTList * cur = LoadedUsers;
    CSLoadedUser_t * pCSLoadedUser;
    while ((pCSLoadedUser = (CSLoadedUser_t *) HTList_nextObject(cur))) {
        if (!strcasecomp(CSUser_name(pCSLoadedUser->pCSUser), name))
            return pCSLoadedUser;
    }
    return 0;
}

PUBLIC BOOL CSLoadedUser_remove(CSUser_t * pCSUser)
{
    CSLoadedUser_t * pCSLoadedUser;
    if (!(pCSLoadedUser = CSLoadedUser_findUser(pCSUser)))
        return NO;
    HTList_removeObject(LoadedUsers, (void *)pCSLoadedUser);
    CSLoadedUser_delete(pCSLoadedUser);
    return YES;
}

/* PUBLIC version of findName */
PUBLIC BOOL CSLoadedUser_find(char * name)
{
    return (CSLoadedUser_findName(name) != 0);
}

PRIVATE CSLoadedUser_t * CSLoadedUser_findUrl(char * url)
{
    HTList * cur = LoadedUsers;
    CSLoadedUser_t * pCSLoadedUser;
    while ((pCSLoadedUser = (CSLoadedUser_t *) HTList_nextObject(cur))) {
        if (!strcasecomp(pCSLoadedUser->url, url))
            return pCSLoadedUser;
    }
    return 0;
}

CSApp_userCallback * PUserCallback = 0;

PUBLIC BOOL CSLoadedUser_add(CSUser_t * pCSUser, char * url)
{
    int callBackRet;
    CSLoadedUser_t * pCSLoadedUser;
    callBackRet = (*PUserCallback)(pCSUser, DefaultReqParms.pVoid);
    switch (callBackRet) {
        case 1:
            DefaultReqParms.pCSUser = pCSUser;
	    HTTRACE(PICS_TRACE, "PICS: Setting default user to \"%s\".\n" _ CSUser_name(pCSUser));
            break;
	case 0:
	    HTTRACE(PICS_TRACE, "PICS: Loaded user \"%s\".\n" _ CSUser_name(pCSUser));
	    break;
	case -1:
	    HTTRACE(PICS_TRACE, "PICS: User \"%s\" not loaded.\n" _ CSUser_name(pCSUser));
	    return YES;
	default:
	    HTTRACE(PICS_TRACE, "PICS: Aborting load user \"%s\".\n" _ CSUser_name(pCSUser));
	    return NO;
    }
    if ((pCSLoadedUser = CSLoadedUser_findName(CSUser_name(pCSUser)))) {
        HTPrint("PICS: Replacing previous user \"%s\".\n", 
		CSUser_name(pCSUser));
	HTList_removeObject(LoadedUsers, (void *)pCSLoadedUser);
    }
    pCSLoadedUser = CSLoadedUser_new(pCSUser, url);
    return (HTList_addObject(LoadedUsers, (void *)pCSLoadedUser));
}

PUBLIC BOOL CSLoadedUser_deleteAll (void)
{
    CSLoadedUser_t * pCSLoadedUser;

    while ((pCSLoadedUser = (CSLoadedUser_t *) HTList_removeLastObject(LoadedUsers))) {
        CSLoadedUser_delete(pCSLoadedUser);
    }
    HTList_delete(LoadedUsers);
    LoadedUsers = NULL;
    return YES;
}

PUBLIC int CSLoadedUser_enum(CSLoadedUserCallback * pCallback, void * pVoid)
{
    HTList * cur = LoadedUsers;
    CSLoadedUser_t * pCSLoadedUser;
    int retVal, i = 0;
    while ((pCSLoadedUser = (CSLoadedUser_t *) HTList_nextObject(cur))) {
        if ((retVal = (*pCallback)(pCSLoadedUser->pCSUser, i, pVoid)) != CSError_OK)
            return (retVal);
        i++;
    }
    return 0;
}

PUBLIC CSUser_t * CSLoadedUser_load(char * url, char * relatedName)
{
    BOOL err = 0;
    char * fullURL = HTParse(url, relatedName, PARSE_ALL);
    CSLoadedUser_t * pCSLoadedUser;
    if (!LoadURLToConverter(fullURL, 0, 0, 0, "PICS user file"))
/*    if (!LoadURLToConverter(fullURL, 0, S_user, CSParseUser, 
			    "PICS user file", 0, 0, 0)) */
        err = 1;
    else if ((pCSLoadedUser = CSLoadedUser_findUrl(fullURL)) == NULL)
        err = 1;
    HT_FREE(fullURL);
   return err ? 0 : pCSLoadedUser->pCSUser;
}

/* R E Q P A R M S */
HTList * ReqParms = 0;

PRIVATE ReqParms_t * ReqParms_new(HTRequest * pReq, CSUser_t * pCSUser, CSDisposition_callback * pCallback, CSDisposition_criteria criteria, void * pVoid)
{
    ReqParms_t * me;
    if ((me = (ReqParms_t *) HT_CALLOC(1, sizeof(ReqParms_t))) == NULL)
        HT_OUTOFMEM("ReqParms_t");
    me->pReq = pReq;
    me->disposition = CSError_APP;
    me->reqState = reqState_NEW;
    me->pCSUser = pCSUser;
    me->pCallback = pCallback;
    me->criteria = criteria;
    me->pVoid = pVoid;
    return me;
}

PRIVATE void ReqParms_free(ReqParms_t * pReqParms)
{
    HT_FREE(pReqParms);
}

PRIVATE ReqParms_t * ReqParms_copy(ReqParms_t * old)
{
    ReqParms_t * me;
    if ((me = (ReqParms_t *) HT_CALLOC(1, sizeof(ReqParms_t))) == NULL)
        HT_OUTOFMEM("ReqParms_t");
    me->pReq = old->pReq;
    me->disposition = old->disposition;
    me->reqState = old->reqState;
    me->pCSUser = old->pCSUser;
    me->pCallback = old->pCallback;
    me->criteria = old->criteria;
    me->pVoid = old->pVoid;
    return me;
}

PRIVATE ReqParms_t * ReqParms_getReq(HTRequest * pReq)
{
    HTList * cur = ReqParms;
    ReqParms_t * pReqParms;
    while ((pReqParms = (ReqParms_t *) HTList_nextObject(cur)))
        if (pReqParms->pReq == pReq)
            return pReqParms;
    return 0;
}
/*
PRIVATE ReqParms_t * ReqParms_getBureauReq(HTRequest * pBureauReq)
{
    HTList * cur = ReqParms;
    ReqParms_t * pReqParms;
    while ((pReqParms = (ReqParms_t *) HTList_nextObject(cur)))
        if (pReqParms->pBureauReq == pBureauReq)
            return pReqParms;
    return 0;
}
*/
PRIVATE BOOL ReqParms_cache(ReqParms_t * pReqParms, CSLabel_t * pCSLabel)
{
    return NO;
}

PRIVATE BOOL ReqParms_checkCache(ReqParms_t * pReqParms, int * pRet)
{
    return NO;
}

PUBLIC BOOL CSApp_label(HTRequest * pReq, CSLabel_t * pCSLabel)
{
    ReqParms_t * pReqParms;
    if (!(pReqParms = ReqParms_getReq(pReq)))
        pReqParms = &DefaultReqParms;
/*
    if (!(pReqParms = ReqParms_getBureauReq(pReq)))
        pReqParms = &DefaultReqParms;
    if (pReqParms->pBureauReq != pReq) {
        HTPrint("PICS: Could not find original request\n");
	return NO;
    }
*/
    pReqParms->pCSLabel = pCSLabel;
    pReqParms->disposition = CSCheckLabel_checkLabelAndUser(pCSLabel, 
							   pReqParms->pCSUser);
    ReqParms_cache(pReqParms, pCSLabel);
    return YES;
}

PRIVATE int ReqParms_checkDisposition(ReqParms_t * pReqParms)
{
    int kill;
    kill = pReqParms->disposition != CSError_OK;
    if ((kill && pReqParms->criteria & CSApp_callOnBad) || 
	(!kill && pReqParms->criteria & CSApp_callOnGood))
        pReqParms->disposition = (*pReqParms->pCallback)(pReqParms->pReq, 
							 pReqParms->pCSLabel, 
							 pReqParms->pCSUser, 
						       pReqParms->disposition, 
							 pReqParms->pVoid);
    return (pReqParms->disposition == CSError_OK ? HT_OK : HT_INTERRUPTED);
    CSLabel_free(pReqParms->pCSLabel);
    if (pReqParms->disposition == CSError_OK)
	return HT_OK;
    return HT_OK;
}

PRIVATE BOOL ReqParms_removeRequest(ReqParms_t * pReqParms)
{
    HTList_removeObject(ReqParms, (void *)pReqParms);
    ReqParms_free(pReqParms);
    return YES;
}
/*
PRIVATE BOOL ReqParms_removeRequest(HTRequest * pReq)
{
    ReqParms_t * pReqParms;
    if ((pReqParms = ReqParms_getReq(pReq)))
        return HTList_removeObject(ReqParms, (void *)pReqParms);
    return NO;
}

PRIVATE CSUser_t * ReqParms_getUser(HTRequest * pReq)
{
    ReqParms_t * pReqParms;
    if ((pReqParms = ReqParms_getReq(pReq)))
        return pReqParms->pCSUser;
    return 0;
}
*/

/* U S E R */
PUBLIC BOOL CSApp_registerDefaultUserByName(char * user, char * password)
{
    CSUser_t * pCSUser;
    CSLoadedUser_t * pCSLoadedUser;
    if (!(pCSLoadedUser = CSLoadedUser_findName(user))) {
        HTTRACE(PICS_TRACE, "PICS: User \"%s\" not found.\n" _ CSUser_name(pCSUser));
        return NO;
    }
    pCSUser = pCSLoadedUser->pCSUser;
    if (CSUser_checkPassword(pCSUser, password) == NO) {
        HTPrint("PICS: Bad password for user \"%s\".\n", CSUser_name(pCSUser));
        return NO;
    }
    DefaultReqParms.pCSUser = pCSUser;
    return YES;
}

PUBLIC CSUser_t * CSApp_registerUserByName(char* user, char* password)
{
    CSLoadedUser_t * pCSLoadedUser;
    if (!(pCSLoadedUser = CSLoadedUser_findName(user)))
        return 0;
    if (CSUser_checkPassword(pCSLoadedUser->pCSUser, password) == NO) {
        HTPrint("PICS: Bad password for user \"%s\"\n", 
		CSUser_name(pCSLoadedUser->pCSUser));
        return 0;
    }
    return pCSLoadedUser->pCSUser;
}

PUBLIC BOOL CSApp_setDefaultUser(CSUser_t * pCSUser)
{
    if (!pCSUser)
        return NO;
    DefaultReqParms.pCSUser = pCSUser;
    return YES;
}

PUBLIC BOOL CSApp_checkHUser(CSUser_t * pCSUser)
{
    return YES;
}

PUBLIC BOOL CSApp_unregisterDefaultUser(void)
{
    DefaultReqParms.pCSUser = 0;
    return YES;
}

PUBLIC BOOL CSApp_unregisterUser(CSUser_t * pCSUser)
{
    if (DefaultReqParms.pCSUser == pCSUser)
        DefaultReqParms.pCSUser = 0;
    return CSLoadedUser_remove(pCSUser);
}

/* base of all streams */
#define PUTBLOCK(b, l)	(*target->isa->put_block)(target, b, l)
struct _HTStream {
    const HTStreamClass *	isa;
    /* ... */
};

/* HTNet Filters */
PRIVATE HTNetAfter CSApp_bureauError;
PRIVATE int CSApp_bureauAfter (HTRequest * pReq, HTResponse * response,
			       void * context, int status)
{
    ReqParms_t * pReqParms = (ReqParms_t *)context;
    /*    if (!pReqParms || (pReq != pReqParms->pBureauReq))
        return HT_ERROR; */
    pReqParms->reqState = reqState_BUREAU_DONE;
    HTRequest_deleteAfter(pReq, CSApp_bureauAfter);
    HTRequest_deleteAfter(pReq, CSApp_bureauError);
    HTTRACE(PICS_TRACE, "PICS: Load was %sOK\n" _ 
			    pReqParms->disposition == CSError_OK ? "" : "!");
    ReqParms_removeRequest(pReqParms);
    if (pReqParms->disposition != CSError_OK)
        return HT_OK;
    /*    HTRequest_setAnchor(pReq, pReqParms->anchor); */
    HTRequest_setOutputFormat(pReq, pReqParms->outputFormat);
    HTRequest_setOutputStream(pReq, pReqParms->outputStream);
    HTRequest_setMethod(pReq, pReqParms->method);
    return HTLoadAnchor((HTAnchor *)pReqParms->anchor, pReq);
}

PRIVATE int CSApp_bureauError (HTRequest * pReq, HTResponse * response,
			       void * context, int status)
{
    ReqParms_t * pReqParms = (ReqParms_t *)context;
    /*    if (!pReqParms || (pReq != pReqParms->pBureauReq))
        return HT_ERROR; */
    pReqParms->reqState = reqState_BUREAU_ERR;
    HTPrint("PICS: couldn't find label service.\n");
    return HT_OK;
}

PRIVATE int CSApp_netBefore (HTRequest * pReq, void * param, int mode)
{
    HTParentAnchor * pParentAnchor;
    ReqParms_t * pReqParms;
    char * bureau;
    char * url;
    char * ptr;
    int ret;

    /*    if (ReqParms_getBureauReq(pReq) || 
	pReq == DefaultReqParms.pBureauReq)
        return HT_OK;
    if (!(pReqParms = ReqParms_getReq(pReq))) {
        pReqParms = &DefaultReqParms;
	DefaultReqParms.pReq = pReq;
    } */
    if ((pReqParms = ReqParms_getReq(pReq))) {
        if (pReqParms->reqState == reqState_BUREAU_START) /* bureau req */
	    return HT_OK;                                 /* so ignore  */
    } else {
        if (!DefaultReqParms.pCSUser)
	    return HT_OK; /* no PICS user so no PICS */
        pReqParms = ReqParms_copy(&DefaultReqParms);
	pReqParms->pReq = pReq;
    }
    if (!(bureau = CSUser_bureau(pReqParms->pCSUser))) {
        HTRequest_setGenerator(pReq, ListWithHeaderGenerator, NO);
        return HT_OK;				/* Header will handle it */
    }
    if (ReqParms_checkCache(pReqParms, &ret))
        return ret;
    url = HTAnchor_address((HTAnchor*)HTRequest_anchor(pReq));
    ptr = CSUser_getLabels(pReqParms->pCSUser, url, CSOption_normal, 
			   CSCompleteness_full);
    pReqParms->anchor = HTRequest_anchor(pReq);
    pReqParms->outputFormat = HTRequest_outputFormat(pReq);
    HTRequest_setOutputFormat(pReq, WWW_SOURCE);
    pReqParms->outputStream = HTRequest_outputStream(pReq);
    HTRequest_setOutputStream(pReq, CSParseLabel(pReq, 0, 0, 0, 0));
    /*    pReqParms->pBureauReq = pReq; */
    pReqParms->reqState = reqState_BUREAU_START; /* mark as a BUREAU req */
    HTRequest_setPreemptive(pReq, YES);
    HTTRACE(PICS_TRACE, "PICS: label request:\n%s\n" _ ptr);
    /* get label and set disposition */

    HTRequest_addAfter(pReq, CSApp_bureauAfter, NULL, (void *) pReqParms, HT_LOADED,
		       HT_FILTER_MIDDLE, YES);
    HTRequest_addAfter(pReq, CSApp_bureauError, NULL, (void *) pReqParms, HT_ERROR,
		       HT_FILTER_MIDDLE, YES);

    pParentAnchor = (HTParentAnchor *) HTAnchor_findAddress(ptr);
    if ((ret = HTLoadAnchor((HTAnchor *) pParentAnchor, pReq)) != YES)
        HTPrint("PICS: Can't access label bureau at %s.\n", ptr);
    return HT_OK;
}

/*HTPostCallback CSApp_headerGenerator;*/
PRIVATE int CSApp_headerGenerator (HTRequest * pReq, HTStream * target)
{
    char * translated;
    HTParentAnchor *anchor = HTRequest_anchor(pReq);
    char * url;
    ReqParms_t * pReqParms = ReqParms_getReq(pReq);

    /*    if (!pReqParms) {
        if ((pReqParms = ReqParms_getBureauReq(pReq)))
	    return HT_OK;
        pReqParms = &DefaultReqParms;
    } */
if (!pReqParms || pReqParms->reqState != reqState_NEW || !pReqParms->pCSUser)
HTPrint("PICS: CSApp_headerGenerator prob\n");
#if 0
    if (!pReqParms->pCSUser) {
        HTTRACE(PICS_TRACE, "PICS: No user selected\n");
	return HT_OK;
    }
    if (CSUser_bureau(pReqParms->pCSUser)) /* handled by CSApp_netBefore */
        return HT_OK;
#endif
    url = HTAnchor_address((HTAnchor *) anchor);
    if ((translated = CSUser_acceptLabels(pReqParms->pCSUser, CSCompleteness_full))) {
        HTTRACE(PICS_TRACE, "PICS: Accept \"%s\".\n" _ translated);
        PUTBLOCK(translated, strlen(translated));
        HT_FREE(translated);
    }
    HT_FREE(url);
    return HT_OK;
}

/*HTParserCallback CSApp_headerParser;*/
PRIVATE int CSApp_headerParser (HTRequest * pReq, HTResponse * response,
				char * token, char * value)
{
    CSParse_t * pCSParse;
    ReqParms_t * pReqParms = ReqParms_getReq(pReq);

    if (!pReqParms) {
        pReqParms = &DefaultReqParms;
	DefaultReqParms.pReq = pReq;
    }
    if (!pReqParms->pCSUser) /* if there is no user */
       	return HT_OK;             /* send the document on its way */
 /*   pReqParms->disposition = CSCheckLabel_parseAndValidateLabelStr(value, pReqParms->pCSUser); */
    pCSParse = CSParse_newLabel(0, 0);

    CSParse_parseChunk(pCSParse, value, (int) strlen(value), 0);
    pReqParms->disposition = 
           CSCheckLabel_checkLabelAndUser(CSParse_getLabel(pCSParse), 
					  pReqParms->pCSUser);

    pReqParms->pCSLabel = CSParse_getLabel(pCSParse);
    CSParse_delete(pCSParse);
    HTTRACE(PICS_TRACE, "PICS: PICS mime header \"%s\" got %d.\n" _ value _ pReqParms->disposition);
    return ReqParms_checkDisposition(pReqParms);
}

/* application functions */
PUBLIC BOOL CSApp_registerApp(CSDisposition_callback * pCallback, 
			      CSDisposition_criteria criteria, 
			      CSApp_userCallback * pUserCallback, void * pVoid)
{
    HTList* conversions;

    PUserCallback = pUserCallback;

    /* set up DefaultReqParms */
    DefaultReqParms.pCallback = pCallback;
    DefaultReqParms.criteria = criteria;
    DefaultReqParms.pVoid = pVoid;

    /* Tell HTMIME which headers we will deal with */
    if (!ListWithHeaderGenerator)
        ListWithHeaderGenerator = HTList_new();
    HTList_addObject(ListWithHeaderGenerator, (void *)CSApp_headerGenerator);
    /*    HTHeader_addGenerator(CSApp_headerGenerator); */
    HTNet_addBefore(CSApp_netBefore, NULL, NULL, 5);
    HTHeader_addParser(S_mimeLabel, FALSE, CSApp_headerParser);

    /* set converters so pics profiles may be read */
    conversions = HTFormat_conversion();
#if 0
    HTConversion_add(conversions, S_machRead, "*/*", CSParseMachRead, 
		     1.0, 0.0, 0.0);
    HTConversion_add(conversions, S_label, "*/*", CSParseLabel, 1.0, 0.0, 0.0);
#endif
    HTConversion_add(conversions, S_user, "*/*", CSParseUser, 1.0, 0.0, 0.0);

    HTBind_add("rat", S_machRead, "7bit", NULL, NULL, 1.0);
    HTBind_add("pcu", S_user, "7bit", NULL, NULL, 1.0);
    HTBind_add("lab", S_label, "7bit", NULL, NULL, 1.0);
    HTBind_add("url", S_URLList, "7bit", NULL, NULL, 1.0);

    if (!LoadedUsers)
        LoadedUsers = HTList_new();
    return YES;
}

/*  while ((pCSLoadedUser = (CSLoadedUser_t *) HTList_removeLastObject(LoadedUsers)))
    HTList_removeObject(pCSLoadedUser);
    return YES; */

PUBLIC BOOL CSApp_unregisterApp()
{
    HTHeader_deleteGenerator(CSApp_headerGenerator);
    HTHeader_deleteParser(S_mimeLabel);
    return YES;
}

PUBLIC BOOL CSApp_registerReq(HTRequest* pReq, CSUser_t * pCSUser, CSDisposition_callback pCallback, CSDisposition_criteria criteria, void * pVoid)
{
    ReqParms_t * pReqParms;
    if ((pReqParms = ReqParms_getReq(pReq))) {
        return NO;
    }
    if (!pReq || !pCSUser)
        return NO;
    pReqParms = ReqParms_new(pReq, pCSUser, pCallback, criteria, pVoid);
    if (!ReqParms)
      ReqParms = HTList_new();
    HTList_addObject(ReqParms, (void *)pReqParms);
    return YES;
}

PUBLIC BOOL CSApp_unregisterReq(HTRequest* pReq)
{
    ReqParms_t * pReqParms;
    if ((pReqParms = ReqParms_getReq(pReq)) == NULL) {
        return NO;
    }
    HTList_removeObject(ReqParms, (void *)pReqParms);
    ReqParms_free(pReqParms);
    return YES;
}

PUBLIC HTRequest * CSApp_originalRequest(HTRequest* pReq)
{
  /*    ReqParms_t * pReqParms;
    if ((pReqParms = ReqParms_getBureauReq(pReq)) == NULL) {
        return NULL;
    }
    return pReqParms->pReq;
    */
    return pReq;
}

/* M I S C */
PUBLIC char * CSApp_libraryVersion(void)
{
    return "1.1";
}

