while (true) {
    unpacker = GetUnpacker(layer);
    if (unpacker) {
      if (unpacker->FindDataPacket(qtpath, packet_type, channel, data_loc)) {
        return true;
      } else {
        layer = parent_layer_[layer];
        if (layer == 0) {
          return false;
        }
      }
    } else {
      std::cerr << "No unpacker for " << layer << std::endl;
      return false;
    }
  }

// Uses unpacker to get data from the glc file.

#include "./glc_unpacker.h"
#include <iostream>  // NOLINT(readability/streams)
#include <map>
#include <sstream>  // NOLINT(readability/streams)
#include <string>
#include <cstring>
#include <cassert>
#include "./file_package.h"
#include "./file_unpacker.h"
#include "./glc_reader.h"

const char* LAYER_INFO = "earth/layer_info.txt";
// Types for layers
const char* IMAGERY_LAYER_TYPE = "IMAGE";
const char* TERRAIN_LAYER_TYPE = "TERRAIN";
const char* VECTOR_LAYER_TYPE = "VECTOR";
const char* MAP_LAYER_TYPE = "MAP";

// GEE identifying bytes in all glxs.
const std::uint32_t GEE_ID = 0x47454547;
const std::uint64_t GEE_ID_OFFSET = 8;

/**
 * Constructor. Load the index to all of the files and
 * packages in the composite file. If this is a package file,
 * treat it as a composite with a single layer that is the
 * whole file. If files_only flag is true, only read
 * top level files (not used for serving tiles).
 */
GlcUnpacker::GlcUnpacker(const GlcReader& glc_reader,
                         bool is_composite,
                         bool files_only)
    : glc_reader_(glc_reader),
    is_composite_(is_composite),
    is_gee_(false),
    is_2d_(false),
    is_3d_(false) {
  length_ = glc_reader_.Size();

  // Check file is a GEE file first.
  std::uint32_t id;
  std::int64_t offset = length_ - GEE_ID_OFFSET;
  if (!glc_reader_.ReadData(&id, offset, sizeof(id))) {
    std::cerr << "Unable to read file id." << std::endl;
    return;
  }
  if (id != GEE_ID) {
    std::cerr << "Id does not match expected GEE id." << std::endl;
    return;
  } else {
    is_gee_ = true;
  }

  // Get offset to index.
  offset = length_ - Package::kIndexOffsetOffset;
  std::uint32_t num_files = 0;
  std::int64_t index_offset;
  if (!glc_reader_.ReadData(
      &index_offset, offset, Package::kIndexOffsetSize)) {
    std::cerr << "Unable to read file offset." << std::endl;
    return;
  }
  // If negative, use as offset from end of file.
  if (index_offset < 0) {
    reader_offset_ = length_ + index_offset;
  } else {
    reader_offset_ = index_offset;
  }

  // Read in the index header.
  if (!Read(&num_files, sizeof(num_files))) {
    std::cerr << "Unable to read number of files in file." << std::endl;
    return;
  }

  // Read in the index entries.
  std::string path;
  PackageFileLoc file_loc;
  for (std::uint32_t i = 0; i < num_files; ++i) {
    // Read in the relative path of the index entry.
    std::uint16_t path_len;
    if (!Read(&path_len, sizeof(path_len))) {
      std::cerr << "Unable to read file name length." << std::endl;
      return;
    }

    path.resize(path_len);
    if (!Read(&path[0], path_len)) {
      std::cerr << "Unable to read file name." << std::endl;
      return;
    }

    // Read in the size and offset of the index entry.
    if (!Read(&file_loc, sizeof(PackageFileLoc))) {
      std::cerr << "Unable to read file size and offset." << std::endl;
      return;
    }
    // If offsets in index are negative, add them to file size to get offset
    // relative to beginning of file.
    file_loc.NormalizeNegativeOffset(length_);
    index_[path] = file_loc;
  }

  // For a real composite, set up file_unpacker for each layer.
  if (is_composite) {
    SetUpLayerUnpackers(files_only);

  // If this is just a glb or glm, set up a single layer 0.
  } else {
    std::string suffix = glc_reader_.Suffix();
    if (suffix == "glb") {
      is_3d_ = true;
    } else if (suffix == "glm")  {
      is_2d_ = true;
    } else {
      std::cout << "Unknown suffix: " << suffix << std::endl;
      return;
    }

    if (files_only) {
      return;
    }

    unpacker_index_[0] = new FileUnpacker(glc_reader_, 0, length_);
  }

  // Read in earth/info.txt
  std::map<std::string, PackageFileLoc>::iterator it
      = index_.find("earth/info.txt");
  if (it != index_.end()) {
    file_loc = it->second;
    if (!glc_reader_.Read(&info_, file_loc.Offset(), file_loc.Size())) {
      std::cerr << "Unable to read earth/info.txt" << std::endl;
    }
  }
}

GlcUnpacker::~GlcUnpacker() {
  std::map<int, FileUnpacker*>::iterator it;
  for (it = unpacker_index_.begin(); it != unpacker_index_.end(); ++it) {
    delete it->second;
  }
}

/**
 * Helper method for the Constructor that creates a file_unpacker for each
 * layer listed in the layer_info.txt file.
 */
void GlcUnpacker::SetUpLayerUnpackers(bool files_only) {
  PackageFileLoc file_loc;
  if (!FindFile(LAYER_INFO, &file_loc)) {
    std::cerr << "Unable to load layer info." << std::endl;
    return;
  }

  std::string layer_info;
  if (!glc_reader_.Read(&layer_info, file_loc.Offset(), file_loc.Size())) {
    std::cerr << "Unable to read layer info." << std::endl;
    return;
  }

  std::stringstream stream(
      layer_info, std::stringstream::in);

  std::string layer_name;
  std::string layer_path;
  std::string layer_type;
  int layer_id;
  int parent_layer;

  // Read in layer info.
  while (true) {
    stream >> layer_name;
    stream >> layer_path;
    stream >> layer_type;
    stream >> layer_id;

    // Ensure that a full line of data was available.
    if (stream.eof()) {
      break;
    }

    stream >> parent_layer;

    // Open new unpacker for glb layer.
    if ((layer_type == IMAGERY_LAYER_TYPE) ||
        (layer_type == TERRAIN_LAYER_TYPE) ||
        (layer_type == VECTOR_LAYER_TYPE) ||
        (layer_type == MAP_LAYER_TYPE)) {
      if (layer_type == MAP_LAYER_TYPE) {
        is_2d_ = true;
      } else {
        is_3d_ = true;
      }
      if (!files_only) {
        std::map<std::string, PackageFileLoc>::iterator it =
            index_.find(layer_path);
        if (it != index_.end()) {
          unpacker_index_[layer_id] = new FileUnpacker(
              glc_reader_, it->second.Offset(), it->second.Size());
          parent_layer_[layer_id] = parent_layer;
          layer_type_[layer_id] = layer_type;
        } else {
          std::cerr << "Missing layer: " << layer_path << std::endl;
        }
      }
    } else if (layer_type == "DBROOT") {
      meta_dbroot_path_ = layer_path;
    }
  }
}

/**
 * Helper for reading in consecutive fields from the glc file.
 */
bool GlcUnpacker::Read(void* data, std::uint64_t size) {
  if (glc_reader_.ReadData(data, reader_offset_, size)) {
    reader_offset_ += size;
    return true;
  }
  return false;
}

/**
 * Find data packet and set offset and size for the packet. Data packets can
 * be imagery, terrain or vectors.
 */
bool GlcUnpacker::FindDataPacket(const char* qtpath,
                                 int packet_type,
                                 int channel,
                                 int layer,
                                 PackageFileLoc* data_loc) {
  if (!is_gee_) {
    std::cerr << "Not a GEE file." << std::endl;
    return false;
  }

  FileUnpacker* unpacker;

}

/**
 * Find map data packet and set offset and size for the packet.
 * Map data packets can be imagery or vectors.
 */
bool GlcUnpacker::FindMapDataPacket(const char* qtpath,
                                    int packet_type,
                                    int channel,
                                    int layer,
                                    PackageFileLoc* data_loc) {
  if (!is_gee_) {
    std::cerr << "Not a GEE file." << std::endl;
    return false;
  }

  FileUnpacker* unpacker;
  while (true) {
    unpacker = GetUnpacker(layer);
    if (unpacker) {
      if (unpacker->FindMapDataPacket(qtpath, packet_type, channel, data_loc)) {
        return true;
      } else {
        layer = parent_layer_[layer];
        if (layer == 0) {
          return false;
        }
      }
    } else {
      return false;
    }
  }
}

void GlcUnpacker::MapDataPacketWalker(const map_packet_walker& walker) const
{
  if (!is_gee_) {
    std::cerr << "Not a GEE file." << std::endl;
    return;
  }

  for( auto& index_item : unpacker_index_) {
    if (index_item.second->MapDataPacketWalker(index_item.first, walker) == true) {
      break;
    }
  }
}

void GlcUnpacker::MapDataPacketWalker(int layer, const map_packet_walker& walker) const
{
  if (!is_gee_) {
    std::cerr << "Not a GEE file." << std::endl;
    return;
  }
  auto iter = unpacker_index_.find(layer);
  if (iter == unpacker_index_.end()) {
    std::cerr << "Layer " << layer << " not found." << std::endl;
    return;
  }
  iter->second->MapDataPacketWalker(layer, walker);
}

/**
 * Find the names of all files in each layer of a globe.
 */
bool GlcUnpacker::MapFileWalker(const map_file_walker& walker)
{
    for( auto& index_item : unpacker_index_) {
        if (MapFileWalker(index_item.first, walker)) {
          return true;
        }
    }
    return false;
}

bool GlcUnpacker::MapFileWalker(int layer, const map_file_walker& walker)
{
  FileUnpacker* unpacker = GetUnpacker(layer);

  for (int i = 0; i < unpacker->IndexSize(); ++i) {
    const char *package_file = unpacker->IndexFile(i);

    if (walker(layer, package_file) != true) {
      return true;
    }
  }
  return false;
}

/**
 * Find qtp packet and set offset and size for the packet. Qtp packets can
 * be quadtree packets or a dbroot packet.
 */
bool GlcUnpacker::FindQtpPacket(const char* qtpath,
                                int packet_type,
                                int channel,
                                int layer,
                                PackageFileLoc* data_loc) {
  if (!is_gee_) {
    std::cerr << "Not a GEE file." << std::endl;
    return false;
  }

  FileUnpacker* unpacker;
  while (true) {
    unpacker = GetUnpacker(layer);
    if (unpacker) {
      if (unpacker->FindQtpPacket(qtpath, packet_type, channel, data_loc)) {
        return true;
      } else {
        layer = parent_layer_[layer];
        if (layer == 0) {
          return false;
        }
      }
    } else {
      return false;
    }
  }
}

/**
 * Find max LOD where there is data of some kind at the given address.
 * Does not look at resolutions higher than the given address so
 * possible values are 0 to len(qtpath) - 1. As for all other qtpaths,
 * expects leading "0".
 */
int GlcUnpacker::MaxResolutionLod(const char* qtpath, bool is_2d) {
  std::string new_qtpath(qtpath);
  size_t len = new_qtpath.size();
  int lod = len - 1;
  for (size_t i = 1; i < len; ++i) {
    if (HasData(new_qtpath.c_str(), is_2d)) {
      return lod;
    }
    new_qtpath = new_qtpath.substr(0, lod);
    --lod;
  }

  return lod;
}

/**
 * Returns whether there are any data at the given address.
 */
bool GlcUnpacker::HasData(const char* qtpath, bool is_2d) {
  std::map<int, FileUnpacker*>::iterator it;
  for (it = unpacker_index_.begin(); it != unpacker_index_.end(); ++it) {
    int layer_id = it->first;

    // Skip 2d if we are looking for 3d data.
    if (layer_type_[layer_id] == MAP_LAYER_TYPE) {
      if (!is_2d) {
        continue;
      }
    // Skip 3d if we are looking for 2d data.
    } else {
      if (is_2d) {
        continue;
      }
    }

    FileUnpacker* unpacker = GetUnpacker(layer_id);
    if (unpacker->HasData(qtpath, is_2d)) {
      return true;
    }
  }

  return false;
}

/**
 * Find layer file and set the offset and size for retrieving the file from the
 * package.
 */
bool GlcUnpacker::FindLayerFile(const char* file_name,
                                int layer,
                                PackageFileLoc* file_loc) {
  FileUnpacker* unpacker = GetUnpacker(layer);
  if (unpacker) {
    return unpacker->FindFile(file_name, file_loc);
  } else {
    return false;
  }
}

/**
 * Find file and set the offset and size for retrieving the file from the
 * package.
 */
bool GlcUnpacker::FindFile(const char* file_name,
                           PackageFileLoc* file_loc) const {
  std::map<std::string, PackageFileLoc>::const_iterator it;
  it = index_.find(file_name);
  if (it != index_.end()) {
    file_loc->Set(it->second.Offset(), it->second.Size());
    return true;
  } else {
    std::cerr << "Unable to find: " << file_name << std::endl;
    file_loc->Set(0, 0);
    return false;
  }
}

/**
 * Find meta dbroot for the composite globe.
 */
bool GlcUnpacker::FindMetaDbRoot(PackageFileLoc* data_loc) {
  if (!meta_dbroot_path_.empty()) {
    return FindFile(meta_dbroot_path_.c_str(), data_loc);
  }

  data_loc->Set(0, 0);
  return false;
}

/**
 * Find dbroot for the composite globe.
 */
bool GlcUnpacker::FindDbRoot(PackageFileLoc* data_loc) {
  if (is_composite_) {
    return FindMetaDbRoot(data_loc);
  } else if (is_3d_) {
    assert(unpacker_index_[0]);
    return unpacker_index_[0]->FindDbRoot(data_loc);
  }

  data_loc->Set(0, 0);
  return false;
}

/**
 * Get idx-th file in index. Assumes iteration order is stable if
 * index is unchanged.
 */
const char* GlcUnpacker::IndexFile(int idx) const {
  std::map<std::string, PackageFileLoc>::const_iterator it;
  it = index_.begin();
  for (int i = 0; (i < idx) && (it != index_.end()); ++i, ++it) ;

  if (it != index_.end()) {
    return it->first.c_str();
  }

  return "";
}

/**
 * Get the unpacker associated with the given layer.  Returns null
 * if it is not found.
 */
FileUnpacker* GlcUnpacker::GetUnpacker(int layer) {
  std::map<int, FileUnpacker*>::iterator it = unpacker_index_.find(layer);
  if (it == unpacker_index_.end()) {
    std::cerr << "No layer " << layer << std::endl;
    return 0;
  }

  return it->second;
}

/**
 * Get number of layers in current globe or map.
 */
int GlcUnpacker::NumberOfLayers() {
  return unpacker_index_.size();
}

/**
 * Get nth layer's index.
 */
int GlcUnpacker::LayerIndex(int n) {
  if ((n < 0) || (n >= static_cast<int>(unpacker_index_.size()))) {
    return -1;
  }

  std::map<int, FileUnpacker*>::iterator it = unpacker_index_.begin();
  for (int j = 0; j < n; ++j, ++it) ;
  return it->first;
}

/**
 * Extracts the first timestamp from the info file, which should
 * be a GMT timestamp. Assumes date begins with 20 (fails in 2100).
 * The beginning of the info file is quite structured so this
 * should be reliable. It starts with 3 lines similar to the
 * following:
 *   Portable Globe
 *   2012-02-24 01:26:07 GMT
 */
std::string GlcUnpacker::ExtractDateFromInfo() {
  size_t idx = info_.find("\n20");
  return info_.substr(idx + 1, 4)
       + info_.substr(idx + 6, 2)
       + info_.substr(idx + 9, 2)
       + info_.substr(idx + 12, 2)
       + info_.substr(idx + 15, 2)
       + info_.substr(idx + 18, 2);
}

/**
 * Calculates a crc for the info data.
 */
 std::uint32_t GlcUnpacker::InfoCrc() {
  std::uint32_t crc = 0;
  unsigned char* ptr = reinterpret_cast<unsigned char*>(&info_[0]);
  for (std::uint32_t i = 0; i < info_.size(); ++i) {
    // Use the full bit space by shifting to one of the
    std::uint32_t value = *ptr++ << ((i & 3) * 8);
    crc += value;
  }
  return crc;
}

/**
 * Calculate the id associated with this file. Assumes that the bundle
 * contains a file called "earth/info.txt" which uniquely identifies
 * the file. If not, it returns "noinfo-<file_size>".
 */
const char* GlcUnpacker::Id() {
  std::stringstream sstream;
  std::string info;
  if (id_.empty()) {
    if (info_.empty()) {
      sstream << "noinfo";
    } else {
      sstream << ExtractDateFromInfo();
      sstream << "-" << std::hex << InfoCrc();
    }
    sstream << "-" << std::hex << length_;
    id_ = sstream.str();
  }

  return id_.c_str();
}

std::map<int, std::string> GlcUnpacker::getKmlData() {
  std::map<int, std::string> kmlData;

  for (auto &mapLayer : unpacker_index_) {
    FileUnpacker *layerFile = mapLayer.second;
    auto layerId = mapLayer.first;

    for (int i = 0; i < layerFile->IndexSize(); ++i) {
      auto package_file = layerFile->IndexFile(i);

      if (strcmp(package_file, "earth/polygon.kml")) {
        continue;
      }

      PackageFileLoc file_loc;
      if (layerFile->FindFile(package_file, &file_loc)) {
        auto& kmlDataStr = kmlData[layerId];
        if (!glc_reader_.Read(&kmlDataStr, file_loc.Offset(), file_loc.Size())) {
            std::cerr << "Unable to read kml file data." << std::endl;
        }
      } else {
          std::cerr << "Unable to to position to the earth/polygon.kml file data." << std::endl;
      }

      break;
    }
  }

  return kmlData;
}


/*

 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "NonConnectedState.h"
#include "ConnectingState.h"

#include "framework/Tokeniser.h"
#include "framework/ConsoleBackend.h"
#include "framework/LoggingInstance.h"

namespace Ember {

NonConnectedState::NonConnectedState(ServerServiceSignals& signals, Session& session) :
		Connect("connect", this, "Connect to a server."),
		mSignals(signals),
		mSession(session),
		mChildState(nullptr) {
}

void NonConnectedState::destroyChildState() {
	//Make sure to sever the connection, so that we don't end up in an infinite loop if something goes wrong when shutting down.
	mDisconnectedConnection.disconnect();
	if (mChildState) {
		mChildState->destroyChildState();
		mChildState.reset();
	}
}

ServerServiceSignals& NonConnectedState::getSignals() const {
	return mSignals;
}

IState& NonConnectedState::getTopState() {
	if (mChildState) {
		return mChildState->getTopState();
	}
	return *this;
}

bool NonConnectedState::connect(const std::string& host, short port) {
	destroyChildState();
	mChildState = std::make_unique<ConnectingState>(*this, mSession, host, port);
	if (!mChildState->connect()) {
		destroyChildState();
	} else {
		mDisconnectedConnection.disconnect();
		mDisconnectedConnection = mChildState->getConnection().Disconnected.connect(sigc::mem_fun(*this, &NonConnectedState::disconnected));
	}

	return mChildState != nullptr;
}

bool NonConnectedState::connectLocal(const std::string& socket) {
	destroyChildState();
	mChildState = std::make_unique<ConnectingState>(*this, mSession, socket);
	if (!mChildState->connect()) {
		destroyChildState();
	} else {
		mDisconnectedConnection.disconnect();
		mDisconnectedConnection = mChildState->getConnection().Disconnected.connect(sigc::mem_fun(*this, &NonConnectedState::disconnected));
	}

	return mChildState != nullptr;
}

void NonConnectedState::disconnected() {
	S_LOG_INFO("Disconnected");

	ConsoleBackend::getSingleton().pushMessage("Disconnected from server.", "important");

	destroyChildState();
}

void NonConnectedState::runCommand(const std::string& command, const std::string& args) {
	// Connect command
	if (Connect == command) {
		// Split string into server / port pair
		Tokeniser tokeniser = Tokeniser();
		tokeniser.initTokens(args);
		std::string server = tokeniser.nextToken();
		std::string port = tokeniser.remainingTokens();
		std::string msg;
		msg = "Connecting to: [" + server + "]";
		ConsoleBackend::getSingleton().pushMessage(msg, "info");
		if (port.empty())
			connect(server);
		else
			connect(server, (short) std::stoi(port));

		// Disonnect command
	}
}

void NonConnectedState::disconnect() {
}

bool NonConnectedState::logout()

void NonConnectedState::takeTransferredCharacter(const Eris::TransferInfo& transferInfo) {
}

void NonConnectedState::transfer(const Eris::TransferInfo& transferInfo) {
	//Start by disconnecting from current server, and reconnecting to new server.
	destroyChildState();
	connect(transferInfo.getHost(), static_cast<short>(transferInfo.getPort()));
}

}


/*

 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "NonConnectedState.h"
#include "ConnectingState.h"

#include "framework/Tokeniser.h"
#include "framework/ConsoleBackend.h"
#include "framework/LoggingInstance.h"

namespace Ember {

NonConnectedState::NonConnectedState(ServerServiceSignals& signals, Session& session) :
		Connect("connect", this, "Connect to a server."),
		mSignals(signals),
		mSession(session),
		mChildState(nullptr) {
}

void NonConnectedState::destroyChildState() {
	//Make sure to sever the connection, so that we don't end up in an infinite loop if something goes wrong when shutting down.
	mDisconnectedConnection.disconnect();
	if (mChildState) {
		mChildState->destroyChildState();
		mChildState.reset();
	}
}

ServerServiceSignals& NonConnectedState::getSignals() const {
	return mSignals;
}

IState& NonConnectedState::getTopState() {
	if (mChildState) {
		return mChildState->getTopState();
	}
	return *this;
}

bool NonConnectedState::connect(const std::string& host, short port) {
	destroyChildState();
	mChildState = std::make_unique<ConnectingState>(*this, mSession, host, port);
	if (!mChildState->connect()) {
		destroyChildState();
	} else {
		mDisconnectedConnection.disconnect();
		mDisconnectedConnection = mChildState->getConnection().Disconnected.connect(sigc::mem_fun(*this, &NonConnectedState::disconnected));
	}

	return mChildState != nullptr;
}

bool NonConnectedState::connectLocal(const std::string& socket) {
	destroyChildState();
	mChildState = std::make_unique<ConnectingState>(*this, mSession, socket);
	if (!mChildState->connect()) {
		destroyChildState();
	} else {
		mDisconnectedConnection.disconnect();
		mDisconnectedConnection = mChildState->getConnection().Disconnected.connect(sigc::mem_fun(*this, &NonConnectedState::disconnected));
	}

	return mChildState != nullptr;
}

void NonConnectedState::disconnected() {
	S_LOG_INFO("Disconnected");

	ConsoleBackend::getSingleton().pushMessage("Disconnected from server.", "important");

	destro

}

void NonConnectedState::runCommand(const std::string& command, const std::string& args) {
	// Connect command
	if (Connect == command) {
		// Split string into server / port pair
		Tokeniser tokeniser = Tokeniser();
		tokeniser.initTokens(args);
		std::string server = tokeniser.nextToken();
		std::string port = tokeniser.remainingTokens();
		std::string msg;
		msg = "Connecting to: [" + server + "]";
		ConsoleBackend::getSingleton().pushMessage(msg, "info");
		if (port.empty())
			connect(server);
		else
			connect(server, (short) std::stoi(port));

		// Disonnect command
	}
}

void NonConnectedState::disconnect() {
}

bool NonConnectedState::logout() {
	return false;
}

void NonConnectedState::takeTransferredCharacter(const Eris::TransferInfo& transferInfo) {
}

void NonConnectedState::transfer(const Eris::TransferInfo& transferInfo) {
	//Start by disconnecting from current server, and reconnecting to new server.
	destroyChildState();
	connect(transferInfo.getHost(), static_cast<short>(transferInfo.getPort()));
}

}


{
        if (m_valid) {
            auto pubkey = m_privateKey->public_value();
            return QByteArray(reinterpret_cast<char*>(pubkey.data()), pubkey.size());
        }
        return {};
    }

/*
 *
 */

#include "SessionCipher.h"

#include "crypto/Random.h"
#include "crypto/SymmetricCipher.h"

#include <QDebug>
#include <botan/dh.h>
#include <botan/pk_ops.h>

namespace FdoSecrets
{
    // XXX: remove the redundant definitions once we are at C++17
    constexpr char PlainCipher::Algorithm[];
    constexpr char DhIetf1024Sha256Aes128CbcPkcs7::Algorithm[];

    DhIetf1024Sha256Aes128CbcPkcs7::DhIetf1024Sha256Aes128CbcPkcs7(const QByteArray& clientPublicKey)
    {
        try {
            m_privateKey.reset(new Botan::DH_PrivateKey(*randomGen()->getRng(), Botan::DL_Group("modp/ietf/1024")));
            m_valid = updateClientPublicKey(clientPublicKey);
        } catch (std::exception& e) {
            qCritical("Failed to derive DH key: %s", e.what());
            m_privateKey.reset();
            m_valid = false;
        }
    }

    bool DhIetf1024Sha256Aes128CbcPkcs7::updateClientPublicKey(const QByteArray& clientPublicKey)
    {
        if (!m_privateKey) {
            return false;
        }

        try {
            Botan::secure_vector<uint8_t> salt(32, '\0');
            auto dhka = m_privateKey->create_key_agreement_op(*randomGen()->getRng(), "HKDF(SHA-256)", "");
            auto aesKey = dhka->agree(16,
                                      reinterpret_cast<const uint8_t*>(clientPublicKey.constData()),
                                      clientPublicKey.size(),
                                      salt.data(),
                                      salt.size());
            m_aesKey = QByteArray(reinterpret_cast<char*>(aesKey.data()), aesKey.size());
            return true;
        } catch (std::exception& e) {
            qCritical("Failed to update client public key: %s", e.what());
            return false;
        }
    }

    Secret DhIetf1024Sha256Aes128CbcPkcs7::encrypt(const Secret& input)
    {
        Secret output = input;
        output.parameters.clear();
        output.value.clear();

        SymmetricCipher encrypter;
        auto IV = randomGen()->randomArray(SymmetricCipher::defaultIvSize(SymmetricCipher::Aes128_CBC));
        if (!encrypter.init(SymmetricCipher::Aes128_CBC, SymmetricCipher::Encrypt, m_aesKey, IV)) {
            qWarning() << "Error encrypt: " << encrypter.errorString();
            return output;
        }

        output.parameters = IV;
        output.value = input.value;
        if (!encrypter.finish(output.value)) {
            qWarning() << "Error encrypt: " << encrypter.errorString();
            return output;
        }

        return output;
    }

    Secret DhIetf1024Sha256Aes128CbcPkcs7::decrypt(const Secret& input)
    {
        SymmetricCipher decrypter;
        if (!decrypter.init(SymmetricCipher::Aes128_CBC, SymmetricCipher::Decrypt, m_aesKey, input.parameters)) {
            qWarning() << "Error decoding: " << decrypter.errorString();
            return input;
        }

        Secret output = input;
        output.parameters.clear();
        if (!decrypter.finish(output.value)) {
            qWarning() << "Error decoding: " << decrypter.errorString();
            return input;
        }
        return output;
    }

    bool DhIetf1024Sha256Aes128CbcPkcs7::isValid() const
    {
        return m_valid;
    }

    QVariant DhIetf1024Sha256Aes128CbcPkcs7::negotiationOutput() const


try {
            m_privateKey.reset(new Botan::DH_PrivateKey(*randomGen()->getRng(), Botan::DL_Group("modp/ietf/1024")));
            m_valid = updateClientPublicKey(clientPublicKey);
        } catch (std::exception& e) {
            qCritical("Failed to derive DH key: %s", e.what());
            m_privateKey.reset();
            m_valid = false;
        }

/*
 *
 */

#include "SessionCipher.h"

#include "crypto/Random.h"
#include "crypto/SymmetricCipher.h"

#include <QDebug>
#include <botan/dh.h>
#include <botan/pk_ops.h>

namespace FdoSecrets
{
    // XXX: remove the redundant definitions once we are at C++17
    constexpr char PlainCipher::Algorithm[];
    constexpr char DhIetf1024Sha256Aes128CbcPkcs7::Algorithm[];

    DhIetf1024Sha256Aes128CbcPkcs7::DhIetf1024Sha256Aes128CbcPkcs7(const QByteArray& clientPublicKey)
    {

    }

    bool DhIetf1024Sha256Aes128CbcPkcs7::updateClientPublicKey(const QByteArray& clientPublicKey)
    {
        if (!m_privateKey) {
            return false;
        }

        try {
            Botan::secure_vector<uint8_t> salt(32, '\0');
            auto dhka = m_privateKey->create_key_agreement_op(*randomGen()->getRng(), "HKDF(SHA-256)", "");
            auto aesKey = dhka->agree(16,
                                      reinterpret_cast<const uint8_t*>(clientPublicKey.constData()),
                                      clientPublicKey.size(),
                                      salt.data(),
                                      salt.size());
            m_aesKey = QByteArray(reinterpret_cast<char*>(aesKey.data()), aesKey.size());
            return true;
        } catch (std::exception& e) {
            qCritical("Failed to update client public key: %s", e.what());
            return false;
        }
    }

    Secret DhIetf1024Sha256Aes128CbcPkcs7::encrypt(const Secret& input)
    {
        Secret output = input;
        output.parameters.clear();
        output.value.clear();

        SymmetricCipher encrypter;
        auto IV = randomGen()->randomArray(SymmetricCipher::defaultIvSize(SymmetricCipher::Aes128_CBC));
        if (!encrypter.init(SymmetricCipher::Aes128_CBC, SymmetricCipher::Encrypt, m_aesKey, IV)) {
            qWarning() << "Error encrypt: " << encrypter.errorString();
            return output;
        }

        output.parameters = IV;
        output.value = input.value;
        if (!encrypter.finish(output.value)) {
            qWarning() << "Error encrypt: " << encrypter.errorString();
            return output;
        }

        return output;
    }

    Secret DhIetf1024Sha256Aes128CbcPkcs7::decrypt(const Secret& input)
    {
        SymmetricCipher decrypter;
        if (!decrypter.init(SymmetricCipher::Aes128_CBC, SymmetricCipher::Decrypt, m_aesKey, input.parameters)) {
            qWarning() << "Error decoding: " << decrypter.errorString();
            return input;
        }

        Secret output = input;
        output.parameters.clear();
        if (!decrypter.finish(output.value)) {
            qWarning() << "Error decoding: " << decrypter.errorString();
            return input;
        }
        return output;
    }

    bool DhIetf1024Sha256Aes128CbcPkcs7::isValid() const
    {
        return m_valid;
    }

    QVariant DhIetf1024Sha256Aes128CbcPkcs7::negotiationOutput() const
    {
        if (m_valid) {
            auto pubkey = m_privateKey->public_value();
            return QByteArray(reinterpret_cast<char*>(pubkey.data()), pubkey.size());
        }
        return {};
    }
} // namespace FdoSecrets


{
	return ""; // matching Get ( SystemDrive )
}

/*
 BELinuxFunctions.cpp
 BaseElements Plug-In

 For conditions of distribution and use please see the copyright notice in BEPlugin.cpp

 http://example.com

 */

#include "BEPluginGlobalDefines.h"
#include "BELinuxFunctions.h"
#include "BELinuxFunctionStrings.h"
#include "BEPluginUtilities.h"
#include "BEPluginException.h"

#include <map>

#include <unistd.h>
#include <limits.h>

using namespace std;

void InitialiseForPlatform ( )
{
}

const std::wstring ClipboardFormats ( void )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return L"";
}

const std::string ClipboardText ( const std::wstring& atype )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return "";
}

const bool SetClipboardText ( const std::string& data, const std::wstring& atype )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return false;
}

const std::vector<unsigned char> ClipboardFile ( const std::wstring& atype )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

    // should never get here
    const std::vector<unsigned char> empty;

	return empty;
}

const bool SetClipboardFile ( const std::vector<unsigned char>& data, const std::wstring& atype )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return false;
}

std::wstring SelectFile ( std::wstring& prompt, std::wstring& in_folder )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return L"";
}

std::wstring SelectFolder ( std::wstring& prompt, std::wstring& in_folder )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return L"";
}

std::wstring SaveFileDialog ( std::wstring& prompt, std::wstring& fileName, std::wstring& inFolder )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return L"";
}

int DisplayDialog ( std::wstring& title, std::wstring& message, std::wstring& ok_button, std::wstring& cancel_button, std::wstring& alternate_button )
{
	return kCommandIsUnavailableError;
}

// Progress Dialog

fmx::errcode DisplayProgressDialog ( const std::wstring& title, const std::wstring& description, const long maximum, const bool can_cancel )
{
	return kCommandIsUnavailableError;
}

fmx::errcode UpdateProgressDialog ( const long value, const std::wstring& description )
{
	return kCommandIsUnavailableError;
}

// user preferences

bool SetPreference ( std::string& key, std::string& value, std::string& domain )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return false;
}

std::string GetPreference ( std::string& key, std::string& domain )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return "";
}

void GetPreference ( std::wstring& key, std::wstring& domain )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );
}

// other

bool OpenURL ( std::wstring& url )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return false;
}

bool OpenFile ( std::wstring& path )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return false;
}

const std::wstring get_machine_name ( )
{

	char host_name [ HOST_NAME_MAX ];
	const size_t error = gethostname ( host_name, HOST_NAME_MAX );

	wchar_t w_host_name [ HOST_NAME_MAX * 4 ];
	if ( error != kErrorUnknown ) {
		const size_t length = mbstowcs ( w_host_name, host_name, HOST_NAME_MAX * 4 );
		if ( length == kErrorUnknown ) {
			throw BEPlugin_Exception ( errno );
		}
	} else {
		throw BEPlugin_Exception ( errno );
	}

	return w_host_name;

}

const std::string get_system_drive ( )

unsigned long Sub_LoadString ( const unsigned long string_id, FMX_Unichar * intoHere, const long intoHereMax )
{
	unsigned long returnResult = 0;

	std::string wanted;
	try {
		wanted = function_strings.at ( string_id );

		if ( kFMXT_AppConfigStr == string_id  || PLUGIN_DESCRIPTION_STRING_ID == string_id ) {
            wanted.replace ( wanted.find ( "%@" ), 2, PLUGIN_DESCRIPTION_STRING_ID_STRING );
		}

	} catch ( exception& /* e */ ) {
		returnResult = kRequestedDataIsMissingError;
	}

	if( (intoHere != NULL) && (intoHereMax > 1) ) {

		fmx::TextUniquePtr text;
		text->Assign ( wanted.c_str() );
		text->GetUnicode ( intoHere, 0, fmx::Text::kSize_End );
		intoHere[wanted.size()] = 0x0000;

	} else {
		returnResult = -123;
	}

	return returnResult;

} // Sub_LinuxLoadString


bool SetPreference ( std::string& key, std::string& value, std::string& domain )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return false;
}

/*
 BELinuxFunctions.cpp
 BaseElements Plug-In

 For conditions of distribution and use please see the copyright notice in BEPlugin.cpp

 http://example.com

 */

#include "BEPluginGlobalDefines.h"
#include "BELinuxFunctions.h"
#include "BELinuxFunctionStrings.h"
#include "BEPluginUtilities.h"
#include "BEPluginException.h"

#include <map>

#include <unistd.h>
#include <limits.h>

using namespace std;

void InitialiseForPlatform ( )
{
}

const std::wstring ClipboardFormats ( void )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return L"";
}

const std::string ClipboardText ( const std::wstring& atype )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return "";
}

const bool SetClipboardText ( const std::string& data, const std::wstring& atype )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return false;
}

const std::vector<unsigned char> ClipboardFile ( const std::wstring& atype )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

    // should never get here
    const std::vector<unsigned char> empty;

	return empty;
}

const bool SetClipboardFile ( const std::vector<unsigned char>& data, const std::wstring& atype )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return false;
}

std::wstring SelectFile ( std::wstring& prompt, std::wstring& in_folder )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return L"";
}

std::wstring SelectFolder ( std::wstring& prompt, std::wstring& in_folder )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return L"";
}

std::wstring SaveFileDialog ( std::wstring& prompt, std::wstring& fileName, std::wstring& inFolder )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return L"";
}

int DisplayDialog ( std::wstring& title, std::wstring& message, std::wstring& ok_button, std::wstring& cancel_button, std::wstring& alternate_button )
{
	return kCommandIsUnavailableError;
}

// Progress Dialog

fmx::errcode DisplayProgressDialog ( const std::wstring& title, const std::wstring& description, const long maximum, const bool can_cancel )
{
	return kCommandIsUnavailableError;
}

fmx::errcode UpdateProgressDialog ( const long value, const std::wstring& description )
{
	return kCommandIsUnavailableError;
}

// user preferences

std::string GetPreference ( std::string& key, std::string& domain )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return "";
}

void GetPreference ( std::wstring& key, std::wstring& domain )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );
}

// other

bool OpenURL ( std::wstring& url )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return false;
}

bool OpenFile ( std::wstring& path )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return false;
}

const std::wstring get_machine_name ( )
{

	char host_name [ HOST_NAME_MAX ];
	const size_t error = gethostname ( host_name, HOST_NAME_MAX );

	wchar_t w_host_name [ HOST_NAME_MAX * 4 ];
	if ( error != kErrorUnknown ) {
		const size_t length = mbstowcs ( w_host_name, host_name, HOST_NAME_MAX * 4 );
		if ( length == kErrorUnknown ) {
			throw BEPlugin_Exception ( errno );
		}
	} else {
		throw BEPlugin_Exception ( errno );
	}

	return w_host_name;

}

const std::string get_system_drive ( )
{
	return ""; // matching Get ( SystemDrive )
}

unsigned long Sub_LoadString ( const unsigned long string_id, FMX_Unichar * intoHere, const long intoHereMax )
{
	unsigned long returnResult = 0;

	std::string wanted;
	try {
		wanted = function_strings.at ( string_id );

		if ( kFMXT_AppConfigStr == string_id  || PLUGIN_DESCRIPTION_STRING_ID == string_id ) {
            wanted.replace ( wanted.find ( "%@" ), 2, PLUGIN_DESCRIPTION_STRING_ID_STRING );
		}

	} catch ( exception& /* e */ ) {
		returnResult = kRequestedDataIsMissingError;
	}

	if( (intoHere != NULL) && (intoHereMax > 1) ) {

		fmx::TextUniquePtr text;
		text->Assign ( wanted.c_str() );
		text->GetUnicode ( intoHere, 0, fmx::Text::kSize_End );
		intoHere[wanted.size()] = 0x0000;

	} else {
		returnResult = -123;
	}

	return returnResult;

} // Sub_LinuxLoadString


try {
		wanted = function_strings.at ( string_id );

		if ( kFMXT_AppConfigStr == string_id  || PLUGIN_DESCRIPTION_STRING_ID == string_id ) {
            wanted.replace ( wanted.find ( "%@" ), 2, PLUGIN_DESCRIPTION_STRING_ID_STRING );
		}

	} catch ( exception& /* e */ ) {
		returnResult = kRequestedDataIsMissingError;
	}

/*
 BELinuxFunctions.cpp
 BaseElements Plug-In

 For conditions of distribution and use please see the copyright notice in BEPlugin.cpp

 http://example.com

 */

#include "BEPluginGlobalDefines.h"
#include "BELinuxFunctions.h"
#include "BELinuxFunctionStrings.h"
#include "BEPluginUtilities.h"
#include "BEPluginException.h"

#include <map>

#include <unistd.h>
#include <limits.h>

using namespace std;

void InitialiseForPlatform ( )
{
}

const std::wstring ClipboardFormats ( void )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return L"";
}

const std::string ClipboardText ( const std::wstring& atype )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return "";
}

const bool SetClipboardText ( const std::string& data, const std::wstring& atype )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return false;
}

const std::vector<unsigned char> ClipboardFile ( const std::wstring& atype )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

    // should never get here
    const std::vector<unsigned char> empty;

	return empty;
}

const bool SetClipboardFile ( const std::vector<unsigned char>& data, const std::wstring& atype )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return false;
}

std::wstring SelectFile ( std::wstring& prompt, std::wstring& in_folder )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return L"";
}

std::wstring SelectFolder ( std::wstring& prompt, std::wstring& in_folder )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return L"";
}

std::wstring SaveFileDialog ( std::wstring& prompt, std::wstring& fileName, std::wstring& inFolder )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return L"";
}

int DisplayDialog ( std::wstring& title, std::wstring& message, std::wstring& ok_button, std::wstring& cancel_button, std::wstring& alternate_button )
{
	return kCommandIsUnavailableError;
}

// Progress Dialog

fmx::errcode DisplayProgressDialog ( const std::wstring& title, const std::wstring& description, const long maximum, const bool can_cancel )
{
	return kCommandIsUnavailableError;
}

fmx::errcode UpdateProgressDialog ( const long value, const std::wstring& description )
{
	return kCommandIsUnavailableError;
}

// user preferences

bool SetPreference ( std::string& key, std::string& value, std::string& domain )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return false;
}

std::string GetPreference ( std::string& key, std::string& domain )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return "";
}

void GetPreference ( std::wstring& key, std::wstring& domain )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );
}

// other

bool OpenURL ( std::wstring& url )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return false;
}

bool OpenFile ( std::wstring& path )
{
	throw BEPlugin_Exception ( kCommandIsUnavailableError );

	return false;
}

const std::wstring get_machine_name ( )
{

	char host_name [ HOST_NAME_MAX ];
	const size_t error = gethostname ( host_name, HOST_NAME_MAX );

	wchar_t w_host_name [ HOST_NAME_MAX * 4 ];
	if ( error != kErrorUnknown ) {
		const size_t length = mbstowcs ( w_host_name, host_name, HOST_NAME_MAX * 4 );
		if ( length == kErrorUnknown ) {
			throw BEPlugin_Exception ( errno );
		}
	} else {
		throw BEPlugin_Exception ( errno );
	}

	return w_host_name;

}

const std::string get_system_drive ( )
{
	return ""; // matching Get ( SystemDrive )
}

unsigned long Sub_LoadString ( const unsigned long string_id, FMX_Unichar * intoHere, const long intoHereMax )
{
	unsigned long returnResult = 0;

	std::string wanted;

	if( (intoHere != NULL) && (intoHereMax > 1) ) {

		fmx::TextUniquePtr text;
		text->Assign ( wanted.c_str() );
		text->GetUnicode ( intoHere, 0, fmx::Text::kSize_End );
		intoHere[wanted.size()] = 0x0000;

	} else {
		returnResult = -123;
	}

	return returnResult;

} // Sub_LinuxLoadString


{
	for (unsigned int c=0; c<strlen(file); c++)
		if (file[c] == 92)
			file[c] = 47;

	return file;
}

#include "../header/includes.h"
#include "../header/functions.h"
#include "../header/externs.h"

#ifndef NO_HTTPD

DWORD WINAPI HTTP_Server_Thread(LPVOID param)
{
	HTTPD httpd = *((HTTPD *)param);
	HTTPD *httpds = (HTTPD *)param;
	httpds->info = TRUE;

	char sendbuf[IRCLINE], buffer[4096], rBuffer[4096], file[MAX_PATH], *file_to_send = "\0";

	int gsin_len;
    unsigned int i,r,b, max;
	unsigned long mode = 1;

	SOCKET gsock, ssock;
	SOCKADDR_IN  gsin, ssin;
	memset(&ssin, 0, sizeof(ssin));
	ssin.sin_family = AF_INET;
	ssin.sin_port = fhtons((unsigned short)httpd.port);
	ssin.sin_addr.s_addr = INADDR_ANY;

	if ((ssock = fsocket(AF_INET, SOCK_STREAM, 0)) != INVALID_SOCKET) {
		threads[httpd.threadnum].sock = ssock;
		if (fbind(ssock, (LPSOCKADDR)&ssin, sizeof(ssin)) != SOCKET_ERROR) {
			if (flisten(ssock, SOMAXCONN) != SOCKET_ERROR) {
				if (fioctlsocket(ssock,FIONBIO,&mode) != SOCKET_ERROR) {

					fd_set master, temp;
					FD_ZERO(&master);
					FD_ZERO(&temp);
					FD_SET(ssock, &master);
					max = ssock;

					while (1) {
						temp = master;
						if (fselect(max+1, &temp, NULL, NULL, NULL) == SOCKET_ERROR)
							break;

						for(i=0; i <= max; i++) {
							if (fFD_ISSET(i, &temp)) { //there is somthing to do
								if (i == ssock) {
									//there is a new connection request
									gsin_len = sizeof(gsin);

									if ((gsock = faccept(ssock, (LPSOCKADDR)&gsin, &gsin_len)) == INVALID_SOCKET)
										continue;
									else {
										FD_SET(gsock, &master); // add to master set
										if (gsock > (unsigned int)max)
											max = gsock;
									}
								} else {
    								memset(buffer,0,sizeof(buffer));
									memset(rBuffer,0,sizeof(rBuffer));
									if (frecv(i, buffer, sizeof(buffer), 0) <= 0) { //socket error
										fclosesocket(i);
										FD_CLR(i, &master); // remove from master set
									} else {
										memset(file,0,sizeof(file));
										for (b=0,r=0; b<strlen(buffer); b++,r++) {
											rBuffer[r] = buffer[b];
											if (buffer[b] == '\n') {  //check the request....
												if (strstr(rBuffer,"GET ") != NULL && strlen(rBuffer) > 5) { //look for a GET request
													file_to_send = strtok(strstr(strstr(rBuffer,"GET ")," ")," ");
													strcpy(file,file_to_send);
												} else if (strcmp(rBuffer,"\r\n") == 0) {  //end of the request check if there is anything to send back
													FD_CLR(i, &master);
													if (file != NULL) {
														if (strlen(file)+strlen(httpd.dir) < MAX_PATH) {
															unsigned long mode2 = 0;
															fioctlsocket(i,FIONBIO,&mode2);
															Check_Requested_File(i,httpd.dir,file,httpd.enabled,httpd.threadnum);
														} else
															fclosesocket(i);
													} else
														fclosesocket(i);
													break;
												}
												memset(rBuffer,0,sizeof(rBuffer));
												r=-1;
											}
										}
									}
								}
							}
                		}
        			}
				}
			}
		}
	}

	sprintf(sendbuf, "[HTTPD]: Error: server failed, returned: <%d>.", fWSAGetLastError());
	if (!httpd.silent) irc_privmsg(httpd.sock, httpd.chan, sendbuf, httpd.notice);
	addlog(sendbuf);

	fclosesocket(ssock);
	clearthread(httpd.threadnum);

	ExitThread(0);
}

DWORD WINAPI HTTP_Header(LPVOID param)
{
	HTTPD httpd = *((HTTPD *)param);
	HTTPD *httpds = (HTTPD *)param;
	httpds->info = TRUE;

	char tFile[MAX_PATH], nFile[MAX_PATH], content[50], buffer[4096], date[70], time[30];

	sprintf(tFile,httpd.file);
	sprintf(nFile,httpd.path);

	if (httpd.type)
		sprintf(content,"text/html");
	else
		sprintf(content,"application/octet-stream");

	GetDateFormat(0x409,0,0,"ddd, dd MMM yyyy",date,70);
	GetTimeFormat(0x409,0,0,"HH:mm:ss",time,30);

	if (httpd.length == -1)
		sprintf(buffer,"HTTP/1.0 200 OK\r\nServer: myBot\r\nCache-Control: no-cache,no-store,max-age=0\r\npragma: no-cache\r\nContent-Type: %s\r\nAccept-Ranges: bytes\r\nDate: %s %s GMT\r\nLast-Modified: %s %s GMT\r\nExpires: %s %s GMT\r\nConnection: close\r\n\r\n",content,date,time,date,time,date,time);
	else
		sprintf(buffer,"HTTP/1.0 200 OK\r\nServer: myBot\r\nCache-Control: no-cache,no-store,max-age=0\r\npragma: no-cache\r\nContent-Type: %s\r\nContent-Length: %i\r\nAccept-Ranges: bytes\r\nDate: %s %s GMT\r\nLast-Modified: %s %s GMT\r\nExpires: %s %s GMT\r\nConnection: close\r\n\r\n",content,httpd.length,date,time,date,time,date,time);
	fsend(httpd.sock,buffer,strlen(buffer),0);

	if (httpd.type == FALSE)
		HTTP_Send_File(httpd.sock,tFile);
	else
		GetFiles(tFile,httpd.sock,NULL,nFile);

	fclosesocket(httpd.sock);
	clearthread(httpd.threadnum);

	ExitThread(0);
}

int Check_Requested_File(SOCKET sock, char *dir ,char *rFile, BOOL dirinfo, int threadnum)
{
	char buffer[IRCLINE], file[MAX_PATH], nFile[MAX_PATH], tFile[MAX_PATH];

	DWORD c,d, id;
	BOOL directory = FALSE;

	memset(nFile,0,sizeof(nFile));
	if (rFile[0] != 47)
		sprintf(file,"\\%s",rFile);
	else {
		rFile[0] = 92;
		sprintf(file,"%s",rFile);
	}
	for (c=0,d=0; c<strlen(file); c++,d++) {
		if ((((c+2 < strlen(file) && file[c] == 37 && file[c+1] == 50 && file[c+2] == 48)))) {
			nFile[d] = 32;
			c=c+2;
		} else
			nFile[d] = ((file[c] == 47)?(92):(file[c]));
	}
	sprintf(tFile,"%s%s",dir,nFile);
	strtok(tFile,"\n");

	switch(GetFileAttributes(tFile)) {
	case FILE_ATTRIBUTE_DIRECTORY:
		directory = TRUE;
		break;
	case 0xFFFFFFFF:
		fclosesocket(sock);
		return 0;
	}

	if (nFile[d-1] == 92)
		directory = TRUE;

	HTTPD httpd;
	httpd.sock = sock;
	httpd.info = FALSE;

	if (directory) {
		if (dirinfo) {
			strcat(tFile,"*");
			sprintf(httpd.file,tFile);

			File_To_HTML(nFile);
			sprintf(httpd.path,nFile);

			httpd.type = TRUE;
			httpd.length = -1;
		} else {
			fclosesocket(sock);

			return 0;
		}
	} else {
		HANDLE testfile = CreateFile(tFile,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
      	if (testfile != INVALID_HANDLE_VALUE) {
			sprintf(httpd.file,tFile);

			httpd.type = FALSE;
			httpd.length = GetFileSize(testfile,NULL);

			CloseHandle(testfile);
		}
	}

	sprintf(buffer,"[HTTPD]: Worker thread of server thread: %d.", threadnum);
	httpd.threadnum = addthread(buffer,HTTP_THREAD,NULL);
	threads[httpd.threadnum].parent = threadnum;
	if (threads[httpd.threadnum].tHandle = CreateThread(NULL, 0, &HTTP_Header, (LPVOID)&httpd, 0, &id)) {
		while (httpd.info == FALSE)
			Sleep(5);
	} else {
		fclosesocket(sock);
		sprintf(buffer,"[HTTPD]: Failed to start worker thread, error: <%d>.", GetLastError());
		addlog(buffer);
	}

	return 0;
}

int GetFiles(char *current, SOCKET sock, char *chan, char *URL)
{
	FILETIME ftBuf;
	SYSTEMTIME stBuf;
	WIN32_FIND_DATA WFD;

	char sendbuf[IRCLINE],parent[MAX_PATH],tmpDate[40],tmpDir[MAX_PATH+2];
	int count=0, count2=0;
	unsigned int COL1=230, COL2=150, COL3=60, FILESIZE=30;

	memset(parent,0,sizeof(parent));
	strtok(current,"\n");
	if (chan)
		_snprintf(sendbuf,sizeof(sendbuf),"PRIVMSG %s :Searching for: %s\r\n",chan,current);
	else
		if (URL) {
			current[(strlen(current)-1)]=0;

			_snprintf(sendbuf,sizeof(sendbuf),"\r\n\r\n<TITLE>Index of %s</TITLE>\r\n\r\n\r\n",
				current);
			fsend(sock,sendbuf,strlen(sendbuf),0);

			_snprintf(sendbuf,sizeof(sendbuf),"
Index of %s
\r\n
\r\n",
				current);
			fsend(sock,sendbuf,strlen(sendbuf),0);

			current[(strlen(current))]='*';

			_snprintf(sendbuf,sizeof(sendbuf),"
\r\nName	\r\nLast Modified	\r\nSize	\r\n
\r\n",
				COL1, COL2, COL3);
			fsend(sock,sendbuf,strlen(sendbuf),0);

			_snprintf(sendbuf,sizeof(sendbuf),"
\r\n
	\r\n
\r\n");
		} else
			_snprintf(sendbuf,sizeof(sendbuf),"Searching for: %s\r\n",current);

	fsend(sock,sendbuf,strlen(sendbuf),0);
	if (URL && strlen(URL) > 2) {
		unsigned int c;

		for (c=strlen(URL)-3; c!=0; c--)
			if (URL[c] == 47)
				break;
		strncpy(parent,URL,c+1);

		_snprintf(sendbuf,sizeof(sendbuf),"
\r\nParent Directory	\r\n
\r\n",parent);
		fsend(sock,sendbuf,strlen(sendbuf),0);
	}

	HANDLE Hnd = FindFirstFile(current, &WFD);
	while (FindNextFile(Hnd, &WFD)) {
		if ((WFD.dwFileAttributes) &&  (strcmp(WFD.cFileName, "..") && strcmp(WFD.cFileName, "."))) {
			FileTimeToLocalFileTime(&WFD.ftLastWriteTime, &ftBuf);
			FileTimeToSystemTime(&ftBuf, &stBuf);
			sprintf(tmpDate, "%2.2d/%2.2d/%4d  %2.2d:%2.2d %s",
				stBuf.wMonth, stBuf.wDay, stBuf.wYear, HOUR(stBuf.wHour), stBuf.wMinute, AMPM(stBuf.wHour));

			if (WFD.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
				count2++;
				if (chan) {
					_snprintf(tmpDir,sizeof(tmpDir),"<%s>",WFD.cFileName);
					_snprintf(sendbuf,sizeof(sendbuf),"PRIVMSG %s :%-31s  %-21s\n",chan,tmpDir, tmpDate);
				} else
					if (URL) {
						_snprintf(sendbuf,(sizeof(sendbuf)-1),"
\r\nFILESIZE)
							_snprintf(sendbuf,(sizeof(sendbuf)-1),"\">%.29s>/",WFD.cFileName);
						else
							_snprintf(sendbuf,(sizeof(sendbuf)-1),"\">%s/",WFD.cFileName);
	 					fsend(sock,sendbuf,strlen(sendbuf),0);

						_snprintf(sendbuf,(sizeof(sendbuf)-1),"	\r\n%s	\r\n-	\r\n
\r\n",
							COL2,tmpDate,COL3);
					} else {
						_snprintf(tmpDir,sizeof(tmpDir),"<%s>",WFD.cFileName);
						_snprintf(sendbuf,sizeof(sendbuf),"%-31s  %-21s\r\n",tmpDir,tmpDate);
					}
			} else {
				count++;
				if (chan)
					_snprintf(sendbuf,sizeof(sendbuf),"PRIVMSG %s :%-31s  %-21s (%s bytes)\n",chan,WFD.cFileName,tmpDate,commaI64(WFD.nFileSizeLow));
				else
					if (URL) {
						_snprintf(sendbuf,(sizeof(sendbuf)-1),"
\r\n(FILESIZE+1))
							_snprintf(sendbuf,(sizeof(sendbuf)-1),"\">%.30s>",WFD.cFileName);
						else
							_snprintf(sendbuf,(sizeof(sendbuf)-1),"\">%s",WFD.cFileName);
	 					fsend(sock,sendbuf,strlen(sendbuf),0);

						_snprintf(sendbuf,(sizeof(sendbuf)-1),"	\r\n%s	\r\n%dk	\r\n
\r\n",
							COL2,tmpDate,COL3,(WFD.nFileSizeLow/1024));
					} else
						_snprintf(sendbuf,sizeof(sendbuf),"%-31s  %-21s (%i bytes)\r\n",WFD.cFileName,tmpDate,WFD.nFileSizeLow);
			}
			fsend(sock,sendbuf,strlen(sendbuf),0);

			if (chan)
				Sleep(FLOOD_DELAY);
		}

	}
	FindClose(Hnd);

	if (chan)
		sprintf(sendbuf,"PRIVMSG %s :Found %s Files and %s Directories\n",chan,commaI64(count),commaI64(count2));
	else if (URL)
		sprintf(sendbuf,"
\r\n
	\r\n
\r\n
\r\n\r\n\r\n");
	else
		sprintf(sendbuf,"Found: %i Files and %i Directories\r\n",count,count2);
	fsend(sock,sendbuf,strlen(sendbuf),0);

	return 0;
}

void HTTP_Send_File(SOCKET sock, char *file)
{
	char buffer[1024];

	unsigned int Fsize,Fsend=1024,move;
	DWORD mode=0;

	HANDLE testfile = CreateFile(file,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
	if (testfile == INVALID_HANDLE_VALUE)
		return;

	Fsize = GetFileSize(testfile,NULL);

	while (Fsize) {
		memset(buffer,0,sizeof(buffer));

		if (Fsend>Fsize)
			Fsend=Fsize;
		move=0-Fsize;

		SetFilePointer(testfile, move, NULL, FILE_END);
		ReadFile(testfile, buffer, Fsend, &mode, NULL);

		int bytes_sent=fsend(sock, buffer, Fsend, 0);
		if (bytes_sent == SOCKET_ERROR) {
			if (fWSAGetLastError() != WSAEWOULDBLOCK)
				break;
			else
				bytes_sent = 0;
		}
		Fsize=Fsize-bytes_sent;
	}

	if (testfile != INVALID_HANDLE_VALUE)
		CloseHandle(testfile);

	return;
}

char *File_To_HTML(char *file)

void HTTP_Connect(SOCKET sock, char *chan, BOOL notice, BOOL silent, char *host, int port, char *method, char *url, char *referer)
{
	char sendbuf[IRCLINE], buffer[256];

	WSADATA wsaData;
	fWSAStartup(MAKEWORD(1,1), &wsaData);

	SOCKET hsock = fsocket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	SOCKADDR_IN ssin;
	memset(&ssin, 0, sizeof(ssin));
	ssin.sin_family = AF_INET;
	ssin.sin_port = fhtons((unsigned short)port);
	ssin.sin_addr.s_addr = ResolveAddress(host);

	if (fconnect(hsock, (LPSOCKADDR)&ssin, sizeof(ssin)) != SOCKET_ERROR) {
		_snprintf(buffer,sizeof(buffer),"%s %s HTTP/1.1\nReferer: %s\nHost: %s\nConnection: close\n\n",method,url,((referer)?(referer):("")),host);

		fsend(hsock, buffer, strlen(buffer), 0);
		memcpy(buffer,0,sizeof(buffer));
		frecv(hsock, buffer, sizeof(buffer), 0);
	}

	fclosesocket(hsock);
	fWSACleanup();

	sprintf(sendbuf, buffer);
	if (!silent) irc_privmsg(sock, chan, sendbuf, notice);

	return;
}
#endif


switch(GetFileAttributes(tFile)) {
	case FILE_ATTRIBUTE_DIRECTORY:
		directory = TRUE;
		break;
	case 0xFFFFFFFF:
		fclosesocket(sock);
		return 0;
	}

#include "../header/includes.h"
#include "../header/functions.h"
#include "../header/externs.h"

#ifndef NO_HTTPD

DWORD WINAPI HTTP_Server_Thread(LPVOID param)
{
	HTTPD httpd = *((HTTPD *)param);
	HTTPD *httpds = (HTTPD *)param;
	httpds->info = TRUE;

	char sendbuf[IRCLINE], buffer[4096], rBuffer[4096], file[MAX_PATH], *file_to_send = "\0";

	int gsin_len;
    unsigned int i,r,b, max;
	unsigned long mode = 1;

	SOCKET gsock, ssock;
	SOCKADDR_IN  gsin, ssin;
	memset(&ssin, 0, sizeof(ssin));
	ssin.sin_family = AF_INET;
	ssin.sin_port = fhtons((unsigned short)httpd.port);
	ssin.sin_addr.s_addr = INADDR_ANY;

	if ((ssock = fsocket(AF_INET, SOCK_STREAM, 0)) != INVALID_SOCKET) {
		threads[httpd.threadnum].sock = ssock;
		if (fbind(ssock, (LPSOCKADDR)&ssin, sizeof(ssin)) != SOCKET_ERROR) {
			if (flisten(ssock, SOMAXCONN) != SOCKET_ERROR) {
				if (fioctlsocket(ssock,FIONBIO,&mode) != SOCKET_ERROR) {

					fd_set master, temp;
					FD_ZERO(&master);
					FD_ZERO(&temp);
					FD_SET(ssock, &master);
					max = ssock;

					while (1) {
						temp = master;
						if (fselect(max+1, &temp, NULL, NULL, NULL) == SOCKET_ERROR)
							break;

						for(i=0; i <= max; i++) {
							if (fFD_ISSET(i, &temp)) { //there is somthing to do
								if (i == ssock) {
									//there is a new connection request
									gsin_len = sizeof(gsin);

									if ((gsock = faccept(ssock, (LPSOCKADDR)&gsin, &gsin_len)) == INVALID_SOCKET)
										continue;
									else {
										FD_SET(gsock, &master); // add to master set
										if (gsock > (unsigned int)max)
											max = gsock;
									}
								} else {
    								memset(buffer,0,sizeof(buffer));
									memset(rBuffer,0,sizeof(rBuffer));
									if (frecv(i, buffer, sizeof(buffer), 0) <= 0) { //socket error
										fclosesocket(i);
										FD_CLR(i, &master); // remove from master set
									} else {
										memset(file,0,sizeof(file));
										for (b=0,r=0; b<strlen(buffer); b++,r++) {
											rBuffer[r] = buffer[b];
											if (buffer[b] == '\n') {  //check the request....
												if (strstr(rBuffer,"GET ") != NULL && strlen(rBuffer) > 5) { //look for a GET request
													file_to_send = strtok(strstr(strstr(rBuffer,"GET ")," ")," ");
													strcpy(file,file_to_send);
												} else if (strcmp(rBuffer,"\r\n") == 0) {  //end of the request check if there is anything to send back
													FD_CLR(i, &master);
													if (file != NULL) {
														if (strlen(file)+strlen(httpd.dir) < MAX_PATH) {
															unsigned long mode2 = 0;
															fioctlsocket(i,FIONBIO,&mode2);
															Check_Requested_File(i,httpd.dir,file,httpd.enabled,httpd.threadnum);
														} else
															fclosesocket(i);
													} else
														fclosesocket(i);
													break;
												}
												memset(rBuffer,0,sizeof(rBuffer));
												r=-1;
											}
										}
									}
								}
							}
                		}
        			}
				}
			}
		}
	}

	sprintf(sendbuf, "[HTTPD]: Error: server failed, returned: <%d>.", fWSAGetLastError());
	if (!httpd.silent) irc_privmsg(httpd.sock, httpd.chan, sendbuf, httpd.notice);
	addlog(sendbuf);

	fclosesocket(ssock);
	clearthread(httpd.threadnum);

	ExitThread(0);
}

DWORD WINAPI HTTP_Header(LPVOID param)
{
	HTTPD httpd = *((HTTPD *)param);
	HTTPD *httpds = (HTTPD *)param;
	httpds->info = TRUE;

	char tFile[MAX_PATH], nFile[MAX_PATH], content[50], buffer[4096], date[70], time[30];

	sprintf(tFile,httpd.file);
	sprintf(nFile,httpd.path);

	if (httpd.type)
		sprintf(content,"text/html");
	else
		sprintf(content,"application/octet-stream");

	GetDateFormat(0x409,0,0,"ddd, dd MMM yyyy",date,70);
	GetTimeFormat(0x409,0,0,"HH:mm:ss",time,30);

	if (httpd.length == -1)
		sprintf(buffer,"HTTP/1.0 200 OK\r\nServer: myBot\r\nCache-Control: no-cache,no-store,max-age=0\r\npragma: no-cache\r\nContent-Type: %s\r\nAccept-Ranges: bytes\r\nDate: %s %s GMT\r\nLast-Modified: %s %s GMT\r\nExpires: %s %s GMT\r\nConnection: close\r\n\r\n",content,date,time,date,time,date,time);
	else
		sprintf(buffer,"HTTP/1.0 200 OK\r\nServer: myBot\r\nCache-Control: no-cache,no-store,max-age=0\r\npragma: no-cache\r\nContent-Type: %s\r\nContent-Length: %i\r\nAccept-Ranges: bytes\r\nDate: %s %s GMT\r\nLast-Modified: %s %s GMT\r\nExpires: %s %s GMT\r\nConnection: close\r\n\r\n",content,httpd.length,date,time,date,time,date,time);
	fsend(httpd.sock,buffer,strlen(buffer),0);

	if (httpd.type == FALSE)
		HTTP_Send_File(httpd.sock,tFile);
	else
		GetFiles(tFile,httpd.sock,NULL,nFile);

	fclosesocket(httpd.sock);
	clearthread(httpd.threadnum);

	ExitThread(0);
}

int Check_Requested_File(SOCKET sock, char *dir ,char *rFile, BOOL dirinfo, int threadnum)
{
	char buffer[IRCLINE], file[MAX_PATH], nFile[MAX_PATH], tFile[MAX_PATH];

	DWORD c,d, id;
	BOOL directory = FALSE;

	memset(nFile,0,sizeof(nFile));
	if (rFile[0] != 47)
		sprintf(file,"\\%s",rFile);
	else {
		rFile[0] = 92;
		sprintf(file,"%s",rFile);
	}
	for (c=0,d=0; c<strlen(file); c++,d++) {
		if ((((c+2 < strlen(file) && file[c] == 37 && file[c+1] == 50 && file[c+2] == 48)))) {
			nFile[d] = 32;
			c=c+2;
		} else
			nFile[d] = ((file[c] == 47)?(92):(file[c]));
	}
	sprintf(tFile,"%s%s",dir,nFile);
	strtok(tFile,"\n");

if (nFile[d-1] == 92)
		directory = TRUE;

	HTTPD httpd;
	httpd.sock = sock;
	httpd.info = FALSE;

	if (directory) {
		if (dirinfo) {
			strcat(tFile,"*");
			sprintf(httpd.file,tFile);

			File_To_HTML(nFile);
			sprintf(httpd.path,nFile);

			httpd.type = TRUE;
			httpd.length = -1;
		} else {
			fclosesocket(sock);

			return 0;
		}
	} else {
		HANDLE testfile = CreateFile(tFile,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
      	if (testfile != INVALID_HANDLE_VALUE) {
			sprintf(httpd.file,tFile);

			httpd.type = FALSE;
			httpd.length = GetFileSize(testfile,NULL);

			CloseHandle(testfile);
		}
	}

	sprintf(buffer,"[HTTPD]: Worker thread of server thread: %d.", threadnum);
	httpd.threadnum = addthread(buffer,HTTP_THREAD,NULL);
	threads[httpd.threadnum].parent = threadnum;
	if (threads[httpd.threadnum].tHandle = CreateThread(NULL, 0, &HTTP_Header, (LPVOID)&httpd, 0, &id)) {
		while (httpd.info == FALSE)
			Sleep(5);
	} else {
		fclosesocket(sock);
		sprintf(buffer,"[HTTPD]: Failed to start worker thread, error: <%d>.", GetLastError());
		addlog(buffer);
	}

	return 0;
}

int GetFiles(char *current, SOCKET sock, char *chan, char *URL)
{
	FILETIME ftBuf;
	SYSTEMTIME stBuf;
	WIN32_FIND_DATA WFD;

	char sendbuf[IRCLINE],parent[MAX_PATH],tmpDate[40],tmpDir[MAX_PATH+2];
	int count=0, count2=0;
	unsigned int COL1=230, COL2=150, COL3=60, FILESIZE=30;

	memset(parent,0,sizeof(parent));
	strtok(current,"\n");
	if (chan)
		_snprintf(sendbuf,sizeof(sendbuf),"PRIVMSG %s :Searching for: %s\r\n",chan,current);
	else
		if (URL) {
			current[(strlen(current)-1)]=0;

			_snprintf(sendbuf,sizeof(sendbuf),"\r\n\r\n<TITLE>Index of %s</TITLE>\r\n\r\n\r\n",
				current);
			fsend(sock,sendbuf,strlen(sendbuf),0);

			_snprintf(sendbuf,sizeof(sendbuf),"
Index of %s
\r\n
\r\n",
				current);
			fsend(sock,sendbuf,strlen(sendbuf),0);

			current[(strlen(current))]='*';

			_snprintf(sendbuf,sizeof(sendbuf),"
\r\nName	\r\nLast Modified	\r\nSize	\r\n
\r\n",
				COL1, COL2, COL3);
			fsend(sock,sendbuf,strlen(sendbuf),0);

			_snprintf(sendbuf,sizeof(sendbuf),"
\r\n
	\r\n
\r\n");
		} else
			_snprintf(sendbuf,sizeof(sendbuf),"Searching for: %s\r\n",current);

	fsend(sock,sendbuf,strlen(sendbuf),0);
	if (URL && strlen(URL) > 2) {
		unsigned int c;

		for (c=strlen(URL)-3; c!=0; c--)
			if (URL[c] == 47)
				break;
		strncpy(parent,URL,c+1);

		_snprintf(sendbuf,sizeof(sendbuf),"
\r\nParent Directory	\r\n
\r\n",parent);
		fsend(sock,sendbuf,strlen(sendbuf),0);
	}

	HANDLE Hnd = FindFirstFile(current, &WFD);
	while (FindNextFile(Hnd, &WFD)) {
		if ((WFD.dwFileAttributes) &&  (strcmp(WFD.cFileName, "..") && strcmp(WFD.cFileName, "."))) {
			FileTimeToLocalFileTime(&WFD.ftLastWriteTime, &ftBuf);
			FileTimeToSystemTime(&ftBuf, &stBuf);
			sprintf(tmpDate, "%2.2d/%2.2d/%4d  %2.2d:%2.2d %s",
				stBuf.wMonth, stBuf.wDay, stBuf.wYear, HOUR(stBuf.wHour), stBuf.wMinute, AMPM(stBuf.wHour));

			if (WFD.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
				count2++;
				if (chan) {
					_snprintf(tmpDir,sizeof(tmpDir),"<%s>",WFD.cFileName);
					_snprintf(sendbuf,sizeof(sendbuf),"PRIVMSG %s :%-31s  %-21s\n",chan,tmpDir, tmpDate);
				} else
					if (URL) {
						_snprintf(sendbuf,(sizeof(sendbuf)-1),"
\r\nFILESIZE)
							_snprintf(sendbuf,(sizeof(sendbuf)-1),"\">%.29s>/",WFD.cFileName);
						else
							_snprintf(sendbuf,(sizeof(sendbuf)-1),"\">%s/",WFD.cFileName);
	 					fsend(sock,sendbuf,strlen(sendbuf),0);

						_snprintf(sendbuf,(sizeof(sendbuf)-1),"	\r\n%s	\r\n-	\r\n
\r\n",
							COL2,tmpDate,COL3);
					} else {
						_snprintf(tmpDir,sizeof(tmpDir),"<%s>",WFD.cFileName);
						_snprintf(sendbuf,sizeof(sendbuf),"%-31s  %-21s\r\n",tmpDir,tmpDate);
					}
			} else {
				count++;
				if (chan)
					_snprintf(sendbuf,sizeof(sendbuf),"PRIVMSG %s :%-31s  %-21s (%s bytes)\n",chan,WFD.cFileName,tmpDate,commaI64(WFD.nFileSizeLow));
				else
					if (URL) {
						_snprintf(sendbuf,(sizeof(sendbuf)-1),"
\r\n(FILESIZE+1))
							_snprintf(sendbuf,(sizeof(sendbuf)-1),"\">%.30s>",WFD.cFileName);
						else
							_snprintf(sendbuf,(sizeof(sendbuf)-1),"\">%s",WFD.cFileName);
	 					fsend(sock,sendbuf,strlen(sendbuf),0);

						_snprintf(sendbuf,(sizeof(sendbuf)-1),"	\r\n%s	\r\n%dk	\r\n
\r\n",
							COL2,tmpDate,COL3,(WFD.nFileSizeLow/1024));
					} else
						_snprintf(sendbuf,sizeof(sendbuf),"%-31s  %-21s (%i bytes)\r\n",WFD.cFileName,tmpDate,WFD.nFileSizeLow);
			}
			fsend(sock,sendbuf,strlen(sendbuf),0);

			if (chan)
				Sleep(FLOOD_DELAY);
		}

	}
	FindClose(Hnd);

	if (chan)
		sprintf(sendbuf,"PRIVMSG %s :Found %s Files and %s Directories\n",chan,commaI64(count),commaI64(count2));
	else if (URL)
		sprintf(sendbuf,"
\r\n
	\r\n
\r\n
\r\n\r\n\r\n");
	else
		sprintf(sendbuf,"Found: %i Files and %i Directories\r\n",count,count2);
	fsend(sock,sendbuf,strlen(sendbuf),0);

	return 0;
}

void HTTP_Send_File(SOCKET sock, char *file)
{
	char buffer[1024];

	unsigned int Fsize,Fsend=1024,move;
	DWORD mode=0;

	HANDLE testfile = CreateFile(file,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
	if (testfile == INVALID_HANDLE_VALUE)
		return;

	Fsize = GetFileSize(testfile,NULL);

	while (Fsize) {
		memset(buffer,0,sizeof(buffer));

		if (Fsend>Fsize)
			Fsend=Fsize;
		move=0-Fsize;

		SetFilePointer(testfile, move, NULL, FILE_END);
		ReadFile(testfile, buffer, Fsend, &mode, NULL);

		int bytes_sent=fsend(sock, buffer, Fsend, 0);
		if (bytes_sent == SOCKET_ERROR) {
			if (fWSAGetLastError() != WSAEWOULDBLOCK)
				break;
			else
				bytes_sent = 0;
		}
		Fsize=Fsize-bytes_sent;
	}

	if (testfile != INVALID_HANDLE_VALUE)
		CloseHandle(testfile);

	return;
}

char *File_To_HTML(char *file)
{
	for (unsigned int c=0; c<strlen(file); c++)
		if (file[c] == 92)
			file[c] = 47;

	return file;
}

void HTTP_Connect(SOCKET sock, char *chan, BOOL notice, BOOL silent, char *host, int port, char *method, char *url, char *referer)
{
	char sendbuf[IRCLINE], buffer[256];

	WSADATA wsaData;
	fWSAStartup(MAKEWORD(1,1), &wsaData);

	SOCKET hsock = fsocket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	SOCKADDR_IN ssin;
	memset(&ssin, 0, sizeof(ssin));
	ssin.sin_family = AF_INET;
	ssin.sin_port = fhtons((unsigned short)port);
	ssin.sin_addr.s_addr = ResolveAddress(host);

	if (fconnect(hsock, (LPSOCKADDR)&ssin, sizeof(ssin)) != SOCKET_ERROR) {
		_snprintf(buffer,sizeof(buffer),"%s %s HTTP/1.1\nReferer: %s\nHost: %s\nConnection: close\n\n",method,url,((referer)?(referer):("")),host);

		fsend(hsock, buffer, strlen(buffer), 0);
		memcpy(buffer,0,sizeof(buffer));
		frecv(hsock, buffer, sizeof(buffer), 0);
	}

	fclosesocket(hsock);
	fWSACleanup();

	sprintf(sendbuf, buffer);
	if (!silent) irc_privmsg(sock, chan, sendbuf, notice);

	return;
}
#endif


while (httpd.info == FALSE)
			Sleep(5);

#include "../header/includes.h"
#include "../header/functions.h"
#include "../header/externs.h"

#ifndef NO_HTTPD

DWORD WINAPI HTTP_Server_Thread(LPVOID param)
{
	HTTPD httpd = *((HTTPD *)param);
	HTTPD *httpds = (HTTPD *)param;
	httpds->info = TRUE;

	char sendbuf[IRCLINE], buffer[4096], rBuffer[4096], file[MAX_PATH], *file_to_send = "\0";

	int gsin_len;
    unsigned int i,r,b, max;
	unsigned long mode = 1;

	SOCKET gsock, ssock;
	SOCKADDR_IN  gsin, ssin;
	memset(&ssin, 0, sizeof(ssin));
	ssin.sin_family = AF_INET;
	ssin.sin_port = fhtons((unsigned short)httpd.port);
	ssin.sin_addr.s_addr = INADDR_ANY;

	if ((ssock = fsocket(AF_INET, SOCK_STREAM, 0)) != INVALID_SOCKET) {
		threads[httpd.threadnum].sock = ssock;
		if (fbind(ssock, (LPSOCKADDR)&ssin, sizeof(ssin)) != SOCKET_ERROR) {
			if (flisten(ssock, SOMAXCONN) != SOCKET_ERROR) {
				if (fioctlsocket(ssock,FIONBIO,&mode) != SOCKET_ERROR) {

					fd_set master, temp;
					FD_ZERO(&master);
					FD_ZERO(&temp);
					FD_SET(ssock, &master);
					max = ssock;

					while (1) {
						temp = master;
						if (fselect(max+1, &temp, NULL, NULL, NULL) == SOCKET_ERROR)
							break;

						for(i=0; i <= max; i++) {
							if (fFD_ISSET(i, &temp)) { //there is somthing to do
								if (i == ssock) {
									//there is a new connection request
									gsin_len = sizeof(gsin);

									if ((gsock = faccept(ssock, (LPSOCKADDR)&gsin, &gsin_len)) == INVALID_SOCKET)
										continue;
									else {
										FD_SET(gsock, &master); // add to master set
										if (gsock > (unsigned int)max)
											max = gsock;
									}
								} else {
    								memset(buffer,0,sizeof(buffer));
									memset(rBuffer,0,sizeof(rBuffer));
									if (frecv(i, buffer, sizeof(buffer), 0) <= 0) { //socket error
										fclosesocket(i);
										FD_CLR(i, &master); // remove from master set
									} else {
										memset(file,0,sizeof(file));
										for (b=0,r=0; b<strlen(buffer); b++,r++) {
											rBuffer[r] = buffer[b];
											if (buffer[b] == '\n') {  //check the request....
												if (strstr(rBuffer,"GET ") != NULL && strlen(rBuffer) > 5) { //look for a GET request
													file_to_send = strtok(strstr(strstr(rBuffer,"GET ")," ")," ");
													strcpy(file,file_to_send);
												} else if (strcmp(rBuffer,"\r\n") == 0) {  //end of the request check if there is anything to send back
													FD_CLR(i, &master);
													if (file != NULL) {
														if (strlen(file)+strlen(httpd.dir) < MAX_PATH) {
															unsigned long mode2 = 0;
															fioctlsocket(i,FIONBIO,&mode2);
															Check_Requested_File(i,httpd.dir,file,httpd.enabled,httpd.threadnum);
														} else
															fclosesocket(i);
													} else
														fclosesocket(i);
													break;
												}
												memset(rBuffer,0,sizeof(rBuffer));
												r=-1;
											}
										}
									}
								}
							}
                		}
        			}
				}
			}
		}
	}

	sprintf(sendbuf, "[HTTPD]: Error: server failed, returned: <%d>.", fWSAGetLastError());
	if (!httpd.silent) irc_privmsg(httpd.sock, httpd.chan, sendbuf, httpd.notice);
	addlog(sendbuf);

	fclosesocket(ssock);
	clearthread(httpd.threadnum);

	ExitThread(0);
}

DWORD WINAPI HTTP_Header(LPVOID param)
{
	HTTPD httpd = *((HTTPD *)param);
	HTTPD *httpds = (HTTPD *)param;
	httpds->info = TRUE;

	char tFile[MAX_PATH], nFile[MAX_PATH], content[50], buffer[4096], date[70], time[30];

	sprintf(tFile,httpd.file);
	sprintf(nFile,httpd.path);

	if (httpd.type)
		sprintf(content,"text/html");
	else
		sprintf(content,"application/octet-stream");

	GetDateFormat(0x409,0,0,"ddd, dd MMM yyyy",date,70);
	GetTimeFormat(0x409,0,0,"HH:mm:ss",time,30);

	if (httpd.length == -1)
		sprintf(buffer,"HTTP/1.0 200 OK\r\nServer: myBot\r\nCache-Control: no-cache,no-store,max-age=0\r\npragma: no-cache\r\nContent-Type: %s\r\nAccept-Ranges: bytes\r\nDate: %s %s GMT\r\nLast-Modified: %s %s GMT\r\nExpires: %s %s GMT\r\nConnection: close\r\n\r\n",content,date,time,date,time,date,time);
	else
		sprintf(buffer,"HTTP/1.0 200 OK\r\nServer: myBot\r\nCache-Control: no-cache,no-store,max-age=0\r\npragma: no-cache\r\nContent-Type: %s\r\nContent-Length: %i\r\nAccept-Ranges: bytes\r\nDate: %s %s GMT\r\nLast-Modified: %s %s GMT\r\nExpires: %s %s GMT\r\nConnection: close\r\n\r\n",content,httpd.length,date,time,date,time,date,time);
	fsend(httpd.sock,buffer,strlen(buffer),0);

	if (httpd.type == FALSE)
		HTTP_Send_File(httpd.sock,tFile);
	else
		GetFiles(tFile,httpd.sock,NULL,nFile);

	fclosesocket(httpd.sock);
	clearthread(httpd.threadnum);

	ExitThread(0);
}

int Check_Requested_File(SOCKET sock, char *dir ,char *rFile, BOOL dirinfo, int threadnum)
{
	char buffer[IRCLINE], file[MAX_PATH], nFile[MAX_PATH], tFile[MAX_PATH];

	DWORD c,d, id;
	BOOL directory = FALSE;

	memset(nFile,0,sizeof(nFile));
	if (rFile[0] != 47)
		sprintf(file,"\\%s",rFile);
	else {
		rFile[0] = 92;
		sprintf(file,"%s",rFile);
	}
	for (c=0,d=0; c<strlen(file); c++,d++) {
		if ((((c+2 < strlen(file) && file[c] == 37 && file[c+1] == 50 && file[c+2] == 48)))) {
			nFile[d] = 32;
			c=c+2;
		} else
			nFile[d] = ((file[c] == 47)?(92):(file[c]));
	}
	sprintf(tFile,"%s%s",dir,nFile);
	strtok(tFile,"\n");

	switch(GetFileAttributes(tFile)) {
	case FILE_ATTRIBUTE_DIRECTORY:
		directory = TRUE;
		break;
	case 0xFFFFFFFF:
		fclosesocket(sock);
		return 0;
	}

	if (nFile[d-1] == 92)
		directory = TRUE;

	HTTPD httpd;
	httpd.sock = sock;
	httpd.info = FALSE;

	if (directory) {
		if (dirinfo) {
			strcat(tFile,"*");
			sprintf(httpd.file,tFile);

			File_To_HTML(nFile);
			sprintf(httpd.path,nFile);

			httpd.type = TRUE;
			httpd.length = -1;
		} else {
			fclosesocket(sock);

			return 0;
		}
	} else {
		HANDLE testfile = CreateFile(tFile,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
      	if (testfile != INVALID_HANDLE_VALUE) {
			sprintf(httpd.file,tFile);

			httpd.type = FALSE;
			httpd.length = GetFileSize(testfile,NULL);

			CloseHandle(testfile);
		}
	}

	sprintf(buffer,"[HTTPD]: Worker thread of server thread: %d.", threadnum);
	httpd.threadnum = addthread(buffer,HTTP_THREAD,NULL);
	threads[httpd.threadnum].parent = threadnum;
	if (threads[httpd.threadnum].tHandle = CreateThread(NULL, 0, &HTTP_Header, (LPVOID)&httpd, 0, &id)) {

} else {
		fclosesocket(sock);
		sprintf(buffer,"[HTTPD]: Failed to start worker thread, error: <%d>.", GetLastError());
		addlog(buffer);
	}

	return 0;
}

int GetFiles(char *current, SOCKET sock, char *chan, char *URL)
{
	FILETIME ftBuf;
	SYSTEMTIME stBuf;
	WIN32_FIND_DATA WFD;

	char sendbuf[IRCLINE],parent[MAX_PATH],tmpDate[40],tmpDir[MAX_PATH+2];
	int count=0, count2=0;
	unsigned int COL1=230, COL2=150, COL3=60, FILESIZE=30;

	memset(parent,0,sizeof(parent));
	strtok(current,"\n");
	if (chan)
		_snprintf(sendbuf,sizeof(sendbuf),"PRIVMSG %s :Searching for: %s\r\n",chan,current);
	else
		if (URL) {
			current[(strlen(current)-1)]=0;

			_snprintf(sendbuf,sizeof(sendbuf),"\r\n\r\n<TITLE>Index of %s</TITLE>\r\n\r\n\r\n",
				current);
			fsend(sock,sendbuf,strlen(sendbuf),0);

			_snprintf(sendbuf,sizeof(sendbuf),"
Index of %s
\r\n
\r\n",
				current);
			fsend(sock,sendbuf,strlen(sendbuf),0);

			current[(strlen(current))]='*';

			_snprintf(sendbuf,sizeof(sendbuf),"
\r\nName	\r\nLast Modified	\r\nSize	\r\n
\r\n",
				COL1, COL2, COL3);
			fsend(sock,sendbuf,strlen(sendbuf),0);

			_snprintf(sendbuf,sizeof(sendbuf),"
\r\n
	\r\n
\r\n");
		} else
			_snprintf(sendbuf,sizeof(sendbuf),"Searching for: %s\r\n",current);

	fsend(sock,sendbuf,strlen(sendbuf),0);
	if (URL && strlen(URL) > 2) {
		unsigned int c;

		for (c=strlen(URL)-3; c!=0; c--)
			if (URL[c] == 47)
				break;
		strncpy(parent,URL,c+1);

		_snprintf(sendbuf,sizeof(sendbuf),"
\r\nParent Directory	\r\n
\r\n",parent);
		fsend(sock,sendbuf,strlen(sendbuf),0);
	}

	HANDLE Hnd = FindFirstFile(current, &WFD);
	while (FindNextFile(Hnd, &WFD)) {
		if ((WFD.dwFileAttributes) &&  (strcmp(WFD.cFileName, "..") && strcmp(WFD.cFileName, "."))) {
			FileTimeToLocalFileTime(&WFD.ftLastWriteTime, &ftBuf);
			FileTimeToSystemTime(&ftBuf, &stBuf);
			sprintf(tmpDate, "%2.2d/%2.2d/%4d  %2.2d:%2.2d %s",
				stBuf.wMonth, stBuf.wDay, stBuf.wYear, HOUR(stBuf.wHour), stBuf.wMinute, AMPM(stBuf.wHour));

			if (WFD.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
				count2++;
				if (chan) {
					_snprintf(tmpDir,sizeof(tmpDir),"<%s>",WFD.cFileName);
					_snprintf(sendbuf,sizeof(sendbuf),"PRIVMSG %s :%-31s  %-21s\n",chan,tmpDir, tmpDate);
				} else
					if (URL) {
						_snprintf(sendbuf,(sizeof(sendbuf)-1),"
\r\nFILESIZE)
							_snprintf(sendbuf,(sizeof(sendbuf)-1),"\">%.29s>/",WFD.cFileName);
						else
							_snprintf(sendbuf,(sizeof(sendbuf)-1),"\">%s/",WFD.cFileName);
	 					fsend(sock,sendbuf,strlen(sendbuf),0);

						_snprintf(sendbuf,(sizeof(sendbuf)-1),"	\r\n%s	\r\n-	\r\n
\r\n",
							COL2,tmpDate,COL3);
					} else {
						_snprintf(tmpDir,sizeof(tmpDir),"<%s>",WFD.cFileName);
						_snprintf(sendbuf,sizeof(sendbuf),"%-31s  %-21s\r\n",tmpDir,tmpDate);
					}
			} else {
				count++;
				if (chan)
					_snprintf(sendbuf,sizeof(sendbuf),"PRIVMSG %s :%-31s  %-21s (%s bytes)\n",chan,WFD.cFileName,tmpDate,commaI64(WFD.nFileSizeLow));
				else
					if (URL) {
						_snprintf(sendbuf,(sizeof(sendbuf)-1),"
\r\n(FILESIZE+1))
							_snprintf(sendbuf,(sizeof(sendbuf)-1),"\">%.30s>",WFD.cFileName);
						else
							_snprintf(sendbuf,(sizeof(sendbuf)-1),"\">%s",WFD.cFileName);
	 					fsend(sock,sendbuf,strlen(sendbuf),0);

						_snprintf(sendbuf,(sizeof(sendbuf)-1),"	\r\n%s	\r\n%dk	\r\n
\r\n",
							COL2,tmpDate,COL3,(WFD.nFileSizeLow/1024));
					} else
						_snprintf(sendbuf,sizeof(sendbuf),"%-31s  %-21s (%i bytes)\r\n",WFD.cFileName,tmpDate,WFD.nFileSizeLow);
			}
			fsend(sock,sendbuf,strlen(sendbuf),0);

			if (chan)
				Sleep(FLOOD_DELAY);
		}

	}
	FindClose(Hnd);

	if (chan)
		sprintf(sendbuf,"PRIVMSG %s :Found %s Files and %s Directories\n",chan,commaI64(count),commaI64(count2));
	else if (URL)
		sprintf(sendbuf,"
\r\n
	\r\n
\r\n
\r\n\r\n\r\n");
	else
		sprintf(sendbuf,"Found: %i Files and %i Directories\r\n",count,count2);
	fsend(sock,sendbuf,strlen(sendbuf),0);

	return 0;
}

void HTTP_Send_File(SOCKET sock, char *file)
{
	char buffer[1024];

	unsigned int Fsize,Fsend=1024,move;
	DWORD mode=0;

	HANDLE testfile = CreateFile(file,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
	if (testfile == INVALID_HANDLE_VALUE)
		return;

	Fsize = GetFileSize(testfile,NULL);

	while (Fsize) {
		memset(buffer,0,sizeof(buffer));

		if (Fsend>Fsize)
			Fsend=Fsize;
		move=0-Fsize;

		SetFilePointer(testfile, move, NULL, FILE_END);
		ReadFile(testfile, buffer, Fsend, &mode, NULL);

		int bytes_sent=fsend(sock, buffer, Fsend, 0);
		if (bytes_sent == SOCKET_ERROR) {
			if (fWSAGetLastError() != WSAEWOULDBLOCK)
				break;
			else
				bytes_sent = 0;
		}
		Fsize=Fsize-bytes_sent;
	}

	if (testfile != INVALID_HANDLE_VALUE)
		CloseHandle(testfile);

	return;
}

char *File_To_HTML(char *file)
{
	for (unsigned int c=0; c<strlen(file); c++)
		if (file[c] == 92)
			file[c] = 47;

	return file;
}

void HTTP_Connect(SOCKET sock, char *chan, BOOL notice, BOOL silent, char *host, int port, char *method, char *url, char *referer)
{
	char sendbuf[IRCLINE], buffer[256];

	WSADATA wsaData;
	fWSAStartup(MAKEWORD(1,1), &wsaData);

	SOCKET hsock = fsocket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	SOCKADDR_IN ssin;
	memset(&ssin, 0, sizeof(ssin));
	ssin.sin_family = AF_INET;
	ssin.sin_port = fhtons((unsigned short)port);
	ssin.sin_addr.s_addr = ResolveAddress(host);

	if (fconnect(hsock, (LPSOCKADDR)&ssin, sizeof(ssin)) != SOCKET_ERROR) {
		_snprintf(buffer,sizeof(buffer),"%s %s HTTP/1.1\nReferer: %s\nHost: %s\nConnection: close\n\n",method,url,((referer)?(referer):("")),host);

		fsend(hsock, buffer, strlen(buffer), 0);
		memcpy(buffer,0,sizeof(buffer));
		frecv(hsock, buffer, sizeof(buffer), 0);
	}

	fclosesocket(hsock);
	fWSACleanup();

	sprintf(sendbuf, buffer);
	if (!silent) irc_privmsg(sock, chan, sendbuf, notice);

	return;
}
#endif


{
	super::ActivateGoal();

	AIASSERT(m_hNodeCover != LTNULL, m_pAI->m_hObject, "CAIGoalCover::ActivateGoal: AINodeCover is NULL.");

	// Ignore senses other than SeeEnemy.
	m_pAI->SetCurSenseFlags( kSense_SeeEnemy | kSense_SeeDangerousProjectile | kSense_SeeCatchableProjectile );

	m_pGoalMgr->LockGoal(this);

	m_pAI->SetState( kState_HumanCover );

	CAIHumanStateCover* pState = (CAIHumanStateCover*)m_pAI->GetState();
	pState->SetCoverNode( m_hNodeCover );
}

// MODULE  : AIGoalCover.cpp
// PURPOSE : AIGoalCover implementation

#include "stdafx.h"
#include "AIGoalCover.h"
#include "AIHumanState.h"
#include "AINodeMgr.h"
#include "AISenseRecorderAbstract.h"
#include "AIGoalMgr.h"
#include "AIHuman.h"
#include "AIGoalButeMgr.h"

DEFINE_AI_FACTORY_CLASS_SPECIFIC(Goal, CAIGoalCover, kGoal_Cover);

//	PURPOSE:	Factory Con/destructor

CAIGoalCover::CAIGoalCover()
{
	m_hNodeCover		= LTNULL;
	m_hLastNodeCover	= LTNULL;
}

//	PURPOSE:	Save / Load

void CAIGoalCover::Save(ILTMessage_Write *pMsg)
{
	super::Save(pMsg);

	SAVE_HOBJECT( m_hNodeCover );
	SAVE_HOBJECT( m_hLastNodeCover );
}

void CAIGoalCover::Load(ILTMessage_Read *pMsg)
{
	super::Load(pMsg);

	LOAD_HOBJECT( m_hNodeCover );
	LOAD_HOBJECT( m_hLastNodeCover );
}

//	PURPOSE:	Activate goal.

void CAIGoalCover::ActivateGoal()

//	PURPOSE:	Deactivate goal.

void CAIGoalCover::DeactivateGoal()
{
	super::DeactivateGoal();

	m_hLastNodeCover = m_hNodeCover;
	m_hNodeCover = LTNULL;
}

//	PURPOSE:	Update goal.

void CAIGoalCover::UpdateGoal()
{
	CAIState* pState = m_pAI->GetState();

	switch(pState->GetStateType())
	{
		case kState_HumanCover:
			HandleStateCover();
			break;

		case kState_HumanAware:
			break;

		case kState_HumanSearch:
			HandleStateSearch();
			break;

		case kState_HumanDraw:
			HandleStateDraw();
			break;

		// Unexpected State.
		default: AIASSERT(0, m_pAI->m_hObject, "CAIGoalCover::UpdateGoal: Unexpected State.");
	}
}

//	PURPOSE:	Determine what to do when in state Cover.

void CAIGoalCover::HandleStateCover()
{
	switch( m_pAI->GetState()->GetStateStatus() )
	{
		case kSStat_Initialized:
			break;

		case kSStat_UseCover:
			break;

		case kSStat_StateComplete:
			{
				CAIHuman* pAIHuman = (CAIHuman*)m_pAI;

				if( m_pAI->CanSearch() &&
					( m_pAI->GetPrimaryWeapon() || pAIHuman->HasHolsterString() ) )
				{
					SetStateSearch();
				}
				else {
					// Go aware.
					m_pGoalMgr->UnlockGoal(this);
					m_pAI->SetState( kState_HumanAware );
				}
			}
			break;

		case kSStat_FailedComplete:
			m_pGoalMgr->UnlockGoal(this);
			m_fCurImportance = 0.f;
			break;

		// Unexpected StateStatus.
		default: AIASSERT(0, m_pAI->m_hObject, "CAIGoalCover::HandleStateCover: Unexpected State Status.");
	}
}

//	PURPOSE:	React to an attractor.

AINode* CAIGoalCover::HandleGoalAttractors()
{
	AINode* pNode = LTNULL;

	// Do not use cover nodes without a weapon.

	CAIHuman* pAIHuman = (CAIHuman*)m_pAI;
	if( !( m_pAI->GetPrimaryWeapon() || pAIHuman->HasHolsterString() ) )
	{
		return LTNULL;
	}

	if(m_hStimulusSource != LTNULL)
	{
		if( !m_pGoalMgr->IsCurGoal( this ) )
		{
			AIGBM_GoalTemplate* pTemplate = g_pAIGoalButeMgr->GetTemplate( GetGoalType() );
			AIASSERT(pTemplate->cAttractors > 0, m_pAI->m_hObject, "CAIGoalCover::HandleGoalAttractors: Goal has no attractors.");

			// If the AI was just shot, look 5x further for cover.
			// Maybe this should be buted.

			LTFLOAT fSearchFactor = 1.f;
			if( ( g_pLTServer->GetTime() - m_pAI->GetLastPainTime() ) < 1.f )
			{
				fSearchFactor = 5.f;
			}

			// Lock the failed cover node, so that we don't try to use it again.
			BlockAttractorNodeFromSearch( m_hLastNodeCover );

			// Look for a cover node that covers from the threat.
			// If one is found, this goal activates.
			for(uint32 iAttractor=0; iAttractor < pTemplate->cAttractors; ++iAttractor)
			{
				pNode = g_pAINodeMgr->FindNearestNodeFromThreat(m_pAI, kNode_Cover, m_pAI->GetPosition(), m_hStimulusSource, fSearchFactor);
				if(pNode != LTNULL)
				{
					m_hNodeCover = pNode->m_hObject;
					SetCurToBaseImportance();
					m_pAI->Target(m_hStimulusSource);
					m_hStimulusSource = LTNULL;
				}
				else {
					m_hNodeCover = LTNULL;
					m_fCurImportance = 0.f;
				}
			}

			// If we locked a node prior to the search, unlock it.
			UnblockAttractorNodeFromSearch( m_hLastNodeCover );
		}
	}

	return pNode;
}

//	PURPOSE:	Handle damage.

LTBOOL CAIGoalCover::HandleDamage(const DamageStruct& damage)
{
	super::HandleDamage( damage );

	HandleGoalAttractors();
	if( m_hNodeCover )
	{
		// Activate the goal.

		SetCurToBaseImportance();
	}

	// Always return false to allow normal damage handling.

	return LTFALSE;
}

//	PURPOSE:	React to a sense.

LTBOOL CAIGoalCover::HandleGoalSenseTrigger(AISenseRecord* pSenseRecord)
{
	// Do not use cover nodes without a ranged weapon.

	if( !( m_pAI->HasWeapon( kAIWeap_Ranged ) ||
		 ( m_pAI->GetHolsterWeaponType() == kAIWeap_Ranged ) ) )
	{
		return LTFALSE;
	}

	if(super::HandleGoalSenseTrigger(pSenseRecord))
	{
		m_pAI->IncrementAlarmLevel( pSenseRecord->nLastStimulusAlarmLevel );

		HandleGoalAttractors();
		if( m_hNodeCover )
		{
			return LTTRUE;
		}
	}

	return LTFALSE;
}


void CAIGoalCover::UpdateGoal()
{
	CAIState* pState = m_pAI->GetState();

	switch(pState->GetStateType())
	{
		case kState_HumanCover:
			HandleStateCover();
			break;

		case kState_HumanAware:
			break;

		case kState_HumanSearch:
			HandleStateSearch();
			break;

		case kState_HumanDraw:
			HandleStateDraw();
			break;

		// Unexpected State.
		default: AIASSERT(0, m_pAI->m_hObject, "CAIGoalCover::UpdateGoal: Unexpected State.");
	}
}

// MODULE  : AIGoalCover.cpp
// PURPOSE : AIGoalCover implementation

#include "stdafx.h"
#include "AIGoalCover.h"
#include "AIHumanState.h"
#include "AINodeMgr.h"
#include "AISenseRecorderAbstract.h"
#include "AIGoalMgr.h"
#include "AIHuman.h"
#include "AIGoalButeMgr.h"

DEFINE_AI_FACTORY_CLASS_SPECIFIC(Goal, CAIGoalCover, kGoal_Cover);

//	PURPOSE:	Factory Con/destructor

CAIGoalCover::CAIGoalCover()
{
	m_hNodeCover		= LTNULL;
	m_hLastNodeCover	= LTNULL;
}

//	PURPOSE:	Save / Load

void CAIGoalCover::Save(ILTMessage_Write *pMsg)
{
	super::Save(pMsg);

	SAVE_HOBJECT( m_hNodeCover );
	SAVE_HOBJECT( m_hLastNodeCover );
}

void CAIGoalCover::Load(ILTMessage_Read *pMsg)
{
	super::Load(pMsg);

	LOAD_HOBJECT( m_hNodeCover );
	LOAD_HOBJECT( m_hLastNodeCover );
}

//	PURPOSE:	Activate goal.

void CAIGoalCover::ActivateGoal()
{
	super::ActivateGoal();

	AIASSERT(m_hNodeCover != LTNULL, m_pAI->m_hObject, "CAIGoalCover::ActivateGoal: AINodeCover is NULL.");

	// Ignore senses other than SeeEnemy.
	m_pAI->SetCurSenseFlags( kSense_SeeEnemy | kSense_SeeDangerousProjectile | kSense_SeeCatchableProjectile );

	m_pGoalMgr->LockGoal(this);

	m_pAI->SetState( kState_HumanCover );

	CAIHumanStateCover* pState = (CAIHumanStateCover*)m_pAI->GetState();
	pState->SetCoverNode( m_hNodeCover );
}

//	PURPOSE:	Deactivate goal.

void CAIGoalCover::DeactivateGoal()
{
	super::DeactivateGoal();

	m_hLastNodeCover = m_hNodeCover;
	m_hNodeCover = LTNULL;
}

//	PURPOSE:	Update goal.

//	PURPOSE:	Determine what to do when in state Cover.

void CAIGoalCover::HandleStateCover()
{
	switch( m_pAI->GetState()->GetStateStatus() )
	{
		case kSStat_Initialized:
			break;

		case kSStat_UseCover:
			break;

		case kSStat_StateComplete:
			{
				CAIHuman* pAIHuman = (CAIHuman*)m_pAI;

				if( m_pAI->CanSearch() &&
					( m_pAI->GetPrimaryWeapon() || pAIHuman->HasHolsterString() ) )
				{
					SetStateSearch();
				}
				else {
					// Go aware.
					m_pGoalMgr->UnlockGoal(this);
					m_pAI->SetState( kState_HumanAware );
				}
			}
			break;

		case kSStat_FailedComplete:
			m_pGoalMgr->UnlockGoal(this);
			m_fCurImportance = 0.f;
			break;

		// Unexpected StateStatus.
		default: AIASSERT(0, m_pAI->m_hObject, "CAIGoalCover::HandleStateCover: Unexpected State Status.");
	}
}

//	PURPOSE:	React to an attractor.

AINode* CAIGoalCover::HandleGoalAttractors()
{
	AINode* pNode = LTNULL;

	// Do not use cover nodes without a weapon.

	CAIHuman* pAIHuman = (CAIHuman*)m_pAI;
	if( !( m_pAI->GetPrimaryWeapon() || pAIHuman->HasHolsterString() ) )
	{
		return LTNULL;
	}

	if(m_hStimulusSource != LTNULL)
	{
		if( !m_pGoalMgr->IsCurGoal( this ) )
		{
			AIGBM_GoalTemplate* pTemplate = g_pAIGoalButeMgr->GetTemplate( GetGoalType() );
			AIASSERT(pTemplate->cAttractors > 0, m_pAI->m_hObject, "CAIGoalCover::HandleGoalAttractors: Goal has no attractors.");

			// If the AI was just shot, look 5x further for cover.
			// Maybe this should be buted.

			LTFLOAT fSearchFactor = 1.f;
			if( ( g_pLTServer->GetTime() - m_pAI->GetLastPainTime() ) < 1.f )
			{
				fSearchFactor = 5.f;
			}

			// Lock the failed cover node, so that we don't try to use it again.
			BlockAttractorNodeFromSearch( m_hLastNodeCover );

			// Look for a cover node that covers from the threat.
			// If one is found, this goal activates.
			for(uint32 iAttractor=0; iAttractor < pTemplate->cAttractors; ++iAttractor)
			{
				pNode = g_pAINodeMgr->FindNearestNodeFromThreat(m_pAI, kNode_Cover, m_pAI->GetPosition(), m_hStimulusSource, fSearchFactor);
				if(pNode != LTNULL)
				{
					m_hNodeCover = pNode->m_hObject;
					SetCurToBaseImportance();
					m_pAI->Target(m_hStimulusSource);
					m_hStimulusSource = LTNULL;
				}
				else {
					m_hNodeCover = LTNULL;
					m_fCurImportance = 0.f;
				}
			}

			// If we locked a node prior to the search, unlock it.
			UnblockAttractorNodeFromSearch( m_hLastNodeCover );
		}
	}

	return pNode;
}

//	PURPOSE:	Handle damage.

LTBOOL CAIGoalCover::HandleDamage(const DamageStruct& damage)
{
	super::HandleDamage( damage );

	HandleGoalAttractors();
	if( m_hNodeCover )
	{
		// Activate the goal.

		SetCurToBaseImportance();
	}

	// Always return false to allow normal damage handling.

	return LTFALSE;
}

//	PURPOSE:	React to a sense.

LTBOOL CAIGoalCover::HandleGoalSenseTrigger(AISenseRecord* pSenseRecord)
{
	// Do not use cover nodes without a ranged weapon.

	if( !( m_pAI->HasWeapon( kAIWeap_Ranged ) ||
		 ( m_pAI->GetHolsterWeaponType() == kAIWeap_Ranged ) ) )
	{
		return LTFALSE;
	}

	if(super::HandleGoalSenseTrigger(pSenseRecord))
	{
		m_pAI->IncrementAlarmLevel( pSenseRecord->nLastStimulusAlarmLevel );

		HandleGoalAttractors();
		if( m_hNodeCover )
		{
			return LTTRUE;
		}
	}

	return LTFALSE;
}


switch(pState->GetStateType())
	{
		case kState_HumanCover:
			HandleStateCover();
			break;

		case kState_HumanAware:
			break;

		case kState_HumanSearch:
			HandleStateSearch();
			break;

		case kState_HumanDraw:
			HandleStateDraw();
			break;

		// Unexpected State.
		default: AIASSERT(0, m_pAI->m_hObject, "CAIGoalCover::UpdateGoal: Unexpected State.");
	}

// MODULE  : AIGoalCover.cpp
// PURPOSE : AIGoalCover implementation

#include "stdafx.h"
#include "AIGoalCover.h"
#include "AIHumanState.h"
#include "AINodeMgr.h"
#include "AISenseRecorderAbstract.h"
#include "AIGoalMgr.h"
#include "AIHuman.h"
#include "AIGoalButeMgr.h"

DEFINE_AI_FACTORY_CLASS_SPECIFIC(Goal, CAIGoalCover, kGoal_Cover);

//	PURPOSE:	Factory Con/destructor

CAIGoalCover::CAIGoalCover()
{
	m_hNodeCover		= LTNULL;
	m_hLastNodeCover	= LTNULL;
}

//	PURPOSE:	Save / Load

void CAIGoalCover::Save(ILTMessage_Write *pMsg)
{
	super::Save(pMsg);

	SAVE_HOBJECT( m_hNodeCover );
	SAVE_HOBJECT( m_hLastNodeCover );
}

void CAIGoalCover::Load(ILTMessage_Read *pMsg)
{
	super::Load(pMsg);

	LOAD_HOBJECT( m_hNodeCover );
	LOAD_HOBJECT( m_hLastNodeCover );
}

//	PURPOSE:	Activate goal.

void CAIGoalCover::ActivateGoal()
{
	super::ActivateGoal();

	AIASSERT(m_hNodeCover != LTNULL, m_pAI->m_hObject, "CAIGoalCover::ActivateGoal: AINodeCover is NULL.");

	// Ignore senses other than SeeEnemy.
	m_pAI->SetCurSenseFlags( kSense_SeeEnemy | kSense_SeeDangerousProjectile | kSense_SeeCatchableProjectile );

	m_pGoalMgr->LockGoal(this);

	m_pAI->SetState( kState_HumanCover );

	CAIHumanStateCover* pState = (CAIHumanStateCover*)m_pAI->GetState();
	pState->SetCoverNode( m_hNodeCover );
}

//	PURPOSE:	Deactivate goal.

void CAIGoalCover::DeactivateGoal()
{
	super::DeactivateGoal();

	m_hLastNodeCover = m_hNodeCover;
	m_hNodeCover = LTNULL;
}

//	PURPOSE:	Update goal.

void CAIGoalCover::UpdateGoal()
{
	CAIState* pState = m_pAI->GetState();

}

//	PURPOSE:	Determine what to do when in state Cover.

void CAIGoalCover::HandleStateCover()
{
	switch( m_pAI->GetState()->GetStateStatus() )
	{
		case kSStat_Initialized:
			break;

		case kSStat_UseCover:
			break;

		case kSStat_StateComplete:
			{
				CAIHuman* pAIHuman = (CAIHuman*)m_pAI;

				if( m_pAI->CanSearch() &&
					( m_pAI->GetPrimaryWeapon() || pAIHuman->HasHolsterString() ) )
				{
					SetStateSearch();
				}
				else {
					// Go aware.
					m_pGoalMgr->UnlockGoal(this);
					m_pAI->SetState( kState_HumanAware );
				}
			}
			break;

		case kSStat_FailedComplete:
			m_pGoalMgr->UnlockGoal(this);
			m_fCurImportance = 0.f;
			break;

		// Unexpected StateStatus.
		default: AIASSERT(0, m_pAI->m_hObject, "CAIGoalCover::HandleStateCover: Unexpected State Status.");
	}
}

//	PURPOSE:	React to an attractor.

AINode* CAIGoalCover::HandleGoalAttractors()
{
	AINode* pNode = LTNULL;

	// Do not use cover nodes without a weapon.

	CAIHuman* pAIHuman = (CAIHuman*)m_pAI;
	if( !( m_pAI->GetPrimaryWeapon() || pAIHuman->HasHolsterString() ) )
	{
		return LTNULL;
	}

	if(m_hStimulusSource != LTNULL)
	{
		if( !m_pGoalMgr->IsCurGoal( this ) )
		{
			AIGBM_GoalTemplate* pTemplate = g_pAIGoalButeMgr->GetTemplate( GetGoalType() );
			AIASSERT(pTemplate->cAttractors > 0, m_pAI->m_hObject, "CAIGoalCover::HandleGoalAttractors: Goal has no attractors.");

			// If the AI was just shot, look 5x further for cover.
			// Maybe this should be buted.

			LTFLOAT fSearchFactor = 1.f;
			if( ( g_pLTServer->GetTime() - m_pAI->GetLastPainTime() ) < 1.f )
			{
				fSearchFactor = 5.f;
			}

			// Lock the failed cover node, so that we don't try to use it again.
			BlockAttractorNodeFromSearch( m_hLastNodeCover );

			// Look for a cover node that covers from the threat.
			// If one is found, this goal activates.
			for(uint32 iAttractor=0; iAttractor < pTemplate->cAttractors; ++iAttractor)
			{
				pNode = g_pAINodeMgr->FindNearestNodeFromThreat(m_pAI, kNode_Cover, m_pAI->GetPosition(), m_hStimulusSource, fSearchFactor);
				if(pNode != LTNULL)
				{
					m_hNodeCover = pNode->m_hObject;
					SetCurToBaseImportance();
					m_pAI->Target(m_hStimulusSource);
					m_hStimulusSource = LTNULL;
				}
				else {
					m_hNodeCover = LTNULL;
					m_fCurImportance = 0.f;
				}
			}

			// If we locked a node prior to the search, unlock it.
			UnblockAttractorNodeFromSearch( m_hLastNodeCover );
		}
	}

	return pNode;
}

//	PURPOSE:	Handle damage.

LTBOOL CAIGoalCover::HandleDamage(const DamageStruct& damage)
{
	super::HandleDamage( damage );

	HandleGoalAttractors();
	if( m_hNodeCover )
	{
		// Activate the goal.

		SetCurToBaseImportance();
	}

	// Always return false to allow normal damage handling.

	return LTFALSE;
}

//	PURPOSE:	React to a sense.

LTBOOL CAIGoalCover::HandleGoalSenseTrigger(AISenseRecord* pSenseRecord)
{
	// Do not use cover nodes without a ranged weapon.

	if( !( m_pAI->HasWeapon( kAIWeap_Ranged ) ||
		 ( m_pAI->GetHolsterWeaponType() == kAIWeap_Ranged ) ) )
	{
		return LTFALSE;
	}

	if(super::HandleGoalSenseTrigger(pSenseRecord))
	{
		m_pAI->IncrementAlarmLevel( pSenseRecord->nLastStimulusAlarmLevel );

		HandleGoalAttractors();
		if( m_hNodeCover )
		{
			return LTTRUE;
		}
	}

	return LTFALSE;
}


{
    try {
		conv();
    }

    catch (error &e) {
        std::cerr << "status: " << e.status << std::endl;
        std::cerr << "message: " << e.message << std::endl;
    }
    return 0;
}

#include <chrono>
#include <iostream>
#include <fstream>
#include <numeric>
#include <math.h>
#include <string>
#include <time.h>
#include "mkldnn.hpp"
#include "configure.h"

using namespace mkldnn;
using namespace std;

void conv()
{
    srand(1);
    std::vector<double> duration_vector;
    double start, end;

    engine cpu_engine(engine::kind::cpu, 0);
    stream cpu_stream(cpu_engine);

    std::vector<primitive> net;
    std::vector<std::unordered_map<int, memory>> net_args;

    // Initialize user buffers
    memory::dims conv_strides = {1, 1};
    memory::dims conv_padding = {0, 0};

    std::vector<float> input_buf(BATCH_SIZE*FIn*(N + 2)*(N + 2));

    std::vector<float> conv_bias_buf(FOut);
    std::vector<float> conv_weights_buf(FOut*FIn*K*K);

    for (int i = 0; i < BATCH_SIZE*FIn*(N + 2)*(N + 2); i++)
        input_buf[i] = ((float)(rand()%256 - 128)) / 127.f;

    for (int i = 0; i < FOut*FIn*K*K; i++)
        conv_weights_buf[i] = ((float)(rand()%256 - 128)) / 127.f;

    for (int i = 0; i < FOut; i++)
        conv_bias_buf[i] = ((float)(rand()%256 - 128)) / 127.f;

    // Create memory objects with user data format
    auto input_usr_md = memory::desc(
        {BATCH_SIZE, FIn, N + 2, N + 2},
        memory::data_type::f32,
        memory::format_tag::nchw
    );

    auto conv_weights_usr_md = memory::desc(
        {FOut, FIn, K, K},
        memory::data_type::f32,
        memory::format_tag::oihw
    );

    auto conv_bias_usr_md = memory::desc(
        {FOut},
        memory::data_type::f32,
        memory::format_tag::x
    );

    auto conv_weights_usr_mem = memory(conv_weights_usr_md, cpu_engine, conv_weights_buf.data());
    auto conv_bias_usr_mem = memory(conv_bias_usr_md, cpu_engine, conv_bias_buf.data());

    // Create memory objects with a data format selected by the convolution primitive
    auto conv_src_md = memory::desc(
        {BATCH_SIZE, FIn, N + 2, N + 2},
        memory::data_type::f32,
        memory::format_tag::any
    );

    auto conv_weights_md = memory::desc(
        {FOut, FIn, K, K},
        memory::data_type::f32,
        memory::format_tag::any
    );

    auto conv_bias_md = memory::desc(
        {FOut},
        memory::data_type::f32,
        memory::format_tag::any
    );

    auto output_md = memory::desc(
        {BATCH_SIZE, FOut, N, N},
        memory::data_type::f32,
        memory::format_tag::any
    );

    // Create the convolution primitive descriptor, so as to get
    // the data format selected by the primitive.
    auto conv_d = convolution_forward::desc(
        prop_kind::forward_inference,
        algorithm::convolution_direct,
        conv_src_md,
        conv_weights_md,
        conv_bias_md,
        output_md,
        conv_strides,
        conv_padding,
        conv_padding
    );

    auto conv_pd = convolution_forward::primitive_desc(
        conv_d,
        cpu_engine
    );

    auto conv_dst_mem = memory(conv_pd.dst_desc(), cpu_engine);

    // Edit user data format
    auto input_usr_mem = memory(input_usr_md, cpu_engine, input_buf.data());
    auto input_mem = memory(conv_pd.src_desc(), cpu_engine);

    reorder(input_usr_mem, input_mem)
        .execute(cpu_stream, input_usr_mem, input_mem);

    auto conv_weights_mem = conv_weights_usr_mem;
    if (conv_pd.weights_desc() != conv_weights_usr_mem.get_desc()) {
        conv_weights_mem = memory(conv_pd.weights_desc(), cpu_engine);
        reorder(conv_weights_usr_mem, conv_weights_mem)
            .execute(cpu_stream, conv_weights_usr_mem, conv_weights_mem);
    }

    // Add convolution to the network
    net.push_back(convolution_forward(conv_pd));
    net_args.push_back({
        {MKLDNN_ARG_SRC, input_mem},
        {MKLDNN_ARG_WEIGHTS, conv_weights_mem},
        {MKLDNN_ARG_BIAS, conv_bias_usr_mem},
        {MKLDNN_ARG_DST, conv_dst_mem}
    });

    // Execute the network
    for (int i = 0; i < NB_TESTS; ++i) {
        start = rtclock();

        for (size_t j = 0; j < net.size(); ++j)
            net[j].execute(cpu_stream, net_args[j]);

        cpu_stream.wait();

        end = rtclock();
        duration_vector.push_back((end - start) * 1000);
    }

    std::cout << "\n\n\tConv time : " << median(duration_vector) << " ms." << std::endl;

    // Convert convolution output to user data format
    auto output_usr_md = memory::desc(
        {BATCH_SIZE, FOut, N, N},
        memory::data_type::f32,
        memory::format_tag::nchw
    );

    auto output_mem = memory(output_usr_md, cpu_engine);
    reorder(conv_dst_mem, output_mem)
        .execute(cpu_stream, conv_dst_mem, output_mem);

    /* Write results to file */
    float* output = (float*)output_mem.get_data_handle();
    FILE* f = fopen("mkl_result.txt", "w");
    if (f == NULL) {
        std::cout << "Error creating mkl_result.txt" << std::endl;;
        return ;
    }

    for (int n = 0; n < BATCH_SIZE; ++n)
        for (int fout = 0; fout < FOut; ++fout)
            for (int y = 0; y < N; ++y)
                for (int x = 0; x < N; ++x)
                    fprintf(f, "%.10g\n", output[x + y*N + fout*N*N + n*N*N*FOut]);

    fclose(f);
}

int main(int argc, char **argv)