/*********************************************************************

 PDF-AS.SigHandler.cpp

*********************************************************************/

#include "PDF-AS.SigHandler.h"
#include "FormsHFT.h"
#include <string>
#include <ctime>
#include <map>

using namespace std;

HFT gDigSigHFT = NULL;
HFT gAcroFormHFT = NULL;
HFT gPubSecHFT = NULL;

boolean gSigHandlerInitialized = false;
clock_t openStamp = 0;
clock_t validatedStamp = 0;
map<string, bool> verifyUrls;

#define OPEN_INTERVAL 2000 // ms. no validation after document was opened
#define VALID_INTERVAL 6000 // ms. no multi signature validation

/*-------------------------------------------------------
	Custom validation Callbacks
-------------------------------------------------------*/

// on document open
static  ACCBPROTO1 void ACCBPROTO2 DSDocOpen(PDDoc pdDoc) {
	// do nothing, no auto validation		
	openStamp = clock();	
}

// not called
static ACCBPROTO1 ASBool ACCBPROTO2 DSCanValidate(PDDoc pdDoc, CosObj sigField, CosObj sigAnnot, ASAtom filter ) {	
	return true;
}

// validate signature
static	ACCBPROTO1 DSValidState ACCBPROTO2 DSValidateSig(PDDoc pdDoc, CosObj sigField, CosObj sigAnnot) {
	int i = 9;
		
	long startDif = clock() - openStamp;
	if (startDif < OPEN_INTERVAL) {
		return DSSigValid;
	}

	long validateDif = clock() - validatedStamp;
	//if (validateDif < VALID_INTERVAL) {
	//	return DSSigValid;
	//}
	
	CosObj sigEntry = CosDictGet(sigAnnot, ASAtomFromString("V"));
	CosObj urlObj = CosDictGet(sigEntry, ASAtomFromString("ContactInfo"));
	char *urlStr = "https://www.buergerkarte.at/signature-verification"; // default url
	if (CosObjGetType(urlObj) == CosString) {
		ASTCount len;
		urlStr = CosStringValue(urlObj, &len );	
	}

	if (validateDif < VALID_INTERVAL) {
		// multi sig verify
		//string ustr (urlStr);
		if (verifyUrls.find(urlStr) == verifyUrls.end()) {
			verifyUrls[urlStr] = true;
		} else {			
			return DSSigValid;
		}		
	} else {
		verifyUrls.clear();
		verifyUrls[urlStr];
	}

	char msg[1024];
	sprintf(msg, "Dieses Dokument enth�lt PDF-AS Signaturen. Wollen Sie diese unter %s verifizieren?", urlStr);
	

	ASInt32 choice = AVAlert(ALERT_NOTE, msg, "Ja", "Nein", NULL, false);
	validatedStamp = clock();
	if(choice==2) {
		return DSSigUnknown;
	}
	//AVAlertNote("Diese PDF-AS Signatur kann unter www.buergerkarte.at verifiziert werden");
	//string url = "https://www.buergerkarte.at/signature-verification"; // get this from document	
	char script[2048];
	sprintf(script, "app.launchURL('%s', true)", urlStr);
	AFExecuteThisScript (pdDoc, script, NULL);

	return DSSigValid;
}



/*-------------------------------------------------------
	Core Handshake Callbacks
-------------------------------------------------------*/

/* DocSignExportHFTs
** ------------------------------------------------------
**
** Create and register the HFT's.
**
** Return true to continue loading plug-in.
** Return false to cause plug-in loading to stop.
*/
ACCB1 ASBool ACCB2 DocSignExportHFTs(void)
{
	return true;
}

/* DocSignImportReplaceAndRegister
** ------------------------------------------------------
**
** This routine is where you can:
**	1) Import plug-in supplied HFTs.
**	2) Replace functions in the HFTs you're using (where allowed).
**	3) Register to receive notification events.
**
** Return true to continue loading plug-in.
** Return false to cause plug-in loading to stop.
*/
ACCB1 ASBool ACCB2 DocSignImportReplaceAndRegister(void)
{

	gDigSigHFT = ASExtensionMgrGetHFT(ASAtomFromString("DigSigHFT"), 1);
	if (!gDigSigHFT)
		return false;

	gAcroFormHFT = Init_AcroFormHFT;
	if(!gAcroFormHFT)
		return false;

		/* PubSec HFT */
	gPubSecHFT = ASExtensionMgrGetHFT(ASAtomFromString("PubSecHFT"), 1);
	if (!gPubSecHFT)
		return false;


	return true;
}

/* DocSignInit
** ------------------------------------------------------
**
** The main initialization routine.
**
** Return true to continue loading plug-in.
** Return false to cause plug-in loading to stop.
*/
ACCB1 ASBool ACCB2 DocSignInit(void)
{


	DSRegisterSignatureHandler();


	return true;
}



void DSRegisterSignatureHandler()
{
	DigSigHandlerRec gSigHandlerRec;
	if( gDigSigHFT == NULL ) return;
	if (!gSigHandlerInitialized)
	{
		memset( &gSigHandlerRec, 0, sizeof(DigSigHandlerRec) );
		gSigHandlerRec.size = sizeof (DigSigHandlerRec);
		gSigHandlerRec.uiName = PDFAS_HANDLER_NAME;
		gSigHandlerRec.filterKey = ASAtomFromString(PDFAS_HANDLER_NAME);
		gSigHandlerRec.canBlindSign = true;
		gSigHandlerRec.canEncrypt = true;
		gSigHandlerRec.dsDocOpen = ASCallbackCreateProto(DSDocOpenProc, DSDocOpen );
		//gSigHandlerRec.dsGetBoolProperty = ASCallbackCreateProto(DSGetBoolPropertyProc, DSGetBoolProperty );
		gSigHandlerRec.dsCanValidate = ASCallbackCreateProto(DSCanValidateProc, DSCanValidate );
		//gSigHandlerRec.dsDocClose = ASCallbackCreateProto(DSDocCloseProc, DSDocClose );
		//gSigHandlerRec.dsDefaultValue = ASCallbackCreateProto(DSDefaultValueProc, DSDefaultValue );

		//gSigHandlerRec.dsNewSigData =
		//	ASCallbackCreateProto(DSNewSigDataProc, DSNewSigData );
		//gSigHandlerRec.dsCommitSign =
		//	ASCallbackCreateProto(DSCommitSignProc, DSCommitSign );
		//gSigHandlerRec.dsFinishSign =
		//	ASCallbackCreateProto(DSFinishSignProc, DSFinishSign );
		//gSigHandlerRec.dsFreeSigData =
		//	ASCallbackCreateProto(DSFreeSigDataProc, DSFreeSigData );
		gSigHandlerRec.dsValidateSig = ASCallbackCreateProto(DSValidateSigProc, DSValidateSig );
		//gSigHandlerRec.dsGetValidState =
		//	ASCallbackCreateProto(DSGetValidStateProc, DSGetValidState );
		//gSigHandlerRec.dsProperties = (void (__cdecl*)(PDDoc ,CosObj, CosObj))NULL;
		//ASCallbackCreateProto(DSPropertiesProc, DSProperties );
		//gSigHandlerRec.dsUnValidateSig =
		//	ASCallbackCreateProto(DSUnValidateSigProc, DSUnValidateSig );
		//gSigHandlerRec.dsReValidateSig =
		//	ASCallbackCreateProto(DSUnValidateSigProc, DSReValidateSig );
		gSigHandlerInitialized = true;
		}

	DigSigRegisterFilter( gExtensionID, &gSigHandlerRec );

}

/** not used, left as example **/
void RegisterFHandler() {
	PubSecHandlerRec fHandlerRec;
	if( true ) {

		memset( &fHandlerRec, 0, sizeof(fHandlerRec) );


		fHandlerRec.size = sizeof(PubSecHandlerRec);

		//fHandlerRec.getBoolProperty = ASCallbackCreateProto(PSGetBoolPropertyProc, GetBoolProperty );
		//fHandlerRec.getAtomProperty = ASCallbackCreateProto(PSGetAtomPropertyProc, GetAtomProperty );
		//fHandlerRec.getTextProperty = ASCallbackCreateProto(PSGetTextPropertyProc, GetTextProperty );
		//fHandlerRec.getInt32Property = ASCallbackCreateProto(PSGetInt32PropertyProc, GetInt32Property );

		//fHandlerRec.newEngine = ASCallbackCreateProto(PSNewEngineProc, DSHandler::NewEngine );
		//fHandlerRec.destroyEngine = ASCallbackCreateProto(PSDestroyEngineProc, DSHandler::DestroyEngine );

		//fHandlerRec.sessionAcquire = ASCallbackCreateProto(PSSessionAcquireProc, DSHandler::SessionAcquire );
		//fHandlerRec.sessionRelease = ASCallbackCreateProto(PSSessionReleaseProc, DSHandler::SessionRelease );
		//fHandlerRec.sessionReady = ASCallbackCreateProto(PSSessionReadyProc, DSHandler::SessionReady );
		//fHandlerRec.performOperation = ASCallbackCreateProto(PSPerformOperationProc, DSHandler::PerformOperation );


		//fHandlerRec.sigGetSigProperties = ASCallbackCreateProto(PSSigGetSigPropertiesProc, DSHandler::SigGetSigProperties );
		//fHandlerRec.sigAuthenticate = ASCallbackCreateProto(PSSigAuthenticateProc, DSHandler::SigAuthenticate );
		//fHandlerRec.sigGetSigValue = ASCallbackCreateProto(PSSigGetSigValueProc, DSHandler::SigGetSigValue );

		//// Set up this callback if you want to have custom appearance
		//fHandlerRec.sigCreateAPNXObj = ASCallbackCreateProto(PSSigCreateAPNXObjProc, DSHandler::SigCreateAPNXObj );
		//fHandlerRec.sigValidate = ASCallbackCreateProto(PSSigValidateProc, DSHandler::SigValidate );
		//fHandlerRec.sigValidateDialog = NULL;
		//fHandlerRec.sigPropDialog = NULL;

		//fHandlerRec.getLogo = ASCallbackCreateProto(PSGetLogoProc, DSHandler::GetLogo );

		//// SigVal methods
		//fHandlerRec.sigValGetText = ASCallbackCreateProto(PSSigValGetTextProc, DSSigVal::GetText );
		//// Once you set up the PSSigCreateAPNXObjProc callback, you must set up this callback
		//// in order to have the PSGetLogoProc callback invoked
		//fHandlerRec.sigValGetAPLabel = ASCallbackCreateProto(PSSigValGetAPLabelProc, DSSigVal::GetAPLabel );

		//// Cert exchange methods
		//fHandlerRec.exportData = ASCallbackCreateProto(PSExportDataProc, DSHandler::ExportData );
		//fHandlerRec.importData = NULL;
		//
		//// Encryption methods
		//fHandlerRec.cryptOpenCMSEnvelope = ASCallbackCreateProto(PSOpenCMSEnvelopeProc, DSHandler::openCMSEnvelope);
		//fHandlerRec.cryptGetImplicitRecipients = ASCallbackCreateProto(PSGetImplicitRecipientsProc, DSHandler::getImplicitRecipients);

		//fbHandlerIsInit = true;
	}

	/* Register security handler. 
	   Note that ownership of this struct is retained by this plug-in */

	ASBool bOk = PSRegisterHandler( gExtensionID, &fHandlerRec );

}

/* DocSignUnload
** ------------------------------------------------------
**
** The unload routine.
**
** Called when your plug-in is being unloaded when the application quits.
** Use this routine to release any system resources you may have
** allocated.
**
** Returning false will cause an alert to display that unloading failed.
*/
ACCB1 ASBool ACCB2 DocSignUnload(void)
{

	return true;
}

/* GetExtensionName
** ------------------------------------------------------
**
** Get the extension name associated with this plugin
*/
ASAtom GetExtensionName()
{
	return ASAtomFromString("PDF-AS.SigHandler");	/* Change to your extension's name */
}


/*
** PIHandshake
** Required Plug-in handshaking routine: Do not change it's name! PIMain.c expects
** this function to be named and typed as shown.
*/
ACCB1 ASBool ACCB2 PIHandshake(Uns32 handshakeVersion, void *handshakeData)
{
	if (handshakeVersion == HANDSHAKE_V0200) {
		/* Cast handshakeData to the appropriate type */
		PIHandshakeData_V0200 *hsData = (PIHandshakeData_V0200 *)handshakeData;

		/* Set the name we want to go by */
		hsData->extensionName = GetExtensionName();

		/* If you export your own HFT, do so in here */
		hsData->exportHFTsCallback = ASCallbackCreate(&DocSignExportHFTs);

		/*
		** If you import plug-in HFTs, replace functionality, and/or want to register for notifications before
		** the user has a chance to do anything, do so in here.
		*/
		hsData->importReplaceAndRegisterCallback = ASCallbackCreate(
																		 &DocSignImportReplaceAndRegister);

		/* Perform your plug-in's initialization in here */
		hsData->initCallback = ASCallbackCreate(&DocSignInit);

		/* Perform any memory freeing or state saving on "quit" in here */
		hsData->unloadCallback = ASCallbackCreate(&DocSignUnload);

		/* All done */
		return true;

	} /* Each time the handshake version changes, add a new "else if" branch */

	/*
	** If we reach here, then we were passed a handshake version number we don't know about.
	** This shouldn't ever happen since our main() routine chose the version number.
	*/
	return false;
}