/**
 * Function scheduled to be run on the successful start of services
 * tries to look up the dns record for TEST_DOMAIN
 *
 * @param cls closure
 * @param success GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
 *                GNUNET_NO if content was already there or not found
 *                GNUNET_YES (or other positive value) on success
 * @param emsg NULL on success, otherwise an error message
 */
static void
commence_testing (void *cls,
		  int32_t success,
		  const char *emsg)
{
  nsqe = NULL;
  if (NULL != emsg)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                "Failed to store record in namestore: %s\n",
		emsg);
    end_badly_now ();
    return;
  }
  gns_handle = GNUNET_GNS_connect (cfg);
  if (NULL == gns_handle)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                "Failed to connect to GNS!\n");
    end_badly_now ();
    return;
  }
  lr = GNUNET_GNS_lookup (gns_handle, TEST_DOMAIN, GNUNET_GNS_RECORD_A,
			  GNUNET_YES,
			  NULL,
			  &on_lookup_result, TEST_DOMAIN);
}
static void
do_check (void *cls,
          const struct GNUNET_CONFIGURATION_Handle *ccfg,
          struct GNUNET_TESTING_Peer *peer)
{
  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded alice_pkey;
  struct GNUNET_CRYPTO_RsaPrivateKey *alice_key;
  struct GNUNET_NAMESTORE_RecordData rd;
  char* alice_keyfile;
  char* ip = TEST_IP;
  struct in_addr web;

  cfg = ccfg;
  die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);

  /* put records into namestore */
  namestore_handle = GNUNET_NAMESTORE_connect(cfg);
  if (NULL == namestore_handle)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
		"Failed to connect to namestore\n");
    end_badly_now ();
    return;
  }
  if (GNUNET_OK != 
      GNUNET_CONFIGURATION_get_value_filename (cfg, "gns",
					       "ZONEKEY",
					       &alice_keyfile))
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
		"Failed to get key from cfg\n");
    end_badly_now ();
    return;
  }

  alice_key = GNUNET_CRYPTO_rsa_key_create_from_file (alice_keyfile);
  GNUNET_CRYPTO_rsa_key_get_public (alice_key, &alice_pkey);
  GNUNET_free (alice_keyfile);
  rd.expiration_time = UINT64_MAX;
  GNUNET_assert (1 == inet_pton (AF_INET, ip, &web));
  rd.data_size = sizeof(struct in_addr);
  rd.data = &web;
  rd.record_type = GNUNET_DNSPARSER_TYPE_A;
  rd.flags = GNUNET_NAMESTORE_RF_AUTHORITY;
  nsqe = GNUNET_NAMESTORE_record_create (namestore_handle,
					 alice_key,
					 TEST_RECORD_NAME,
					 &rd,
					 &commence_testing,
					 NULL);
  GNUNET_CRYPTO_rsa_key_free (alice_key);
}
/**
 * Function scheduled to be run on the successful start of services
 * tries to look up the dns record for TEST_DOMAIN
 */
static void
commence_testing (void *cls, int32_t success, const char *emsg)
{
  char name[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
  char* pos;
  struct GNUNET_CRYPTO_ShortHashAsciiEncoded hash_str;
  
  gns_handle = GNUNET_GNS_connect(cfg);
  if (NULL == gns_handle)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                "Failed to connect to GNS!\n");
    end_badly_now ();
    return;
  }

  pos = name;
  strcpy(pos, TEST_RECORD_NAME);
  pos += strlen(TEST_RECORD_NAME);
  strcpy(pos, ".");
  pos++;
  GNUNET_CRYPTO_short_hash_to_enc(&bob_hash, &hash_str);
  strcpy(pos, (char*)&hash_str);
  pos += strlen((char*)&hash_str);
  strcpy(pos, ".");
  pos++;
  strcpy(pos, GNUNET_GNS_TLD_ZKEY);

  GNUNET_GNS_lookup(gns_handle, name, GNUNET_GNS_RECORD_A,
                    GNUNET_NO,
                    NULL,
                    &on_lookup_result, NULL);
}
/**
 * Function scheduled to be run on the successful start of services
 * tries to look up the dns record for TEST_DOMAIN
 */
static void
commence_testing (void *cls, int32_t success, const char *emsg)
{
  gns_handle = GNUNET_GNS_connect(cfg);
  if (NULL == gns_handle)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                "Failed to connect to GNS!\n");
    end_badly_now();
    return;
  }
  GNUNET_GNS_lookup(gns_handle, TEST_DOMAIN, GNUNET_GNS_RECORD_MX,
                    GNUNET_NO,
                    NULL,
                    &on_lookup_result, TEST_DOMAIN);
}
/**
 * Function scheduled to be run on the successful start of services
 * tries to shorten the name TEST_DOMAIN using gns
 */
static void
commence_testing (void *cls, int32_t success, const char *emsg)
{

  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Connecting to gns\n");
  gns_handle = GNUNET_GNS_connect(cfg);
  if (NULL == gns_handle)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                "Failed to connect to gns\n");
    end_badly_now();
    return;
  }

  GNUNET_GNS_get_authority(gns_handle, TEST_DOMAIN, &process_auth_result,
                     TEST_DOMAIN);
}
static void
do_check (void *cls,
          const struct GNUNET_CONFIGURATION_Handle *ccfg,
          struct GNUNET_TESTING_Peer *peer)
{
  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded alice_pkey;
  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded bob_pkey;
  struct GNUNET_CRYPTO_RsaPrivateKey *alice_key;
  struct GNUNET_CRYPTO_RsaPrivateKey *bob_key;
  struct GNUNET_CRYPTO_ShortHashCode bob_hash;
  struct GNUNET_CRYPTO_RsaSignature *sig;
  char* alice_keyfile;
  struct srv_data *srv_data;
  struct GNUNET_TIME_Absolute et;

  cfg = ccfg;
  die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);

  /* put records into namestore */
  namestore_handle = GNUNET_NAMESTORE_connect(cfg);
  if (NULL == namestore_handle)
  {
    GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to connect to namestore\n");
    end_badly_now();
    return;
  }

  if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns",
                                                          "ZONEKEY",
                                                          &alice_keyfile))
  {
    GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n");
    end_badly_now();
    return;
  }

  alice_key = GNUNET_CRYPTO_rsa_key_create_from_file (alice_keyfile);
  bob_key = GNUNET_CRYPTO_rsa_key_create_from_file (KEYFILE_BOB);

  GNUNET_CRYPTO_rsa_key_get_public (alice_key, &alice_pkey);
  GNUNET_CRYPTO_rsa_key_get_public (bob_key, &bob_pkey);

  struct GNUNET_NAMESTORE_RecordData rd;
  char* ip = TEST_IP;
  struct in_addr *sipserver = GNUNET_malloc (sizeof (struct in_addr));
  srv_data = GNUNET_malloc (sizeof (struct srv_data) + strlen (TEST_SRV_NAME) + 1);
  uint16_t srv_weight = 60;
  uint16_t srv_prio = 50;
  uint16_t srv_port = 5060;

  rd.expiration_time = UINT64_MAX;
  GNUNET_assert(1 == inet_pton (AF_INET, ip, sipserver));
  
  GNUNET_CRYPTO_short_hash(&bob_pkey, sizeof(bob_pkey), &bob_hash);

  rd.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode);
  rd.data = &bob_hash;
  rd.record_type = GNUNET_GNS_RECORD_PKEY;
  rd.flags = GNUNET_NAMESTORE_RF_AUTHORITY;

  GNUNET_NAMESTORE_record_create (namestore_handle,
                                  alice_key,
                                  TEST_AUTHORITY_NAME,
                                  &rd,
                                  NULL,
                                  NULL);

  rd.data_size = sizeof (struct in_addr);
  rd.data = sipserver;
  rd.record_type = GNUNET_DNSPARSER_TYPE_A;
  sig = GNUNET_NAMESTORE_create_signature(bob_key,
                                          GNUNET_TIME_UNIT_FOREVER_ABS,
                                          TEST_RECORD_NAME,
                                          &rd, 1);
  et.abs_value = rd.expiration_time;
  GNUNET_NAMESTORE_record_put (namestore_handle,
                               &bob_pkey,
                               TEST_RECORD_NAME,
                               et,
                               1,
                               &rd,
                               sig,
                               NULL,
                               NULL);
  GNUNET_free (sig);
  
  rd.data_size = sizeof (struct srv_data)+strlen(TEST_SRV_NAME)+1;
  srv_data->port = srv_port;
  srv_data->prio = srv_prio;
  srv_data->weight = srv_weight;
  strcpy((char*)&srv_data[1], TEST_SRV_NAME);
  rd.data = srv_data;
  rd.record_type = GNUNET_GNS_RECORD_SRV;
  sig = GNUNET_NAMESTORE_create_signature(bob_key,
                                          GNUNET_TIME_UNIT_FOREVER_ABS,
                                          TEST_RECORD_NAME_SRV,
                                          &rd, 1);
  et.abs_value = rd.expiration_time;
  GNUNET_NAMESTORE_record_put (namestore_handle,
                               &bob_pkey,
                               TEST_RECORD_NAME_SRV,
                               et,
                               1,
                               &rd,
                               sig,
                               &commence_testing,
                               NULL);
  GNUNET_free (alice_keyfile);
  GNUNET_free (srv_data);
  GNUNET_free (sipserver);
  GNUNET_free (sig);
  GNUNET_CRYPTO_rsa_key_free (bob_key);
  GNUNET_CRYPTO_rsa_key_free (alice_key);
}
/**
 * Callback to be called when the requested peer information is available
 *
 * @param cb_cls the closure from GNUNET_TETSBED_peer_get_information()
 * @param op the operation this callback corresponds to
 * @param pinfo the result; will be NULL if the operation has failed
 * @param emsg error message if the operation has failed; will be NULL if the
 *          operation is successfull
 */
static void 
peerinfo_cb (void *cb_cls, struct GNUNET_TESTBED_Operation *op,
	     const struct GNUNET_TESTBED_PeerInformation *pinfo,
	     const char *emsg)
{
  int res;
  GNUNET_assert (GNUNET_TESTBED_PIT_CONFIGURATION == pinfo->pit);
  if (GNUNET_NO == dave_is_setup)
    res = setup_dave (pinfo->result.cfg);
  else if (GNUNET_NO == bob_is_setup)
    res = setup_bob (pinfo->result.cfg);
  else
    res = setup_alice (pinfo->result.cfg);
  
  if (get_cfg_ops[0] == op)
    get_cfg_ops[0] = NULL;
  else if (get_cfg_ops[1] == op)
    get_cfg_ops[1] = NULL;
  else
    get_cfg_ops[2] = NULL;
  GNUNET_TESTBED_operation_done (op);
  op = NULL;
  if (GNUNET_SYSERR == res)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to setup peer \n");
    end_badly_now();
  }
  else
    connect_peers ();
  /*if (get_cfg_ops[0] == op)
  {
    GNUNET_assert (GNUNET_TESTBED_PIT_CONFIGURATION == pinfo->pit);
    res = setup_dave (pinfo->result.cfg);
    GNUNET_TESTBED_operation_done (get_cfg_ops[0]);
    get_cfg_ops[0] = NULL;
    if (GNUNET_SYSERR == res)
    {
      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to setup dave \n");
      end_badly_now();
    }
    else
    {
      connect_peers ();
    }
  }
  else if (get_cfg_ops[1] == op)
  {
    GNUNET_assert (GNUNET_TESTBED_PIT_CONFIGURATION == pinfo->pit);
    res = setup_bob (pinfo->result.cfg);
    GNUNET_TESTBED_operation_done (get_cfg_ops[1]);
    get_cfg_ops[1] = NULL;
    if (GNUNET_SYSERR == res)
    {
      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to setup dave \n");
      end_badly_now();
    }
    else
    {
      connect_peers ();
    }
  }
  else if (get_cfg_ops[2] == op)
  {
    GNUNET_assert (GNUNET_TESTBED_PIT_CONFIGURATION == pinfo->pit);
    res = setup_alice (pinfo->result.cfg);
    GNUNET_TESTBED_operation_done (get_cfg_ops[2]);
    get_cfg_ops[2] = NULL;
    if (GNUNET_SYSERR == res)
    {
      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to setup dave \n");
      end_badly_now();
    }
    else
    {
      connect_peers ();
    }
  }*/
}
void do_check (void *cls,
              const struct GNUNET_CONFIGURATION_Handle *ccfg,
              struct GNUNET_TESTING_Peer *peer)
{
  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded our_pkey;
  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded alice_pkey;
  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded bob_pkey;
  struct GNUNET_CRYPTO_RsaPrivateKey *our_key;
  struct GNUNET_CRYPTO_RsaPrivateKey *alice_key;
  struct GNUNET_CRYPTO_RsaPrivateKey *bob_key;
  struct GNUNET_CRYPTO_ShortHashCode bob_hash;
  struct GNUNET_CRYPTO_ShortHashCode alice_hash;
  struct GNUNET_CRYPTO_RsaSignature *sig;
  char* our_keyfile;

  cfg = ccfg;
  die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Running test\n");

  /* put records into namestore */
  namestore_handle = GNUNET_NAMESTORE_connect(cfg);
  if (NULL == namestore_handle)
  {
    GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to connect to namestore\n");
    end_badly_now();
    return;
  }

  if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns",
                                                          "ZONEKEY",
                                                          &our_keyfile))
  {
    GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n");
    end_badly_now();
    return;
  }

  our_key = GNUNET_CRYPTO_rsa_key_create_from_file (our_keyfile);
  GNUNET_free(our_keyfile);

  bob_key = GNUNET_CRYPTO_rsa_key_create_from_file (KEYFILE_BOB);
  alice_key = GNUNET_CRYPTO_rsa_key_create_from_file (KEYFILE_ALICE);

  GNUNET_CRYPTO_rsa_key_get_public (our_key, &our_pkey);
  GNUNET_CRYPTO_rsa_key_get_public (alice_key, &alice_pkey);
  GNUNET_CRYPTO_rsa_key_get_public (bob_key, &bob_pkey);

  struct GNUNET_NAMESTORE_RecordData rd;
  char* ip = TEST_IP;
  struct in_addr *web = GNUNET_malloc (sizeof(struct in_addr));
  rd.expiration_time = UINT64_MAX;
  GNUNET_assert (1 == inet_pton (AF_INET, ip, web));

  GNUNET_CRYPTO_short_hash(&bob_pkey, sizeof(bob_pkey), &bob_hash);

  rd.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode);
  rd.data = &bob_hash;
  rd.record_type = GNUNET_GNS_RECORD_PKEY;
  rd.flags = GNUNET_NAMESTORE_RF_AUTHORITY;

  /* put bob into our zone */
  GNUNET_NAMESTORE_record_create (namestore_handle,
                                  our_key,
                                  TEST_AUTHORITY_BOB,
                                  &rd,
                                  NULL,
                                  NULL);

  /* put alice into bobs zone */
  GNUNET_CRYPTO_short_hash(&alice_pkey, sizeof(alice_pkey), &alice_hash);
  rd.data = &alice_hash;
  sig = GNUNET_NAMESTORE_create_signature(bob_key, GNUNET_TIME_UNIT_FOREVER_ABS, TEST_AUTHORITY_ALICE,
                                          &rd, 1);

  GNUNET_NAMESTORE_record_put (namestore_handle,
                               &bob_pkey,
                               TEST_AUTHORITY_ALICE,
                               GNUNET_TIME_UNIT_FOREVER_ABS,
                               1,
                               &rd,
                               sig,
                               NULL,
                               NULL);

  GNUNET_free (sig);

  /* put www A record and PSEU into alice's zone */

  rd.data_size = sizeof(struct in_addr);
  rd.data = web;
  rd.record_type = GNUNET_DNSPARSER_TYPE_A;
  sig = GNUNET_NAMESTORE_create_signature(alice_key,GNUNET_TIME_UNIT_FOREVER_ABS,  TEST_RECORD_NAME,
                                          &rd, 1);

  GNUNET_NAMESTORE_record_put (namestore_handle,
                               &alice_pkey,
                               TEST_RECORD_NAME,
                               GNUNET_TIME_UNIT_FOREVER_ABS,
                               1,
                               &rd,
                               sig,
                               NULL,
                               NULL);

  rd.data_size = strlen(TEST_ALICE_PSEU);
  rd.data = TEST_ALICE_PSEU;
  rd.record_type = GNUNET_GNS_RECORD_PSEU;
  GNUNET_free(sig);

  sig = GNUNET_NAMESTORE_create_signature(alice_key,GNUNET_TIME_UNIT_FOREVER_ABS,  "",
                                          &rd, 1);

  GNUNET_NAMESTORE_record_put (namestore_handle,
                               &alice_pkey,
                               "",
                               GNUNET_TIME_UNIT_FOREVER_ABS,
                               1,
                               &rd,
                               sig,
                               &commence_testing,
                               NULL);

  GNUNET_free (web);
  GNUNET_free (sig);
  GNUNET_CRYPTO_rsa_key_free (alice_key);
  GNUNET_CRYPTO_rsa_key_free (bob_key);
  GNUNET_CRYPTO_rsa_key_free (our_key);
}