<commit_before>/* bzflag
 * Copyright (c) 1993-2013 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "InputMenu.h"

/* common implementation headers */
#include "StateDatabase.h"
#include "FontManager.h"

/* local implementation headers */
#include "MainMenu.h"
#include "HUDDialogStack.h"
#include "LocalPlayer.h"
#include "playing.h"
#include "HUDui.h"

InputMenu::InputMenu() : keyboardMapMenu(NULL)
{
  std::string currentJoystickDevice = BZDB.get("joystickname");
  // cache font face ID
  int fontFace = MainMenu::getFontFace();
  // add controls
  std::vector<HUDuiControl*>& listHUD = getControls();

  HUDuiLabel* label = new HUDuiLabel;
  label->setFontFace(fontFace);
  label->setString("Input Settings");
  listHUD.push_back(label);

  keyMapping = new HUDuiLabel;
  keyMapping->setFontFace(fontFace);
  keyMapping->setLabel("Change Key Mapping");
  listHUD.push_back(keyMapping);

  HUDuiList* option = new HUDuiList;

  option = new HUDuiList;
  std::vector<std::string>* options = &option->getList();
  // set joystick Device
  option->setFontFace(fontFace);
  option->setLabel("Joystick device:");
  option->setCallback(callback, "J");
  options = &option->getList();
  options->push_back(std::string("Off"));
  std::vector<std::string> joystickDevices;
  getMainWindow()->getJoyDevices(joystickDevices);
  int i;
  for (i = 0; i < (int)joystickDevices.size(); i++) {
    options->push_back(joystickDevices[i]);
  }
  joystickDevices.erase(joystickDevices.begin(), joystickDevices.end());
  for (i = 0; i < (int)options->size(); i++) {
    if ((*options)[i].compare(currentJoystickDevice) == 0) {
      option->setIndex(i);
      break;
    }
  }
  option->update();
  listHUD.push_back(option);

  activeInput = new HUDuiList;
  activeInput->setFontFace(fontFace);
  activeInput->setLabel("Active input device:");
  activeInput->setCallback(callback, "A");
  options = &activeInput->getList();
  options->push_back("Auto");
  options->push_back(LocalPlayer::getInputMethodName(LocalPlayer::Keyboard));
  options->push_back(LocalPlayer::getInputMethodName(LocalPlayer::Mouse));
  options->push_back(LocalPlayer::getInputMethodName(LocalPlayer::Joystick));
  activeInput->update();
  listHUD.push_back(activeInput);

  option = new HUDuiList;
  // force feedback
  option->setFontFace(fontFace);
  option->setLabel("Force feedback:");
  option->setCallback(callback, "F");
  options = &option->getList();
  options->push_back(std::string("None"));
  options->push_back(std::string("Rumble"));
  options->push_back(std::string("Directional"));
  for (i = 0; i < (int)options->size(); i++) {
    std::string currentOption = (*options)[i];
    if (BZDB.get("forceFeedback") == currentOption)
      option->setIndex(i);
  }
  option->update();
  listHUD.push_back(option);

  option = new HUDuiList;
  // axis settings
  jsx = option;
  option->setFontFace(fontFace);
  option->setLabel("Joystick X Axis:");
  option->setCallback(callback, "X");
  listHUD.push_back(option);
  option = new HUDuiList;
  jsy = option;
  option->setFontFace(fontFace);
  option->setLabel("Joystick Y Axis:");
  option->setCallback(callback, "Y");
  listHUD.push_back(option);
  fillJSOptions();

  option = new HUDuiList;
  // confine mouse
  option->setFontFace(fontFace);
  option->setLabel("Confine mouse:");
  option->setCallback(callback, "G");
  options = &option->getList();
  options->push_back(std::string("No"));
  options->push_back(std::string("Window"));
  options->push_back(std::string("MotionBox"));
  if (getMainWindow()->isGrabEnabled()) {
    option->setIndex(1);
  } else if (BZDB.isTrue("mouseClamp")) {
    option->setIndex(2);
  } else {
    option->setIndex(0);
  }
  option->update();
  listHUD.push_back(option);

  option = new HUDuiList;
  // jump while typing on/off
  option->setFontFace(fontFace);
  option->setLabel("Jump while typing:");
  option->setCallback(callback, "H");
  options = &option->getList();
  options->push_back(std::string("No"));
  options->push_back(std::string("Yes"));
  option->setIndex(BZDB.isTrue("jumpTyping") ? 1 : 0);
  option->update();
  listHUD.push_back(option);

  initNavigation(listHUD, 1,listHUD.size()-1);
}

InputMenu::~InputMenu()
{
  delete keyboardMapMenu;
}

void InputMenu::fillJSOptions()
{
  std::vector<std::string>* xoptions = &jsx->getList();
  std::vector<std::string>* yoptions = &jsy->getList();
  std::vector<std::string> joystickAxes;
  getMainWindow()->getJoyDeviceAxes(joystickAxes);
  if (joystickAxes.empty())
    joystickAxes.push_back("N/A");
  int i;
  for (i = 0; i < (int)joystickAxes.size(); i++) {
    xoptions->push_back(joystickAxes[i]);
    yoptions->push_back(joystickAxes[i]);
  }
  bool found = false;
  for (i = 0; i < (int)xoptions->size(); i++) {
    std::string currentOption = (*xoptions)[i];
    if (BZDB.get("jsXAxis") == currentOption) {
      jsx->setIndex(i);
      found = true;
    }
  }
  if (!found)
    jsx->setIndex(0);
  jsx->update();
  found = false;
  for (i = 0; i < (int)yoptions->size(); i++) {
    std::string currentOption = (*yoptions)[i];
    if (BZDB.get("jsYAxis") == currentOption) {
      jsy->setIndex(i);
      found = true;
    }
  }
  if (!found) {
    if (yoptions->size() > 1)
      jsy->setIndex(1);
    else
      jsy->setIndex(0);
  }
  jsy->update();
}

void			InputMenu::execute()
{
  HUDuiControl* _focus = HUDui::getFocus();
  if (_focus == keyMapping) {
    if (!keyboardMapMenu) keyboardMapMenu = new KeyboardMapMenu;
    HUDDialogStack::get()->push(keyboardMapMenu);
  }
}

void			InputMenu::callback(HUDuiControl* w, const void* data) {
  HUDuiList* listHUD = (HUDuiList*)w;
  std::vector<std::string> *options = &listHUD->getList();
  std::string selectedOption = (*options)[listHUD->getIndex()];
  switch (((const char*)data)[0]) {

    /* Joystick name */
    case 'J':
      BZDB.set("joystickname", selectedOption);
      getMainWindow()->initJoystick(selectedOption);
      // re-fill all of the joystick-specific options lists
      // fillJSOptions();
      break;

    /* Joystick x-axis */
    case 'X':
      BZDB.set("jsXAxis", selectedOption);
      getMainWindow()->setJoyXAxis(selectedOption);
      break;

    /* Joystick y-axis */
    case 'Y':
      BZDB.set("jsYAxis", selectedOption);
      getMainWindow()->setJoyYAxis(selectedOption);
      break;

    /* Active input device */
    case 'A':
      {
	LocalPlayer*   myTank = LocalPlayer::getMyTank();
	// Are we forced to use one input device, or do we allow it to change automatically?
	if (selectedOption == "Auto") {
	  BZDB.set("allowInputChange", "1");
	} else {
	  BZDB.set("allowInputChange", "0");
	  BZDB.set("activeInputDevice", selectedOption);
	  // Set the current input device to whatever we're forced to
	  if (myTank) {
	    myTank->setInputMethod(BZDB.get("activeInputDevice"));
	  }
	}
      }
      break;

    /* Grab mouse */
    case 'G':
      {
	const bool grabbing = (selectedOption == "Window");
	BZDB.set("mousegrab", grabbing ? "1" : "0");
	getMainWindow()->enableGrabMouse(grabbing);

	const bool clamped = (selectedOption == "MotionBox");
	BZDB.set("mouseClamp", clamped ? "1" : "0");
      }
      break;

    /* Jump while typing */
    case 'H':
      {
	bool jump = (selectedOption == "Yes");
	BZDB.setBool("jumpTyping", jump ? true : false);
      }
      break;

    /* Force feedback */
    case 'F':
      BZDB.set("forceFeedback", selectedOption);
      break;

  }
}

void			InputMenu::resize(int _width, int _height)
{
  HUDDialog::resize(_width, _height);
  int i;

  // use a big font for title, smaller font for the rest
  const float titleFontSize = (float)_height / 15.0f;
  const float fontSize = (float)_height / 45.0f;
  FontManager &fm = FontManager::instance();

  // reposition title
  std::vector<HUDuiControl*>& listHUD = getControls();
  HUDuiLabel* title = (HUDuiLabel*)listHUD[0];
  title->setFontSize(titleFontSize);
  const float titleWidth = fm.getStrLength(MainMenu::getFontFace(), titleFontSize, title->getString());
  const float titleHeight = fm.getStrHeight(MainMenu::getFontFace(), titleFontSize, " ");
  float x = 0.5f * ((float)_width - titleWidth);
  float y = (float)_height - titleHeight;
  title->setPosition(x, y);

  // reposition options
  x = 0.5f * ((float)_width + 0.5f * titleWidth);
  y -= 0.6f * titleHeight;
  const float h = fm.getStrHeight(MainMenu::getFontFace(), fontSize, " ");
  const int count = listHUD.size();
  for (i = 1; i < count; i++) {
    listHUD[i]->setFontSize(fontSize);
    listHUD[i]->setPosition(x, y);
    y -= 1.0f * h;
  }

  // load current settings
  std::vector<std::string> *options = &activeInput->getList();
  for (i = 0; i < (int)options->size(); i++) {
    std::string currentOption = (*options)[i];
    if (BZDB.get("activeInputDevice") == currentOption)
      activeInput->setIndex(i);
  }
  if (BZDB.isTrue("allowInputChange"))
    activeInput->setIndex(0);
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>Refill the joystick axis list on the menu when a user switches a joystick device, without having to restart the client<commit_after>/* bzflag
 * Copyright (c) 1993-2013 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "InputMenu.h"

/* common implementation headers */
#include "StateDatabase.h"
#include "FontManager.h"

/* local implementation headers */
#include "MainMenu.h"
#include "HUDDialogStack.h"
#include "LocalPlayer.h"
#include "playing.h"
#include "HUDui.h"

InputMenu::InputMenu() : keyboardMapMenu(NULL)
{
  std::string currentJoystickDevice = BZDB.get("joystickname");
  // cache font face ID
  int fontFace = MainMenu::getFontFace();
  // add controls
  std::vector<HUDuiControl*>& listHUD = getControls();

  HUDuiLabel* label = new HUDuiLabel;
  label->setFontFace(fontFace);
  label->setString("Input Settings");
  listHUD.push_back(label);

  keyMapping = new HUDuiLabel;
  keyMapping->setFontFace(fontFace);
  keyMapping->setLabel("Change Key Mapping");
  listHUD.push_back(keyMapping);

  HUDuiList* option = new HUDuiList;

  option = new HUDuiList;
  std::vector<std::string>* options = &option->getList();
  // set joystick Device
  option->setFontFace(fontFace);
  option->setLabel("Joystick device:");
  option->setCallback(callback, "J");
  options = &option->getList();
  options->push_back(std::string("Off"));
  std::vector<std::string> joystickDevices;
  getMainWindow()->getJoyDevices(joystickDevices);
  int i;
  for (i = 0; i < (int)joystickDevices.size(); i++) {
    options->push_back(joystickDevices[i]);
  }
  joystickDevices.erase(joystickDevices.begin(), joystickDevices.end());
  for (i = 0; i < (int)options->size(); i++) {
    if ((*options)[i].compare(currentJoystickDevice) == 0) {
      option->setIndex(i);
      break;
    }
  }
  option->update();
  listHUD.push_back(option);

  activeInput = new HUDuiList;
  activeInput->setFontFace(fontFace);
  activeInput->setLabel("Active input device:");
  activeInput->setCallback(callback, "A");
  options = &activeInput->getList();
  options->push_back("Auto");
  options->push_back(LocalPlayer::getInputMethodName(LocalPlayer::Keyboard));
  options->push_back(LocalPlayer::getInputMethodName(LocalPlayer::Mouse));
  options->push_back(LocalPlayer::getInputMethodName(LocalPlayer::Joystick));
  activeInput->update();
  listHUD.push_back(activeInput);

  option = new HUDuiList;
  // force feedback
  option->setFontFace(fontFace);
  option->setLabel("Force feedback:");
  option->setCallback(callback, "F");
  options = &option->getList();
  options->push_back(std::string("None"));
  options->push_back(std::string("Rumble"));
  options->push_back(std::string("Directional"));
  for (i = 0; i < (int)options->size(); i++) {
    std::string currentOption = (*options)[i];
    if (BZDB.get("forceFeedback") == currentOption)
      option->setIndex(i);
  }
  option->update();
  listHUD.push_back(option);

  option = new HUDuiList;
  // axis settings
  jsx = option;
  option->setFontFace(fontFace);
  option->setLabel("Joystick X Axis:");
  option->setCallback(callback, "X");
  listHUD.push_back(option);
  option = new HUDuiList;
  jsy = option;
  option->setFontFace(fontFace);
  option->setLabel("Joystick Y Axis:");
  option->setCallback(callback, "Y");
  listHUD.push_back(option);
  fillJSOptions();

  option = new HUDuiList;
  // confine mouse
  option->setFontFace(fontFace);
  option->setLabel("Confine mouse:");
  option->setCallback(callback, "G");
  options = &option->getList();
  options->push_back(std::string("No"));
  options->push_back(std::string("Window"));
  options->push_back(std::string("MotionBox"));
  if (getMainWindow()->isGrabEnabled()) {
    option->setIndex(1);
  } else if (BZDB.isTrue("mouseClamp")) {
    option->setIndex(2);
  } else {
    option->setIndex(0);
  }
  option->update();
  listHUD.push_back(option);

  option = new HUDuiList;
  // jump while typing on/off
  option->setFontFace(fontFace);
  option->setLabel("Jump while typing:");
  option->setCallback(callback, "H");
  options = &option->getList();
  options->push_back(std::string("No"));
  options->push_back(std::string("Yes"));
  option->setIndex(BZDB.isTrue("jumpTyping") ? 1 : 0);
  option->update();
  listHUD.push_back(option);

  initNavigation(listHUD, 1,listHUD.size()-1);
}

InputMenu::~InputMenu()
{
  delete keyboardMapMenu;
}

void InputMenu::fillJSOptions()
{
  std::vector<std::string>* xoptions = &jsx->getList();
  std::vector<std::string>* yoptions = &jsy->getList();
  std::vector<std::string> joystickAxes;
  getMainWindow()->getJoyDeviceAxes(joystickAxes);
  if (joystickAxes.empty())
    joystickAxes.push_back("N/A");
  int i;
  for (i = 0; i < (int)joystickAxes.size(); i++) {
    xoptions->push_back(joystickAxes[i]);
    yoptions->push_back(joystickAxes[i]);
  }
  bool found = false;
  for (i = 0; i < (int)xoptions->size(); i++) {
    std::string currentOption = (*xoptions)[i];
    if (BZDB.get("jsXAxis") == currentOption) {
      jsx->setIndex(i);
      found = true;
    }
  }
  if (!found)
    jsx->setIndex(0);
  jsx->update();
  found = false;
  for (i = 0; i < (int)yoptions->size(); i++) {
    std::string currentOption = (*yoptions)[i];
    if (BZDB.get("jsYAxis") == currentOption) {
      jsy->setIndex(i);
      found = true;
    }
  }
  if (!found) {
    if (yoptions->size() > 1)
      jsy->setIndex(1);
    else
      jsy->setIndex(0);
  }
  jsy->update();
}

void			InputMenu::execute()
{
  HUDuiControl* _focus = HUDui::getFocus();
  if (_focus == keyMapping) {
    if (!keyboardMapMenu) keyboardMapMenu = new KeyboardMapMenu;
    HUDDialogStack::get()->push(keyboardMapMenu);
  }
}

void			InputMenu::callback(HUDuiControl* w, const void* data) {
  HUDuiList* listHUD = (HUDuiList*)w;
  std::vector<std::string> *options = &listHUD->getList();
  std::string selectedOption = (*options)[listHUD->getIndex()];
  InputMenu *menu = (InputMenu *) HUDDialogStack::get()->top();
  switch (((const char*)data)[0]) {

    /* Joystick name */
    case 'J':
      BZDB.set("joystickname", selectedOption);
      getMainWindow()->initJoystick(selectedOption);
      // re-fill all of the joystick-specific options lists
      if (menu)
        menu->fillJSOptions();
      break;

    /* Joystick x-axis */
    case 'X':
      BZDB.set("jsXAxis", selectedOption);
      getMainWindow()->setJoyXAxis(selectedOption);
      break;

    /* Joystick y-axis */
    case 'Y':
      BZDB.set("jsYAxis", selectedOption);
      getMainWindow()->setJoyYAxis(selectedOption);
      break;

    /* Active input device */
    case 'A':
      {
	LocalPlayer*   myTank = LocalPlayer::getMyTank();
	// Are we forced to use one input device, or do we allow it to change automatically?
	if (selectedOption == "Auto") {
	  BZDB.set("allowInputChange", "1");
	} else {
	  BZDB.set("allowInputChange", "0");
	  BZDB.set("activeInputDevice", selectedOption);
	  // Set the current input device to whatever we're forced to
	  if (myTank) {
	    myTank->setInputMethod(BZDB.get("activeInputDevice"));
	  }
	}
      }
      break;

    /* Grab mouse */
    case 'G':
      {
	const bool grabbing = (selectedOption == "Window");
	BZDB.set("mousegrab", grabbing ? "1" : "0");
	getMainWindow()->enableGrabMouse(grabbing);

	const bool clamped = (selectedOption == "MotionBox");
	BZDB.set("mouseClamp", clamped ? "1" : "0");
      }
      break;

    /* Jump while typing */
    case 'H':
      {
	bool jump = (selectedOption == "Yes");
	BZDB.setBool("jumpTyping", jump ? true : false);
      }
      break;

    /* Force feedback */
    case 'F':
      BZDB.set("forceFeedback", selectedOption);
      break;

  }
}

void			InputMenu::resize(int _width, int _height)
{
  HUDDialog::resize(_width, _height);
  int i;

  // use a big font for title, smaller font for the rest
  const float titleFontSize = (float)_height / 15.0f;
  const float fontSize = (float)_height / 45.0f;
  FontManager &fm = FontManager::instance();

  // reposition title
  std::vector<HUDuiControl*>& listHUD = getControls();
  HUDuiLabel* title = (HUDuiLabel*)listHUD[0];
  title->setFontSize(titleFontSize);
  const float titleWidth = fm.getStrLength(MainMenu::getFontFace(), titleFontSize, title->getString());
  const float titleHeight = fm.getStrHeight(MainMenu::getFontFace(), titleFontSize, " ");
  float x = 0.5f * ((float)_width - titleWidth);
  float y = (float)_height - titleHeight;
  title->setPosition(x, y);

  // reposition options
  x = 0.5f * ((float)_width + 0.5f * titleWidth);
  y -= 0.6f * titleHeight;
  const float h = fm.getStrHeight(MainMenu::getFontFace(), fontSize, " ");
  const int count = listHUD.size();
  for (i = 1; i < count; i++) {
    listHUD[i]->setFontSize(fontSize);
    listHUD[i]->setPosition(x, y);
    y -= 1.0f * h;
  }

  // load current settings
  std::vector<std::string> *options = &activeInput->getList();
  for (i = 0; i < (int)options->size(); i++) {
    std::string currentOption = (*options)[i];
    if (BZDB.get("activeInputDevice") == currentOption)
      activeInput->setIndex(i);
  }
  if (BZDB.isTrue("allowInputChange"))
    activeInput->setIndex(0);
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2003 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include "callbacks.h"
#include "LocalPlayer.h"
#include "HUDRenderer.h"

extern LocalPlayer*	myTank;
extern HUDRenderer*	hud;

void setFlagHelp(const std::string& name, void*)
{
  static const float FlagHelpDuration = 60.0f;
  if (BZDB->isTrue(name))
    hud->setFlagHelp(myTank->getFlag(), FlagHelpDuration);
  else
    hud->setFlagHelp(Flags::Null, 0.0);
}

// ex: shiftwidth=2 tabstop=8
<commit_msg>always check that myTank exists<commit_after>/* bzflag
 * Copyright (c) 1993 - 2003 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include "callbacks.h"
#include "LocalPlayer.h"
#include "HUDRenderer.h"

extern LocalPlayer*	myTank;
extern HUDRenderer*	hud;

void setFlagHelp(const std::string& name, void*)
{
  if (myTank == NULL)
    return;
  static const float FlagHelpDuration = 60.0f;
  if (BZDB->isTrue(name))
    hud->setFlagHelp(myTank->getFlag(), FlagHelpDuration);
  else
    hud->setFlagHelp(Flags::Null, 0.0);
}

// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>/* bzflag
* Copyright (c) 1993 - 2005 Tim Riker
*
* This package is free software;  you can redistribute it and/or
* modify it under the terms of the license found in the file
* named COPYING that should have accompanied this file.
*
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/

#include <string>
#include <vector>
#include <map>

#include "common.h"
#include "bzfio.h"
#include "version.h"
#include "TextUtils.h"
#include "commands.h"
#include "bzfsAPI.h"
#include "DirectoryNames.h"

#ifdef _WIN32
std::string extension = ".dll";
std::string globalPluginDir = ".\\plugins\\";
#else
std::string extension = ".so";
std::string globalPluginDir = "$(prefix)/lib/bzflag/";
#endif

typedef std::map<std::string, bz_APIPluginHandler*> tmCustomPluginMap;
tmCustomPluginMap customPluginMap;

typedef struct
{
	std::string plugin;

#ifdef _WIN32
	HINSTANCE	handle;
#else
	void*		handle;
#endif
}trPluginRecord;

std::string findPlugin ( std::string pluginName )
{
	// see if we can just open the bloody thing
	FILE	*fp = fopen(pluginName.c_str(),"rb");
	if (fp)
	{
		fclose(fp);
		return pluginName;
	}

	// now try it with the standard extension
	std::string name = pluginName + extension;
	fp = fopen(name.c_str(),"rb");
	if (fp)
	{
		fclose(fp);
		return name;
	}

	// check the local users plugins dir
	name = getConfigDirName(BZ_CONFIG_DIR_VERSION) + pluginName + extension;
	fp = fopen(name.c_str(),"rb");
	if (fp)
	{
		fclose(fp);
		return name;
	}

	// check the global plugins dir
	name = globalPluginDir + pluginName + extension;
	fp = fopen(name.c_str(),"rb");
	if (fp)
	{
		fclose(fp);
		return name;
	}

	return std::string("");
}

std::vector<trPluginRecord>	vPluginList;

void unload1Plugin ( int iPluginID );

#ifdef _WIN32
#include <windows.h>

int getPluginVersion ( HINSTANCE hLib )
{
	int (*lpProc)(void);
	lpProc = (int (__cdecl *)(void))GetProcAddress(hLib, "bz_GetVersion");
	if (lpProc)
		return lpProc();
	return 0;
}

bool load1Plugin ( std::string plugin, std::string config )
{
	int (*lpProc)(const char*);

	std::string realPluginName = findPlugin(plugin);

	HINSTANCE	hLib = LoadLibrary(realPluginName.c_str());
	if (hLib)
	{
		if (getPluginVersion(hLib) < BZ_API_VERSION)
		{
			DEBUG1("Plugin:%s found but expects an older API version (%d), upgrade it\n",plugin.c_str(),getPluginVersion(hLib));
			FreeLibrary(hLib);
			return false;
		}
		else
		{
			lpProc = (int (__cdecl *)(const char*))GetProcAddress(hLib, "bz_Load");
			if (lpProc)
			{
				lpProc(config.c_str());
				DEBUG1("Plugin:%s loaded\n",plugin.c_str());

				trPluginRecord pluginRecord;
				pluginRecord.handle = hLib;
				pluginRecord.plugin = plugin;
				vPluginList.push_back(pluginRecord);
				return true;
			}
			else
			{
				DEBUG1("Plugin:%s found but does not contain bz_Load method\n",plugin.c_str());
				FreeLibrary(hLib);
				return false;
			}
		}
	}
	else
	{
		DEBUG1("Plugin:%s not found\n",plugin.c_str());
		return true;
	}
}

void unload1Plugin ( int iPluginID )
{
	int (*lpProc)(void);

	trPluginRecord &plugin = vPluginList[iPluginID];

	lpProc = (int (__cdecl *)(void))GetProcAddress(plugin.handle, "bz_Unload");
	if (lpProc)
		lpProc();
	else
		DEBUG1("Plugin does not contain bz_UnLoad method\n");

	FreeLibrary(plugin.handle);
	plugin.handle = NULL;
}
#else

#include <dlfcn.h>
std::vector<void*>	vLibHandles;

int getPluginVersion ( void* hLib )
{
	int (*lpProc)(void);
	*(void**) &lpProc = dlsym(hLib,"bz_GetVersion");
	if (lpProc)
		return (*lpProc)();
	return 0;
}

bool load1Plugin ( std::string plugin, std::string config )
{
	int (*lpProc)(const char*);

	std::string realPluginName = findPlugin(plugin);

	void *hLib = dlopen(realPluginName.c_str(), RTLD_LAZY | RTLD_GLOBAL);
	if (hLib)
	{
		if (dlsym(hLib, "bz_Load") == NULL) {
			DEBUG1("Plugin:%s found but does not contain bz_Load method, error %s\n",plugin.c_str(),dlerror());
			dlclose(hLib);
			return false;
		}

		int version = getPluginVersion(hLib);
		if (version < BZ_API_VERSION)
		{
			DEBUG1("Plugin:%s found but expects an older API version (%d), upgrade it\n", plugin.c_str(), version);
			dlclose(hLib);
			return false;
		}
		else
		{
			*(void**) &lpProc = dlsym(hLib,"bz_Load");
			if (lpProc)
			{
				(*lpProc)(config.c_str());
				DEBUG1("Plugin:%s loaded\n",plugin.c_str());
				trPluginRecord pluginRecord;
				pluginRecord.handle = hLib;
				pluginRecord.plugin = plugin;
				vPluginList.push_back(pluginRecord);
				return true;
			}
		}
	}
	else
	{
		DEBUG1("Plugin:%s not found, error %s\n",plugin.c_str(), dlerror());
		return false;
	}

	DEBUG1("If you see this, there is something terribly wrong.\n");
	return false;
}

void unload1Plugin ( int iPluginID )
{
	int (*lpProc)(void);
	trPluginRecord &plugin = vPluginList[iPluginID];

	*(void**) &lpProc = dlsym(plugin.handle, "bz_Unload");
	if (lpProc)
		(*lpProc)();
	else
		DEBUG1("Plugin does not contain bz_UnLoad method, error %s\n",dlerror());

	dlclose(plugin.handle);
	plugin.handle = NULL;
}
#endif

bool loadPlugin ( std::string plugin, std::string config )
{
	// check and see if it's an extension we have a handler for
	std::string ext;

	std::vector<std::string> parts = TextUtils::tokenize(plugin,std::string("."));
	ext = parts[parts.size()-1];

	tmCustomPluginMap::iterator itr = customPluginMap.find(TextUtils::tolower(ext));

	if (itr != customPluginMap.end() && itr->second)
	{
		bz_APIPluginHandler *handler = itr->second;
		return handler->handle(plugin,config);
	}
	else
		return load1Plugin(plugin,config);
}

bool unloadPlugin ( std::string plugin )
{
	// unload the first one of the name we find
	for (unsigned int i = 0; i < vPluginList.size();i++)
	{
		if ( vPluginList[i].plugin == plugin )
		{
			unload1Plugin(i);
			vPluginList.erase(vPluginList.begin()+i);
			return true;
		}
	}
        return false;
}

void unloadPlugins ( void )
{
	for (unsigned int i = 0; i < vPluginList.size();i++)
		unload1Plugin(i);
	vPluginList.clear();

	removeCustomSlashCommand("loadplugin");
	removeCustomSlashCommand("unloadplugin");
	removeCustomSlashCommand("listplugins");
}

std::vector<std::string> getPluginList ( void )
{
	std::vector<std::string> plugins;
	for (unsigned int i = 0; i < vPluginList.size();i++)
		plugins.push_back(vPluginList[i].plugin);

	return plugins;
}

void parseServerCommand(const char *message, int dstPlayerId);

class DynamicPluginCommands : public bz_CustomSlashCommandHandler
{
public:
	virtual ~DynamicPluginCommands(){};
	virtual bool handle ( int playerID, bzApiString _command, bzApiString _message )
	{
		bz_PlayerRecord	record;

		std::string command = _command.c_str();
		std::string message = _message.c_str();

		bz_PlayerRecord	*p = bz_getPlayerByIndex(playerID);
		if (!p)
			return false;

		record = *p;

		bz_freePlayerRecord(p);

		// list dosn't need admin
		if ( TextUtils::tolower(command) == "listplugins" )
		{
			std::vector<std::string>	plugins = getPluginList();

			if (!plugins.size())
				bz_sendTextMessage(BZ_SERVER,playerID,"No Plug-ins loaded.");
			else
			{
				bz_sendTextMessage(BZ_SERVER,playerID,"Plug-ins loaded:");

				for ( unsigned int i = 0; i < plugins.size(); i++)
					bz_sendTextMessage(BZ_SERVER,playerID,plugins[i].c_str());
			}
			return true;
		}

		if ( !record.admin )
		{
			bz_sendTextMessage(BZ_SERVER,playerID,"You do not have permission to (un)load plug-ins.");
			return true;
		}

		if ( TextUtils::tolower(command) == "loadplugin" )
		{
			if ( !message.size() )
			{
				bz_sendTextMessage(BZ_SERVER,playerID,"Usage: /loadplugin plug-in");
				return true;
			}

			std::vector<std::string> params = TextUtils::tokenize(message,std::string(","));

			std::string config;
			if ( params.size() >1)
				config = params[1];

			if (loadPlugin(params[0],config))
				bz_sendTextMessage(BZ_SERVER,playerID,"Plug-in loaded.");
			else
				bz_sendTextMessage(BZ_SERVER,playerID,"Plug-in load failed.");
			return true;
		}

		if ( TextUtils::tolower(command) == "unloadplugin" )
		{
			if ( !message.size() )
			{
				bz_sendTextMessage(BZ_SERVER,playerID,"Usage: /unloadplugin plug-in");
				return true;
			}

			if ( unloadPlugin(message) )
				bz_sendTextMessage(BZ_SERVER,playerID,"Plug-in unloaded.");

			return true;
		}
		return true;
	}
};

DynamicPluginCommands	command;

void initPlugins ( void )
{
	customPluginMap.clear();

	registerCustomSlashCommand("loadplugin",&command);
	registerCustomSlashCommand("unloadplugin",&command);
	registerCustomSlashCommand("listplugins",&command);
}

bool registerCustomPluginHandler ( std::string exte, bz_APIPluginHandler *handler )
{
	std::string ext = TextUtils::tolower(exte);
	customPluginMap[ext] = handler;
	return true;
}

bool removeCustomPluginHandler ( std::string ext, bz_APIPluginHandler *handler )
{
	tmCustomPluginMap::iterator itr = customPluginMap.find(TextUtils::tolower(ext));

	if (itr == customPluginMap.end() || itr->second != handler)
		return false;

	customPluginMap.erase(itr);
	return true;
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>don't indicate successful load on plugin not found on win32<commit_after>/* bzflag
* Copyright (c) 1993 - 2005 Tim Riker
*
* This package is free software;  you can redistribute it and/or
* modify it under the terms of the license found in the file
* named COPYING that should have accompanied this file.
*
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/

#include <string>
#include <vector>
#include <map>

#include "common.h"
#include "bzfio.h"
#include "version.h"
#include "TextUtils.h"
#include "commands.h"
#include "bzfsAPI.h"
#include "DirectoryNames.h"

#ifdef _WIN32
std::string extension = ".dll";
std::string globalPluginDir = ".\\plugins\\";
#else
std::string extension = ".so";
std::string globalPluginDir = "$(prefix)/lib/bzflag/";
#endif

typedef std::map<std::string, bz_APIPluginHandler*> tmCustomPluginMap;
tmCustomPluginMap customPluginMap;

typedef struct
{
	std::string plugin;

#ifdef _WIN32
	HINSTANCE	handle;
#else
	void*		handle;
#endif
}trPluginRecord;

std::string findPlugin ( std::string pluginName )
{
	// see if we can just open the bloody thing
	FILE	*fp = fopen(pluginName.c_str(),"rb");
	if (fp)
	{
		fclose(fp);
		return pluginName;
	}

	// now try it with the standard extension
	std::string name = pluginName + extension;
	fp = fopen(name.c_str(),"rb");
	if (fp)
	{
		fclose(fp);
		return name;
	}

	// check the local users plugins dir
	name = getConfigDirName(BZ_CONFIG_DIR_VERSION) + pluginName + extension;
	fp = fopen(name.c_str(),"rb");
	if (fp)
	{
		fclose(fp);
		return name;
	}

	// check the global plugins dir
	name = globalPluginDir + pluginName + extension;
	fp = fopen(name.c_str(),"rb");
	if (fp)
	{
		fclose(fp);
		return name;
	}

	return std::string("");
}

std::vector<trPluginRecord>	vPluginList;

void unload1Plugin ( int iPluginID );

#ifdef _WIN32
#include <windows.h>

int getPluginVersion ( HINSTANCE hLib )
{
	int (*lpProc)(void);
	lpProc = (int (__cdecl *)(void))GetProcAddress(hLib, "bz_GetVersion");
	if (lpProc)
		return lpProc();
	return 0;
}

bool load1Plugin ( std::string plugin, std::string config )
{
	int (*lpProc)(const char*);

	std::string realPluginName = findPlugin(plugin);

	HINSTANCE	hLib = LoadLibrary(realPluginName.c_str());
	if (hLib)
	{
		if (getPluginVersion(hLib) < BZ_API_VERSION)
		{
			DEBUG1("Plugin:%s found but expects an older API version (%d), upgrade it\n",plugin.c_str(),getPluginVersion(hLib));
			FreeLibrary(hLib);
			return false;
		}
		else
		{
			lpProc = (int (__cdecl *)(const char*))GetProcAddress(hLib, "bz_Load");
			if (lpProc)
			{
				lpProc(config.c_str());
				DEBUG1("Plugin:%s loaded\n",plugin.c_str());

				trPluginRecord pluginRecord;
				pluginRecord.handle = hLib;
				pluginRecord.plugin = plugin;
				vPluginList.push_back(pluginRecord);
				return true;
			}
			else
			{
				DEBUG1("Plugin:%s found but does not contain bz_Load method\n",plugin.c_str());
				FreeLibrary(hLib);
				return false;
			}
		}
	}
	else
	{
		DEBUG1("Plugin:%s not found\n",plugin.c_str());
		return false;
	}
}

void unload1Plugin ( int iPluginID )
{
	int (*lpProc)(void);

	trPluginRecord &plugin = vPluginList[iPluginID];

	lpProc = (int (__cdecl *)(void))GetProcAddress(plugin.handle, "bz_Unload");
	if (lpProc)
		lpProc();
	else
		DEBUG1("Plugin does not contain bz_UnLoad method\n");

	FreeLibrary(plugin.handle);
	plugin.handle = NULL;
}
#else

#include <dlfcn.h>
std::vector<void*>	vLibHandles;

int getPluginVersion ( void* hLib )
{
	int (*lpProc)(void);
	*(void**) &lpProc = dlsym(hLib,"bz_GetVersion");
	if (lpProc)
		return (*lpProc)();
	return 0;
}

bool load1Plugin ( std::string plugin, std::string config )
{
	int (*lpProc)(const char*);

	std::string realPluginName = findPlugin(plugin);

	void *hLib = dlopen(realPluginName.c_str(), RTLD_LAZY | RTLD_GLOBAL);
	if (hLib)
	{
		if (dlsym(hLib, "bz_Load") == NULL) {
			DEBUG1("Plugin:%s found but does not contain bz_Load method, error %s\n",plugin.c_str(),dlerror());
			dlclose(hLib);
			return false;
		}

		int version = getPluginVersion(hLib);
		if (version < BZ_API_VERSION)
		{
			DEBUG1("Plugin:%s found but expects an older API version (%d), upgrade it\n", plugin.c_str(), version);
			dlclose(hLib);
			return false;
		}
		else
		{
			*(void**) &lpProc = dlsym(hLib,"bz_Load");
			if (lpProc)
			{
				(*lpProc)(config.c_str());
				DEBUG1("Plugin:%s loaded\n",plugin.c_str());
				trPluginRecord pluginRecord;
				pluginRecord.handle = hLib;
				pluginRecord.plugin = plugin;
				vPluginList.push_back(pluginRecord);
				return true;
			}
		}
	}
	else
	{
		DEBUG1("Plugin:%s not found, error %s\n",plugin.c_str(), dlerror());
		return false;
	}

	DEBUG1("If you see this, there is something terribly wrong.\n");
	return false;
}

void unload1Plugin ( int iPluginID )
{
	int (*lpProc)(void);
	trPluginRecord &plugin = vPluginList[iPluginID];

	*(void**) &lpProc = dlsym(plugin.handle, "bz_Unload");
	if (lpProc)
		(*lpProc)();
	else
		DEBUG1("Plugin does not contain bz_UnLoad method, error %s\n",dlerror());

	dlclose(plugin.handle);
	plugin.handle = NULL;
}
#endif

bool loadPlugin ( std::string plugin, std::string config )
{
	// check and see if it's an extension we have a handler for
	std::string ext;

	std::vector<std::string> parts = TextUtils::tokenize(plugin,std::string("."));
	ext = parts[parts.size()-1];

	tmCustomPluginMap::iterator itr = customPluginMap.find(TextUtils::tolower(ext));

	if (itr != customPluginMap.end() && itr->second)
	{
		bz_APIPluginHandler *handler = itr->second;
		return handler->handle(plugin,config);
	}
	else
		return load1Plugin(plugin,config);
}

bool unloadPlugin ( std::string plugin )
{
	// unload the first one of the name we find
	for (unsigned int i = 0; i < vPluginList.size();i++)
	{
		if ( vPluginList[i].plugin == plugin )
		{
			unload1Plugin(i);
			vPluginList.erase(vPluginList.begin()+i);
			return true;
		}
	}
        return false;
}

void unloadPlugins ( void )
{
	for (unsigned int i = 0; i < vPluginList.size();i++)
		unload1Plugin(i);
	vPluginList.clear();

	removeCustomSlashCommand("loadplugin");
	removeCustomSlashCommand("unloadplugin");
	removeCustomSlashCommand("listplugins");
}

std::vector<std::string> getPluginList ( void )
{
	std::vector<std::string> plugins;
	for (unsigned int i = 0; i < vPluginList.size();i++)
		plugins.push_back(vPluginList[i].plugin);

	return plugins;
}

void parseServerCommand(const char *message, int dstPlayerId);

class DynamicPluginCommands : public bz_CustomSlashCommandHandler
{
public:
	virtual ~DynamicPluginCommands(){};
	virtual bool handle ( int playerID, bzApiString _command, bzApiString _message )
	{
		bz_PlayerRecord	record;

		std::string command = _command.c_str();
		std::string message = _message.c_str();

		bz_PlayerRecord	*p = bz_getPlayerByIndex(playerID);
		if (!p)
			return false;

		record = *p;

		bz_freePlayerRecord(p);

		// list dosn't need admin
		if ( TextUtils::tolower(command) == "listplugins" )
		{
			std::vector<std::string>	plugins = getPluginList();

			if (!plugins.size())
				bz_sendTextMessage(BZ_SERVER,playerID,"No Plug-ins loaded.");
			else
			{
				bz_sendTextMessage(BZ_SERVER,playerID,"Plug-ins loaded:");

				for ( unsigned int i = 0; i < plugins.size(); i++)
					bz_sendTextMessage(BZ_SERVER,playerID,plugins[i].c_str());
			}
			return true;
		}

		if ( !record.admin )
		{
			bz_sendTextMessage(BZ_SERVER,playerID,"You do not have permission to (un)load plug-ins.");
			return true;
		}

		if ( TextUtils::tolower(command) == "loadplugin" )
		{
			if ( !message.size() )
			{
				bz_sendTextMessage(BZ_SERVER,playerID,"Usage: /loadplugin plug-in");
				return true;
			}

			std::vector<std::string> params = TextUtils::tokenize(message,std::string(","));

			std::string config;
			if ( params.size() >1)
				config = params[1];

			if (loadPlugin(params[0],config))
				bz_sendTextMessage(BZ_SERVER,playerID,"Plug-in loaded.");
			else
				bz_sendTextMessage(BZ_SERVER,playerID,"Plug-in load failed.");
			return true;
		}

		if ( TextUtils::tolower(command) == "unloadplugin" )
		{
			if ( !message.size() )
			{
				bz_sendTextMessage(BZ_SERVER,playerID,"Usage: /unloadplugin plug-in");
				return true;
			}

			if ( unloadPlugin(message) )
				bz_sendTextMessage(BZ_SERVER,playerID,"Plug-in unloaded.");

			return true;
		}
		return true;
	}
};

DynamicPluginCommands	command;

void initPlugins ( void )
{
	customPluginMap.clear();

	registerCustomSlashCommand("loadplugin",&command);
	registerCustomSlashCommand("unloadplugin",&command);
	registerCustomSlashCommand("listplugins",&command);
}

bool registerCustomPluginHandler ( std::string exte, bz_APIPluginHandler *handler )
{
	std::string ext = TextUtils::tolower(exte);
	customPluginMap[ext] = handler;
	return true;
}

bool removeCustomPluginHandler ( std::string ext, bz_APIPluginHandler *handler )
{
	tmCustomPluginMap::iterator itr = customPluginMap.find(TextUtils::tolower(ext));

	if (itr == customPluginMap.end() || itr->second != handler)
		return false;

	customPluginMap.erase(itr);
	return true;
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>/* bzflag
* Copyright (c) 1993 - 2005 Tim Riker
*
* This package is free software;  you can redistribute it and/or
* modify it under the terms of the license found in the file
* named COPYING that should have accompanied this file.
*
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/

#include <string>
#include <vector>
#include <map>

#include "common.h"
#include "bzfio.h"
#include "version.h"
#include "TextUtils.h"
#include "commands.h"
#include "bzfsAPI.h"
#include "DirectoryNames.h"

#ifdef _WIN32
std::string extension = ".dll";
std::string globalPluginDir = ".\\plugins\\";
#else
std::string extension = ".so";
std::string globalPluginDir = "$(prefix)/lib/bzflag/";
#endif

typedef std::map<std::string, bz_APIPluginHandler*> tmCustomPluginMap;
tmCustomPluginMap customPluginMap;

typedef struct
{
	std::string plugin;

#ifdef _WIN32
	HINSTANCE	handle;
#else
	void*		handle;
#endif
}trPluginRecord;

std::string findPlugin ( std::string pluginName )
{
	// see if we can just open the bloody thing
	FILE	*fp = fopen(pluginName.c_str(),"rb");
	if (fp)
	{
		fclose(fp);
		return pluginName;
	}

	// now try it with the standard extension
	std::string name = pluginName + extension;
	fp = fopen(name.c_str(),"rb");
	if (fp)
	{
		fclose(fp);
		return name;
	}

	// check the local users plugins dir
	name = getConfigDirName(BZ_CONFIG_DIR_VERSION) + pluginName + extension;
	fp = fopen(name.c_str(),"rb");
	if (fp)
	{
		fclose(fp);
		return name;
	}

	// check the global plugins dir
	name = globalPluginDir + pluginName + extension;
	fp = fopen(name.c_str(),"rb");
	if (fp)
	{
		fclose(fp);
		return name;
	}

	return std::string("");
}

std::vector<trPluginRecord>	vPluginList;

void unload1Plugin ( int iPluginID );

#ifdef _WIN32
#include <windows.h>

int getPluginVersion ( HINSTANCE hLib )
{
	int (*lpProc)(void);
	lpProc = (int (__cdecl *)(void))GetProcAddress(hLib, "bz_GetVersion");
	if (lpProc)
		return lpProc();
	return 0;
}

bool load1Plugin ( std::string plugin, std::string config )
{
	int (*lpProc)(const char*);

	std::string realPluginName = findPlugin(plugin);

	HINSTANCE	hLib = LoadLibrary(realPluginName.c_str());
	if (hLib)
	{
		if (getPluginVersion(hLib) < BZ_API_VERSION)
		{
			DEBUG1("Plugin:%s found but expects an older API version (%d), upgrade it\n",plugin.c_str(),getPluginVersion(hLib));
			FreeLibrary(hLib);
			return false;
		}
		else
		{
			lpProc = (int (__cdecl *)(const char*))GetProcAddress(hLib, "bz_Load");
			if (lpProc)
			{
				lpProc(config.c_str());
				DEBUG1("Plugin:%s loaded\n",plugin.c_str());

				trPluginRecord pluginRecord;
				pluginRecord.handle = hLib;
				pluginRecord.plugin = plugin;
				vPluginList.push_back(pluginRecord);
				return true;
			}
			else
			{
				DEBUG1("Plugin:%s found but does not contain bz_Load method\n",plugin.c_str());
				FreeLibrary(hLib);
				return false;
			}
		}
	}
	else
	{
		DEBUG1("Plugin:%s not found\n",plugin.c_str());
		return true;
	}
}

void unload1Plugin ( int iPluginID )
{
	int (*lpProc)(void);

	trPluginRecord &plugin = vPluginList[iPluginID];

	lpProc = (int (__cdecl *)(void))GetProcAddress(plugin.handle, "bz_Unload");
	if (lpProc)
		lpProc();
	else
		DEBUG1("Plugin does not contain bz_UnLoad method\n");

	FreeLibrary(plugin.handle);
	plugin.handle = NULL;
}
#else

#include <dlfcn.h>
std::vector<void*>	vLibHandles;

int getPluginVersion ( void* hLib )
{
	int (*lpProc)(void);
	*(void**) &lpProc = dlsym(hLib,"bz_GetVersion");
	if (lpProc)
		return (*lpProc)();
	return 0;
}

bool load1Plugin ( std::string plugin, std::string config )
{
	int (*lpProc)(const char*);

	std::string realPluginName = findPlugin(plugin);

	void *hLib = dlopen(realPluginName.c_str(), RTLD_LAZY | RTLD_GLOBAL);
	if (hLib)
	{
		if (dlsym(hLib, "bz_Load") == NULL) {
			DEBUG1("Plugin:%s found but does not contain bz_Load method, error %s\n",plugin.c_str(),dlerror());
			dlclose(hLib);
			return false;
		}

		int version = getPluginVersion(hLib);
		if (version < BZ_API_VERSION)
		{
			DEBUG1("Plugin:%s found but expects an older API version (%d), upgrade it\n", plugin.c_str(), version);
			dlclose(hLib);
			return false
		}
		else
		{
			*(void**) &lpProc = dlsym(hLib,"bz_Load");
			if (lpProc)
			{
				(*lpProc)(config.c_str());
				DEBUG1("Plugin:%s loaded\n",plugin.c_str());
				trPluginRecord pluginRecord;
				pluginRecord.handle = hLib;
				pluginRecord.plugin = plugin;
				vPluginList.push_back(pluginRecord);
				return true;
			}
		}
	}
	else
	{
		DEBUG1("Plugin:%s not found, error %s\n",plugin.c_str(), dlerror());
		return false;
	}
}

void unload1Plugin ( int iPluginID )
{
	int (*lpProc)(void);
	trPluginRecord &plugin = vPluginList[iPluginID];

	*(void**) &lpProc = dlsym(plugin.handle, "bz_Unload");
	if (lpProc)
		(*lpProc)();
	else
		DEBUG1("Plugin does not contain bz_UnLoad method, error %s\n",dlerror());

	dlclose(plugin.handle);
	plugin.handle = NULL;
}
#endif

bool loadPlugin ( std::string plugin, std::string config )
{
	// check and see if it's an extension we have a handler for
	std::string ext;

	std::vector<std::string> parts = TextUtils::tokenize(plugin,std::string("."));
	ext = parts[parts.size()-1];

	tmCustomPluginMap::iterator itr = customPluginMap.find(TextUtils::tolower(ext));

	if (itr != customPluginMap.end() && itr->second)
	{
		bz_APIPluginHandler *handler = itr->second;
		return handler->handle(plugin,config);
	}
	else
		return load1Plugin(plugin,config);
}

void unloadPlugin ( std::string plugin )
{
	// unload the first one of the name we find
	for (unsigned int i = 0; i < vPluginList.size();i++)
	{
		if ( vPluginList[i].plugin == plugin )
		{
			unload1Plugin(i);
			vPluginList.erase(vPluginList.begin()+i);
			return;
		}
	}
}

void unloadPlugins ( void )
{
	for (unsigned int i = 0; i < vPluginList.size();i++)
		unload1Plugin(i);
	vPluginList.clear();

	removeCustomSlashCommand("loadplugin");
	removeCustomSlashCommand("unloadplugin");
	removeCustomSlashCommand("listplugins");
}

std::vector<std::string> getPluginList ( void )
{
	std::vector<std::string> plugins;
	for (unsigned int i = 0; i < vPluginList.size();i++)
		plugins.push_back(vPluginList[i].plugin);

	return plugins;
}

void parseServerCommand(const char *message, int dstPlayerId);

class DynamicPluginCommands : public bz_CustomSlashCommandHandler
{
public:
	virtual ~DynamicPluginCommands(){};
	virtual bool handle ( int playerID, bzApiString _command, bzApiString _message )
	{
		bz_PlayerRecord	record;

		std::string command = _command.c_str();
		std::string message = _message.c_str();

		bz_PlayerRecord	*p = bz_getPlayerByIndex(playerID);
		if (!p)
			return false;

		record = *p;

		bz_freePlayerRecord(p);

		// list dosn't need admin
		if ( TextUtils::tolower(command) == "listplugins" )
		{
			std::vector<std::string>	plugins = getPluginList();

			if (!plugins.size())
				bz_sendTextMessage(BZ_SERVER,playerID,"No Plug-ins loaded.");
			else
			{
				bz_sendTextMessage(BZ_SERVER,playerID,"Plug-ins loaded:");

				for ( unsigned int i = 0; i < plugins.size(); i++)
					bz_sendTextMessage(BZ_SERVER,playerID,plugins[i].c_str());
			}
			return true;
		}

		if ( !record.admin )
		{
			bz_sendTextMessage(BZ_SERVER,playerID,"You do not have permission to (un)load plug-ins.");
			return true;
		}

		if ( TextUtils::tolower(command) == "loadplugin" )
		{
			if ( !message.size() )
			{
				bz_sendTextMessage(BZ_SERVER,playerID,"Usage: /loadplugin plug-in");
				return true;
			}

			std::vector<std::string> params = TextUtils::tokenize(message,std::string(","));

			std::string config;
			if ( params.size() >1)
				config = params[1];

			if (loadPlugin(params[0],config))
				bz_sendTextMessage(BZ_SERVER,playerID,"Plug-in loaded.");
			else
				bz_sendTextMessage(BZ_SERVER,playerID,"Plug-in load failed.");
			return true;
		}

		if ( TextUtils::tolower(command) == "unloadplugin" )
		{
			if ( !message.size() )
			{
				bz_sendTextMessage(BZ_SERVER,playerID,"Usage: /unloadplugin plug-in");
				return true;
			}

			unloadPlugin(message);

			bz_sendTextMessage(BZ_SERVER,playerID,"Plug-in unloaded.");
			return true;
		}
		return true;
	}
};

DynamicPluginCommands	command;

void initPlugins ( void )
{
	customPluginMap.clear();

	registerCustomSlashCommand("loadplugin",&command);
	registerCustomSlashCommand("unloadplugin",&command);
	registerCustomSlashCommand("listplugins",&command);
}

bool registerCustomPluginHandler ( std::string exte, bz_APIPluginHandler *handler )
{
	std::string ext = TextUtils::tolower(exte);
	customPluginMap[ext] = handler;
	return true;
}

bool removeCustomPluginHandler ( std::string ext, bz_APIPluginHandler *handler )
{
	tmCustomPluginMap::iterator itr = customPluginMap.find(TextUtils::tolower(ext));

	if (itr == customPluginMap.end() || itr->second != handler)
		return false;

	customPluginMap.erase(itr);
	return true;
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>generally statements in C end in a semicolon.  also quell a warning.<commit_after>/* bzflag
* Copyright (c) 1993 - 2005 Tim Riker
*
* This package is free software;  you can redistribute it and/or
* modify it under the terms of the license found in the file
* named COPYING that should have accompanied this file.
*
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/

#include <string>
#include <vector>
#include <map>

#include "common.h"
#include "bzfio.h"
#include "version.h"
#include "TextUtils.h"
#include "commands.h"
#include "bzfsAPI.h"
#include "DirectoryNames.h"

#ifdef _WIN32
std::string extension = ".dll";
std::string globalPluginDir = ".\\plugins\\";
#else
std::string extension = ".so";
std::string globalPluginDir = "$(prefix)/lib/bzflag/";
#endif

typedef std::map<std::string, bz_APIPluginHandler*> tmCustomPluginMap;
tmCustomPluginMap customPluginMap;

typedef struct
{
	std::string plugin;

#ifdef _WIN32
	HINSTANCE	handle;
#else
	void*		handle;
#endif
}trPluginRecord;

std::string findPlugin ( std::string pluginName )
{
	// see if we can just open the bloody thing
	FILE	*fp = fopen(pluginName.c_str(),"rb");
	if (fp)
	{
		fclose(fp);
		return pluginName;
	}

	// now try it with the standard extension
	std::string name = pluginName + extension;
	fp = fopen(name.c_str(),"rb");
	if (fp)
	{
		fclose(fp);
		return name;
	}

	// check the local users plugins dir
	name = getConfigDirName(BZ_CONFIG_DIR_VERSION) + pluginName + extension;
	fp = fopen(name.c_str(),"rb");
	if (fp)
	{
		fclose(fp);
		return name;
	}

	// check the global plugins dir
	name = globalPluginDir + pluginName + extension;
	fp = fopen(name.c_str(),"rb");
	if (fp)
	{
		fclose(fp);
		return name;
	}

	return std::string("");
}

std::vector<trPluginRecord>	vPluginList;

void unload1Plugin ( int iPluginID );

#ifdef _WIN32
#include <windows.h>

int getPluginVersion ( HINSTANCE hLib )
{
	int (*lpProc)(void);
	lpProc = (int (__cdecl *)(void))GetProcAddress(hLib, "bz_GetVersion");
	if (lpProc)
		return lpProc();
	return 0;
}

bool load1Plugin ( std::string plugin, std::string config )
{
	int (*lpProc)(const char*);

	std::string realPluginName = findPlugin(plugin);

	HINSTANCE	hLib = LoadLibrary(realPluginName.c_str());
	if (hLib)
	{
		if (getPluginVersion(hLib) < BZ_API_VERSION)
		{
			DEBUG1("Plugin:%s found but expects an older API version (%d), upgrade it\n",plugin.c_str(),getPluginVersion(hLib));
			FreeLibrary(hLib);
			return false;
		}
		else
		{
			lpProc = (int (__cdecl *)(const char*))GetProcAddress(hLib, "bz_Load");
			if (lpProc)
			{
				lpProc(config.c_str());
				DEBUG1("Plugin:%s loaded\n",plugin.c_str());

				trPluginRecord pluginRecord;
				pluginRecord.handle = hLib;
				pluginRecord.plugin = plugin;
				vPluginList.push_back(pluginRecord);
				return true;
			}
			else
			{
				DEBUG1("Plugin:%s found but does not contain bz_Load method\n",plugin.c_str());
				FreeLibrary(hLib);
				return false;
			}
		}
	}
	else
	{
		DEBUG1("Plugin:%s not found\n",plugin.c_str());
		return true;
	}
}

void unload1Plugin ( int iPluginID )
{
	int (*lpProc)(void);

	trPluginRecord &plugin = vPluginList[iPluginID];

	lpProc = (int (__cdecl *)(void))GetProcAddress(plugin.handle, "bz_Unload");
	if (lpProc)
		lpProc();
	else
		DEBUG1("Plugin does not contain bz_UnLoad method\n");

	FreeLibrary(plugin.handle);
	plugin.handle = NULL;
}
#else

#include <dlfcn.h>
std::vector<void*>	vLibHandles;

int getPluginVersion ( void* hLib )
{
	int (*lpProc)(void);
	*(void**) &lpProc = dlsym(hLib,"bz_GetVersion");
	if (lpProc)
		return (*lpProc)();
	return 0;
}

bool load1Plugin ( std::string plugin, std::string config )
{
	int (*lpProc)(const char*);

	std::string realPluginName = findPlugin(plugin);

	void *hLib = dlopen(realPluginName.c_str(), RTLD_LAZY | RTLD_GLOBAL);
	if (hLib)
	{
		if (dlsym(hLib, "bz_Load") == NULL) {
			DEBUG1("Plugin:%s found but does not contain bz_Load method, error %s\n",plugin.c_str(),dlerror());
			dlclose(hLib);
			return false;
		}

		int version = getPluginVersion(hLib);
		if (version < BZ_API_VERSION)
		{
			DEBUG1("Plugin:%s found but expects an older API version (%d), upgrade it\n", plugin.c_str(), version);
			dlclose(hLib);
			return false;
		}
		else
		{
			*(void**) &lpProc = dlsym(hLib,"bz_Load");
			if (lpProc)
			{
				(*lpProc)(config.c_str());
				DEBUG1("Plugin:%s loaded\n",plugin.c_str());
				trPluginRecord pluginRecord;
				pluginRecord.handle = hLib;
				pluginRecord.plugin = plugin;
				vPluginList.push_back(pluginRecord);
				return true;
			}
		}
	}
	else
	{
		DEBUG1("Plugin:%s not found, error %s\n",plugin.c_str(), dlerror());
		return false;
	}

	DEBUG1("If you see this, there is something terribly wrong.\n");
	return false;
}

void unload1Plugin ( int iPluginID )
{
	int (*lpProc)(void);
	trPluginRecord &plugin = vPluginList[iPluginID];

	*(void**) &lpProc = dlsym(plugin.handle, "bz_Unload");
	if (lpProc)
		(*lpProc)();
	else
		DEBUG1("Plugin does not contain bz_UnLoad method, error %s\n",dlerror());

	dlclose(plugin.handle);
	plugin.handle = NULL;
}
#endif

bool loadPlugin ( std::string plugin, std::string config )
{
	// check and see if it's an extension we have a handler for
	std::string ext;

	std::vector<std::string> parts = TextUtils::tokenize(plugin,std::string("."));
	ext = parts[parts.size()-1];

	tmCustomPluginMap::iterator itr = customPluginMap.find(TextUtils::tolower(ext));

	if (itr != customPluginMap.end() && itr->second)
	{
		bz_APIPluginHandler *handler = itr->second;
		return handler->handle(plugin,config);
	}
	else
		return load1Plugin(plugin,config);
}

void unloadPlugin ( std::string plugin )
{
	// unload the first one of the name we find
	for (unsigned int i = 0; i < vPluginList.size();i++)
	{
		if ( vPluginList[i].plugin == plugin )
		{
			unload1Plugin(i);
			vPluginList.erase(vPluginList.begin()+i);
			return;
		}
	}
}

void unloadPlugins ( void )
{
	for (unsigned int i = 0; i < vPluginList.size();i++)
		unload1Plugin(i);
	vPluginList.clear();

	removeCustomSlashCommand("loadplugin");
	removeCustomSlashCommand("unloadplugin");
	removeCustomSlashCommand("listplugins");
}

std::vector<std::string> getPluginList ( void )
{
	std::vector<std::string> plugins;
	for (unsigned int i = 0; i < vPluginList.size();i++)
		plugins.push_back(vPluginList[i].plugin);

	return plugins;
}

void parseServerCommand(const char *message, int dstPlayerId);

class DynamicPluginCommands : public bz_CustomSlashCommandHandler
{
public:
	virtual ~DynamicPluginCommands(){};
	virtual bool handle ( int playerID, bzApiString _command, bzApiString _message )
	{
		bz_PlayerRecord	record;

		std::string command = _command.c_str();
		std::string message = _message.c_str();

		bz_PlayerRecord	*p = bz_getPlayerByIndex(playerID);
		if (!p)
			return false;

		record = *p;

		bz_freePlayerRecord(p);

		// list dosn't need admin
		if ( TextUtils::tolower(command) == "listplugins" )
		{
			std::vector<std::string>	plugins = getPluginList();

			if (!plugins.size())
				bz_sendTextMessage(BZ_SERVER,playerID,"No Plug-ins loaded.");
			else
			{
				bz_sendTextMessage(BZ_SERVER,playerID,"Plug-ins loaded:");

				for ( unsigned int i = 0; i < plugins.size(); i++)
					bz_sendTextMessage(BZ_SERVER,playerID,plugins[i].c_str());
			}
			return true;
		}

		if ( !record.admin )
		{
			bz_sendTextMessage(BZ_SERVER,playerID,"You do not have permission to (un)load plug-ins.");
			return true;
		}

		if ( TextUtils::tolower(command) == "loadplugin" )
		{
			if ( !message.size() )
			{
				bz_sendTextMessage(BZ_SERVER,playerID,"Usage: /loadplugin plug-in");
				return true;
			}

			std::vector<std::string> params = TextUtils::tokenize(message,std::string(","));

			std::string config;
			if ( params.size() >1)
				config = params[1];

			if (loadPlugin(params[0],config))
				bz_sendTextMessage(BZ_SERVER,playerID,"Plug-in loaded.");
			else
				bz_sendTextMessage(BZ_SERVER,playerID,"Plug-in load failed.");
			return true;
		}

		if ( TextUtils::tolower(command) == "unloadplugin" )
		{
			if ( !message.size() )
			{
				bz_sendTextMessage(BZ_SERVER,playerID,"Usage: /unloadplugin plug-in");
				return true;
			}

			unloadPlugin(message);

			bz_sendTextMessage(BZ_SERVER,playerID,"Plug-in unloaded.");
			return true;
		}
		return true;
	}
};

DynamicPluginCommands	command;

void initPlugins ( void )
{
	customPluginMap.clear();

	registerCustomSlashCommand("loadplugin",&command);
	registerCustomSlashCommand("unloadplugin",&command);
	registerCustomSlashCommand("listplugins",&command);
}

bool registerCustomPluginHandler ( std::string exte, bz_APIPluginHandler *handler )
{
	std::string ext = TextUtils::tolower(exte);
	customPluginMap[ext] = handler;
	return true;
}

bool removeCustomPluginHandler ( std::string ext, bz_APIPluginHandler *handler )
{
	tmCustomPluginMap::iterator itr = customPluginMap.find(TextUtils::tolower(ext));

	if (itr == customPluginMap.end() || itr->second != handler)
		return false;

	customPluginMap.erase(itr);
	return true;
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>#include "mainwindow.h"
#include "ui_mainwindow.h"

//#include <QQuickView>
#include <QGLFormat>
#include <QListView>
#include <QComboBox>
#include <QFileDialog>
#include <QMessageBox>

#include <memory>

#include <asdf_multiplat/main/asdf_multiplat.h>
#include <asdf_multiplat/data/content_manager.h>
#include <hexmap/data/spline.h>

#include <glm/gtc/matrix_transform.hpp>

#include "palette_widget.h"
#include "spline_settings_widget.h"
#include "ui_spline_settings_widget.h"
#include "ui_tools_panel.h"
#include "dialogs/new_map_dialog.h"
#include "ui_new_map_dialog.h"

using namespace std;
//using namespace glm;  //causes namespace collision with uint

namespace
{
    constexpr int scroll_sub_ticks = 10;
}

using editor_t = asdf::hexmap::editor::editor_t;
using tool_type_e = editor_t::tool_type_e;
using spline_t = asdf::hexmap::data::spline_t;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    setWindowTitle("Hexmap");
    editor = &(ui->hexmap_widget->editor);

    {
        connect(ui->actionNew,     &QAction::triggered, this, &MainWindow::new_map);
        connect(ui->actionOpen,    &QAction::triggered, this, &MainWindow::open_map);
        connect(ui->actionSave,    &QAction::triggered, this, &MainWindow::save_map);
        connect(ui->actionSave_As, &QAction::triggered, this, &MainWindow::save_map_as);
    }

    // give hexmap widget a pointer to this, so it can set up scrollbar ranges after initializeGL is called
    // can't do it now because we need the hex_map to be created, which requires an openGL context that hasnt
    // been initialized yet
    // EDIT: This may be solvable with the hex_map_initialized signal
    ui->hexmap_widget->main_window = this;
    ui->hexmap_widget->setMouseTracking(true); //enable to get mouseMove events

    connect(ui->hexmap_hscroll, &QScrollBar::valueChanged, this, &MainWindow::scrollbar_changed);
    connect(ui->hexmap_vscroll, &QScrollBar::valueChanged, this, &MainWindow::scrollbar_changed);

    {
        connect(ui->hexmap_widget, &hexmap_widget_t::hex_map_initialized,
                            this, &MainWindow::hex_map_initialized);
        connect(ui->hexmap_widget, &hexmap_widget_t::editor_tool_changed,
                             this, &MainWindow::editor_tool_changed);
        connect(ui->hexmap_widget, &hexmap_widget_t::camera_changed,
                             this, &MainWindow::set_scrollbar_stuff);

        //FIXME cleanup and/or optimize
        connect(ui->hexmap_widget, &hexmap_widget_t::editor_tool_changed,
                [this](tool_type_e tool){
                    if(tool == editor_t::place_splines)
                    {
                        ui->right_dock->setWidget(spline_settings_widget);
                    }
                    else
                    {
                        ui->right_dock->setWidget(palette_widget);
                    }
                }
        );
    }

    {
        auto* tools_ui = ui->tools_panel->ui;
        auto pressed = &QToolButton::pressed;

        connect(tools_ui->SelectTool, pressed, [this](){ui->hexmap_widget->set_editor_tool(tool_type_e::select);});
        connect(tools_ui->BrushTool,  pressed, [this](){ui->hexmap_widget->set_editor_tool(tool_type_e::terrain_paint);});
        connect(tools_ui->ObjectTool, pressed, [this](){ui->hexmap_widget->set_editor_tool(tool_type_e::place_objects);});
        connect(tools_ui->LineTool,   pressed, [this](){ui->hexmap_widget->set_editor_tool(tool_type_e::place_splines);});
    }

    {
        palette_widget = new palette_widget_t(this);

        palette_widget->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred));
        //palette_widget->setMinimumSize(200, 300);
        palette_widget->updateGeometry();

        connect(palette_widget->list_view, SIGNAL(pressed(const QModelIndex&)),
                        ui->hexmap_widget, SLOT(set_palette_item(const QModelIndex&)));

        ui->right_dock->setWidget(palette_widget);
    }

    {
        spline_settings_widget = new spline_settings_widget_t();

        connect(spline_settings_widget->ui->InterpolationDropDown, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged)
            , [this](int index)
              {
                  ASSERT(index >= 0, "");
                  auto interp = (spline_t::interpolation_e)(index);
                  ui->hexmap_widget->editor.set_current_spline_interpolation(interp);
              });

        connect(spline_settings_widget->ui->LineThicknessSpinner, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
                [this](double value)
                {
                    auto& editor = ui->hexmap_widget->editor;
                    auto node_style = editor.new_node_style;
                    ASSERT(value <= std::numeric_limits<float>::max(), "spline thickness too large to store in a float");
                    node_style.thickness = static_cast<float>(value);
                    ui->hexmap_widget->editor.set_spline_node_style(node_style);
                });
    }

}

MainWindow::~MainWindow()
{
    delete ui;
}

/*
   ________________
  |   entire map   |
  | ________       |
  ||        |      |
  || screen |      |
  ||________|      |
  |________________|
            ^------^ scroll range
*/

/// TODO: refactor this such that most of the math is done in the hexmap widget
///       and the widget then calls this function with scrollbar ranges as params
void MainWindow::set_scrollbar_stuff(asdf::camera_t const& camera)
{
    using namespace glm;

    hexmap_widget_t* hxm_wgt = ui->hexmap_widget;

    vec2 hex_size(asdf::hexmap::hex_width, asdf::hexmap::hex_height);

    auto const& map_size = hxm_wgt->map_size(); //array size
    vec2 map_size_units = vec2(map_size) * hex_size; //total map width in units. Width is not equal to array width because hexagons overlap, and hexagons aren't one unit tall
    map_size_units.x -= (map_size.x - 1) * asdf::hexmap::hex_width_d4; //handle horizontal overlap
    map_size_units.y += asdf::hexmap::hex_height_d2; //add room for the offset

    //get size of a hex in pixels. hex_width and hex_height constexpr constants exist in ui/hex_map.h
    vec2 hx_size_px = hex_size * camera.zoom();
    vec2 map_size_px = map_size_units * hx_size_px;

    base_camera_offset = glm::vec2();
    base_camera_offset.x = width()/2 / asdf::hexmap::px_per_unit;
    base_camera_offset.y = map_size_units.y - (height()/2 / asdf::hexmap::px_per_unit);

    hxm_wgt->camera_pos(base_camera_offset, false);

    //range is equal to how many units fit on the screen minus total map size in units

    //map_size_screen_px = unproject map_size_units from camera?

    glm::vec2 wgt_size(hxm_wgt->width(), hxm_wgt->height());

    auto hxm_proj = hxm_wgt->hex_map->camera.projection_ortho();

    vec4 vp;
    vp.x = 0.0f;
    vp.y = 0.0f;
    vp.z = wgt_size.x;
    vp.w = wgt_size.y;
    auto unprojd = unProject(vec3(wgt_size, 0.0f), glm::mat4(), hxm_proj, vp);

    auto screen_size_units = glm::vec2(unprojd);
    auto scr_range_units = glm::vec2(map_size_units) - glm::vec2(screen_size_units);

    auto* h_scr = ui->hexmap_hscroll;
    h_scr->setMinimum(0);
    h_scr->setMaximum(scr_range_units.x * scroll_sub_ticks);
    h_scr->setPageStep(screen_size_units.x * scroll_sub_ticks);

    auto* v_scr = ui->hexmap_hscroll;
    v_scr->setMinimum(0);
    v_scr->setMaximum(scr_range_units.y * scroll_sub_ticks);
    v_scr->setPageStep(screen_size_units.y * scroll_sub_ticks);

    scrollbar_changed();
}

void MainWindow::scrollbar_changed()
{
    //LOG("scrollbar changed;  x:%d  y%d", ui->hexmap_hscroll->value(), ui->hexmap_vscroll->value());

    glm::vec2 p(ui->hexmap_hscroll->value(), -ui->hexmap_vscroll->value());
    p /= scroll_sub_ticks;
    p += base_camera_offset;

    ui->hexmap_widget->camera_pos(p, false);
    ui->hexmap_widget->update();
}

void MainWindow::new_map()
{
    if(editor->map_is_dirty)
    {
        QMessageBox msgBox;
        msgBox.setText("The document has been modified.");
        msgBox.setInformativeText("Do you want to save your changes?");
        msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
        msgBox.setDefaultButton(QMessageBox::Save);
        int ret = msgBox.exec();

        switch (ret) {
          case QMessageBox::Save:
              save_map();
              break;
          case QMessageBox::Discard:
              break;
          case QMessageBox::Cancel:
              return;
          default: break;
        }
    }

    new_map_dialog_t nm(this);
    if(!nm.exec()) { //exec() blocks the mainw window until the modal dialog is dismissed
        return;
    } else {
        glm::uvec2 map_size(nm.ui->spb_width->value(), nm.ui->spb_height->value());
        ui->hexmap_widget->editor.new_map_action(map_size);
    }
}

void MainWindow::open_map()
{
    QDir map_file(QString(editor->map_filepath.c_str()));

    QString filepath = QFileDialog::getOpenFileName(this,
        tr("Open Map"), map_file.path(), tr("Hexmap Files (*.hxm)"));

    if(filepath.size() > 0)
    {
        editor->load_action(std::string(filepath.toUtf8().constData()));
    }
}

void MainWindow::save_map()
{
    if(ui->hexmap_widget->editor.map_filepath.size() == 0)
    {
        save_map_as();
    }
    else
    {
        ui->hexmap_widget->editor.save_action();
    }
}

void MainWindow::save_map_as()
{
    QString dir(ui->hexmap_widget->editor.map_filepath.c_str());
    QString filepath = QFileDialog::getSaveFileName(this, tr("Save Map"), dir, tr("Hexmap Files (*.hxm)"));

    if(filepath.size() > 0)
    {
        editor->save_action( std::string(filepath.toUtf8().constData()) );
    }
}

void MainWindow::mouseMoveEvent(QMouseEvent* event)
{

}

void MainWindow::mousePressEvent(QMouseEvent* event)
{

}

void MainWindow::mouseReleaseEvent(QMouseEvent* event)
{

}

void MainWindow::hex_map_initialized(asdf::hexmap::editor::editor_t& editor)
{
    terrain_palette_model = new palette_item_model_t();
    objects_palette_model = new palette_item_model_t();

    terrain_palette_model->build_from_terrain_bank(editor.rendered_map->terrain_bank);
    objects_palette_model->build_from_atlas(*(editor.rendered_map->objects_atlas.get()));

    editor_tool_changed(editor.current_tool);
}

void MainWindow::editor_tool_changed(tool_type_e new_tool)
{
    switch(new_tool)
    {
        case tool_type_e::terrain_paint:
            palette_widget->list_view->setModel(terrain_palette_model);
            break;
        case tool_type_e::place_objects:
            palette_widget->list_view->setModel(objects_palette_model);
            break;

    default:
        palette_widget->list_view->setModel(nullptr);
        break;
    }
}
<commit_msg>connected spline_widget coloreSelected signal to a function that updates the editor's spline style<commit_after>#include "mainwindow.h"
#include "ui_mainwindow.h"

//#include <QQuickView>
#include <QGLFormat>
#include <QListView>
#include <QComboBox>
#include <QFileDialog>
#include <QMessageBox>

#include <memory>

#include <asdf_multiplat/main/asdf_multiplat.h>
#include <asdf_multiplat/data/content_manager.h>
#include <hexmap/data/spline.h>

#include <glm/gtc/matrix_transform.hpp>

#include "palette_widget.h"
#include "spline_settings_widget.h"
#include "ui_spline_settings_widget.h"
#include "ui_tools_panel.h"
#include "dialogs/new_map_dialog.h"
#include "ui_new_map_dialog.h"

using namespace std;
//using namespace glm;  //causes namespace collision with uint

namespace
{
    constexpr int scroll_sub_ticks = 10;
}

using editor_t = asdf::hexmap::editor::editor_t;
using tool_type_e = editor_t::tool_type_e;
using spline_t = asdf::hexmap::data::spline_t;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    setWindowTitle("Hexmap");
    editor = &(ui->hexmap_widget->editor);

    {
        connect(ui->actionNew,     &QAction::triggered, this, &MainWindow::new_map);
        connect(ui->actionOpen,    &QAction::triggered, this, &MainWindow::open_map);
        connect(ui->actionSave,    &QAction::triggered, this, &MainWindow::save_map);
        connect(ui->actionSave_As, &QAction::triggered, this, &MainWindow::save_map_as);
    }

    // give hexmap widget a pointer to this, so it can set up scrollbar ranges after initializeGL is called
    // can't do it now because we need the hex_map to be created, which requires an openGL context that hasnt
    // been initialized yet
    // EDIT: This may be solvable with the hex_map_initialized signal
    ui->hexmap_widget->main_window = this;
    ui->hexmap_widget->setMouseTracking(true); //enable to get mouseMove events

    connect(ui->hexmap_hscroll, &QScrollBar::valueChanged, this, &MainWindow::scrollbar_changed);
    connect(ui->hexmap_vscroll, &QScrollBar::valueChanged, this, &MainWindow::scrollbar_changed);

    {
        connect(ui->hexmap_widget, &hexmap_widget_t::hex_map_initialized,
                            this, &MainWindow::hex_map_initialized);
        connect(ui->hexmap_widget, &hexmap_widget_t::editor_tool_changed,
                             this, &MainWindow::editor_tool_changed);
        connect(ui->hexmap_widget, &hexmap_widget_t::camera_changed,
                             this, &MainWindow::set_scrollbar_stuff);

        //FIXME cleanup and/or optimize
        connect(ui->hexmap_widget, &hexmap_widget_t::editor_tool_changed,
                [this](tool_type_e tool){
                    if(tool == editor_t::place_splines)
                    {
                        ui->right_dock->setWidget(spline_settings_widget);
                    }
                    else
                    {
                        ui->right_dock->setWidget(palette_widget);
                    }
                }
        );
    }

    {
        auto* tools_ui = ui->tools_panel->ui;
        auto pressed = &QToolButton::pressed;

        connect(tools_ui->SelectTool, pressed, [this](){ui->hexmap_widget->set_editor_tool(tool_type_e::select);});
        connect(tools_ui->BrushTool,  pressed, [this](){ui->hexmap_widget->set_editor_tool(tool_type_e::terrain_paint);});
        connect(tools_ui->ObjectTool, pressed, [this](){ui->hexmap_widget->set_editor_tool(tool_type_e::place_objects);});
        connect(tools_ui->LineTool,   pressed, [this](){ui->hexmap_widget->set_editor_tool(tool_type_e::place_splines);});
    }

    {
        palette_widget = new palette_widget_t(this);

        palette_widget->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred));
        //palette_widget->setMinimumSize(200, 300);
        palette_widget->updateGeometry();

        connect(palette_widget->list_view, SIGNAL(pressed(const QModelIndex&)),
                        ui->hexmap_widget, SLOT(set_palette_item(const QModelIndex&)));

        ui->right_dock->setWidget(palette_widget);
    }

    {
        spline_settings_widget = new spline_settings_widget_t();

        connect(spline_settings_widget->ui->InterpolationDropDown, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged)
            , [this](int index)
              {
                  ASSERT(index >= 0, "");
                  auto interp = (spline_t::interpolation_e)(index);
                  ui->hexmap_widget->editor.set_current_spline_interpolation(interp);
              });

        connect(spline_settings_widget->ui->LineThicknessSpinner, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
                [this](double value)
                {
                    auto& editor = ui->hexmap_widget->editor;
                    auto node_style = editor.new_node_style;
                    ASSERT(value <= std::numeric_limits<float>::max(), "spline thickness too large to store in a float");
                    node_style.thickness = static_cast<float>(value);
                    ui->hexmap_widget->editor.set_spline_node_style(node_style);
                });

        connect(spline_settings_widget, &spline_settings_widget_t::colorSelected,
                [this](QColor c) {
                    auto& editor = ui->hexmap_widget->editor;
                    auto node_style = editor.new_node_style;
                    node_style.color = color_t(c.redF(), c.greenF(), c.blueF(), c.alphaF());
                    ui->hexmap_widget->editor.set_spline_node_style(node_style);
                });
    }

}

MainWindow::~MainWindow()
{
    delete ui;
}

/*
   ________________
  |   entire map   |
  | ________       |
  ||        |      |
  || screen |      |
  ||________|      |
  |________________|
            ^------^ scroll range
*/

/// TODO: refactor this such that most of the math is done in the hexmap widget
///       and the widget then calls this function with scrollbar ranges as params
void MainWindow::set_scrollbar_stuff(asdf::camera_t const& camera)
{
    using namespace glm;

    hexmap_widget_t* hxm_wgt = ui->hexmap_widget;

    vec2 hex_size(asdf::hexmap::hex_width, asdf::hexmap::hex_height);

    auto const& map_size = hxm_wgt->map_size(); //array size
    vec2 map_size_units = vec2(map_size) * hex_size; //total map width in units. Width is not equal to array width because hexagons overlap, and hexagons aren't one unit tall
    map_size_units.x -= (map_size.x - 1) * asdf::hexmap::hex_width_d4; //handle horizontal overlap
    map_size_units.y += asdf::hexmap::hex_height_d2; //add room for the offset

    //get size of a hex in pixels. hex_width and hex_height constexpr constants exist in ui/hex_map.h
    vec2 hx_size_px = hex_size * camera.zoom();
    vec2 map_size_px = map_size_units * hx_size_px;

    base_camera_offset = glm::vec2();
    base_camera_offset.x = width()/2 / asdf::hexmap::px_per_unit;
    base_camera_offset.y = map_size_units.y - (height()/2 / asdf::hexmap::px_per_unit);

    hxm_wgt->camera_pos(base_camera_offset, false);

    //range is equal to how many units fit on the screen minus total map size in units

    //map_size_screen_px = unproject map_size_units from camera?

    glm::vec2 wgt_size(hxm_wgt->width(), hxm_wgt->height());

    auto hxm_proj = hxm_wgt->hex_map->camera.projection_ortho();

    vec4 vp;
    vp.x = 0.0f;
    vp.y = 0.0f;
    vp.z = wgt_size.x;
    vp.w = wgt_size.y;
    auto unprojd = unProject(vec3(wgt_size, 0.0f), glm::mat4(), hxm_proj, vp);

    auto screen_size_units = glm::vec2(unprojd);
    auto scr_range_units = glm::vec2(map_size_units) - glm::vec2(screen_size_units);

    auto* h_scr = ui->hexmap_hscroll;
    h_scr->setMinimum(0);
    h_scr->setMaximum(scr_range_units.x * scroll_sub_ticks);
    h_scr->setPageStep(screen_size_units.x * scroll_sub_ticks);

    auto* v_scr = ui->hexmap_hscroll;
    v_scr->setMinimum(0);
    v_scr->setMaximum(scr_range_units.y * scroll_sub_ticks);
    v_scr->setPageStep(screen_size_units.y * scroll_sub_ticks);

    scrollbar_changed();
}

void MainWindow::scrollbar_changed()
{
    //LOG("scrollbar changed;  x:%d  y%d", ui->hexmap_hscroll->value(), ui->hexmap_vscroll->value());

    glm::vec2 p(ui->hexmap_hscroll->value(), -ui->hexmap_vscroll->value());
    p /= scroll_sub_ticks;
    p += base_camera_offset;

    ui->hexmap_widget->camera_pos(p, false);
    ui->hexmap_widget->update();
}

void MainWindow::new_map()
{
    if(editor->map_is_dirty)
    {
        QMessageBox msgBox;
        msgBox.setText("The document has been modified.");
        msgBox.setInformativeText("Do you want to save your changes?");
        msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
        msgBox.setDefaultButton(QMessageBox::Save);
        int ret = msgBox.exec();

        switch (ret) {
          case QMessageBox::Save:
              save_map();
              break;
          case QMessageBox::Discard:
              break;
          case QMessageBox::Cancel:
              return;
          default: break;
        }
    }

    new_map_dialog_t nm(this);
    if(!nm.exec()) { //exec() blocks the mainw window until the modal dialog is dismissed
        return;
    } else {
        glm::uvec2 map_size(nm.ui->spb_width->value(), nm.ui->spb_height->value());
        ui->hexmap_widget->editor.new_map_action(map_size);
    }
}

void MainWindow::open_map()
{
    QDir map_file(QString(editor->map_filepath.c_str()));

    QString filepath = QFileDialog::getOpenFileName(this,
        tr("Open Map"), map_file.path(), tr("Hexmap Files (*.hxm)"));

    if(filepath.size() > 0)
    {
        editor->load_action(std::string(filepath.toUtf8().constData()));
    }
}

void MainWindow::save_map()
{
    if(ui->hexmap_widget->editor.map_filepath.size() == 0)
    {
        save_map_as();
    }
    else
    {
        ui->hexmap_widget->editor.save_action();
    }
}

void MainWindow::save_map_as()
{
    QString dir(ui->hexmap_widget->editor.map_filepath.c_str());
    QString filepath = QFileDialog::getSaveFileName(this, tr("Save Map"), dir, tr("Hexmap Files (*.hxm)"));

    if(filepath.size() > 0)
    {
        editor->save_action( std::string(filepath.toUtf8().constData()) );
    }
}

void MainWindow::mouseMoveEvent(QMouseEvent* event)
{

}

void MainWindow::mousePressEvent(QMouseEvent* event)
{

}

void MainWindow::mouseReleaseEvent(QMouseEvent* event)
{

}

void MainWindow::hex_map_initialized(asdf::hexmap::editor::editor_t& editor)
{
    terrain_palette_model = new palette_item_model_t();
    objects_palette_model = new palette_item_model_t();

    terrain_palette_model->build_from_terrain_bank(editor.rendered_map->terrain_bank);
    objects_palette_model->build_from_atlas(*(editor.rendered_map->objects_atlas.get()));

    editor_tool_changed(editor.current_tool);
}

void MainWindow::editor_tool_changed(tool_type_e new_tool)
{
    switch(new_tool)
    {
        case tool_type_e::terrain_paint:
            palette_widget->list_view->setModel(terrain_palette_model);
            break;
        case tool_type_e::place_objects:
            palette_widget->list_view->setModel(objects_palette_model);
            break;

    default:
        palette_widget->list_view->setModel(nullptr);
        break;
    }
}
<|endoftext|>


<commit_before>/******************************************************************************
 *  Copyright (c) 2015 Jamis Hoo
 *  Distributed under the MIT license
 *  (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT)
 *
 *  Project:
 *  Filename: canopy_clustering.cc
 *  Version: 1.0
 *  Author: Jamis Hoo
 *  E-mail: hoojamis@gmail.com
 *  Date: Jul 18, 2015
 *  Time: 22:23:28
 *  Description:
 *****************************************************************************/
#include <iostream>
#include <cassert>

#include "hadoop/Pipes.hh"
#include "hadoop/TemplateFactory.hh"
#include "hadoop/StringUtils.hh"

#include "netflix_movie.h"

constexpr size_t canopy_threshold = 10;

class CanopyMapper: public HadoopPipes::Mapper {
public:
    CanopyMapper(HadoopPipes::TaskContext& /* context */) { }

    void map(HadoopPipes::MapContext& context) {
        Movie movie(context.getInputValue());
        bool cover_by_other_canopies = false;

        for (const auto& mv: canopy_centers)
            if (movie.user_match_count(mv) < canopy_threshold) {
                cover_by_other_canopies = true;
                break;
            }

        if (!cover_by_other_canopies) {
            size_t colon_pos = context.getInputValue().find_first_of(':');
            std::string emit_key = context.getInputValue().substr(0, colon_pos);
            std::string emit_value = context.getInputValue().substr(colon_pos + 1);
            context.emit(emit_key, emit_value);

            canopy_centers.emplace_back(movie);
        }
    }

private:
    std::vector<Movie> canopy_centers;
};

class CanopyReducer: public HadoopPipes::Reducer {
public:
    CanopyReducer(HadoopPipes::TaskContext& /* context */) { }

    void reduce(HadoopPipes::ReduceContext& context) {
        bool once_flag = false;
        while (context.nextValue()) {
            assert(once_flag == false);
            once_flag = true;

            Movie movie(context.getInputKey() + ":" + context.getInputValue());

            bool cover_by_other_canopies = false;

            for (const auto& mv: canopy_centers)
                if (movie.user_match_count(mv) < canopy_threshold) {
                    cover_by_other_canopies = true;
                    break;
                }

            if (!cover_by_other_canopies) {
                context.emit(context.getInputKey(), context.getInputValue());

                canopy_centers.emplace_back(movie);
            }
        }
    }

private:
    std::vector<Movie> canopy_centers;
};

int main() {
    return HadoopPipes::runTask(HadoopPipes::TemplateFactory<CanopyMapper, CanopyReducer>());
}
<commit_msg>fix bug<commit_after>/******************************************************************************
 *  Copyright (c) 2015 Jamis Hoo
 *  Distributed under the MIT license
 *  (See accompanying file LICENSE or copy at http://opensource.org/licenses/MIT)
 *
 *  Project:
 *  Filename: canopy_clustering.cc
 *  Version: 1.0
 *  Author: Jamis Hoo
 *  E-mail: hoojamis@gmail.com
 *  Date: Jul 18, 2015
 *  Time: 22:23:28
 *  Description:
 *****************************************************************************/
#include <iostream>
#include <cassert>

#include "hadoop/Pipes.hh"
#include "hadoop/TemplateFactory.hh"
#include "hadoop/StringUtils.hh"

#include "netflix_movie.h"

constexpr size_t canopy_threshold = 10;

class CanopyMapper: public HadoopPipes::Mapper {
public:
    CanopyMapper(HadoopPipes::TaskContext& /* context */) { }

    void map(HadoopPipes::MapContext& context) {
        Movie movie(context.getInputValue());
        bool cover_by_other_canopies = false;

        for (const auto& mv: canopy_centers)
            if (movie.user_match_count(mv) > canopy_threshold) {
                cover_by_other_canopies = true;
                break;
            }

        if (!cover_by_other_canopies) {
            size_t colon_pos = context.getInputValue().find_first_of(':');
            std::string emit_key = context.getInputValue().substr(0, colon_pos);
            std::string emit_value = context.getInputValue().substr(colon_pos + 1);
            context.emit(emit_key, emit_value);

            /*
            std::cout << "Found center: " << std::hex
                      << movie.movie_id() << "(" << movie.num_users() << ")"
                      << std::endl;
            */
            canopy_centers.emplace_back(movie);
        }
    }

private:
    std::vector<Movie> canopy_centers;
};

class CanopyReducer: public HadoopPipes::Reducer {
public:
    CanopyReducer(HadoopPipes::TaskContext& /* context */) { }

    void reduce(HadoopPipes::ReduceContext& context) {
        bool once_flag = false;
        while (context.nextValue()) {
            assert(once_flag == false);
            once_flag = true;

            Movie movie(context.getInputKey() + ":" + context.getInputValue());

            /*
            if (movie.movie_id() == 1) {
                std::cout << movie.movie_id() << ":";
                for (size_t i = 0; i < movie.num_users(); ++i)
                    std::cout << movie.user_id(i) << "," << movie.rating(i) << ",";
                std::cout << std::endl;
            }
            */

            bool cover_by_other_canopies = false;

            for (const auto& mv: canopy_centers)
                if (movie.user_match_count(mv) > canopy_threshold) {
                    cover_by_other_canopies = true;
                    /*
                    std::cout << "Merge center " << std::hex
                              << movie.movie_id() << "(" << movie.num_users() << ")"
                              << " to " << mv.movie_id() << "(" << mv.num_users() << ")" << std::endl;
                    */
                    break;
                }

            if (!cover_by_other_canopies) {
                context.emit(context.getInputKey(), context.getInputValue());

                canopy_centers.emplace_back(movie);
            }
        }
    }

private:
    std::vector<Movie> canopy_centers;
};

int main() {
    return HadoopPipes::runTask(HadoopPipes::TemplateFactory<CanopyMapper, CanopyReducer>());
}
<|endoftext|>


<commit_before>#include "KrbService.h"

#include <krb5/krb5.h>

#include <string>
#include <algorithm>

namespace KFS
{

using std::string;
using std::max;

class KrbService::Impl
{
public:
    Impl()
        : mCtx(),
          mAuthCtx(),
          mServer(),
          mKeyTab(),
          mErrCode(0),
          mInitedFlag(false),
          mServiceName(),
          mErrorMsg()
        {}
    ~Impl()
    {
        Impl::CleanupSelf();
    }
    const char* Init(
        const char* inServeiceNamePtr)
    {
        CleanupSelf();
        mErrorMsg.clear();
        mServiceName.clear();
        if (inServeiceNamePtr) {
            mServiceName = inServeiceNamePtr;
        }
        InitSelf();
        if (mErrCode) {
            mErrorMsg = ErrToStr(mErrCode);
            CleanupSelf();
        }
        return mErrorMsg.c_str();
    }
    const char* ApReq(
        const char* inDataPtr,
        int         inDataLen)
    {
        krb5_data theData = { 0 };
        theData.length = max(0, inDataLen);
        theData.data   = const_cast<char*>(inDataPtr);
        krb5_flags   theReqOptions = { 0 };
        krb5_ticket* theTicket     = 0;
        krb5_error_code theErr = krb5_rd_req(
            mCtx,
            &mAuthCtx,
            &theData,
            mServer,
            mKeyTab,
            &theReqOptions,
            &theTicket
        );
        krb5_free_ticket(mCtx, theTicket);
        if (! theErr) {
            return 0;
        }
        mErrorMsg = ErrToStr(mErrCode);
        return mErrorMsg.c_str();
    }

private:
    string            mKeyTabFileName;
    krb5_context      mCtx;
    krb5_auth_context mAuthCtx;
    krb5_principal    mServer;
    krb5_keytab       mKeyTab;
    krb5_error_code   mErrCode;
    bool              mInitedFlag;
    string            mServiceName;
    string            mErrorMsg;

    void InitSelf()
    {
        mErrCode = krb5_init_context(&mCtx);
        if (mErrCode) {
            return;
        }
        mErrCode = krb5_auth_con_init(mCtx, &mAuthCtx);
        if (mErrCode) {
            krb5_free_context(mCtx);
            return;
        }
        mInitedFlag = true;
        krb5_rcache theRCachePtr = 0;
        mErrCode = krb5_auth_con_getrcache(mCtx, mAuthCtx, &theRCachePtr);
        if (mErrCode) {
            return;
        }
	mErrCode = krb5_sname_to_principal(
            mCtx, 0, mServiceName.c_str(), KRB5_NT_SRV_HST, &mServer);
        if (mErrCode) {
            return;
        }
	if (! theRCachePtr)  {
            mErrCode = krb5_get_server_rcache(
                mCtx, krb5_princ_component(mCtx, mServer, 0), &theRCachePtr);
            if (mErrCode) {
                return;
            }
        }
        mErrCode = krb5_auth_con_setrcache(mCtx, mAuthCtx, theRCachePtr);
        if (mErrCode) {
            return;
        }
        mKeyTab = 0;
        mErrCode = mKeyTabFileName.empty() ?
            krb5_kt_default(mCtx, &mKeyTab) :
            krb5_kt_resolve(mCtx, mKeyTabFileName.c_str(), &mKeyTab);
    }
    krb5_error_code CleanupSelf()
    {
        if (! mInitedFlag) {
            return 0;
        }
        mInitedFlag = false;
        krb5_error_code theErr = 0;
        if (mKeyTab) {
            theErr = krb5_kt_close(mCtx, mKeyTab);
            mKeyTab = 0;
        }
        const krb5_error_code theCtxErr = krb5_auth_con_free(mCtx, mAuthCtx);
        if (! theErr && theCtxErr) {
            theErr = theCtxErr;
        }
        krb5_free_context(mCtx);
        return theErr;
    }
    string ErrToStr(
        krb5_error_code inErrCode) const
    {
        if (! inErrCode) {
            return string();
        }
        if ( ! mCtx) {
            return string("no kerberos context");
        }
        const char* const theMsgPtr = krb5_get_error_message(mCtx, inErrCode);
        return string(theMsgPtr);
    }
};

KrbService::KrbService()
    : mImpl(*(new Impl()))
{
}

KrbService::~KrbService()
{
    delete &mImpl;
}

    const char*
KrbService::Init(
        const char* inServeiceNamePtr)
{
    return mImpl.Init(inServeiceNamePtr);
}

}
<commit_msg>Qfs kerberos: rework server side kerberos context to [re]initialize authentication context on each call to process / validate AP_REQ.<commit_after>#include "KrbService.h"

#include <krb5/krb5.h>

#include <string>
#include <algorithm>

namespace KFS
{

using std::string;
using std::max;

class KrbService::Impl
{
public:
    Impl()
        : mCtx(),
          mAuthCtx(),
          mServer(),
          mKeyTab(),
          mErrCode(0),
          mInitedFlag(false),
          mAuthInitedFlag(false),
          mServiceName(),
          mErrorMsg()
        {}
    ~Impl()
    {
        Impl::CleanupSelf();
    }
    const char* Init(
        const char* inServeiceNamePtr)
    {
        CleanupSelf();
        mErrorMsg.clear();
        mServiceName.clear();
        if (inServeiceNamePtr) {
            mServiceName = inServeiceNamePtr;
        }
        InitSelf();
        if (mErrCode) {
            mErrorMsg = ErrToStr(mErrCode);
            CleanupSelf();
        }
        return (mErrCode ? mErrorMsg.c_str() : 0);
    }
    const char* ApReq(
        const char* inDataPtr,
        int         inDataLen)
    {
        CleanupAuth();
        InitAuth();
        if (mErrCode) {
            mErrorMsg = ErrToStr(mErrCode);
        } else {
            krb5_data theData = { 0 };
            theData.length = max(0, inDataLen);
            theData.data   = const_cast<char*>(inDataPtr);
            krb5_flags   theReqOptions = { 0 };
            krb5_ticket* theTicket     = 0;
            krb5_error_code theErr = krb5_rd_req(
                mCtx,
                &mAuthCtx,
                &theData,
                mServer,
                mKeyTab,
                &theReqOptions,
                &theTicket
            );
            krb5_free_ticket(mCtx, theTicket);
            if (! theErr) {
                return 0;
            }
            mErrorMsg = ErrToStr(theErr);
        }
        return mErrorMsg.c_str();
    }

private:
    string            mKeyTabFileName;
    krb5_context      mCtx;
    krb5_auth_context mAuthCtx;
    krb5_principal    mServer;
    krb5_keytab       mKeyTab;
    krb5_error_code   mErrCode;
    bool              mInitedFlag;
    bool              mAuthInitedFlag;
    string            mServiceName;
    string            mErrorMsg;

    void InitSelf()
    {
        mErrCode = krb5_init_context(&mCtx);
        if (mErrCode) {
            return;
        }
	mErrCode = krb5_sname_to_principal(
            mCtx, 0, mServiceName.c_str(), KRB5_NT_SRV_HST, &mServer);
        if (mErrCode) {
            return;
        }
        mKeyTab = 0;
        mErrCode = mKeyTabFileName.empty() ?
            krb5_kt_default(mCtx, &mKeyTab) :
            krb5_kt_resolve(mCtx, mKeyTabFileName.c_str(), &mKeyTab);
    }
    void InitAuth()
    {
        InitAuthSelf();
        if (mErrCode) {
            CleanupAuth();
        }
    }
    void InitAuthSelf()
    {
        if (! mInitedFlag) {
            if (! mErrCode) {
                mErrCode = KRB5_CONFIG_BADFORMAT;
            }
            return;
        }
        mErrCode = krb5_auth_con_init(mCtx, &mAuthCtx);
        if (mErrCode) {
            return;
        }
        mAuthInitedFlag = true;
        krb5_rcache theRCachePtr = 0;
        mErrCode = krb5_auth_con_getrcache(mCtx, mAuthCtx, &theRCachePtr);
        if (mErrCode) {
            return;
        }
	if (! theRCachePtr)  {
            mErrCode = krb5_get_server_rcache(
                mCtx, krb5_princ_component(mCtx, mServer, 0), &theRCachePtr);
            if (mErrCode) {
                return;
            }
        }
        mErrCode = krb5_auth_con_setrcache(mCtx, mAuthCtx, theRCachePtr);
        if (mErrCode) {
            return;
        }
    }
    krb5_error_code CleanupSelf()
    {
        if (! mInitedFlag) {
            return 0;
        }
        krb5_error_code theErr = CleanupAuth();
        mInitedFlag = false;
        if (mKeyTab) {
            krb5_error_code const theCloseErr = krb5_kt_close(mCtx, mKeyTab);
            mKeyTab = 0;
            if (! theErr && theCloseErr) {
                theErr = theCloseErr;
            }
        }
        krb5_free_context(mCtx);
        return theErr;
    }
    krb5_error_code CleanupAuth()
    {
        if (! mInitedFlag || ! mAuthInitedFlag) {
            return 0;
        }
        mAuthInitedFlag = false;
        return krb5_auth_con_free(mCtx, mAuthCtx);
    }
    string ErrToStr(
        krb5_error_code inErrCode) const
    {
        if (! inErrCode) {
            return string();
        }
        if ( ! mCtx) {
            return string("no kerberos context");
        }
        const char* const theMsgPtr = krb5_get_error_message(mCtx, inErrCode);
        return string(theMsgPtr);
    }
};

KrbService::KrbService()
    : mImpl(*(new Impl()))
{
}

KrbService::~KrbService()
{
    delete &mImpl;
}

    const char*
KrbService::Init(
        const char* inServeiceNamePtr)
{
    return mImpl.Init(inServeiceNamePtr);
}

}
<|endoftext|>