<commit_before>/*
 * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "otbWrapperQtWidgetParameterFactory.h"

#include "otbWrapperParameter.h"
#include "otbWrapperQtWidgetModel.h"

#include "otbWrapperQtWidgetParameterBase.h"

#include "otbWrapperQtWidgetEmptyParameter.h"
#include "otbWrapperQtWidgetIntParameter.h"
#include "otbWrapperQtWidgetFloatParameter.h"
#include "otbWrapperQtWidgetStringParameter.h"
#include "otbWrapperQtWidgetStringListParameter.h"
#include "otbWrapperQtWidgetChoiceParameter.h"
#include "otbWrapperQtWidgetListViewParameter.h"
#include "otbWrapperQtWidgetInputImageParameter.h"
#include "otbWrapperQtWidgetComplexInputImageParameter.h"
#include "otbWrapperQtWidgetComplexOutputImageParameter.h"
#include "otbWrapperQtWidgetInputImageListParameter.h"
#include "otbWrapperQtWidgetOutputImageParameter.h"
#include "otbWrapperQtWidgetOutputVectorDataParameter.h"
#include "otbWrapperQtWidgetInputFilenameParameter.h"
#include "otbWrapperQtWidgetInputFilenameListParameter.h"
#include "otbWrapperQtWidgetOutputFilenameParameter.h"
#include "otbWrapperQtWidgetDirectoryParameter.h"
#include "otbWrapperQtWidgetParameterGroup.h"
#include "otbWrapperQtWidgetInputVectorDataListParameter.h"
#include "otbWrapperQtWidgetInputVectorDataParameter.h"
#include "otbWrapperQtWidgetRAMParameter.h"
#include "otbWrapperQtWidgetOutputProcessXMLParameter.h"
#include "otbWrapperQtWidgetInputProcessXMLParameter.h"

namespace otb
{
namespace Wrapper
{

template <class TParameterType, class TQtWidget>
class QtWidgetParameterGenericFactory
{
public:

  static bool CanCreate( Parameter* param )
  {
    return dynamic_cast<TParameterType *>(param) != ITK_NULLPTR;
  }

  static QtWidgetParameterBase* Create( Parameter* param, QtWidgetModel* model )
  {
    QtWidgetParameterBase * widget = ITK_NULLPTR;
    TParameterType * specificParam = dynamic_cast< TParameterType * >( param );

    // Code should break if param is not a TParameterType and not be silent!
    assert( specificParam!=nullptr );

    widget = new TQtWidget( specificParam, model );

    return widget;
  }
};

QtWidgetParameterFactory::QtWidgetParameterFactory()
{
}

QtWidgetParameterFactory::~QtWidgetParameterFactory()
{
}

QtWidgetParameterBase*
QtWidgetParameterFactory::CreateQtWidget( Parameter* param, QtWidgetModel* model )
{
  QtWidgetParameterBase* widget = ITK_NULLPTR;

#define CREATEWIDGET( ParameterType, WidgetType ) \
  else if ( QtWidgetParameterGenericFactory<ParameterType,  WidgetType>::CanCreate(param) ) \
    { \
    widget = QtWidgetParameterGenericFactory<ParameterType,  WidgetType>::Create(param, model); \
    }

  if (0) {}
  CREATEWIDGET(EmptyParameter,          QtWidgetEmptyParameter)
  CREATEWIDGET(IntParameter,            QtWidgetIntParameter)
  CREATEWIDGET(FloatParameter,          QtWidgetFloatParameter)
  CREATEWIDGET(InputFilenameParameter,       QtWidgetInputFilenameParameter)
  CREATEWIDGET(OutputFilenameParameter,       QtWidgetOutputFilenameParameter)
  CREATEWIDGET(DirectoryParameter,      QtWidgetDirectoryParameter)
  CREATEWIDGET(StringParameter,         QtWidgetStringParameter)
  CREATEWIDGET(StringListParameter,     QtWidgetStringListParameter)
  CREATEWIDGET(ChoiceParameter,         QtWidgetChoiceParameter)
  CREATEWIDGET(ListViewParameter,       QtWidgetListViewParameter)
  CREATEWIDGET(InputImageParameter,     QtWidgetInputImageParameter)
  CREATEWIDGET(ComplexInputImageParameter,     QtWidgetComplexInputImageParameter)
  CREATEWIDGET(ComplexOutputImageParameter,     QtWidgetComplexOutputImageParameter)
  CREATEWIDGET(InputImageListParameter, QtWidgetInputImageListParameter)
  CREATEWIDGET(InputFilenameListParameter, QtWidgetInputFilenameListParameter)
  CREATEWIDGET(InputVectorDataListParameter, QtWidgetInputVectorDataListParameter)
  CREATEWIDGET(InputVectorDataParameter, QtWidgetInputVectorDataParameter)
  CREATEWIDGET(OutputImageParameter,    QtWidgetOutputImageParameter)
  CREATEWIDGET(OutputVectorDataParameter, QtWidgetOutputVectorDataParameter)
  CREATEWIDGET(EmptyParameter,          QtWidgetEmptyParameter)
  CREATEWIDGET(ParameterGroup,          QtWidgetParameterGroup)
  CREATEWIDGET(RAMParameter,            QtWidgetRAMParameter)
  CREATEWIDGET(OutputProcessXMLParameter,        QtWidgetOutputProcessXMLParameter)
  CREATEWIDGET(InputProcessXMLParameter,        QtWidgetInputProcessXMLParameter)
#undef CREATEWIDGET

  if (widget)
    {
    widget->CreateWidget();
    widget->UpdateGUI();
    }

  return widget;

}

}
}
<commit_msg>ENH: Fixed compile-time errors due to refactoring of InputVectorDataListParameter.<commit_after>/*
 * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "otbWrapperQtWidgetParameterFactory.h"

#include "otbWrapperParameter.h"
#include "otbWrapperInputFilenameListParameter.h"
#include "otbWrapperInputVectorDataListParameter.h"

#include "otbWrapperQtWidgetChoiceParameter.h"
#include "otbWrapperQtWidgetComplexInputImageParameter.h"
#include "otbWrapperQtWidgetComplexOutputImageParameter.h"
#include "otbWrapperQtWidgetDirectoryParameter.h"
#include "otbWrapperQtWidgetEmptyParameter.h"
#include "otbWrapperQtWidgetFloatParameter.h"
#include "otbWrapperQtWidgetIntParameter.h"
#include "otbWrapperQtWidgetInputFilenameParameter.h"
#include "otbWrapperQtWidgetInputFilenameListParameter.h"
#include "otbWrapperQtWidgetInputImageParameter.h"
#include "otbWrapperQtWidgetInputImageListParameter.h"
#include "otbWrapperQtWidgetInputProcessXMLParameter.h"
#include "otbWrapperQtWidgetInputVectorDataListParameter.h"
#include "otbWrapperQtWidgetInputVectorDataParameter.h"
#include "otbWrapperQtWidgetListViewParameter.h"
#include "otbWrapperQtWidgetModel.h"
#include "otbWrapperQtWidgetOutputFilenameParameter.h"
#include "otbWrapperQtWidgetOutputImageParameter.h"
#include "otbWrapperQtWidgetOutputProcessXMLParameter.h"
#include "otbWrapperQtWidgetOutputVectorDataParameter.h"
#include "otbWrapperQtWidgetParameterBase.h"
#include "otbWrapperQtWidgetParameterGroup.h"
#include "otbWrapperQtWidgetRAMParameter.h"
#include "otbWrapperQtWidgetStringParameter.h"
#include "otbWrapperQtWidgetStringListParameter.h"

namespace otb
{

namespace Wrapper
{

template <class TParameterType, class TQtWidget>
class QtWidgetParameterGenericFactory
{
public:

  static bool CanCreate( Parameter* param )
  {
    return dynamic_cast<TParameterType *>(param) != ITK_NULLPTR;
  }

  static QtWidgetParameterBase* Create( Parameter* param, QtWidgetModel* model )
  {
    QtWidgetParameterBase * widget = ITK_NULLPTR;
    TParameterType * specificParam = dynamic_cast< TParameterType * >( param );

    // Code should break if param is not a TParameterType and not be silent!
    assert( specificParam!=nullptr );

    widget = new TQtWidget( specificParam, model );

    return widget;
  }
};

QtWidgetParameterFactory::QtWidgetParameterFactory()
{
}

QtWidgetParameterFactory::~QtWidgetParameterFactory()
{
}

QtWidgetParameterBase*
QtWidgetParameterFactory::CreateQtWidget( Parameter* param, QtWidgetModel* model )
{
  QtWidgetParameterBase* widget = ITK_NULLPTR;

#define CREATEWIDGET( ParameterType, WidgetType ) \
  else if ( QtWidgetParameterGenericFactory<ParameterType,  WidgetType>::CanCreate(param) ) \
    { \
    widget = QtWidgetParameterGenericFactory<ParameterType,  WidgetType>::Create(param, model); \
    }

  if (0) {}
  CREATEWIDGET(EmptyParameter,          QtWidgetEmptyParameter)
  CREATEWIDGET(IntParameter,            QtWidgetIntParameter)
  CREATEWIDGET(FloatParameter,          QtWidgetFloatParameter)
  CREATEWIDGET(InputFilenameParameter,       QtWidgetInputFilenameParameter)
  CREATEWIDGET(OutputFilenameParameter,       QtWidgetOutputFilenameParameter)
  CREATEWIDGET(DirectoryParameter,      QtWidgetDirectoryParameter)
  CREATEWIDGET(StringParameter,         QtWidgetStringParameter)
  CREATEWIDGET(StringListParameter,     QtWidgetStringListParameter)
  CREATEWIDGET(ChoiceParameter,         QtWidgetChoiceParameter)
  CREATEWIDGET(ListViewParameter,       QtWidgetListViewParameter)
  CREATEWIDGET(InputImageParameter,     QtWidgetInputImageParameter)
  CREATEWIDGET(ComplexInputImageParameter,     QtWidgetComplexInputImageParameter)
  CREATEWIDGET(ComplexOutputImageParameter,     QtWidgetComplexOutputImageParameter)
  CREATEWIDGET(InputImageListParameter, QtWidgetInputImageListParameter)
  CREATEWIDGET(InputFilenameListParameter, QtWidgetInputFilenameListParameter)
  CREATEWIDGET(InputVectorDataListParameter, QtWidgetInputVectorDataListParameter)
  CREATEWIDGET(InputVectorDataParameter, QtWidgetInputVectorDataParameter)
  CREATEWIDGET(OutputImageParameter,    QtWidgetOutputImageParameter)
  CREATEWIDGET(OutputVectorDataParameter, QtWidgetOutputVectorDataParameter)
  CREATEWIDGET(EmptyParameter,          QtWidgetEmptyParameter)
  CREATEWIDGET(ParameterGroup,          QtWidgetParameterGroup)
  CREATEWIDGET(RAMParameter,            QtWidgetRAMParameter)
  CREATEWIDGET(OutputProcessXMLParameter,        QtWidgetOutputProcessXMLParameter)
  CREATEWIDGET(InputProcessXMLParameter,        QtWidgetInputProcessXMLParameter)
#undef CREATEWIDGET

  if (widget)
    {
    widget->CreateWidget();
    widget->UpdateGUI();
    }

  return widget;

}

}
}
<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-2014, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/
/*
 * Analysis component for different trigger patches
 *
 *   Author: Markus Fasel
 */
#include <TClonesArray.h>

#include "AliEmcalTriggerPatchInfo.h"
#include "AliEMCalTriggerBinningComponent.h"
#include "AliEMCalTriggerEventData.h"
#include "AliEMCalTriggerPatchAnalysisComponent.h"

ClassImp(EMCalTriggerPtAnalysis::AliEMCalTriggerPatchAnalysisComponent)

namespace EMCalTriggerPtAnalysis {

//______________________________________________________________________________
AliEMCalTriggerPatchAnalysisComponent::AliEMCalTriggerPatchAnalysisComponent() :
  AliEMCalTriggerTracksAnalysisComponent()
{
  /*
   * Dummy (I/O) constructor, not to be used
   */
}

//______________________________________________________________________________
AliEMCalTriggerPatchAnalysisComponent::AliEMCalTriggerPatchAnalysisComponent(const char *name) :
  AliEMCalTriggerTracksAnalysisComponent(name)
{
  /*
   * Main constructor, to be used by the users
   */
}

//______________________________________________________________________________
void AliEMCalTriggerPatchAnalysisComponent::CreateHistos() {
  /*
   * Create histograms for the trigger patch analysis
   */
  AliEMCalTriggerTracksAnalysisComponent::CreateHistos();

  AliEMCalTriggerBinningDimension *etabinning = fBinning->GetBinning("eta"),
      *phibinning = fBinning->GetBinning("phi");
  const TAxis *patchenergyaxes[4] = {
    DefineAxis("energy", 100, 0., 100),
    DefineAxis("eta", etabinning),
    DefineAxis("phi", phibinning),
    DefineAxis("isMain", 2, -0.5, 1.5)
  };
  const TAxis *patchampaxes[4] = {
    DefineAxis("amplitude", 10000, 0., 10000.),
    DefineAxis("eta", etabinning),
    DefineAxis("phi",  phibinning),
    DefineAxis("isMain", 2, -0.5, 1.5)
  };

  std::string patchnames[] = {"Level0", "JetHigh", "JetLow", "GammaHigh", "GammaLow"};
  std::string triggermodes[] = {"Online", "Offline"};
  for(std::string * triggerpatch = patchnames; triggerpatch < patchnames + sizeof(patchnames)/sizeof(std::string); ++triggerpatch){
	for(std::string *triggermode = triggermodes; triggermode < triggermodes + sizeof(triggermodes)/sizeof(std::string); ++triggermode){
	  fHistos->CreateTHnSparse(Form("Energy%s%s", triggerpatch->c_str(), triggermode->c_str()), Form("Patch energy for %s %s trigger patches", triggerpatch->c_str(), triggermode->c_str()), 4, patchenergyaxes, "s");
      fHistos->CreateTHnSparse(Form("EnergyRough%s%s", triggerpatch->c_str(), triggermode->c_str()), Form("Rough patch energy for %s %s trigger patches", triggerpatch->c_str(), triggermode->c_str()), 4, patchenergyaxes, "s");
      fHistos->CreateTHnSparse(Form("Amplitude%s%s", triggerpatch->c_str(), triggermode->c_str()), Form("Patch amplitude for %s %s trigger patches", triggerpatch->c_str(), triggermode->c_str()), 4, patchampaxes, "s");
	}
  }

}

//______________________________________________________________________________
void AliEMCalTriggerPatchAnalysisComponent::Process(const AliEMCalTriggerEventData* const data) {
  /*
   * Run trigger patch analysis
   */
  AliEmcalTriggerPatchInfo *triggerpatch(NULL);
  TIter patchIter(data->GetTriggerPatchContainer());
  while((triggerpatch = dynamic_cast<AliEmcalTriggerPatchInfo *>(patchIter()))){
    double triggerpatchinfo[4] = {triggerpatch->GetPatchE(), triggerpatch->GetEtaGeo(), triggerpatch->GetPhiGeo(), triggerpatch->IsMainTrigger() ? 1. : 0.};
    double triggerpatchinfoamp[4] = {static_cast<double>(triggerpatch->GetADCAmp()), triggerpatch->GetEtaGeo(), triggerpatch->GetPhiGeo(), triggerpatch->IsMainTrigger() ? 1. : 0.};
    double triggerpatchinfoer[4] = {triggerpatch->GetADCAmpGeVRough(), triggerpatch->GetEtaGeo(), triggerpatch->GetPhiGeo(), triggerpatch->IsMainTrigger() ? 1. : 0.};
    if(triggerpatch->IsOfflineSimple()){
      if(triggerpatch->IsJetHighSimple()){
        fHistos->FillTHnSparse("EnergyJetHighOffline", triggerpatchinfo);
        fHistos->FillTHnSparse("AmplitudeJetHighOffline", triggerpatchinfoamp);
        fHistos->FillTHnSparse("EnergyRoughJetHighOffline", triggerpatchinfoer);
      }
      if(triggerpatch->IsJetLowSimple()){
    	  fHistos->FillTHnSparse("EnergyJetLowOffline", triggerpatchinfo);
        fHistos->FillTHnSparse("AmplitudeJetLowOffline", triggerpatchinfoamp);
        fHistos->FillTHnSparse("EnergyRoughJetLowOffline", triggerpatchinfoer);
      }
      if(triggerpatch->IsGammaHighSimple()){
        fHistos->FillTHnSparse("EnergyGammaHighOffline", triggerpatchinfo);
        fHistos->FillTHnSparse("AmplitudeGammaHighOffline", triggerpatchinfoamp);
        fHistos->FillTHnSparse("EnergyRoughGammaHighOffline", triggerpatchinfoer);
      }
      if(triggerpatch->IsGammaLowSimple()){
        fHistos->FillTHnSparse("EnergyGammaLowOffline", triggerpatchinfo);
        fHistos->FillTHnSparse("AmplitudeGammaLowOffline", triggerpatchinfoamp);
        fHistos->FillTHnSparse("EnergyRoughGammaLowOffline", triggerpatchinfoer);
      }
    } else{
      if(triggerpatch->IsJetHigh()){
        fHistos->FillTHnSparse("EnergyJetHighOnline", triggerpatchinfo);
        fHistos->FillTHnSparse("AmplitudeJetHighOnline", triggerpatchinfoamp);
        fHistos->FillTHnSparse("EnergyRoughJetHighOnline", triggerpatchinfoer);
      }
      if(triggerpatch->IsJetLow()){
    	fHistos->FillTHnSparse("EnergyJetLowOnline", triggerpatchinfo);
        fHistos->FillTHnSparse("AmplitudeJetLowOnline", triggerpatchinfoamp);
        fHistos->FillTHnSparse("EnergyRoughJetLowOnline", triggerpatchinfoer);
      }
      if(triggerpatch->IsGammaHigh()){
        fHistos->FillTHnSparse("EnergyGammaHighOnline", triggerpatchinfo);
        fHistos->FillTHnSparse("AmplitudeGammaHighOnline", triggerpatchinfoamp);
        fHistos->FillTHnSparse("EnergyRoughGammaHighOnline", triggerpatchinfoer);
      }
      if(triggerpatch->IsGammaLow()){
        fHistos->FillTHnSparse("EnergyGammaLowOnline", triggerpatchinfo);
        fHistos->FillTHnSparse("AmplitudeGammaLowOnline", triggerpatchinfoamp);
        fHistos->FillTHnSparse("EnergyRoughGammaLowOnline", triggerpatchinfoer);
      }
      if(triggerpatch->IsLevel0()){
        fHistos->FillTHnSparse("EnergyLevel0Online", triggerpatchinfo);
        fHistos->FillTHnSparse("AmplitudeLevel0Online", triggerpatchinfoamp);
        fHistos->FillTHnSparse("EnergyRoughLevel0Online", triggerpatchinfoer);
      }
    }
  }
}

} /* namespace EMCalTriggerPtAnalysis */
<commit_msg>Change hadling of trigger patch QA: Fill all energy values into a single THnSparse per patch type in order to be able to make correlations afterwards<commit_after>/**************************************************************************
 * Copyright(c) 1998-2014, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/
/*
 * Analysis component for different trigger patches
 *
 *   Author: Markus Fasel
 */
#include <TClonesArray.h>

#include "AliEmcalTriggerPatchInfo.h"
#include "AliEMCalTriggerBinningComponent.h"
#include "AliEMCalTriggerEventData.h"
#include "AliEMCalTriggerPatchAnalysisComponent.h"

ClassImp(EMCalTriggerPtAnalysis::AliEMCalTriggerPatchAnalysisComponent)

namespace EMCalTriggerPtAnalysis {

//______________________________________________________________________________
AliEMCalTriggerPatchAnalysisComponent::AliEMCalTriggerPatchAnalysisComponent() :
  AliEMCalTriggerTracksAnalysisComponent()
{
  /*
   * Dummy (I/O) constructor, not to be used
   */
}

//______________________________________________________________________________
AliEMCalTriggerPatchAnalysisComponent::AliEMCalTriggerPatchAnalysisComponent(const char *name) :
  AliEMCalTriggerTracksAnalysisComponent(name)
{
  /*
   * Main constructor, to be used by the users
   */
}

//______________________________________________________________________________
void AliEMCalTriggerPatchAnalysisComponent::CreateHistos() {
  /*
   * Create histograms for the trigger patch analysis
   */
  AliEMCalTriggerTracksAnalysisComponent::CreateHistos();

  AliEMCalTriggerBinningDimension *etabinning = fBinning->GetBinning("eta"),
      *phibinning = fBinning->GetBinning("phi");
  const TAxis *patchaxes[6] = {
    DefineAxis("energy", 100, 0., 100),
    DefineAxis("energyRough", 100, 0., 100),
    DefineAxis("amplitude", 100, 0., 100.),       // limit for the moment
    DefineAxis("eta", etabinning),
    DefineAxis("phi", phibinning),
    DefineAxis("isMain", 2, -0.5, 1.5)
  };

  std::string patchnames[] = {"Level0", "JetHigh", "JetLow", "GammaHigh", "GammaLow"};
  std::string triggermodes[] = {"Online", "Offline"};
  for(std::string * triggerpatch = patchnames; triggerpatch < patchnames + sizeof(patchnames)/sizeof(std::string); ++triggerpatch){
    for(std::string *triggermode = triggermodes; triggermode < triggermodes + sizeof(triggermodes)/sizeof(std::string); ++triggermode){
      if((!strcmp(triggermode->c_str(), "Offline")) && (!strcmp(triggerpatch->c_str(), "Level0"))) continue; // Don't process L0 in case of offline
      printf("Adding patch for trigger %s in case of %s\n", triggerpatch->c_str(), triggermode->c_str());
      fHistos->CreateTHnSparse(Form("PatchInfo%s%s", triggerpatch->c_str(), triggermode->c_str()), Form("Patch energy for %s %s trigger patches", triggerpatch->c_str(), triggermode->c_str()), 6, patchaxes, "s");
    }
  }

}

//______________________________________________________________________________
void AliEMCalTriggerPatchAnalysisComponent::Process(const AliEMCalTriggerEventData* const data) {
  /*
   * Run trigger patch analysis
   */
  AliEmcalTriggerPatchInfo *triggerpatch(NULL);
  TIter patchIter(data->GetTriggerPatchContainer());
  while((triggerpatch = dynamic_cast<AliEmcalTriggerPatchInfo *>(patchIter()))){
    double triggerpatchinfo[6] = {triggerpatch->GetPatchE(),triggerpatch->GetADCAmpGeVRough(),
        static_cast<double>(triggerpatch->GetADCAmp()), triggerpatch->GetEtaGeo(),
        triggerpatch->GetPhiGeo(), triggerpatch->IsMainTrigger() ? 1. : 0.};
    if(triggerpatch->IsOfflineSimple()){
      if(triggerpatch->IsJetHighSimple()){
        fHistos->FillTHnSparse("PatchInfoJetHighOffline", triggerpatchinfo);
      }
      if(triggerpatch->IsJetLowSimple()){
    	  fHistos->FillTHnSparse("PatchInfoJetLowOffline", triggerpatchinfo);
      }
      if(triggerpatch->IsGammaHighSimple()){
        fHistos->FillTHnSparse("PatchInfoGammaHighOffline", triggerpatchinfo);
      }
      if(triggerpatch->IsGammaLowSimple()){
        fHistos->FillTHnSparse("PatchInfoGammaLowOffline", triggerpatchinfo);
      }
    } else{
      if(triggerpatch->IsJetHigh()){
        fHistos->FillTHnSparse("PatchInfoJetHighOnline", triggerpatchinfo);
      }
      if(triggerpatch->IsJetLow()){
        fHistos->FillTHnSparse("PatchInfoJetLowOnline", triggerpatchinfo);
      }
      if(triggerpatch->IsGammaHigh()){
        fHistos->FillTHnSparse("PatchInfoGammaHighOnline", triggerpatchinfo);
      }
      if(triggerpatch->IsGammaLow()){
        fHistos->FillTHnSparse("PatchInfoGammaLowOnline", triggerpatchinfo);
      }
      if(triggerpatch->IsLevel0()){
        fHistos->FillTHnSparse("PatchInfoLevel0Online", triggerpatchinfo);
      }
    }
  }
}

} /* namespace EMCalTriggerPtAnalysis */
<|endoftext|>


<commit_before>// Tetra Break by ＭＫ 2005/11/02
#include "stdio.h"
#include "tetmain.h"
#include "blocks.h"
#include <Arduboy2.h>

extern Arduboy2 arduboy;
char NEXT_DATA[7][4][4];
char BL_ADJ_DATA[7][2][4];
char BL_CENTER_DATA[7][2];
char BL_DATA[7][2][4];

#define BL_OFFSET_X 2
#define BL_OFFSET_Y 2

int GetRand(int max){
  return (random() / 100) % max;
}

//ここからメイン関数
int TetrisGame::initialize()
{
	//各種変数初期化
	next=0;			//ねくすと
	over1g_level=60;//1Gを超えるレベル
	fall_count=0;	//おちるかうんと
	fix_count=0;	//固定した回数
	key=0;			//入力状態

	//ブロック・ブロック補正情報を定義ファイルから読み込み
  const char *ptr = BLOCK_DEF;
	for(int i=0 ; i<28 ; i++){
    for(int j=0 ; j<4 ; j++){
      NEXT_DATA[i/4][i%4][j] = pgm_read_word_near(ptr++);
    }
	}
	for(int i=0 ; i<14 ; i++){
    for(int j=0 ; j<4 ; j++){
      BL_DATA[i/2][i%2][j] = pgm_read_word_near(ptr++);
    }
	}
	for(int i=0 ; i<14 ; i++){
    for(int j=0 ; j<4 ; j++){
      BL_ADJ_DATA[i/2][i%2][j] = pgm_read_word_near(ptr++);
    }
	}
	for(int i=0 ; i<7 ; i++){
    for(int j=0 ; j<2 ; j++){
      BL_CENTER_DATA[i][j] = pgm_read_word_near(ptr++);
    }
	}

	level = 0;
	enable_levelup = true;
	enable_over1g = true;
	fix_count = 0;
	fixed_flag = true;
	score = 0;
	scene = 1;
	next = GetRand(6);
	fix_ok_flag=0;
	fieldInit(field);
}

char updateInput(){
  return
     arduboy.pressed(A_BUTTON) |
    (arduboy.pressed(B_BUTTON) << 1) |
    (arduboy.pressed(UP_BUTTON) << 2) |
    (arduboy.pressed(DOWN_BUTTON) << 3) |
    (arduboy.pressed(LEFT_BUTTON) << 4) |
    (arduboy.pressed(RIGHT_BUTTON) << 5);
}

void TetrisGame::update(){
	keyold[0] = key;
	for(int i=KEY_DELAY_TIME-1 ; 0<i ; i--){
		keyold[i] = keyold[i-1]&key;
	}
	key = updateInput();
	keyonce = key & (keyold[0] ^ 0xFF);
	keyleg = keyonce|(keyold[KEY_DELAY_TIME-1]);

	switch(scene){
	case MENU:
		break;
	case MAIN:
		if(fixed_flag){
			add_score = blockErace(field)*10;
			score += add_score * (add_score/2);
			if(key&KEY_A)
				spin=-1;
			else if(key&KEY_B)
				spin=1;
			else
				spin=0;
			error = blockGen(spin, next, &block, field);
			if(error){
				scene=2;
				break;
			}
			fixed_flag = 0;
			next = -1;
		}

		if(keyonce&KEY_A)
			spin=-1;
		else if(keyonce&KEY_B)
			spin=1;
		else
			spin=0;

		if(next == -1){	//ネクストが無効だった場合、新規に生成。
			next = GetRand(6);
		}
		fall_count--;
		if(fall_count <= 0){
			fall_count = over1g_level - level;
			g = 1;
			if(fall_count<0){
				for(int g=1 ; g<=20 ; g++){
					fall_count++;
					if(fall_count==0)
						break;
				}
			}
			if(!enable_over1g)
				g = 1;
			if(fix_ok_flag){
				fix_count++;
				if(fix_count%5==0)level++;

				blockFix(&block , field);
				fixed_flag=true;
				fix_ok_flag=false;
			}else{
				for(int i=g;i>0;i--){
					blockMove(0,1,&block);
					error = blockJudge(&block,field);
					if(error==1){
						fix_ok_flag=true;
						fall_count += 30;
						break;
					}
				}
			}
		}
		if(keyonce&KEY_UP){
			if(fix_ok_flag){
				fix_count++;
				if(fix_count%5==0)level++;

				blockFix(&block , field);
				fixed_flag=true;
				fix_ok_flag=false;
			}else{
				for(int i=20;i>0;i--){
					blockMove(0,1,&block);
					error = blockJudge(&block,field);
					if(error==1){
						fix_ok_flag=true;
						fall_count += 30;
						break;
					}
				}
			}
		}else if(keyleg&KEY_LEFT){
			blockMove(-1,0,&block);
			error = blockJudge(&block,field);
			if(error==2)
				blockMove(1,0,&block);
			if(error==1)
				fix_ok_flag=1;
			if(error==0)
				fix_ok_flag=0;
		}else if(keyleg&KEY_RIGHT){
			blockMove(1,0,&block);
			error = blockJudge(&block,field);
			if(error==2)
				blockMove(-1,0,&block);
			if(error==1)
				fix_ok_flag=1;
			if(error==0)
				fix_ok_flag=0;
		}else if(key&KEY_DOWN){
			if(fix_ok_flag){
				fix_count++;
				if(fix_count%5==0)level++;

				blockFix(&block , field);
				fixed_flag=true;
				fix_ok_flag=false;
			}else{
				blockMove(0,1,&block);
				error = blockJudge(&block,field);
				if(error==1){
					fix_ok_flag=true;
					fall_count += 30;
					break;
				}
			}
		}
		if(spin){
			blockSpin(spin,&block);		//回転
			error = blockJudge(&block,field);
			if(error==2){
				blockMove(-1,0,&block);		//ダメなら左にズレてみろ！！
				error = blockJudge(&block,field);
				if(error==2){
					blockMove(2,0,&block);		//それでもダメなら右だ！！
					error = blockJudge(&block,field);
					if(error==2){
						blockMove(-1,0,&block);//全部ダメなら元に戻すしかない…！！
						blockSpin(spin*-1,&block);
					}
				}
			}
			if(error==1)
				fix_ok_flag=1;
			if(error==0)
				fix_ok_flag=0;
		}
		break;
	case GAME_OVER:
		printf("げーむ おーばー\n\n");
		printf("SCORE:%d LEVEL:%d\n\nPress Z key.",score,level);
		break;
	default:
		break;
	}
}

void TetrisGame::draw()
{
  for(int i=0; i<4; i++){
    arduboy.drawPixel(block.x[i], block.y[i]);
  }

  for(int j=0 ; j<24 ; j++){
    for(int i=0 ; i<14 ; i++){
      if(*(field+i*24+j) != 0)
        arduboy.drawPixel(i, j);
    }
  }
}

int TetrisGame::blockErace(char* field)
{
	int erace=0,ok;

	for(int j=BL_OFFSET_Y ; j<20+BL_OFFSET_Y ; j++){
		ok=0;
		for(int i=BL_OFFSET_X ; i<10+BL_OFFSET_X ; i++){
			if(*(field+i*24+j)!=0)
				ok++;
		}
		if(ok==10){
			for(int k=j ; j>1 ; j--){
				for(int i=BL_OFFSET_X ; i<10+BL_OFFSET_X ; i++){
					*(field+i*24+j) = *(field+i*24+j-1);
				}
			}
			erace++;
		}
	}
	return erace;
}

int TetrisGame::blockGen(int spin, int next, Block* data, char* field)
{
	int k=0;

	data->color = next;
	data->spin = 0;
	data->ct_x = BL_CENTER_DATA[next][0] + BL_OFFSET_X;
	data->ct_y = BL_CENTER_DATA[next][1] + BL_OFFSET_Y;
	for(int i=0 ; i<4 ; i++){
		data->hs_x[i] = BL_ADJ_DATA[next][0][i];
		data->hs_y[i] = BL_ADJ_DATA[next][1][i];
		data->x[i] = BL_DATA[next][0][i] + BL_OFFSET_X;
		data->y[i] = BL_DATA[next][1][i] + BL_OFFSET_Y;
	}
	blockSpin(spin,data);
	for(int i=0 ; i<4 ; i++){
		if(*(field + data->x[i]*24 + data->y[i])==1){
			k++;
			break;
		}
	}
	return k;
}

void TetrisGame::blockFix(Block* data, char* field)
{
	int x,y,i;
	for(int i=0 ; i<4 ; i++){
		x = data -> x[i];
		y = data -> y[i];
		*(field+x*24+y) = data -> color+1;
	}
}

int TetrisGame::blockJudge(Block* data, char* field)
{
	int error=0;

	for(int i=0 ; i<4 ; i++){
		if(*(field + data->x[i]*24 + data->y[i])){
			error=2;
			break;
		}
	}
	if(error!=2){
		for(int i=0 ; i<4 ; i++){
			if(*(field + data->x[i]*24 + data->y[i]+1)){
				error=1;
				break;
			}
		}
	}
	return error;
}

void TetrisGame::blockMove(int x, int y, Block* data)
{
	for(int i=0 ; i<4 ; i++){
		data->x[i] += x;
		data->y[i] += y;
	}
	data->ct_x += x;
	data->ct_y += y;
}

void TetrisGame::blockSpin(int spin, Block* data)
{
	int x,y,tmp;
	tmp = data->spin;

	for(int i=0 ; i<4 ; i++){
		data->x[i] -= data->hs_x[tmp];
		data->y[i] -= data->hs_y[tmp];
	}
	tmp += spin;
	if(tmp<0)
		tmp=3;
	if(tmp>3)
		tmp=0;
	data->spin = tmp;

	switch(spin){
	case 1:
		for(int i=0 ; i<4 ; i++){
			x = ((data->y[i] - data->ct_y) * -1) + data->ct_x;
			y = data->x[i] - data->ct_x + data->ct_y;
			data->x[i] = x;
			data->y[i] = y;
		}
		break;
	case -1:
		for(int i=0 ; i<4 ; i++){
			x = data->y[i] - data->ct_y + data->ct_x;
			y = ((data->x[i] - data->ct_x) * -1) + data->ct_y;
			data->x[i] = x;
			data->y[i] = y;
		}
		break;
	default:
		break;
	}

	for(int i=0 ; i<4 ; i++){
		data->x[i] += data->hs_x[tmp];
		data->y[i] += data->hs_y[tmp];
	}
}

void TetrisGame::fieldInit(char* field)
{
	for(int i=0 ; i<13 ; i++){	//フィールド初期化
		for(int j=0 ; j<23 ; j++){
			*(field+i*24+j) = 0;
		}
	}
	for(int i=1 ; i<13 ; i+=11){ //左右に壁作成
		for(int j=1 ; j<23 ; j++){
			*(field+i*24+j) = 8;
		}
	}
	for(int i=1 ; i<12 ; i++){ //上下に壁作成
		*(field+i*24+22) = 8;
	}
}
<commit_msg>大きくしました<commit_after>// Tetra Break by ＭＫ 2005/11/02
#include "stdio.h"
#include "tetmain.h"
#include "blocks.h"
#include <Arduboy2.h>

extern Arduboy2 arduboy;
char NEXT_DATA[7][4][4];
char BL_ADJ_DATA[7][2][4];
char BL_CENTER_DATA[7][2];
char BL_DATA[7][2][4];

#define BL_OFFSET_X 2
#define BL_OFFSET_Y 2
#define FIX_INTERVAL 30

int GetRand(int max){
  return (random() / 100) % max;
}

//ここからメイン関数
int TetrisGame::initialize()
{
	//各種変数初期化
	next=0;			//ねくすと
	over1g_level=60;//1Gを超えるレベル
	fall_count=0;	//おちるかうんと
	fix_count=0;	//固定した回数
	key=0;			//入力状態

	//ブロック・ブロック補正情報を定義ファイルから読み込み
  const char *ptr = BLOCK_DEF;
	for(int i=0 ; i<28 ; i++){
    for(int j=0 ; j<4 ; j++){
      NEXT_DATA[i/4][i%4][j] = pgm_read_word_near(ptr++);
    }
	}
	for(int i=0 ; i<14 ; i++){
    for(int j=0 ; j<4 ; j++){
      BL_DATA[i/2][i%2][j] = pgm_read_word_near(ptr++);
    }
	}
	for(int i=0 ; i<14 ; i++){
    for(int j=0 ; j<4 ; j++){
      BL_ADJ_DATA[i/2][i%2][j] = pgm_read_word_near(ptr++);
    }
	}
	for(int i=0 ; i<7 ; i++){
    for(int j=0 ; j<2 ; j++){
      BL_CENTER_DATA[i][j] = pgm_read_word_near(ptr++);
    }
	}

	level = 0;
	enable_levelup = true;
	enable_over1g = true;
	fix_count = 0;
	fixed_flag = true;
	score = 0;
	scene = 1;
	next = GetRand(6);
	fix_ok_flag=0;
	fieldInit(field);
}

char updateInput(){
  return
     arduboy.pressed(A_BUTTON) |
    (arduboy.pressed(B_BUTTON) << 1) |
    (arduboy.pressed(UP_BUTTON) << 2) |
    (arduboy.pressed(DOWN_BUTTON) << 3) |
    (arduboy.pressed(LEFT_BUTTON) << 4) |
    (arduboy.pressed(RIGHT_BUTTON) << 5);
}

void TetrisGame::update(){
	keyold[0] = key;
	for(int i=KEY_DELAY_TIME-1 ; 0<i ; i--){
		keyold[i] = keyold[i-1]&key;
	}
	key = updateInput();
	keyonce = key & (keyold[0] ^ 0xFF);
	keyleg = keyonce|(keyold[KEY_DELAY_TIME-1]);

	switch(scene){
	case MENU:
		break;
	case MAIN:
		if(fixed_flag){
			add_score = blockErace(field)*10;
			score += add_score * (add_score/2);
			if(key&KEY_A)
				spin=-1;
			else if(key&KEY_B)
				spin=1;
			else
				spin=0;
			error = blockGen(spin, next, &block, field);
			if(error){
				scene=GAME_OVER;
				break;
			}
			fixed_flag = 0;
			next = -1;
		}

		if(keyonce&KEY_A)
			spin=-1;
		else if(keyonce&KEY_B)
			spin=1;
		else
			spin=0;

		if(next == -1){	//ネクストが無効だった場合、新規に生成。
			next = GetRand(6);
		}
		fall_count--;
		if(fall_count <= 0){
			fall_count = over1g_level - level;
			g = 1;
			if(fall_count<0){
				for(int g=1 ; g<=20 ; g++){
					fall_count++;
					if(fall_count==0)
						break;
				}
			}
			if(!enable_over1g)
				g = 1;
			if(fix_ok_flag){
				fix_count++;
				if(fix_count%5==0)level++;

				blockFix(&block , field);
				fixed_flag=true;
				fix_ok_flag=false;
			}else{
				for(int i=g;i>0;i--){
					blockMove(0,1,&block);
					error = blockJudge(&block,field);
					if(error==1){
						fix_ok_flag=true;
						fall_count += 30;
						break;
					}
				}
			}
		}
		if(keyonce&KEY_UP){
			if(fix_ok_flag){
				fix_count++;
				if(fix_count%5==0)level++;

				blockFix(&block , field);
				fixed_flag=true;
				fix_ok_flag=false;
			}else{
				for(int i=20;i>0;i--){
					blockMove(0,1,&block);
					error = blockJudge(&block,field);
					if(error==1){
						fix_ok_flag=true;
						fall_count += 30;
						break;
					}
				}
			}
		}else if(keyleg&KEY_LEFT){
			blockMove(-1,0,&block);
			error = blockJudge(&block,field);
			if(error==2)
				blockMove(1,0,&block);
			if(error==1)
				fix_ok_flag=1;
			if(error==0)
				fix_ok_flag=0;
		}else if(keyleg&KEY_RIGHT){
			blockMove(1,0,&block);
			error = blockJudge(&block,field);
			if(error==2)
				blockMove(-1,0,&block);
			if(error==1)
				fix_ok_flag=1;
			if(error==0)
				fix_ok_flag=0;
		}else if(key&KEY_DOWN){
			if(fix_ok_flag){
				fix_count++;
				if(fix_count%5==0)level++;

				blockFix(&block , field);
				fixed_flag=true;
				fix_ok_flag=false;
			}else{
				blockMove(0,1,&block);
				error = blockJudge(&block,field);
				if(error==1){
					fix_ok_flag=true;
					fall_count += 30;
					break;
				}
			}
		}
		if(spin){
			blockSpin(spin,&block);		//回転
			error = blockJudge(&block,field);
			if(error==2){
				blockMove(-1,0,&block);		//ダメなら左にズレてみろ！！
				error = blockJudge(&block,field);
				if(error==2){
					blockMove(2,0,&block);		//それでもダメなら右だ！！
					error = blockJudge(&block,field);
					if(error==2){
						blockMove(-1,0,&block);//全部ダメなら元に戻すしかない…！！
						blockSpin(spin*-1,&block);
					}
				}
			}
			if(error==1)
				fix_ok_flag=1;
			if(error==0)
				fix_ok_flag=0;
		}
		break;
	case GAME_OVER:
		printf("げーむ おーばー\n\n");
		printf("SCORE:%d LEVEL:%d\n\nPress Z key.",score,level);
		break;
	default:
		break;
	}
}

void TetrisGame::draw()
{
  const int FIELD_OFFSET_X = 40;
  const int FIELD_OFFSET_Y = -5;

  for(int i=0; i<4; i++){
    arduboy.drawRect(
      block.x[i] * 3 + FIELD_OFFSET_X,
      block.y[i] * 3 + FIELD_OFFSET_Y, 2, 2);
  }

  for(int j=BL_OFFSET_Y ; j<24-BL_OFFSET_Y; j++){
    for(int i=BL_OFFSET_X ; i<14-BL_OFFSET_X ; i++){
      if(*(field+i*24+j) != 0)
        arduboy.drawRect(
          i * 3 + FIELD_OFFSET_X, j * 3 + FIELD_OFFSET_Y, 2, 2);
    }
  }

  arduboy.drawRect(43, 1, 2, 62);
  arduboy.drawRect(76, 1, 2, 62);
  arduboy.drawRect(45, 61, 31, 2);
}

int TetrisGame::blockErace(char* field)
{
	int erace=0,ok;

	for(int j=BL_OFFSET_Y ; j<20+BL_OFFSET_Y ; j++){
		ok=0;
		for(int i=BL_OFFSET_X ; i<10+BL_OFFSET_X ; i++){
			if(*(field+i*24+j)!=0)
				ok++;
		}
		if(ok==10){
			for(int k=j ; j>1 ; j--){
				for(int i=BL_OFFSET_X ; i<10+BL_OFFSET_X ; i++){
					*(field+i*24+j) = *(field+i*24+j-1);
				}
			}
			erace++;
		}
	}
	return erace;
}

int TetrisGame::blockGen(int spin, int next, Block* data, char* field)
{
	int k=0;

	data->color = next;
	data->spin = 0;
	data->ct_x = BL_CENTER_DATA[next][0] + BL_OFFSET_X;
	data->ct_y = BL_CENTER_DATA[next][1] + BL_OFFSET_Y;
	for(int i=0 ; i<4 ; i++){
		data->hs_x[i] = BL_ADJ_DATA[next][0][i];
		data->hs_y[i] = BL_ADJ_DATA[next][1][i];
		data->x[i] = BL_DATA[next][0][i] + BL_OFFSET_X;
		data->y[i] = BL_DATA[next][1][i] + BL_OFFSET_Y;
	}
	blockSpin(spin,data);
	for(int i=0 ; i<4 ; i++){
		if(*(field + data->x[i]*24 + data->y[i])==1){
			k++;
			break;
		}
	}
	return k;
}

void TetrisGame::blockFix(Block* data, char* field)
{
	int x,y,i;
	for(int i=0 ; i<4 ; i++){
		x = data -> x[i];
		y = data -> y[i];
		*(field+x*24+y) = data -> color+1;
	}
}

int TetrisGame::blockJudge(Block* data, char* field)
{
	int error=0;

	for(int i=0 ; i<4 ; i++){
		if(*(field + data->x[i]*24 + data->y[i])){
			error=2;
			break;
		}
	}
	if(error!=2){
		for(int i=0 ; i<4 ; i++){
			if(*(field + data->x[i]*24 + data->y[i]+1)){
				error=1;
				break;
			}
		}
	}
	return error;
}

void TetrisGame::blockMove(int x, int y, Block* data)
{
	for(int i=0 ; i<4 ; i++){
		data->x[i] += x;
		data->y[i] += y;
	}
	data->ct_x += x;
	data->ct_y += y;
}

void TetrisGame::blockSpin(int spin, Block* data)
{
	int x,y,tmp;
	tmp = data->spin;

	for(int i=0 ; i<4 ; i++){
		data->x[i] -= data->hs_x[tmp];
		data->y[i] -= data->hs_y[tmp];
	}
	tmp += spin;
	if(tmp<0)
		tmp=3;
	if(tmp>3)
		tmp=0;
	data->spin = tmp;

	switch(spin){
	case 1:
		for(int i=0 ; i<4 ; i++){
			x = ((data->y[i] - data->ct_y) * -1) + data->ct_x;
			y = data->x[i] - data->ct_x + data->ct_y;
			data->x[i] = x;
			data->y[i] = y;
		}
		break;
	case -1:
		for(int i=0 ; i<4 ; i++){
			x = data->y[i] - data->ct_y + data->ct_x;
			y = ((data->x[i] - data->ct_x) * -1) + data->ct_y;
			data->x[i] = x;
			data->y[i] = y;
		}
		break;
	default:
		break;
	}

	for(int i=0 ; i<4 ; i++){
		data->x[i] += data->hs_x[tmp];
		data->y[i] += data->hs_y[tmp];
	}
}

void TetrisGame::fieldInit(char* field)
{
	for(int i=0 ; i<13 ; i++){	//フィールド初期化
		for(int j=0 ; j<23 ; j++){
			*(field+i*24+j) = 0;
		}
	}
	for(int i=1 ; i<13 ; i+=11){ //左右に壁作成
		for(int j=1 ; j<23 ; j++){
			*(field+i*24+j) = 8;
		}
	}
	for(int i=1 ; i<12 ; i++){ //上下に壁作成
		*(field+i*24+22) = 8;
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2018-2019 The Dash Core developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <llmq/quorums.h>
#include <llmq/quorums_blockprocessor.h>
#include <llmq/quorums_commitment.h>
#include <llmq/quorums_dkgsession.h>
#include <llmq/quorums_dkgsessionmgr.h>
#include <llmq/quorums_init.h>
#include <llmq/quorums_utils.h>

#include <evo/specialtx.h>

#include <masternode/activemasternode.h>
#include <chainparams.h>
#include <init.h>
#include <masternode/masternodesync.h>
#include <univalue.h>
#include <validation.h>
#include <shutdown.h>
#include <cxxtimer.hpp>
#include <net.h>
namespace llmq
{

static const std::string DB_QUORUM_SK_SHARE = "q_Qsk";
static const std::string DB_QUORUM_QUORUM_VVEC = "q_Qqvvec";

CQuorumManager* quorumManager;

static uint256 MakeQuorumKey(const CQuorum& q)
{
    CHashWriter hw(SER_NETWORK, 0);
    hw << q.params.type;
    hw << q.qc.quorumHash;
    for (const auto& dmn : q.members) {
        hw << dmn->proTxHash;
    }
    return hw.GetHash();
}

CQuorum::~CQuorum()
{
    // most likely the thread is already done
    stopCachePopulatorThread = true;
    // watch out to not join the thread when we're called from inside the thread, which might happen on shutdown. This
    // is because on shutdown the thread is the last owner of the shared CQuorum instance and thus the destroyer of it.
    if (cachePopulatorThread.joinable() && cachePopulatorThread.get_id() != std::this_thread::get_id()) {
        cachePopulatorThread.join();
    }
}

void CQuorum::Init(const CFinalCommitment& _qc, const CBlockIndex* _pindexQuorum, const uint256& _minedBlockHash, const std::vector<CDeterministicMNCPtr>& _members)
{
    qc = _qc;
    pindexQuorum = _pindexQuorum;
    members = _members;
    minedBlockHash = _minedBlockHash;
}

bool CQuorum::IsMember(const uint256& proTxHash) const
{
    for (auto& dmn : members) {
        if (dmn->proTxHash == proTxHash) {
            return true;
        }
    }
    return false;
}

bool CQuorum::IsValidMember(const uint256& proTxHash) const
{
    for (size_t i = 0; i < members.size(); i++) {
        if (members[i]->proTxHash == proTxHash) {
            return qc.validMembers[i];
        }
    }
    return false;
}

CBLSPublicKey CQuorum::GetPubKeyShare(size_t memberIdx) const
{
    if (quorumVvec == nullptr || memberIdx >= members.size() || !qc.validMembers[memberIdx]) {
        return CBLSPublicKey();
    }
    auto& m = members[memberIdx];
    return blsCache.BuildPubKeyShare(m->proTxHash, quorumVvec, CBLSId::FromHash(m->proTxHash));
}

CBLSSecretKey CQuorum::GetSkShare() const
{
    return skShare;
}

int CQuorum::GetMemberIndex(const uint256& proTxHash) const
{
    for (size_t i = 0; i < members.size(); i++) {
        if (members[i]->proTxHash == proTxHash) {
            return (int)i;
        }
    }
    return -1;
}

void CQuorum::WriteContributions(CEvoDB& evoDb)
{
    uint256 dbKey = MakeQuorumKey(*this);

    if (quorumVvec != nullptr) {
        evoDb.GetRawDB().Write(std::make_pair(DB_QUORUM_QUORUM_VVEC, dbKey), *quorumVvec);
    }
    if (skShare.IsValid()) {
        evoDb.GetRawDB().Write(std::make_pair(DB_QUORUM_SK_SHARE, dbKey), skShare);
    }
}

bool CQuorum::ReadContributions(CEvoDB& evoDb)
{
    uint256 dbKey = MakeQuorumKey(*this);

    BLSVerificationVector qv;
    if (evoDb.Read(std::make_pair(DB_QUORUM_QUORUM_VVEC, dbKey), qv)) {
        quorumVvec = std::make_shared<BLSVerificationVector>(std::move(qv));
    } else {
        return false;
    }

    // We ignore the return value here as it is ok if this fails. If it fails, it usually means that we are not a
    // member of the quorum but observed the whole DKG process to have the quorum verification vector.
    evoDb.Read(std::make_pair(DB_QUORUM_SK_SHARE, dbKey), skShare);

    return true;
}

void CQuorum::StartCachePopulatorThread(std::shared_ptr<CQuorum> _this)
{
    if (_this->quorumVvec == nullptr) {
        return;
    }

    LogPrint(BCLog::LLMQ, "CQuorum::StartCachePopulatorThread -- start\n");

    // this thread will exit after some time
    // when then later some other thread tries to get keys, it will be much faster
    _this->cachePopulatorThread = std::thread([_this]() {
        util::ThreadRename("syscoin-q-cachepop");
        for (size_t i = 0; i < _this->members.size() && !_this->stopCachePopulatorThread && !ShutdownRequested(); i++) {
            if (_this->qc.validMembers[i]) {
                _this->GetPubKeyShare(i);
            }
        }
    });
}

CQuorumManager::CQuorumManager(CEvoDB& _evoDb, CBLSWorker& _blsWorker, CDKGSessionManager& _dkgManager) :
    evoDb(_evoDb),
    blsWorker(_blsWorker),
    dkgManager(_dkgManager)
{
}

void CQuorumManager::UpdatedBlockTip(const CBlockIndex* pindexNew, bool fInitialDownload)
{
    if (!masternodeSync.IsBlockchainSynced()) {
        return;
    }

    for (auto& p : Params().GetConsensus().llmqs) {
        EnsureQuorumConnections(p.first, pindexNew);
    }
}

void CQuorumManager::EnsureQuorumConnections(uint8_t llmqType, const CBlockIndex* pindexNew)
{
    const auto& params = Params().GetConsensus().llmqs.at(llmqType);
    auto myProTxHash = activeMasternodeInfo.proTxHash;
    std::vector<CQuorumCPtr> lastQuorums;
    ScanQuorums(llmqType, pindexNew, (size_t)params.keepOldConnections, lastQuorums);
    std::set<uint256> connmanQuorumsToDelete;
    dkgManager.connman.GetMasternodeQuorums(llmqType, connmanQuorumsToDelete);
    // don't remove connections for the currently in-progress DKG round
    int curDkgHeight = pindexNew->nHeight - (pindexNew->nHeight % params.dkgInterval);
    auto curDkgBlock = pindexNew->GetAncestor(curDkgHeight)->GetBlockHash();
    connmanQuorumsToDelete.erase(curDkgBlock);
    bool allowWatch = gArgs.GetBoolArg("-watchquorums", DEFAULT_WATCH_QUORUMS);
    for (auto& quorum : lastQuorums) {
        if (!quorum->IsMember(myProTxHash) && !allowWatch) {
            continue;
        }
        CLLMQUtils::EnsureQuorumConnections(llmqType, quorum->pindexQuorum, myProTxHash, allowWatch, dkgManager.connman);
        connmanQuorumsToDelete.erase(quorum->qc.quorumHash);
    }
    for (auto& qh : connmanQuorumsToDelete) {
        LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- removing masternodes quorum connections for quorum %s:\n", __func__, qh.ToString());
        dkgManager.connman.RemoveMasternodeQuorumNodes(llmqType, qh);
    }
}

bool CQuorumManager::BuildQuorumFromCommitment(const CFinalCommitment& qc, const CBlockIndex* pindexQuorum, const uint256& minedBlockHash, std::shared_ptr<CQuorum>& quorum) const
{
    std::vector<CDeterministicMNCPtr> members;
    assert(qc.quorumHash == pindexQuorum->GetBlockHash());
    CLLMQUtils::GetAllQuorumMembers(qc.llmqType, pindexQuorum, members);

    quorum->Init(qc, pindexQuorum, minedBlockHash, members);

    bool hasValidVvec = false;
    if (quorum->ReadContributions(evoDb)) {
        hasValidVvec = true;
    } else {
        if (BuildQuorumContributions(qc, quorum)) {
            quorum->WriteContributions(evoDb);
            hasValidVvec = true;
        } else {
            LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- quorum.ReadContributions and BuildQuorumContributions for block %s failed\n", __func__, qc.quorumHash.ToString());
        }
    }

    if (hasValidVvec) {
        // pre-populate caches in the background
        // recovering public key shares is quite expensive and would result in serious lags for the first few signing
        // sessions if the shares would be calculated on-demand
        CQuorum::StartCachePopulatorThread(quorum);
    }

    return true;
}

bool CQuorumManager::BuildQuorumContributions(const CFinalCommitment& fqc, std::shared_ptr<CQuorum>& quorum) const
{
    std::vector<uint16_t> memberIndexes;
    std::vector<BLSVerificationVectorPtr> vvecs;
    BLSSecretKeyVector skContributions;
    if (!dkgManager.GetVerifiedContributions(fqc.llmqType, quorum->pindexQuorum, fqc.validMembers, memberIndexes, vvecs, skContributions)) {
        return false;
    }

    BLSVerificationVectorPtr quorumVvec;
    CBLSSecretKey skShare;

    cxxtimer::Timer t2(true);
    quorumVvec = blsWorker.BuildQuorumVerificationVector(vvecs);
    if (quorumVvec == nullptr) {
        LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- failed to build quorumVvec\n", __func__);
        // without the quorum vvec, there can't be a skShare, so we fail here. Failure is not fatal here, as it still
        // allows to use the quorum as a non-member (verification through the quorum pub key)
        return false;
    }
    skShare = blsWorker.AggregateSecretKeys(skContributions);
    if (!skShare.IsValid()) {
        LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- failed to build skShare\n", __func__);
        // We don't bail out here as this is not a fatal error and still allows us to recover public key shares (as we
        // have a valid quorum vvec at this point)
    }
    t2.stop();

    LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- built quorum vvec and skShare. time=%d\n", __func__, t2.count());

    quorum->quorumVvec = quorumVvec;
    quorum->skShare = skShare;

    return true;
}

bool CQuorumManager::HasQuorum(uint8_t llmqType, const uint256& quorumHash)
{
    return quorumBlockProcessor->HasMinedCommitment(llmqType, quorumHash);
}

void CQuorumManager::ScanQuorums(uint8_t llmqType, size_t maxCount, std::vector<CQuorumCPtr>& quorums)
{
    LOCK(cs_main);
    ScanQuorums(llmqType, ::ChainActive().Tip(), maxCount, quorums);
}

void CQuorumManager::ScanQuorums(uint8_t llmqType, const CBlockIndex* pindexQuorum, size_t maxCount, std::vector<CQuorumCPtr>& result)
{
    result.clear();
    auto& params = Params().GetConsensus().llmqs.at(llmqType);

    auto cacheKey = std::make_pair(llmqType, pindexQuorum->GetBlockHash());
    const size_t cacheMaxSize = params.signingActiveQuorumCount + 1;

    if (maxCount <= cacheMaxSize) {
        LOCK(quorumsCacheCs);
        if (scanQuorumsCache.get(cacheKey, result)) {
            if (result.size() > maxCount) {
                result.resize(maxCount);
            }
            return;
        }
    }
    bool storeCache = false;
    size_t maxCount2 = maxCount;
    if (maxCount2 <= cacheMaxSize) {
        maxCount2 = cacheMaxSize;
        storeCache = true;
    }
    std::vector<const CBlockIndex*> quorumIndexes;
    quorumBlockProcessor->GetMinedCommitmentsUntilBlock(params.type, pindexQuorum, maxCount2, quorumIndexes);
    result.reserve(quorumIndexes.size());
    for (auto& quorumIndex : quorumIndexes) {
        assert(quorumIndex);
        auto quorum = GetQuorum(params.type, quorumIndex);
        assert(quorum != nullptr);
        result.emplace_back(quorum);
    }
    if (storeCache) {
        LOCK(quorumsCacheCs);
        scanQuorumsCache.insert(cacheKey, result);
    }
    if (result.size() > maxCount) {
        result.resize(maxCount);
    }

}

CQuorumCPtr CQuorumManager::GetQuorum(uint8_t llmqType, const uint256& quorumHash)
{
    LOCK(cs_main);
    const CBlockIndex* pindexQuorum = LookupBlockIndex(quorumHash);
    if (!pindexQuorum) {
        LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- block %s not found\n", __func__, quorumHash.ToString());
        return nullptr;
    }
    return GetQuorum(llmqType, pindexQuorum);
}

CQuorumCPtr CQuorumManager::GetQuorum(uint8_t llmqType, const CBlockIndex* pindexQuorum)
{
    assert(pindexQuorum);
    // we must check this before we look into the cache. Reorgs might have happened which would mean we might have
    // cached quorums which are not in the active chain anymore
    const uint256& quorumHash = pindexQuorum->GetBlockHash();
    if (!HasQuorum(llmqType, quorumHash)) {
        return nullptr;
    }

    CFinalCommitment qc;
    uint256 minedBlockHash;
    if (!quorumBlockProcessor->GetMinedCommitment(llmqType, quorumHash, qc, minedBlockHash)) {
        return nullptr;
    }
    {
        LOCK(quorumsCacheCs);

        auto it = quorumsCache.find(std::make_pair(llmqType, quorumHash));
        if (it != quorumsCache.end()) {
            return it->second;
        }

    }
    auto& params = Params().GetConsensus().llmqs.at(llmqType);
    auto quorum = std::make_shared<CQuorum>(params, blsWorker);
    if (!BuildQuorumFromCommitment(qc, pindexQuorum, minedBlockHash, quorum)) {
        return nullptr;
    }
    {
        LOCK(quorumsCacheCs);
        quorumsCache.try_emplace(std::make_pair(llmqType, quorumHash), quorum);
    }
    return quorum;
}
} // namespace llmq
<commit_msg>Update quorums.cpp<commit_after>// Copyright (c) 2018-2019 The Dash Core developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <llmq/quorums.h>
#include <llmq/quorums_blockprocessor.h>
#include <llmq/quorums_commitment.h>
#include <llmq/quorums_dkgsession.h>
#include <llmq/quorums_dkgsessionmgr.h>
#include <llmq/quorums_init.h>
#include <llmq/quorums_utils.h>

#include <evo/specialtx.h>

#include <masternode/activemasternode.h>
#include <chainparams.h>
#include <init.h>
#include <masternode/masternodesync.h>
#include <univalue.h>
#include <validation.h>
#include <shutdown.h>
#include <cxxtimer.hpp>
#include <net.h>
namespace llmq
{

static const std::string DB_QUORUM_SK_SHARE = "q_Qsk";
static const std::string DB_QUORUM_QUORUM_VVEC = "q_Qqvvec";

CQuorumManager* quorumManager;

static uint256 MakeQuorumKey(const CQuorum& q)
{
    CHashWriter hw(SER_NETWORK, 0);
    hw << q.params.type;
    hw << q.qc.quorumHash;
    for (const auto& dmn : q.members) {
        hw << dmn->proTxHash;
    }
    return hw.GetHash();
}

CQuorum::~CQuorum()
{
    // most likely the thread is already done
    stopCachePopulatorThread = true;
    // watch out to not join the thread when we're called from inside the thread, which might happen on shutdown. This
    // is because on shutdown the thread is the last owner of the shared CQuorum instance and thus the destroyer of it.
    if (cachePopulatorThread.joinable() && cachePopulatorThread.get_id() != std::this_thread::get_id()) {
        cachePopulatorThread.join();
    }
}

void CQuorum::Init(const CFinalCommitment& _qc, const CBlockIndex* _pindexQuorum, const uint256& _minedBlockHash, const std::vector<CDeterministicMNCPtr>& _members)
{
    qc = _qc;
    pindexQuorum = _pindexQuorum;
    members = _members;
    minedBlockHash = _minedBlockHash;
}

bool CQuorum::IsMember(const uint256& proTxHash) const
{
    for (auto& dmn : members) {
        if (dmn->proTxHash == proTxHash) {
            return true;
        }
    }
    return false;
}

bool CQuorum::IsValidMember(const uint256& proTxHash) const
{
    for (size_t i = 0; i < members.size(); i++) {
        if (members[i]->proTxHash == proTxHash) {
            return qc.validMembers[i];
        }
    }
    return false;
}

CBLSPublicKey CQuorum::GetPubKeyShare(size_t memberIdx) const
{
    if (quorumVvec == nullptr || memberIdx >= members.size() || !qc.validMembers[memberIdx]) {
        return CBLSPublicKey();
    }
    auto& m = members[memberIdx];
    return blsCache.BuildPubKeyShare(m->proTxHash, quorumVvec, CBLSId::FromHash(m->proTxHash));
}

CBLSSecretKey CQuorum::GetSkShare() const
{
    return skShare;
}

int CQuorum::GetMemberIndex(const uint256& proTxHash) const
{
    for (size_t i = 0; i < members.size(); i++) {
        if (members[i]->proTxHash == proTxHash) {
            return (int)i;
        }
    }
    return -1;
}

void CQuorum::WriteContributions(CEvoDB& evoDb)
{
    uint256 dbKey = MakeQuorumKey(*this);

    if (quorumVvec != nullptr) {
        evoDb.GetRawDB().Write(std::make_pair(DB_QUORUM_QUORUM_VVEC, dbKey), *quorumVvec);
    }
    if (skShare.IsValid()) {
        evoDb.GetRawDB().Write(std::make_pair(DB_QUORUM_SK_SHARE, dbKey), skShare);
    }
}

bool CQuorum::ReadContributions(CEvoDB& evoDb)
{
    uint256 dbKey = MakeQuorumKey(*this);

    BLSVerificationVector qv;
    if (evoDb.Read(std::make_pair(DB_QUORUM_QUORUM_VVEC, dbKey), qv)) {
        quorumVvec = std::make_shared<BLSVerificationVector>(std::move(qv));
    } else {
        return false;
    }

    // We ignore the return value here as it is ok if this fails. If it fails, it usually means that we are not a
    // member of the quorum but observed the whole DKG process to have the quorum verification vector.
    evoDb.Read(std::make_pair(DB_QUORUM_SK_SHARE, dbKey), skShare);

    return true;
}

void CQuorum::StartCachePopulatorThread(std::shared_ptr<CQuorum> _this)
{
    if (_this->quorumVvec == nullptr) {
        return;
    }

    LogPrint(BCLog::LLMQ, "CQuorum::StartCachePopulatorThread -- start\n");

    // this thread will exit after some time
    // when then later some other thread tries to get keys, it will be much faster
    _this->cachePopulatorThread = std::thread(&TraceThread<std::function<void()>>, "syscoin-q-cachepop", [_this] {
        for (size_t i = 0; i < _this->members.size() && !_this->stopCachePopulatorThread && !ShutdownRequested(); i++) {
            if (_this->qc.validMembers[i]) {
                _this->GetPubKeyShare(i);
            }
        }
    });
}

CQuorumManager::CQuorumManager(CEvoDB& _evoDb, CBLSWorker& _blsWorker, CDKGSessionManager& _dkgManager) :
    evoDb(_evoDb),
    blsWorker(_blsWorker),
    dkgManager(_dkgManager)
{
}

void CQuorumManager::UpdatedBlockTip(const CBlockIndex* pindexNew, bool fInitialDownload)
{
    if (!masternodeSync.IsBlockchainSynced()) {
        return;
    }

    for (auto& p : Params().GetConsensus().llmqs) {
        EnsureQuorumConnections(p.first, pindexNew);
    }
}

void CQuorumManager::EnsureQuorumConnections(uint8_t llmqType, const CBlockIndex* pindexNew)
{
    const auto& params = Params().GetConsensus().llmqs.at(llmqType);
    auto myProTxHash = activeMasternodeInfo.proTxHash;
    std::vector<CQuorumCPtr> lastQuorums;
    ScanQuorums(llmqType, pindexNew, (size_t)params.keepOldConnections, lastQuorums);
    std::set<uint256> connmanQuorumsToDelete;
    dkgManager.connman.GetMasternodeQuorums(llmqType, connmanQuorumsToDelete);
    // don't remove connections for the currently in-progress DKG round
    int curDkgHeight = pindexNew->nHeight - (pindexNew->nHeight % params.dkgInterval);
    auto curDkgBlock = pindexNew->GetAncestor(curDkgHeight)->GetBlockHash();
    connmanQuorumsToDelete.erase(curDkgBlock);
    bool allowWatch = gArgs.GetBoolArg("-watchquorums", DEFAULT_WATCH_QUORUMS);
    for (auto& quorum : lastQuorums) {
        if (!quorum->IsMember(myProTxHash) && !allowWatch) {
            continue;
        }
        CLLMQUtils::EnsureQuorumConnections(llmqType, quorum->pindexQuorum, myProTxHash, allowWatch, dkgManager.connman);
        connmanQuorumsToDelete.erase(quorum->qc.quorumHash);
    }
    for (auto& qh : connmanQuorumsToDelete) {
        LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- removing masternodes quorum connections for quorum %s:\n", __func__, qh.ToString());
        dkgManager.connman.RemoveMasternodeQuorumNodes(llmqType, qh);
    }
}

bool CQuorumManager::BuildQuorumFromCommitment(const CFinalCommitment& qc, const CBlockIndex* pindexQuorum, const uint256& minedBlockHash, std::shared_ptr<CQuorum>& quorum) const
{
    std::vector<CDeterministicMNCPtr> members;
    assert(qc.quorumHash == pindexQuorum->GetBlockHash());
    CLLMQUtils::GetAllQuorumMembers(qc.llmqType, pindexQuorum, members);

    quorum->Init(qc, pindexQuorum, minedBlockHash, members);

    bool hasValidVvec = false;
    if (quorum->ReadContributions(evoDb)) {
        hasValidVvec = true;
    } else {
        if (BuildQuorumContributions(qc, quorum)) {
            quorum->WriteContributions(evoDb);
            hasValidVvec = true;
        } else {
            LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- quorum.ReadContributions and BuildQuorumContributions for block %s failed\n", __func__, qc.quorumHash.ToString());
        }
    }

    if (hasValidVvec) {
        // pre-populate caches in the background
        // recovering public key shares is quite expensive and would result in serious lags for the first few signing
        // sessions if the shares would be calculated on-demand
        CQuorum::StartCachePopulatorThread(quorum);
    }

    return true;
}

bool CQuorumManager::BuildQuorumContributions(const CFinalCommitment& fqc, std::shared_ptr<CQuorum>& quorum) const
{
    std::vector<uint16_t> memberIndexes;
    std::vector<BLSVerificationVectorPtr> vvecs;
    BLSSecretKeyVector skContributions;
    if (!dkgManager.GetVerifiedContributions(fqc.llmqType, quorum->pindexQuorum, fqc.validMembers, memberIndexes, vvecs, skContributions)) {
        return false;
    }

    BLSVerificationVectorPtr quorumVvec;
    CBLSSecretKey skShare;

    cxxtimer::Timer t2(true);
    quorumVvec = blsWorker.BuildQuorumVerificationVector(vvecs);
    if (quorumVvec == nullptr) {
        LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- failed to build quorumVvec\n", __func__);
        // without the quorum vvec, there can't be a skShare, so we fail here. Failure is not fatal here, as it still
        // allows to use the quorum as a non-member (verification through the quorum pub key)
        return false;
    }
    skShare = blsWorker.AggregateSecretKeys(skContributions);
    if (!skShare.IsValid()) {
        LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- failed to build skShare\n", __func__);
        // We don't bail out here as this is not a fatal error and still allows us to recover public key shares (as we
        // have a valid quorum vvec at this point)
    }
    t2.stop();

    LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- built quorum vvec and skShare. time=%d\n", __func__, t2.count());

    quorum->quorumVvec = quorumVvec;
    quorum->skShare = skShare;

    return true;
}

bool CQuorumManager::HasQuorum(uint8_t llmqType, const uint256& quorumHash)
{
    return quorumBlockProcessor->HasMinedCommitment(llmqType, quorumHash);
}

void CQuorumManager::ScanQuorums(uint8_t llmqType, size_t maxCount, std::vector<CQuorumCPtr>& quorums)
{
    LOCK(cs_main);
    ScanQuorums(llmqType, ::ChainActive().Tip(), maxCount, quorums);
}

void CQuorumManager::ScanQuorums(uint8_t llmqType, const CBlockIndex* pindexQuorum, size_t maxCount, std::vector<CQuorumCPtr>& result)
{
    result.clear();
    auto& params = Params().GetConsensus().llmqs.at(llmqType);

    auto cacheKey = std::make_pair(llmqType, pindexQuorum->GetBlockHash());
    const size_t cacheMaxSize = params.signingActiveQuorumCount + 1;

    if (maxCount <= cacheMaxSize) {
        LOCK(quorumsCacheCs);
        if (scanQuorumsCache.get(cacheKey, result)) {
            if (result.size() > maxCount) {
                result.resize(maxCount);
            }
            return;
        }
    }
    bool storeCache = false;
    size_t maxCount2 = maxCount;
    if (maxCount2 <= cacheMaxSize) {
        maxCount2 = cacheMaxSize;
        storeCache = true;
    }
    std::vector<const CBlockIndex*> quorumIndexes;
    quorumBlockProcessor->GetMinedCommitmentsUntilBlock(params.type, pindexQuorum, maxCount2, quorumIndexes);
    result.reserve(quorumIndexes.size());
    for (auto& quorumIndex : quorumIndexes) {
        assert(quorumIndex);
        auto quorum = GetQuorum(params.type, quorumIndex);
        assert(quorum != nullptr);
        result.emplace_back(quorum);
    }
    if (storeCache) {
        LOCK(quorumsCacheCs);
        scanQuorumsCache.insert(cacheKey, result);
    }
    if (result.size() > maxCount) {
        result.resize(maxCount);
    }

}

CQuorumCPtr CQuorumManager::GetQuorum(uint8_t llmqType, const uint256& quorumHash)
{
    LOCK(cs_main);
    const CBlockIndex* pindexQuorum = LookupBlockIndex(quorumHash);
    if (!pindexQuorum) {
        LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- block %s not found\n", __func__, quorumHash.ToString());
        return nullptr;
    }
    return GetQuorum(llmqType, pindexQuorum);
}

CQuorumCPtr CQuorumManager::GetQuorum(uint8_t llmqType, const CBlockIndex* pindexQuorum)
{
    assert(pindexQuorum);
    // we must check this before we look into the cache. Reorgs might have happened which would mean we might have
    // cached quorums which are not in the active chain anymore
    const uint256& quorumHash = pindexQuorum->GetBlockHash();
    if (!HasQuorum(llmqType, quorumHash)) {
        return nullptr;
    }

    CFinalCommitment qc;
    uint256 minedBlockHash;
    if (!quorumBlockProcessor->GetMinedCommitment(llmqType, quorumHash, qc, minedBlockHash)) {
        return nullptr;
    }
    {
        LOCK(quorumsCacheCs);

        auto it = quorumsCache.find(std::make_pair(llmqType, quorumHash));
        if (it != quorumsCache.end()) {
            return it->second;
        }

    }
    auto& params = Params().GetConsensus().llmqs.at(llmqType);
    auto quorum = std::make_shared<CQuorum>(params, blsWorker);
    if (!BuildQuorumFromCommitment(qc, pindexQuorum, minedBlockHash, quorum)) {
        return nullptr;
    }
    {
        LOCK(quorumsCacheCs);
        quorumsCache.try_emplace(std::make_pair(llmqType, quorumHash), quorum);
    }
    return quorum;
}
} // namespace llmq
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2004-2016 ZNC, see the NOTICE file for details.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//! @author prozac@rottenboy.com
//
// The encryption here was designed to be compatible with mircryption's CBC
// mode.
//
// Latest tested against:
// MircryptionSuite - Mircryption ver 1.19.01 (dll v1.15.01 , mirc v7.32) CBC
// loaded and ready.
//
// TODO:
//
// 1) Encrypt key storage file
// 2) Secure key exchange using pub/priv keys and the DH algorithm
// 3) Some way of notifying the user that the current channel is in "encryption
// mode" verses plain text
// 4) Temporarily disable a target (nick/chan)
//
// NOTE: This module is currently NOT intended to secure you from your shell
// admin.
//       The keys are currently stored in plain text, so anyone with access to
//       your account (or root) can obtain them.
//       It is strongly suggested that you enable SSL between znc and your
//       client otherwise the encryption stops at znc and gets sent to your
//       client in plain text.
//

#include <znc/Chan.h>
#include <znc/User.h>
#include <znc/IRCNetwork.h>

#define REQUIRESSL 1
#define NICK_PREFIX_KEY "[nick-prefix]"

class CCryptMod : public CModule {
    CString NickPrefix() {
        MCString::iterator it = FindNV(NICK_PREFIX_KEY);
        return it != EndNV() ? it->second : "*";
    }

  public:
    MODCONSTRUCTOR(CCryptMod) {
        AddHelpCommand();
        AddCommand("DelKey", static_cast<CModCommand::ModCmdFunc>(
                                 &CCryptMod::OnDelKeyCommand),
                   "<#chan|Nick>", "Remove a key for nick or channel");
        AddCommand("SetKey", static_cast<CModCommand::ModCmdFunc>(
                                 &CCryptMod::OnSetKeyCommand),
                   "<#chan|Nick> <Key>", "Set a key for nick or channel");
        AddCommand("ListKeys", static_cast<CModCommand::ModCmdFunc>(
                                   &CCryptMod::OnListKeysCommand),
                   "", "List all keys");
    }

    ~CCryptMod() override {}

    EModRet OnUserMsg(CString& sTarget, CString& sMessage) override {
        sTarget.TrimPrefix(NickPrefix());

        if (sMessage.TrimPrefix("``")) {
            return CONTINUE;
        }

        MCString::iterator it = FindNV(sTarget.AsLower());

        if (it != EndNV()) {
            CChan* pChan = GetNetwork()->FindChan(sTarget);
            CString sNickMask = GetNetwork()->GetIRCNick().GetNickMask();
            if (pChan) {
                if (!pChan->AutoClearChanBuffer())
                    pChan->AddBuffer(":" + NickPrefix() + _NAMEDFMT(sNickMask) +
                                         " PRIVMSG " + _NAMEDFMT(sTarget) +
                                         " :{text}",
                                     sMessage);
                GetUser()->PutUser(":" + NickPrefix() + sNickMask +
                                       " PRIVMSG " + sTarget + " :" + sMessage,
                                   nullptr, GetClient());
            }

            CString sMsg = MakeIvec() + sMessage;
            sMsg.Encrypt(it->second);
            sMsg.Base64Encode();
            sMsg = "+OK *" + sMsg;

            PutIRC("PRIVMSG " + sTarget + " :" + sMsg);
            return HALTCORE;
        }

        return CONTINUE;
    }

    EModRet OnUserNotice(CString& sTarget, CString& sMessage) override {
        sTarget.TrimPrefix(NickPrefix());

        if (sMessage.TrimPrefix("``")) {
            return CONTINUE;
        }

        MCString::iterator it = FindNV(sTarget.AsLower());

        if (it != EndNV()) {
            CChan* pChan = GetNetwork()->FindChan(sTarget);
            CString sNickMask = GetNetwork()->GetIRCNick().GetNickMask();
            if (pChan) {
                if (!pChan->AutoClearChanBuffer())
                    pChan->AddBuffer(":" + NickPrefix() + _NAMEDFMT(sNickMask) +
                                         " NOTICE " + _NAMEDFMT(sTarget) +
                                         " :{text}",
                                     sMessage);
                GetUser()->PutUser(":" + NickPrefix() + sNickMask + " NOTICE " +
                                       sTarget + " :" + sMessage,
                                   NULL, GetClient());
            }

            CString sMsg = MakeIvec() + sMessage;
            sMsg.Encrypt(it->second);
            sMsg.Base64Encode();
            sMsg = "+OK *" + sMsg;

            PutIRC("NOTICE " + sTarget + " :" + sMsg);
            return HALTCORE;
        }

        return CONTINUE;
    }

    EModRet OnUserAction(CString& sTarget, CString& sMessage) override {
        sTarget.TrimPrefix(NickPrefix());

        if (sMessage.TrimPrefix("``")) {
            return CONTINUE;
        }

        MCString::iterator it = FindNV(sTarget.AsLower());

        if (it != EndNV()) {
            CChan* pChan = GetNetwork()->FindChan(sTarget);
            CString sNickMask = GetNetwork()->GetIRCNick().GetNickMask();
            if (pChan) {
                if (!pChan->AutoClearChanBuffer())
                    pChan->AddBuffer(":" + NickPrefix() + _NAMEDFMT(sNickMask) +
                                         " PRIVMSG " + _NAMEDFMT(sTarget) +
                                         " :\001ACTION {text}\001",
                                     sMessage);
                GetUser()->PutUser(":" + NickPrefix() + sNickMask +
                                       " PRIVMSG " + sTarget + " :\001ACTION " +
                                       sMessage + "\001",
                                   NULL, GetClient());
            }

            CString sMsg = MakeIvec() + sMessage;
            sMsg.Encrypt(it->second);
            sMsg.Base64Encode();
            sMsg = "+OK *" + sMsg;

            PutIRC("PRIVMSG " + sTarget + " :\001ACTION " + sMsg + "\001");
            return HALTCORE;
        }

        return CONTINUE;
    }

    EModRet OnUserTopic(CString& sTarget, CString& sMessage) override {
        sTarget.TrimPrefix(NickPrefix());

        if (sMessage.TrimPrefix("``")) {
            return CONTINUE;
        }

        MCString::iterator it = FindNV(sTarget.AsLower());

        if (it != EndNV()) {
            sMessage = MakeIvec() + sMessage;
            sMessage.Encrypt(it->second);
            sMessage.Base64Encode();
            sMessage = "+OK *" + sMessage;
        }

        return CONTINUE;
    }

    EModRet OnPrivMsg(CNick& Nick, CString& sMessage) override {
        FilterIncoming(Nick.GetNick(), Nick, sMessage);
        return CONTINUE;
    }

    EModRet OnPrivNotice(CNick& Nick, CString& sMessage) override {
        FilterIncoming(Nick.GetNick(), Nick, sMessage);
        return CONTINUE;
    }

    EModRet OnPrivAction(CNick& Nick, CString& sMessage) override {
        FilterIncoming(Nick.GetNick(), Nick, sMessage);
        return CONTINUE;
    }

    EModRet OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) override {
        FilterIncoming(Channel.GetName(), Nick, sMessage);
        return CONTINUE;
    }

    EModRet OnChanNotice(CNick& Nick, CChan& Channel,
                         CString& sMessage) override {
        FilterIncoming(Channel.GetName(), Nick, sMessage);
        return CONTINUE;
    }

    EModRet OnChanAction(CNick& Nick, CChan& Channel,
                         CString& sMessage) override {
        FilterIncoming(Channel.GetName(), Nick, sMessage);
        return CONTINUE;
    }

    EModRet OnTopic(CNick& Nick, CChan& Channel, CString& sMessage) override {
        FilterIncoming(Channel.GetName(), Nick, sMessage);
        return CONTINUE;
    }

    EModRet OnRaw(CString& sLine) override {
        if (!sLine.Token(1).Equals("332")) {
            return CONTINUE;
        }

        CChan* pChan = GetNetwork()->FindChan(sLine.Token(3));
        if (pChan) {
            CNick* Nick = pChan->FindNick(sLine.Token(2));
            CString sTopic = sLine.Token(4, true);
            sTopic.TrimPrefix(":");

            FilterIncoming(pChan->GetName(), *Nick, sTopic);
            sLine = sLine.Token(0) + " " + sLine.Token(1) + " " +
                    sLine.Token(2) + " " + pChan->GetName() + " :" + sTopic;
        }

        return CONTINUE;
    }

    void FilterIncoming(const CString& sTarget, CNick& Nick,
                        CString& sMessage) {
        if (sMessage.TrimPrefix("+OK *")) {
            MCString::iterator it = FindNV(sTarget.AsLower());

            if (it != EndNV()) {
                sMessage.Base64Decode();
                sMessage.Decrypt(it->second);
                sMessage.LeftChomp(8);
                sMessage = sMessage.c_str();
                Nick.SetNick(NickPrefix() + Nick.GetNick());
            }
        }
    }

    void OnDelKeyCommand(const CString& sCommand) {
        CString sTarget = sCommand.Token(1);

        if (!sTarget.empty()) {
            if (DelNV(sTarget.AsLower())) {
                PutModule("Target [" + sTarget + "] deleted");
            } else {
                PutModule("Target [" + sTarget + "] not found");
            }
        } else {
            PutModule("Usage DelKey <#chan|Nick>");
        }
    }

    void OnSetKeyCommand(const CString& sCommand) {
        CString sTarget = sCommand.Token(1);
        CString sKey = sCommand.Token(2, true);

        // Strip "cbc:" from beginning of string incase someone pastes directly
        // from mircryption
        sKey.TrimPrefix("cbc:");

        if (!sKey.empty()) {
            SetNV(sTarget.AsLower(), sKey);
            PutModule("Set encryption key for [" + sTarget + "] to [" + sKey +
                      "]");
        } else {
            PutModule("Usage: SetKey <#chan|Nick> <Key>");
        }
    }

    void OnListKeysCommand(const CString& sCommand) {
        if (BeginNV() == EndNV()) {
            PutModule("You have no encryption keys set.");
        } else {
            CTable Table;
            Table.AddColumn("Target");
            Table.AddColumn("Key");

            for (MCString::iterator it = BeginNV(); it != EndNV(); ++it) {
                Table.AddRow();
                Table.SetCell("Target", it->first);
                Table.SetCell("Key", it->second);
            }

            MCString::iterator it = FindNV(NICK_PREFIX_KEY);
            if (it == EndNV()) {
                Table.AddRow();
                Table.SetCell("Target", NICK_PREFIX_KEY);
                Table.SetCell("Key", NickPrefix());
            }

            PutModule(Table);
        }
    }

    CString MakeIvec() {
        CString sRet;
        time_t t;
        time(&t);
        int r = rand();
        sRet.append((char*)&t, 4);
        sRet.append((char*)&r, 4);

        return sRet;
    }
};

template <>
void TModInfo<CCryptMod>(CModInfo& Info) {
    Info.SetWikiPage("crypt");
}

NETWORKMODULEDEFS(CCryptMod, "Encryption for channel/private messages")
<commit_msg>Don't use the same or overlapping NickPrefix as StatusPrefix in the crypt module<commit_after>/*
 * Copyright (C) 2004-2016 ZNC, see the NOTICE file for details.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//! @author prozac@rottenboy.com
//
// The encryption here was designed to be compatible with mircryption's CBC
// mode.
//
// Latest tested against:
// MircryptionSuite - Mircryption ver 1.19.01 (dll v1.15.01 , mirc v7.32) CBC
// loaded and ready.
//
// TODO:
//
// 1) Encrypt key storage file
// 2) Secure key exchange using pub/priv keys and the DH algorithm
// 3) Some way of notifying the user that the current channel is in "encryption
// mode" verses plain text
// 4) Temporarily disable a target (nick/chan)
//
// NOTE: This module is currently NOT intended to secure you from your shell
// admin.
//       The keys are currently stored in plain text, so anyone with access to
//       your account (or root) can obtain them.
//       It is strongly suggested that you enable SSL between znc and your
//       client otherwise the encryption stops at znc and gets sent to your
//       client in plain text.
//

#include <znc/Chan.h>
#include <znc/User.h>
#include <znc/IRCNetwork.h>

#define REQUIRESSL 1
// To be removed in future versions
#define NICK_PREFIX_OLD_KEY "[nick-prefix]"
#define NICK_PREFIX_KEY "@nick-prefix@"

class CCryptMod : public CModule {
    CString NickPrefix() {
        MCString::iterator it = FindNV(NICK_PREFIX_KEY);
        /*
         * Check for different Prefixes to not confuse modules with nicknames
         * Also check for overlap for rare cases like:
         * SP = "*"; NP = "*s"; "tatus" sends an encrypted message appearing at "*status"
         */
        CString sStatusPrefix = GetUser()->GetStatusPrefix();
        if (it != EndNV()) {
            size_t sp = sStatusPrefix.size();
            size_t np = it->second.size();
            if (sStatusPrefix.CaseCmp(it->second, std::min(sp, np)) != 0)
                return it->second;
        }
        return sStatusPrefix.StartsWith("*") ? "." : "*";
    }

  public:
    MODCONSTRUCTOR(CCryptMod) {
        AddHelpCommand();
        AddCommand("DelKey", static_cast<CModCommand::ModCmdFunc>(
                                 &CCryptMod::OnDelKeyCommand),
                   "<#chan|Nick>", "Remove a key for nick or channel");
        AddCommand("SetKey", static_cast<CModCommand::ModCmdFunc>(
                                 &CCryptMod::OnSetKeyCommand),
                   "<#chan|Nick> <Key>", "Set a key for nick or channel");
        AddCommand("ListKeys", static_cast<CModCommand::ModCmdFunc>(
                                   &CCryptMod::OnListKeysCommand),
                   "", "List all keys");
    }

    ~CCryptMod() override {}

    bool OnLoad(const CString& sArgsi, CString& sMessage) override {
        MCString::iterator it = FindNV(NICK_PREFIX_KEY);
        if (it == EndNV()) {
            /* Don't have the new prefix key yet */
            it = FindNV(NICK_PREFIX_OLD_KEY);
            if (it != EndNV()) {
                SetNV(NICK_PREFIX_KEY, it->second);
                DelNV(NICK_PREFIX_OLD_KEY);
            }
        }
        return true;
    }

    EModRet OnUserMsg(CString& sTarget, CString& sMessage) override {
        sTarget.TrimPrefix(NickPrefix());

        if (sMessage.TrimPrefix("``")) {
            return CONTINUE;
        }

        MCString::iterator it = FindNV(sTarget.AsLower());

        if (it != EndNV()) {
            CChan* pChan = GetNetwork()->FindChan(sTarget);
            CString sNickMask = GetNetwork()->GetIRCNick().GetNickMask();
            if (pChan) {
                if (!pChan->AutoClearChanBuffer())
                    pChan->AddBuffer(":" + NickPrefix() + _NAMEDFMT(sNickMask) +
                                         " PRIVMSG " + _NAMEDFMT(sTarget) +
                                         " :{text}",
                                     sMessage);
                GetUser()->PutUser(":" + NickPrefix() + sNickMask +
                                       " PRIVMSG " + sTarget + " :" + sMessage,
                                   nullptr, GetClient());
            }

            CString sMsg = MakeIvec() + sMessage;
            sMsg.Encrypt(it->second);
            sMsg.Base64Encode();
            sMsg = "+OK *" + sMsg;

            PutIRC("PRIVMSG " + sTarget + " :" + sMsg);
            return HALTCORE;
        }

        return CONTINUE;
    }

    EModRet OnUserNotice(CString& sTarget, CString& sMessage) override {
        sTarget.TrimPrefix(NickPrefix());

        if (sMessage.TrimPrefix("``")) {
            return CONTINUE;
        }

        MCString::iterator it = FindNV(sTarget.AsLower());

        if (it != EndNV()) {
            CChan* pChan = GetNetwork()->FindChan(sTarget);
            CString sNickMask = GetNetwork()->GetIRCNick().GetNickMask();
            if (pChan) {
                if (!pChan->AutoClearChanBuffer())
                    pChan->AddBuffer(":" + NickPrefix() + _NAMEDFMT(sNickMask) +
                                         " NOTICE " + _NAMEDFMT(sTarget) +
                                         " :{text}",
                                     sMessage);
                GetUser()->PutUser(":" + NickPrefix() + sNickMask + " NOTICE " +
                                       sTarget + " :" + sMessage,
                                   NULL, GetClient());
            }

            CString sMsg = MakeIvec() + sMessage;
            sMsg.Encrypt(it->second);
            sMsg.Base64Encode();
            sMsg = "+OK *" + sMsg;

            PutIRC("NOTICE " + sTarget + " :" + sMsg);
            return HALTCORE;
        }

        return CONTINUE;
    }

    EModRet OnUserAction(CString& sTarget, CString& sMessage) override {
        sTarget.TrimPrefix(NickPrefix());

        if (sMessage.TrimPrefix("``")) {
            return CONTINUE;
        }

        MCString::iterator it = FindNV(sTarget.AsLower());

        if (it != EndNV()) {
            CChan* pChan = GetNetwork()->FindChan(sTarget);
            CString sNickMask = GetNetwork()->GetIRCNick().GetNickMask();
            if (pChan) {
                if (!pChan->AutoClearChanBuffer())
                    pChan->AddBuffer(":" + NickPrefix() + _NAMEDFMT(sNickMask) +
                                         " PRIVMSG " + _NAMEDFMT(sTarget) +
                                         " :\001ACTION {text}\001",
                                     sMessage);
                GetUser()->PutUser(":" + NickPrefix() + sNickMask +
                                       " PRIVMSG " + sTarget + " :\001ACTION " +
                                       sMessage + "\001",
                                   NULL, GetClient());
            }

            CString sMsg = MakeIvec() + sMessage;
            sMsg.Encrypt(it->second);
            sMsg.Base64Encode();
            sMsg = "+OK *" + sMsg;

            PutIRC("PRIVMSG " + sTarget + " :\001ACTION " + sMsg + "\001");
            return HALTCORE;
        }

        return CONTINUE;
    }

    EModRet OnUserTopic(CString& sTarget, CString& sMessage) override {
        sTarget.TrimPrefix(NickPrefix());

        if (sMessage.TrimPrefix("``")) {
            return CONTINUE;
        }

        MCString::iterator it = FindNV(sTarget.AsLower());

        if (it != EndNV()) {
            sMessage = MakeIvec() + sMessage;
            sMessage.Encrypt(it->second);
            sMessage.Base64Encode();
            sMessage = "+OK *" + sMessage;
        }

        return CONTINUE;
    }

    EModRet OnPrivMsg(CNick& Nick, CString& sMessage) override {
        FilterIncoming(Nick.GetNick(), Nick, sMessage);
        return CONTINUE;
    }

    EModRet OnPrivNotice(CNick& Nick, CString& sMessage) override {
        FilterIncoming(Nick.GetNick(), Nick, sMessage);
        return CONTINUE;
    }

    EModRet OnPrivAction(CNick& Nick, CString& sMessage) override {
        FilterIncoming(Nick.GetNick(), Nick, sMessage);
        return CONTINUE;
    }

    EModRet OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) override {
        FilterIncoming(Channel.GetName(), Nick, sMessage);
        return CONTINUE;
    }

    EModRet OnChanNotice(CNick& Nick, CChan& Channel,
                         CString& sMessage) override {
        FilterIncoming(Channel.GetName(), Nick, sMessage);
        return CONTINUE;
    }

    EModRet OnChanAction(CNick& Nick, CChan& Channel,
                         CString& sMessage) override {
        FilterIncoming(Channel.GetName(), Nick, sMessage);
        return CONTINUE;
    }

    EModRet OnTopic(CNick& Nick, CChan& Channel, CString& sMessage) override {
        FilterIncoming(Channel.GetName(), Nick, sMessage);
        return CONTINUE;
    }

    EModRet OnRaw(CString& sLine) override {
        if (!sLine.Token(1).Equals("332")) {
            return CONTINUE;
        }

        CChan* pChan = GetNetwork()->FindChan(sLine.Token(3));
        if (pChan) {
            CNick* Nick = pChan->FindNick(sLine.Token(2));
            CString sTopic = sLine.Token(4, true);
            sTopic.TrimPrefix(":");

            FilterIncoming(pChan->GetName(), *Nick, sTopic);
            sLine = sLine.Token(0) + " " + sLine.Token(1) + " " +
                    sLine.Token(2) + " " + pChan->GetName() + " :" + sTopic;
        }

        return CONTINUE;
    }

    void FilterIncoming(const CString& sTarget, CNick& Nick,
                        CString& sMessage) {
        if (sMessage.TrimPrefix("+OK *")) {
            MCString::iterator it = FindNV(sTarget.AsLower());

            if (it != EndNV()) {
                sMessage.Base64Decode();
                sMessage.Decrypt(it->second);
                sMessage.LeftChomp(8);
                sMessage = sMessage.c_str();
                Nick.SetNick(NickPrefix() + Nick.GetNick());
            }
        }
    }

    void OnDelKeyCommand(const CString& sCommand) {
        CString sTarget = sCommand.Token(1);

        if (!sTarget.empty()) {
            if (DelNV(sTarget.AsLower())) {
                PutModule("Target [" + sTarget + "] deleted");
            } else {
                PutModule("Target [" + sTarget + "] not found");
            }
        } else {
            PutModule("Usage DelKey <#chan|Nick>");
        }
    }

    void OnSetKeyCommand(const CString& sCommand) {
        CString sTarget = sCommand.Token(1);
        CString sKey = sCommand.Token(2, true);

        // Strip "cbc:" from beginning of string incase someone pastes directly
        // from mircryption
        sKey.TrimPrefix("cbc:");

        if (!sKey.empty()) {
            SetNV(sTarget.AsLower(), sKey);
            PutModule("Set encryption key for [" + sTarget + "] to [" + sKey +
                      "]");
        } else {
            PutModule("Usage: SetKey <#chan|Nick> <Key>");
        }
    }

    void OnListKeysCommand(const CString& sCommand) {
        if (BeginNV() == EndNV()) {
            PutModule("You have no encryption keys set.");
        } else {
            CTable Table;
            Table.AddColumn("Target");
            Table.AddColumn("Key");

            for (MCString::iterator it = BeginNV(); it != EndNV(); ++it) {
                Table.AddRow();
                Table.SetCell("Target", it->first);
                Table.SetCell("Key", it->second);
            }

            MCString::iterator it = FindNV(NICK_PREFIX_KEY);
            if (it == EndNV()) {
                Table.AddRow();
                Table.SetCell("Target", NICK_PREFIX_KEY);
                Table.SetCell("Key", NickPrefix());
            }

            PutModule(Table);
        }
    }

    CString MakeIvec() {
        CString sRet;
        time_t t;
        time(&t);
        int r = rand();
        sRet.append((char*)&t, 4);
        sRet.append((char*)&r, 4);

        return sRet;
    }
};

template <>
void TModInfo<CCryptMod>(CModInfo& Info) {
    Info.SetWikiPage("crypt");
}

NETWORKMODULEDEFS(CCryptMod, "Encryption for channel/private messages")
<|endoftext|>