/*
  ICS Simple SSL Client - C++Builder translation of the Delphi demo OverbyteIcsSimpleSslCli1.pas
  (demos-delphi-vcl), ICS V9.8.

  A basic SSL client using TSslWSocket: connect to host and port, start the SSL
  handshake once connected, then send a simple HTTP/1.0 GET and show what comes back.

  How this C++ version differs from the Delphi original, apart from syntax:
  - The received-data stream is a std::unique_ptr member (Delphi: Create and FreeAndNil).
  - The Get URL button is only enabled when the SSL handshake succeeded.
*/

#include <vcl.h>
#pragma hdrstop

#include "OverbyteIcsSimpleSslCli1.h"

#pragma package(smart_init)
#pragma resource "*.dfm"

TForm1 *Form1;

__fastcall TForm1::TForm1(TComponent *Owner)
    : TForm(Owner)
{
}

__fastcall TForm1::~TForm1()
{
    // Free the components (and so close Sock) while RecStream still exists: closing fires SockSessionClosed.
    DestroyComponents();
}

void __fastcall TForm1::FormCreate(TObject *Sender)
{
    Caption = Caption + IcsVerLitSample;   // common ICS sample caption: version and date
    RecStream.reset(new TMemoryStream);
    Memo1->Clear();
    Label4->Caption = IntToStr(Memo1->Lines->Count);
}

void __fastcall TForm1::FormDestroy(TObject *Sender)
{
}

void __fastcall TForm1::SockDebugDisplay(TObject *Sender, const String Msg)
{
    if (Memo1)
        Memo1->Lines->Add(Msg);
}

void __fastcall TForm1::SockSessionConnected(TObject *Sender, WORD ErrCode)
{
    Memo1->Lines->Add("Session Connected");
    if (ErrCode == 0) {
        Sock->SslEnable = true;
        Sock->StartSslHandshake();
        ButtonConnect->Enabled = false;
        ButtonClose->Enabled = true;
    }
}

void __fastcall TForm1::SockSessionClosed(TObject *Sender, WORD ErrCode)
{
    Memo1->Lines->Add("Session Closed");
    ButtonConnect->Enabled = true;
    ButtonURL->Enabled = false;
    ButtonClose->Enabled = false;
    RecStream->Seek(static_cast<__int64>(0), soBeginning);   // plain 0 is ambiguous between the int and Int64 overloads
    if (RecStream->Size > 0) {
        // The reply is shown as ANSI text, as in the Delphi demo.
        AnsiString Lines;
        Lines.SetLength(static_cast<int>(RecStream->Size));
        RecStream->Read(&Lines[1], static_cast<int>(RecStream->Size));
        Memo1->Lines->Add("Data Received during seession:");
        Memo1->Lines->Add(String(Lines));
        RecStream->Size = 0;
    }
    Label4->Caption = IntToStr(Memo1->Lines->Count);
    Memo1->Lines->Add("");
}

void __fastcall TForm1::SockDataAvailable(TObject *Sender, WORD ErrCode)
{
    char Buf[1024];
    for (;;) {
        int Len = Sock->Receive(Buf, static_cast<int>(sizeof(Buf)) - 1);
        if (Len <= 0)
            return;
        RecStream->Write(Buf, Len);
    }
}

void __fastcall TForm1::SockSslHandshakeDone(TObject *Sender, WORD ErrCode, TX509Base *PeerCert, bool &Disconnect)
{
    // The Delphi demo enables the button even when the handshake failed.
    ButtonURL->Enabled = (ErrCode == 0);
}

void __fastcall TForm1::ButtonConnectClick(TObject *Sender)
{
    Sock->Addr = EditHost->Text;
    Sock->Port = EditPort->Text;
    Sock->WSDebugOptions = DefWSDebugClient;         // what to log to the OnDebugDisplay event

    Sock->SslCertVerMethod = CertVerBundle;          // how to check SSL certs
    Sock->SslAllowSelfSign = true;                   // allow own certs
    SslContext1->SslVerifyPeer = true;               // check cert chain
    SslContext1->UseSharedCAStore = true;            // built-in store
    RecStream->Size = 0;
    Label4->Caption = IntToStr(Memo1->Lines->Count);
    Sock->SslEnable = false;                         // enabled in the SessionConnected event
    Memo1->Lines->Add("Start connection to " + Sock->Addr + ":" + Sock->Port);
    Sock->Connect();
}

void __fastcall TForm1::ButtonCloseClick(TObject *Sender)
{
    Memo1->Lines->Add("Closing connection");
    Sock->Close();
}

void __fastcall TForm1::ButtonURLClick(TObject *Sender)
{
    ButtonURL->Enabled = false;
    Sock->SendStr("GET " + EditUrl->Text + " HTTP/1.0\r\n\r\n");
}
