BEGIN;
SET search_path TO challenger;
CREATE OR REPLACE FUNCTION challenger_do_challenge_set_address_and_pin (
  IN in_nonce BYTEA,
  IN in_address TEXT,
  IN in_next_tx_time INT8,
  IN in_now INT8,
  IN in_tan INT4,
  OUT out_not_found BOOLEAN,
  OUT out_last_tx_time INT8,
  OUT out_last_pin INT4,
  OUT out_state TEXT,
  OUT out_pin_transmit BOOLEAN,
  OUT out_auth_attempts_left INT4,
  OUT out_client_redirect_uri TEXT,
  OUT out_address_refused BOOLEAN,
  OUT out_solved BOOLEAN)
LANGUAGE plpgsql
AS $$
DECLARE
  my_status RECORD;
  my_do_update BOOL;
BEGIN
my_do_update = FALSE;
SELECT address
      ,address_attempts_left
      ,pin_transmissions_left
      ,last_tx_time
      ,client_redirect_uri
      ,last_pin
      ,auth_attempts_left
      ,client_state
  INTO my_status
  FROM validations
 WHERE nonce=in_nonce;
IF NOT FOUND
THEN
  out_not_found=TRUE;
  out_last_tx_time=0;
  out_last_pin=0;
  out_pin_transmit=FALSE;
  out_auth_attempts_left=0;
  out_client_redirect_uri=NULL;
  out_address_refused=TRUE;
  out_solved=FALSE;
  out_state=NULL;
  RETURN;
END IF;
out_not_found=FALSE;
out_last_tx_time=my_status.last_tx_time;
out_last_pin=my_status.last_pin;
out_pin_transmit=FALSE;
out_auth_attempts_left=my_status.auth_attempts_left;
out_state=my_status.client_state;
out_client_redirect_uri=my_status.client_redirect_uri;
IF ( 0 > my_status.auth_attempts_left ) 
THEN
  out_address_refused=TRUE;
  out_solved=TRUE;
  out_auth_attempts_left=0;
  RETURN;
END IF;
out_solved=FALSE;
IF ( (0 = my_status.address_attempts_left) AND
     (in_address != my_status.address) )
THEN
  out_address_refused=TRUE;
  out_last_pin=0;
  RETURN;
END IF;
out_address_refused=FALSE;
IF ( (my_status.address IS NULL) OR
     (in_address != my_status.address) )
THEN
  my_status.address_attempts_left = my_status.address_attempts_left - 1;
  my_status.address = in_address;
  my_status.pin_transmissions_left = 3;
  my_status.last_tx_time = 0;
  my_do_update=TRUE;
END IF;
IF ( (my_status.pin_transmissions_left > 0) AND
     (my_status.last_tx_time <= in_next_tx_time) )
THEN
  my_status.pin_transmissions_left = my_status.pin_transmissions_left - 1;
  my_status.last_pin = in_tan;
  my_status.auth_attempts_left = 3;
  my_status.last_tx_time = in_now;
  out_auth_attempts_left = 3;
  out_pin_transmit=TRUE;
  out_last_pin = in_tan;
  out_last_tx_time = in_now;
  my_do_update=TRUE;
END IF;
IF my_do_update
THEN
  UPDATE validations SET
    address=my_status.address
   ,address_attempts_left=my_status.address_attempts_left
   ,pin_transmissions_left=my_status.pin_transmissions_left
   ,last_tx_time=my_status.last_tx_time
   ,last_pin=my_status.last_pin
   ,auth_attempts_left=my_status.auth_attempts_left
  WHERE nonce=$1;
END IF;
RETURN;
END $$;
CREATE OR REPLACE FUNCTION challenger_do_validate_and_solve_pin (
  IN in_nonce BYTEA,
  IN in_new_pin INT4,
  OUT out_not_found BOOLEAN,
  OUT out_exhausted BOOLEAN,
  OUT out_no_challenge BOOLEAN,
  OUT out_solved BOOLEAN,
  OUT out_state TEXT,
  OUT out_address_attempts_left INT4,
  OUT out_auth_attempts_left INT4,
  OUT out_pin_transmissions_left INT4,
  OUT out_client_redirect_uri TEXT)
LANGUAGE plpgsql
AS $$
DECLARE
  my_status RECORD;
BEGIN
SELECT auth_attempts_left
      ,address_attempts_left
      ,pin_transmissions_left
      ,last_pin
      ,client_redirect_uri
      ,client_state
  INTO my_status
  FROM validations
 WHERE nonce=in_nonce;
IF NOT FOUND
THEN
  out_not_found=TRUE;
  out_no_challenge=TRUE;
  out_exhausted=FALSE;
  out_solved=FALSE;
  out_address_attempts_left=0;
  out_auth_attempts_left=0;
  out_pin_transmissions_left=0;
  out_client_redirect_uri=NULL;
  out_state=NULL;
  RETURN;
END IF;
out_not_found=FALSE;
out_address_attempts_left=my_status.address_attempts_left;
out_pin_transmissions_left=my_status.pin_transmissions_left;
out_client_redirect_uri=my_status.client_redirect_uri;
out_state=my_status.client_state;
IF (my_status.last_pin IS NULL)
THEN
  out_solved=FALSE;
  out_exhausted=FALSE;
  out_auth_attempts_left=0;
  out_no_challenge=TRUE;
  RETURN;
END IF;
out_no_challenge=FALSE;
IF (0 > my_status.auth_attempts_left)
THEN
  out_solved=TRUE;
  out_exhausted=TRUE;
  out_auth_attempts_left=0;
  RETURN;
END IF;
IF (0 = my_status.auth_attempts_left)
THEN
  out_solved=FALSE;
  out_exhausted=TRUE;
  out_auth_attempts_left=0;
  RETURN;
END IF;
out_exhausted=FALSE;
out_solved = (my_status.last_pin = in_new_pin);
IF NOT out_solved
THEN
  out_auth_attempts_left=my_status.auth_attempts_left-1;
ELSE
  out_auth_attempts_left=-1; 
END IF;
UPDATE validations
 SET auth_attempts_left=out_auth_attempts_left
 WHERE nonce=$1;
RETURN;
END $$;
COMMIT;
