#include "wvargs.h"
#include "wvbuf.h"
#include "wvfile.h"
#include "wvhttppool.h"
#include "wvocsp.h"


static int got_response = 0;


void load_cert(WvStringParm fname, WvX509 &cert)
{
    WvFile f(fname, O_RDONLY);
    WvDynBuf buf;
    while (f.isok())
        f.read(buf, 100);

    WvX509::DumpMode dumpmode = WvX509::CertDER;

    if (!strncmp("-----BEGIN", (const char *) buf.peek(0, 10), 10))
        dumpmode = WvX509::CertPEM;

    cert.decode(dumpmode, buf);    

    wvcon->print("Loaded certificate with name %s\n", cert.get_subject());
}


static void response_cb(WvStream &s, WvDynBuf &respbuf)
{
    char buf[1024];
    size_t numread = 0;
    size_t totalread = 0;
    while (s.isreadable() && totalread < 32768)
    {
        numread = s.read(buf, 1024);
        if (numread)
            respbuf.put(buf, numread);
        totalread += numread;
    }    
}


static void response_closed_cb()
{
    wvcon->print("Response closed!\n");
    // we just assume that we were successful
    got_response = 1;
}


int main(int argc, char *argv[])
{
    WvArgs args;
    args.add_required_arg("CLIENT_CERTIFICATE", false);
    args.add_required_arg("SIGNING_CERTIFICATE", false);
    args.add_required_arg("URL", false);

    WvStringList remaining_args;
    if (!args.process(argc, argv, &remaining_args))
        return 1;

    WvString clicertfname = remaining_args.popstr();
    WvString issuercertfname = remaining_args.popstr();
    WvString url = remaining_args.popstr();

    WvX509 clicert;
    WvX509 issuer;    
    WvX509 ocspserver;
    
    load_cert(clicertfname, clicert);
    load_cert(issuercertfname, issuer);

    wvcon->print("Sending request...\n");
    WvOCSPReq req(clicert, issuer);
    WvDynBuf reqbuf;
    req.encode(reqbuf);

    WvBufStream input_stream;
    input_stream.write(reqbuf, reqbuf.used());

    WvHttpStream::global_enable_pipelining = false;
    WvHttpPool pool;
    WvIStreamList::globallist.append(&pool, false, "http pool");

    WvStream * response_stream =  pool.addurl(
        url, "POST",
        "Content-Type: application/ocsp-request\r\n",
        &input_stream);

    WvDynBuf respbuf;
    
    response_stream->setcallback(wv::bind(&response_cb, 
                                          wv::ref(*response_stream),
                                          wv::ref(respbuf)));
    response_stream->setclosecallback(&response_closed_cb);

    WvIStreamList::globallist.append(response_stream, false, "response stream");
    wvcon->print("Beginning downloading of response...\n");
    while (!got_response)
        WvIStreamList::globallist.runonce();

    wvcon->print("Got response (length: %s), attempting to decode...\n", 
                 respbuf.used());
    
    WvOCSPResp resp;
    resp.decode(respbuf);
    if (!resp.isok())
    {
        wvcon->print("Response not ok!\n");
        exit(1);
    }
    
    if (!resp.check_nonce(req))
    {
        wvcon->print("Response nonce does not check out!\n");
        exit(1);
    }
    
    WvOCSPResp::Status status = resp.get_status(clicert, issuer);
    wvcon->print("Response status: %s.\n", WvOCSPResp::status_str(status));
}
