| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435 | //---------------------------------------------------------------------------#include <vcl.h>#pragma hdrstop#include "ScpCommander.h"#include "ScpExplorer.h"#include <CoreMain.h>#include <Common.h>#include <Exceptions.h>#include <Cryptography.h>#include "ProgParams.h"#include "VCLCommon.h"#include "WinConfiguration.h"#include "TerminalManager.h"#include "TextsWin.h"#include "WinInterface.h"#include "PasswordEdit.hpp"#include "ProgParams.h"#include "Tools.h"#include "Custom.h"#include "HelpWin.h"#include <Math.hpp>#include <PasTools.hpp>#include <GUITools.h>//---------------------------------------------------------------------------#pragma package(smart_init)//---------------------------------------------------------------------------const UnicodeString AppName = L"WinSCP";//---------------------------------------------------------------------------TConfiguration * __fastcall CreateConfiguration(){  WinConfiguration = new TWinConfiguration();  CustomWinConfiguration = WinConfiguration;  GUIConfiguration = CustomWinConfiguration;  TProgramParams * Params = TProgramParams::Instance();  UnicodeString IniFileName = Params->SwitchValue(INI_SWITCH);  if (!IniFileName.IsEmpty())  {    if (SameText(IniFileName, INI_NUL))    {      WinConfiguration->SetNulStorage();    }    else if (CheckSafe(Params))    {      IniFileName = ExpandFileName(ExpandEnvironmentVariables(IniFileName));      WinConfiguration->IniFileStorageName = IniFileName;    }  }  if (CheckSafe(Params))  {    std::unique_ptr<TStrings> RawConfig(new TStringList());    if (Params->FindSwitch(RAW_CONFIG_SWITCH, RawConfig.get()))    {      WinConfiguration->OptionsStorage = RawConfig.get();    }  }  return WinConfiguration;}//---------------------------------------------------------------------------TOptions * __fastcall GetGlobalOptions(){  return TProgramParams::Instance();}//---------------------------------------------------------------------------TCustomScpExplorerForm * __fastcall CreateScpExplorer(){  TCustomScpExplorerForm * ScpExplorer;  if (WinConfiguration->Interface == ifExplorer)  {    ScpExplorer = SafeFormCreate<TScpExplorerForm>();  }  else  {    ScpExplorer = SafeFormCreate<TScpCommanderForm>();  }  return ScpExplorer;}//---------------------------------------------------------------------------UnicodeString __fastcall SshVersionString(){  return FORMAT(L"WinSCP-release-%s", (Configuration->Version));}//---------------------------------------------------------------------------UnicodeString __fastcall AppNameString(){  return L"WinSCP";}//---------------------------------------------------------------------------UnicodeString __fastcall GetCompanyRegistryKey(){  return L"Software\\Martin Prikryl";}//---------------------------------------------------------------------------UnicodeString __fastcall GetRegistryKey(){  return GetCompanyRegistryKey() + L"\\WinSCP 2";}//---------------------------------------------------------------------------static bool ForcedOnForeground = false;void __fastcall SetOnForeground(bool OnForeground){  ForcedOnForeground = OnForeground;}//---------------------------------------------------------------------------void __fastcall FlashOnBackground(){  DebugAssert(Application);  if (!ForcedOnForeground && !ForegroundTask())  {    FlashWindow(Application->MainFormHandle, true);  }}//---------------------------------------------------------------------------void __fastcall LocalSystemSettings(TCustomForm * /*Control*/){  // noop}//---------------------------------------------------------------------------void __fastcall ShowExtendedException(Exception * E){  ShowExtendedExceptionEx(NULL, E);}//---------------------------------------------------------------------------void __fastcall TerminateApplication(){  Application->Terminate();}//---------------------------------------------------------------------------struct TOpenLocalPathHandler{  UnicodeString LocalPath;  UnicodeString LocalFileName;  void __fastcall Open(TObject * Sender, unsigned int & /*Answer*/)  {    TButton * Button = DebugNotNull(dynamic_cast<TButton *>(Sender));    // Reason for separate AMenu variable is given in TPreferencesDialog::EditorFontColorButtonClick    TPopupMenu * AMenu = new TPopupMenu(Application);    // Popup menu has to survive the popup as TBX calls click handler asynchronously (post).    Menu.reset(AMenu);    TMenuItem * Item;    Item = new TMenuItem(Menu.get());    Menu->Items->Add(Item);    Item->Caption = LoadStr(OPEN_TARGET_FOLDER);    Item->OnClick = OpenFolderClick;    if (!LocalFileName.IsEmpty())    {      Item = new TMenuItem(Menu.get());      Menu->Items->Add(Item);      Item->Caption = LoadStr(OPEN_DOWNLOADED_FILE);      Item->OnClick = OpenFileClick;    }    MenuPopup(Menu.get(), Button);  }private:  std::unique_ptr<TPopupMenu> Menu;  void __fastcall OpenFolderClick(TObject * /*Sender*/)  {    if (LocalFileName.IsEmpty())    {      OpenFolderInExplorer(LocalPath);    }    else    {      OpenFileInExplorer(LocalFileName);    }  }  void __fastcall OpenFileClick(TObject * /*Sender*/)  {    ExecuteShellChecked(LocalFileName, L"");  }};//---------------------------------------------------------------------------void __fastcall ShowExtendedExceptionEx(TTerminal * Terminal,  Exception * E){  bool Show = ShouldDisplayException(E);  bool DoNotDisplay = false;  try  {    // This is special case used particularly when called from .NET assembly    // (which always uses /nointeractiveinput),    // but can be useful for other console runs too    TProgramParams * Params = TProgramParams::Instance();    if (Params->FindSwitch(L"nointeractiveinput"))    {      DoNotDisplay = true;      if (Show && CheckXmlLogParam(Params))      {        // The Started argument won't be used with .NET assembly, as it never uses patterns in XML log file name.        // But it theoretically can be used, when started manually.        std::unique_ptr<TActionLog> ActionLog(new TActionLog(Now(), Configuration));        ActionLog->AddFailure(E);        // unnecessary explicit release        ActionLog.reset(NULL);      }    }  }  catch (Exception & E)  {    // swallow  }  if (!DoNotDisplay)  {    TTerminalManager * Manager = TTerminalManager::Instance(false);    ESshTerminate * Terminate = dynamic_cast<ESshTerminate*>(E);    bool CloseOnCompletion = (Terminate != NULL);    bool ForActiveTerminal =      E->InheritsFrom(__classid(EFatal)) && (Terminal != NULL) &&      (Manager != NULL) && (Manager->ActiveTerminal == Terminal);    unsigned int Result;    if (CloseOnCompletion)    {      if (ForActiveTerminal)      {        DebugAssert(!Terminal->Active);        Manager->DisconnectActiveTerminal();      }      if (Terminate->Operation == odoSuspend)      {        // suspend, so that exit prompt is shown only after windows resume        SuspendWindows();      }      DebugAssert(Show);      bool ConfirmExitOnCompletion =        CloseOnCompletion &&        ((Terminate->Operation == odoDisconnect) || (Terminate->Operation == odoSuspend)) &&        WinConfiguration->ConfirmExitOnCompletion;      if (ConfirmExitOnCompletion)      {        TMessageParams Params(mpNeverAskAgainCheck);        unsigned int Answers = 0;        TQueryButtonAlias Aliases[1];        TOpenLocalPathHandler OpenLocalPathHandler;        if (!Terminate->TargetLocalPath.IsEmpty() && !ForActiveTerminal)        {          OpenLocalPathHandler.LocalPath = Terminate->TargetLocalPath;          OpenLocalPathHandler.LocalFileName = Terminate->DestLocalFileName;          Aliases[0].Button = qaIgnore;          Aliases[0].Alias = LoadStr(OPEN_BUTTON);          Aliases[0].OnSubmit = OpenLocalPathHandler.Open;          Aliases[0].MenuButton = true;          Answers |= Aliases[0].Button;          Params.Aliases = Aliases;          Params.AliasesCount = LENOF(Aliases);        }        if (ForActiveTerminal)        {          UnicodeString MessageFormat =            MainInstructions((Manager->Count > 1) ?              FMTLOAD(DISCONNECT_ON_COMPLETION, (Manager->Count - 1)) :              LoadStr(EXIT_ON_COMPLETION));          Result = FatalExceptionMessageDialog(E, qtInformation, 0,            MessageFormat,            Answers | qaYes | qaNo, HELP_NONE, &Params);        }        else        {          Result =            ExceptionMessageDialog(E, qtInformation, L"", Answers | qaOK, HELP_NONE, &Params);        }      }      else      {        Result = qaYes;      }    }    else    {      if (Show)      {        if (ForActiveTerminal)        {          int SessionReopenTimeout = 0;          if (DebugAlwaysTrue(Manager->ActiveTerminal != NULL) &&              ((Configuration->SessionReopenTimeout == 0) ||               ((double)Manager->ActiveTerminal->ReopenStart == 0) ||               (int(double(Now() - Manager->ActiveTerminal->ReopenStart) * MSecsPerDay) < Configuration->SessionReopenTimeout)))          {            SessionReopenTimeout = GUIConfiguration->SessionReopenAutoIdle;          }          Result = FatalExceptionMessageDialog(E, qtError, SessionReopenTimeout);        }        else        {          Result = ExceptionMessageDialog(E, qtError);        }      }      else      {        Result = qaOK;      }    }    if (Result == qaNeverAskAgain)    {      DebugAssert(CloseOnCompletion);      Result = qaYes;      WinConfiguration->ConfirmExitOnCompletion = false;    }    if (Result == qaYes)    {      DebugAssert(CloseOnCompletion);      DebugAssert(Terminate != NULL);      DebugAssert(Terminate->Operation != odoIdle);      TerminateApplication();      switch (Terminate->Operation)      {        case odoDisconnect:          break;        case odoSuspend:          // suspended before already          break;        case odoShutDown:          ShutDownWindows();          break;        default:          DebugFail();      }    }    else if (Result == qaRetry)    {      // qaRetry is used by FatalExceptionMessageDialog      if (DebugAlwaysTrue(ForActiveTerminal))      {        Manager->ReconnectActiveTerminal();      }    }    else    {      if (ForActiveTerminal)      {        Manager->DisconnectActiveTerminal();      }    }  }}//---------------------------------------------------------------------------void __fastcall ShowNotification(TTerminal * Terminal, const UnicodeString & Str,  TQueryType Type){  TTerminalManager * Manager = TTerminalManager::Instance(false);  DebugAssert(Manager != NULL);  Manager->ScpExplorer->PopupTrayBalloon(Terminal, Str, Type);}//---------------------------------------------------------------------------void __fastcall ConfigureInterface(){  int BidiModeFlag =    AdjustLocaleFlag(LoadStr(BIDI_MODE), WinConfiguration->BidiModeOverride, false, bdRightToLeft, bdLeftToRight);  Application->BiDiMode = static_cast<TBiDiMode>(BidiModeFlag);  SetTBXSysParam(TSP_XPVISUALSTYLE, XPVS_AUTOMATIC);  if (WinConfiguration != NULL)  {    UnicodeString Theme = WinConfiguration->UseDarkTheme() ? L"DarkOfficeXP" : L"OfficeXP";    if (!SameText(TBXCurrentTheme(), Theme))    {      TBXSetTheme(Theme);    }  }  // Has any effect on Wine only  // (otherwise initial UserDocumentDirectory is equivalent to GetPersonalFolder())  UserDocumentDirectory = GetPersonalFolder();}//---------------------------------------------------------------------------void __fastcall DoAboutDialog(TConfiguration *Configuration){  DoAboutDialog(Configuration, true, NULL);}//---------------------------------------------------------------------void __fastcall DoProductLicense(){  DoLicenseDialog(lcWinScp);}//---------------------------------------------------------------------------const UnicodeString PixelsPerInchKey = L"PixelsPerInch";//---------------------------------------------------------------------int __fastcall GetToolbarLayoutPixelsPerInch(TStrings * Storage, TControl * Control){  int Result;  if (Storage->IndexOfName(PixelsPerInchKey))  {    Result = LoadPixelsPerInch(Storage->Values[PixelsPerInchKey], Control);  }  else  {    Result = -1;  }  return Result;}//---------------------------------------------------------------------UnicodeString __fastcall GetToolbarKey(const UnicodeString & ToolbarName){  UnicodeString Result = ToolbarName;  Result = RemoveSuffix(Result, L"Toolbar");  return Result;}//---------------------------------------------------------------------static inline void __fastcall GetToolbarKey(const UnicodeString & ToolbarName,  const UnicodeString & Value, UnicodeString & ToolbarKey){  ToolbarKey = GetToolbarKey(ToolbarName);  if (!Value.IsEmpty())  {    ToolbarKey += L"_" + Value;  }}//---------------------------------------------------------------------------static int __fastcall ToolbarReadInt(const UnicodeString ToolbarName,  const UnicodeString Value, const int Default, const void * ExtraData){  int Result;  if (Value == L"Rev")  {    Result = 2000;  }  else  {    TStrings * Storage = static_cast<TStrings *>(const_cast<void*>(ExtraData));    UnicodeString ToolbarKey;    GetToolbarKey(ToolbarName, Value, ToolbarKey);    if (Storage->IndexOfName(ToolbarKey) >= 0)    {      Result = StrToIntDef(Storage->Values[ToolbarKey], Default);      #if 0      // this does not work well, as it scales down the stretched      // toolbars (path toolbars) too much, it has to be reimplemented smarter      if (Value == L"DockPos")      {        int PixelsPerInch = GetToolbarLayoutPixelsPerInch(Storage);        // When DPI has decreased since the last time, scale down        // toolbar position to get rid of gaps caused by smaller labels.        // Do not do this when DPI has increased as it would introduce gaps,        // as toolbars consists mostly of icons only, that do not scale.        // The toolbars shift themselves anyway, when other toolbars to the left        // get wider. We also risk a bit that toolbar order changes,        // as with very small toolbars (History) we can get scaled down position        // of the following toolbar to the left of it.        // There's special handling (also for scaling-up) stretched toolbars        // in LoadToolbarsLayoutStr        if ((PixelsPerInch > 0) && (Screen->PixelsPerInch < PixelsPerInch))        {          Result = LoadDimension(Result, PixelsPerInch);        }      }      #endif    }    else    {      Result = Default;    }  }  return Result;}//---------------------------------------------------------------------------static UnicodeString __fastcall ToolbarReadString(const UnicodeString ToolbarName,  const UnicodeString Value, const UnicodeString Default, const void * ExtraData){  UnicodeString Result;  TStrings * Storage = static_cast<TStrings *>(const_cast<void*>(ExtraData));  UnicodeString ToolbarKey;  GetToolbarKey(ToolbarName, Value, ToolbarKey);  if (Storage->IndexOfName(ToolbarKey) >= 0)  {    Result = Storage->Values[ToolbarKey];  }  else  {    Result = Default;  }  return Result;}//---------------------------------------------------------------------------static void __fastcall ToolbarWriteInt(const UnicodeString ToolbarName,  const UnicodeString Value, const int Data, const void * ExtraData){  DebugFail();  if (Value != L"Rev")  {    TStrings * Storage = static_cast<TStrings *>(const_cast<void*>(ExtraData));    UnicodeString ToolbarKey;    GetToolbarKey(ToolbarName, Value, ToolbarKey);    DebugAssert(Storage->IndexOfName(ToolbarKey) < 0);    Storage->Values[ToolbarKey] = IntToStr(Data);  }}//---------------------------------------------------------------------------static void __fastcall ToolbarWriteString(const UnicodeString ToolbarName,  const UnicodeString Value, const UnicodeString Data, const void * ExtraData){  DebugAssert(Value.IsEmpty());  TStrings * Storage = static_cast<TStrings *>(const_cast<void*>(ExtraData));  UnicodeString ToolbarKey;  GetToolbarKey(ToolbarName, Value, ToolbarKey);  DebugAssert(Storage->IndexOfName(ToolbarKey) < 0);  Storage->Values[ToolbarKey] = Data;}//---------------------------------------------------------------------------UnicodeString __fastcall GetToolbarsLayoutStr(TControl * OwnerControl){  UnicodeString Result;  TStrings * Storage = new TStringList();  try  {    TBCustomSavePositions(OwnerControl, ToolbarWriteInt, ToolbarWriteString,      Storage);    Storage->Values[PixelsPerInchKey] = SavePixelsPerInch(OwnerControl);    Result = Storage->CommaText;  }  __finally  {    delete Storage;  }  return Result;}//---------------------------------------------------------------------------void __fastcall LoadToolbarsLayoutStr(TControl * OwnerControl, UnicodeString LayoutStr){  TStrings * Storage = new TStringList();  try  {    Storage->CommaText = LayoutStr;    TBCustomLoadPositions(OwnerControl, ToolbarReadInt, ToolbarReadString,      Storage);    int PixelsPerInch = GetToolbarLayoutPixelsPerInch(Storage, OwnerControl);    // Scale toolbars stretched to the first other toolbar to the right    if ((PixelsPerInch > 0) && (PixelsPerInch != GetControlPixelsPerInch(OwnerControl))) // optimization    {      for (int Index = 0; Index < OwnerControl->ComponentCount; Index++)      {        TTBXToolbar * Toolbar =          dynamic_cast<TTBXToolbar *>(OwnerControl->Components[Index]);        if ((Toolbar != NULL) && Toolbar->Stretch &&            (Toolbar->OnGetBaseSize != NULL) &&            // we do not support floating of stretched toolbars            DebugAlwaysTrue(!Toolbar->Floating))        {          TTBXToolbar * FollowingToolbar = NULL;          for (int Index2 = 0; Index2 < OwnerControl->ComponentCount; Index2++)          {            TTBXToolbar * Toolbar2 =              dynamic_cast<TTBXToolbar *>(OwnerControl->Components[Index2]);            if ((Toolbar2 != NULL) && !Toolbar2->Floating &&                (Toolbar2->Parent == Toolbar->Parent) &&                (Toolbar2->DockRow == Toolbar->DockRow) &&                (Toolbar2->DockPos > Toolbar->DockPos) &&                ((FollowingToolbar == NULL) || (FollowingToolbar->DockPos > Toolbar2->DockPos)))            {              FollowingToolbar = Toolbar2;            }          }          if (FollowingToolbar != NULL)          {            int NewWidth = LoadDimension(Toolbar->Width, PixelsPerInch, Toolbar);            FollowingToolbar->DockPos += NewWidth - Toolbar->Width;          }        }      }    }  }  __finally  {    delete Storage;  }}//---------------------------------------------------------------------------TTBXSeparatorItem * __fastcall AddMenuSeparator(TTBCustomItem * Menu){  TTBXSeparatorItem * Item = new TTBXSeparatorItem(Menu);  Menu->Add(Item);  return Item;}//---------------------------------------------------------------------------static TComponent * LastPopupComponent = NULL;static TRect LastPopupRect(-1, -1, -1, -1);static TDateTime LastCloseUp;//---------------------------------------------------------------------------static void __fastcall ConvertMenu(TMenuItem * AItems, TTBCustomItem * Items){  for (int Index = 0; Index < AItems->Count; Index++)  {    TMenuItem * AItem = AItems->Items[Index];    TTBCustomItem * Item;    if (!AItem->Enabled && !AItem->Visible && (AItem->Action == NULL) &&        (AItem->OnClick == NULL) && DebugAlwaysTrue(AItem->Count == 0))    {      TTBXLabelItem * LabelItem = new TTBXLabelItem(Items->Owner);      // TTBXLabelItem has it's own Caption      LabelItem->Caption = AItem->Caption;      LabelItem->SectionHeader = true;      Item = LabelItem;    }    else    {      // see TB2DsgnConverter.pas DoConvert      if (AItem->Caption == L"-")      {        Item = new TTBXSeparatorItem(Items->Owner);      }      else      {        if (AItem->Count > 0)        {          Item = new TTBXSubmenuItem(Items->Owner);        }        else        {          Item = new TTBXItem(Items->Owner);        }        Item->Action = AItem->Action;        Item->AutoCheck = AItem->AutoCheck;        Item->Caption = AItem->Caption;        Item->Checked = AItem->Checked;        if (AItem->Default)        {          Item->Options = Item->Options << tboDefault;        }        Item->Enabled = AItem->Enabled;        Item->GroupIndex = AItem->GroupIndex;        Item->HelpContext = AItem->HelpContext;        Item->ImageIndex = AItem->ImageIndex;        Item->RadioItem = AItem->RadioItem;        Item->ShortCut = AItem->ShortCut;        Item->SubMenuImages = AItem->SubMenuImages;        Item->OnClick = AItem->OnClick;      }      Item->Hint = AItem->Hint;      Item->Tag = AItem->Tag;      Item->Visible = AItem->Visible;      // recurse is supported only for empty submenus (as used for custom commands)      if (AItem->Count > 0)      {        ConvertMenu(AItem, Item);      }    }    Items->Add(Item);  }}//---------------------------------------------------------------------------void __fastcall MenuPopup(TPopupMenu * AMenu, TRect Rect,  TComponent * PopupComponent){  // Pressing the same button within 200ms after closing its popup menu  // does nothing.  // It is to immitate close-by-click behavior. Note that menu closes itself  // before onclick handler of button occurs.  // To support content menu popups, we have to check for the popup location too,  // to allow poping menu on different location (such as different node of TTreeView),  // even if there's another popup opened already (so that the time interval  // below does not elapse).  TDateTime N = Now();  TDateTime Diff = N - LastCloseUp;  if ((PopupComponent == LastPopupComponent) &&      (Rect == LastPopupRect) &&      (Diff < TDateTime(0, 0, 0, 200)))  {    LastPopupComponent = NULL;  }  else  {    TTBXPopupMenu * Menu = dynamic_cast<TTBXPopupMenu *>(AMenu);    if (Menu == NULL)    {      Menu = CreateTBXPopupMenu(AMenu->Owner);      Menu->OnPopup = AMenu->OnPopup;      Menu->Items->SubMenuImages = AMenu->Images;      ConvertMenu(AMenu->Items, Menu->Items);    }    Menu->PopupComponent = PopupComponent;    Menu->PopupEx(Rect);    LastPopupComponent = PopupComponent;    LastPopupRect = Rect;    LastCloseUp = Now();  }}//---------------------------------------------------------------------------const int ColorCols = 8;const int StandardColorRows = 2;const int StandardColorCount = ColorCols * StandardColorRows;const int UserColorRows = 1;const int UserColorCount = UserColorRows * ColorCols;const wchar_t ColorSeparator = L',';//---------------------------------------------------------------------------static void __fastcall GetStandardSessionColorInfo(  int Col, int Row, TColor & Color, UnicodeString & Name){  #define COLOR_INFO(COL, ROW, NAME, COLOR) \    if ((Col == COL) && (Row == ROW)) { Name = NAME; Color = TColor(COLOR); } else  // bottom row of default TBX color set  COLOR_INFO(0, 0, L"Rose",              0xCC99FF)  COLOR_INFO(1, 0, L"Tan",               0x99CCFF)  COLOR_INFO(2, 0, L"Light Yellow",      0x99FFFF)  COLOR_INFO(3, 0, L"Light Green",       0xCCFFCC)  COLOR_INFO(4, 0, L"Light Turquoise",   0xFFFFCC)  COLOR_INFO(5, 0, L"Pale Blue",         0xFFCC99)  COLOR_INFO(6, 0, L"Lavender",          0xFF99CC)  // second row of Excel 2010 palette with second color (Lighter Black) skipped  COLOR_INFO(7, 0, L"Light Orange",      0xB5D5FB)  COLOR_INFO(0, 1, L"Darker White",      0xD8D8D8)  COLOR_INFO(1, 1, L"Darker Tan",        0x97BDC4)  COLOR_INFO(2, 1, L"Lighter Blue",      0xE2B38D)  COLOR_INFO(3, 1, L"Light Blue",        0xE4CCB8)  COLOR_INFO(4, 1, L"Lighter Red",       0xB7B9E5)  COLOR_INFO(5, 1, L"Light Olive Green", 0xBCE3D7)  COLOR_INFO(6, 1, L"Light Purple",      0xD9C1CC)  COLOR_INFO(7, 1, L"Light Aqua",        0xE8DDB7)  DebugFail();  #undef COLOR_INFO}//---------------------------------------------------------------------------static void __fastcall SessionColorSetGetColorInfo(  void * /*Data*/, TTBXCustomColorSet * /*Sender*/, int Col, int Row, TColor & Color, UnicodeString & Name){  GetStandardSessionColorInfo(Col, Row, Color, Name);}//---------------------------------------------------------------------------TColor __fastcall RestoreColor(const UnicodeString & CStr){  return TColor(StrToInt(UnicodeString(L"$") + CStr));}//---------------------------------------------------------------------------UnicodeString __fastcall StoreColor(TColor Color){  return IntToHex(Color, 6);}//---------------------------------------------------------------------------static UnicodeString __fastcall ExtractColorStr(UnicodeString & Colors){  return CutToChar(Colors, ColorSeparator, true);}//---------------------------------------------------------------------------static bool __fastcall IsStandardColor(bool SessionColors, TColor Color){  if (SessionColors)  {    for (int Row = 0; Row < StandardColorRows; Row++)    {      for (int Col = 0; Col < ColorCols; Col++)      {        TColor StandardColor;        UnicodeString Name; // unused        GetStandardSessionColorInfo(Col, Row, StandardColor, Name);        if (StandardColor == Color)        {          return true;        }      }    }    return false;  }  else  {    std::unique_ptr<TTBXColorPalette> DefaultColorPalette(new TTBXColorPalette(NULL));    return (DefaultColorPalette->FindCell(Color).X >= 0);  }}//---------------------------------------------------------------------------class TColorChangeData : public TComponent{public:  __fastcall TColorChangeData(TColorChangeEvent OnColorChange, TColor Color, bool SessionColors);  static TColorChangeData * __fastcall Retrieve(TObject * Object);  void __fastcall ColorChange(TColor Color);  __property TColor Color = { read = FColor };  __property bool SessionColors = { read = FSessionColors };private:  TColorChangeEvent FOnColorChange;  TColor FColor;  bool FSessionColors;};//---------------------------------------------------------------------------__fastcall TColorChangeData::TColorChangeData(    TColorChangeEvent OnColorChange, TColor Color, bool SessionColors) :  TComponent(NULL){  Name = QualifiedClassName();  FOnColorChange = OnColorChange;  FColor = Color;  FSessionColors = SessionColors;}//---------------------------------------------------------------------------TColorChangeData * __fastcall TColorChangeData::Retrieve(TObject * Object){  TComponent * Component = DebugNotNull(dynamic_cast<TComponent *>(Object));  TComponent * ColorChangeDataComponent = Component->FindComponent(QualifiedClassName());  return DebugNotNull(dynamic_cast<TColorChangeData *>(ColorChangeDataComponent));}//---------------------------------------------------------------------------static void SaveCustomColors(bool SessionColors, const UnicodeString & Colors){  if (SessionColors)  {    CustomWinConfiguration->SessionColors = Colors;  }  else  {    CustomWinConfiguration->FontColors = Colors;  }}//---------------------------------------------------------------------------static UnicodeString LoadCustomColors(bool SessionColors){  return SessionColors ? CustomWinConfiguration->SessionColors : CustomWinConfiguration->FontColors;}//---------------------------------------------------------------------------void __fastcall TColorChangeData::ColorChange(TColor Color){  // Color palette returns clNone when no color is selected,  // though it should not really happen.  // See also CreateColorPalette  if (Color == Vcl::Graphics::clNone)  {    Color = TColor(0);  }  if ((Color != TColor(0)) &&      !IsStandardColor(SessionColors, Color))  {    UnicodeString Colors = StoreColor(Color);    UnicodeString Temp = LoadCustomColors(SessionColors);    while (!Temp.IsEmpty())    {      UnicodeString CStr = ExtractColorStr(Temp);      if (RestoreColor(CStr) != Color)      {        Colors += UnicodeString(ColorSeparator) + CStr;      }    }    SaveCustomColors(SessionColors, Colors);  }  FOnColorChange(Color);}//---------------------------------------------------------------------------static void __fastcall ColorDefaultClick(void * /*Data*/, TObject * Sender){  TColorChangeData::Retrieve(Sender)->ColorChange(TColor(0));}//---------------------------------------------------------------------------static void __fastcall ColorPaletteChange(void * /*Data*/, TObject * Sender){  TTBXColorPalette * ColorPalette = DebugNotNull(dynamic_cast<TTBXColorPalette *>(Sender));  TColorChangeData::Retrieve(Sender)->ColorChange(GetNonZeroColor(ColorPalette->Color));}//---------------------------------------------------------------------------static UnicodeString __fastcall CustomColorName(int Index){  return UnicodeString(L"Color") + wchar_t(L'A' + Index);}//---------------------------------------------------------------------------static void __fastcall ColorPickClick(void * /*Data*/, TObject * Sender){  TColorChangeData * ColorChangeData = TColorChangeData::Retrieve(Sender);  std::unique_ptr<TColorDialog> Dialog(new TColorDialog(Application));  Dialog->Options = Dialog->Options << cdFullOpen << cdAnyColor;  Dialog->Color = (ColorChangeData->Color != 0 ? ColorChangeData->Color : clSkyBlue);  UnicodeString Temp = LoadCustomColors(ColorChangeData->SessionColors);  int StandardColorIndex = 0;  for (int Index = 0; Index < MaxCustomColors; Index++)  {    TColor CustomColor;    if (!Temp.IsEmpty())    {      CustomColor = RestoreColor(ExtractColorStr(Temp));    }    else    {      if (ColorChangeData->SessionColors)      {        if (StandardColorIndex < StandardColorCount)        {          UnicodeString Name; // not used          GetStandardSessionColorInfo(            StandardColorIndex % ColorCols, StandardColorIndex / ColorCols,            CustomColor, Name);          StandardColorIndex++;        }        else        {          break;        }      }      else      {        // no standard font colors        break;      }    }    Dialog->CustomColors->Values[CustomColorName(Index)] = StoreColor(CustomColor);  }  if (Dialog->Execute())  {    // so that we do not have to try to preserve the excess colors    DebugAssert(UserColorCount <= MaxCustomColors);    UnicodeString Colors;    for (int Index = 0; Index < MaxCustomColors; Index++)    {      UnicodeString CStr = Dialog->CustomColors->Values[CustomColorName(Index)];      if (!CStr.IsEmpty())      {        TColor CustomColor = RestoreColor(CStr);        if ((CustomColor != static_cast<TColor>(-1)) &&            !IsStandardColor(ColorChangeData->SessionColors, CustomColor))        {          AddToList(Colors, StoreColor(CustomColor), ColorSeparator);        }      }    }    SaveCustomColors(ColorChangeData->SessionColors, Colors);    // call color change only after copying custom colors back,    // so that it can add selected color to the user list    ColorChangeData->ColorChange(GetNonZeroColor(Dialog->Color));  }}//---------------------------------------------------------------------------TPopupMenu * __fastcall CreateSessionColorPopupMenu(TColor Color,  TColorChangeEvent OnColorChange){  std::unique_ptr<TTBXPopupMenu> PopupMenu(new TTBXPopupMenu(Application));  CreateSessionColorMenu(PopupMenu->Items, Color, OnColorChange);  return PopupMenu.release();}//---------------------------------------------------------------------------static void __fastcall UserCustomColorSetGetColorInfo(  void * /*Data*/, TTBXCustomColorSet * Sender, int Col, int Row, TColor & Color, UnicodeString & /*Name*/){  int Index = (Row * Sender->ColCount) + Col;  bool SessionColors = static_cast<bool>(Sender->Tag);  UnicodeString Temp = LoadCustomColors(SessionColors);  while ((Index > 0) && !Temp.IsEmpty())  {    ExtractColorStr(Temp);    Index--;  }  if (!Temp.IsEmpty())  {    Color = RestoreColor(ExtractColorStr(Temp));  }  else  {    // hide the trailing cells    Color = Vcl::Graphics::clNone;  }}//---------------------------------------------------------------------------void __fastcall CreateColorPalette(TTBCustomItem * Owner, TColor Color, int Rows,  TCSGetColorInfo OnGetColorInfo, TColorChangeEvent OnColorChange, bool SessionColors){  TTBXColorPalette * ColorPalette = new TTBXColorPalette(Owner);  if (OnGetColorInfo != NULL)  {    TTBXCustomColorSet * ColorSet = new TTBXCustomColorSet(Owner);    ColorPalette->InsertComponent(ColorSet);    ColorPalette->ColorSet = ColorSet;    // has to be set only after it's assigned to color palette    ColorSet->ColCount = ColorCols;    ColorSet->RowCount = Rows;    ColorSet->OnGetColorInfo = OnGetColorInfo;    ColorSet->Tag = static_cast<int>(SessionColors);  }  // clNone = no selection, see also ColorChange  ColorPalette->Color = (Color != 0) ? Color : Vcl::Graphics::clNone;  ColorPalette->OnChange = MakeMethod<TNotifyEvent>(NULL, ColorPaletteChange);  ColorPalette->InsertComponent(new TColorChangeData(OnColorChange, Color, SessionColors));  Owner->Add(ColorPalette);  Owner->Add(new TTBXSeparatorItem(Owner));}//---------------------------------------------------------------------------static void __fastcall CreateColorMenu(TComponent * AOwner, TColor Color,  TColorChangeEvent OnColorChange, bool SessionColors,  const UnicodeString & DefaultColorCaption, const UnicodeString & DefaultColorHint,  const UnicodeString & HelpKeyword,  const UnicodeString & ColorPickHint){  TTBCustomItem * Owner = dynamic_cast<TTBCustomItem *>(AOwner);  if (DebugAlwaysTrue(Owner != NULL))  {    Owner->Clear();    TTBCustomItem * Item;    Item = new TTBXItem(Owner);    Item->Caption = DefaultColorCaption;    Item->Hint = DefaultColorHint;    Item->HelpKeyword = HelpKeyword;    Item->OnClick = MakeMethod<TNotifyEvent>(NULL, ColorDefaultClick);    Item->Checked = (Color == TColor(0));    Item->InsertComponent(new TColorChangeData(OnColorChange, Color, SessionColors));    Owner->Add(Item);    Owner->Add(new TTBXSeparatorItem(Owner));    int CustomColorCount = 0;    UnicodeString Temp = LoadCustomColors(SessionColors);    while (!Temp.IsEmpty())    {      CustomColorCount++;      ExtractColorStr(Temp);    }    if (CustomColorCount > 0)    {      CustomColorCount = Min(CustomColorCount, UserColorCount);      int RowCount = ((CustomColorCount + ColorCols - 1) / ColorCols);      DebugAssert(RowCount <= UserColorRows);      CreateColorPalette(Owner, Color, RowCount,        MakeMethod<TCSGetColorInfo>(NULL, UserCustomColorSetGetColorInfo),        OnColorChange, SessionColors);    }    if (SessionColors)    {      CreateColorPalette(Owner, Color, StandardColorRows,        MakeMethod<TCSGetColorInfo>(NULL, SessionColorSetGetColorInfo),        OnColorChange, SessionColors);    }    else    {      CreateColorPalette(Owner, Color, -1, NULL, OnColorChange, SessionColors);    }    Owner->Add(new TTBXSeparatorItem(Owner));    Item = new TTBXItem(Owner);    Item->Caption = LoadStr(COLOR_PICK_CAPTION);    Item->Hint = ColorPickHint;    Item->HelpKeyword = HelpKeyword;    Item->OnClick = MakeMethod<TNotifyEvent>(NULL, ColorPickClick);    Item->InsertComponent(new TColorChangeData(OnColorChange, Color, SessionColors));    Owner->Add(Item);  }}//---------------------------------------------------------------------------void __fastcall CreateSessionColorMenu(TComponent * AOwner, TColor Color,  TColorChangeEvent OnColorChange){  CreateColorMenu(    AOwner, Color, OnColorChange, true,    LoadStr(COLOR_TRUE_DEFAULT_CAPTION), LoadStr(EDITOR_BACKGROUND_COLOR_HINT),    HELP_COLOR, LoadStr(COLOR_PICK_HINT));}//---------------------------------------------------------------------------void __fastcall CreateEditorBackgroundColorMenu(TComponent * AOwner, TColor Color,  TColorChangeEvent OnColorChange){  CreateColorMenu(    AOwner, Color, OnColorChange, true,    LoadStr(COLOR_TRUE_DEFAULT_CAPTION), LoadStr(EDITOR_BACKGROUND_COLOR_HINT),    HELP_COLOR, LoadStr(EDITOR_BACKGROUND_COLOR_PICK_HINT));}//---------------------------------------------------------------------------TPopupMenu * __fastcall CreateColorPopupMenu(TColor Color,  TColorChangeEvent OnColorChange){  std::unique_ptr<TTBXPopupMenu> PopupMenu(new TTBXPopupMenu(Application));  CreateColorMenu(    PopupMenu->Items, Color, OnColorChange, false,    LoadStr(COLOR_TRUE_DEFAULT_CAPTION), UnicodeString(),    HELP_NONE, UnicodeString());  return PopupMenu.release();}//---------------------------------------------------------------------------void __fastcall UpgradeSpeedButton(TSpeedButton * /*Button*/){  // no-op yet}//---------------------------------------------------------------------------struct TThreadParam{  TThreadFunc ThreadFunc;  void * Parameter;};//---------------------------------------------------------------------------static int __fastcall ThreadProc(void * AParam){  TThreadParam * Param = reinterpret_cast<TThreadParam *>(AParam);  unsigned int Result = Param->ThreadFunc(Param->Parameter);  delete Param;  EndThread(Result);  return Result;}//---------------------------------------------------------------------------int __fastcall StartThread(void * SecurityAttributes, unsigned StackSize,  TThreadFunc ThreadFunc, void * Parameter, unsigned CreationFlags,  TThreadID & ThreadId){  TThreadParam * Param = new TThreadParam;  Param->ThreadFunc = ThreadFunc;  Param->Parameter = Parameter;  return BeginThread(SecurityAttributes, StackSize, ThreadProc, Param,    CreationFlags, ThreadId);}//---------------------------------------------------------------------------static TShortCut FirstCtrlNumberShortCut = ShortCut(L'0', TShiftState() << ssCtrl);static TShortCut LastCtrlNumberShortCut = ShortCut(L'9', TShiftState() << ssCtrl);static TShortCut FirstCtrlKeyPadShortCut = ShortCut(VK_NUMPAD0, TShiftState() << ssCtrl);static TShortCut LastCtrlKeyPadShortCut = ShortCut(VK_NUMPAD9, TShiftState() << ssCtrl);static TShortCut FirstShiftCtrlAltLetterShortCut = ShortCut(L'A', TShiftState() << ssShift << ssCtrl << ssAlt);static TShortCut LastShiftCtrlAltLetterShortCut = ShortCut(L'Z', TShiftState() << ssShift << ssCtrl << ssAlt);//---------------------------------------------------------------------------void __fastcall InitializeShortCutCombo(TComboBox * ComboBox,  const TShortCuts & ShortCuts){  ComboBox->Items->BeginUpdate();  try  {    ComboBox->Items->Clear();    ComboBox->Items->AddObject(LoadStr(SHORTCUT_NONE), reinterpret_cast<TObject* >(0));    for (TShortCut AShortCut = FirstCtrlNumberShortCut; AShortCut <= LastCtrlNumberShortCut; AShortCut++)    {      if (!ShortCuts.Has(AShortCut))      {        ComboBox->Items->AddObject(ShortCutToText(AShortCut), reinterpret_cast<TObject* >(AShortCut));      }    }    for (TShortCut AShortCut = FirstShiftCtrlAltLetterShortCut; AShortCut <= LastShiftCtrlAltLetterShortCut; AShortCut++)    {      if (!ShortCuts.Has(AShortCut))      {        ComboBox->Items->AddObject(ShortCutToText(AShortCut), reinterpret_cast<TObject* >(AShortCut));      }    }  }  __finally  {    ComboBox->Items->EndUpdate();  }  ComboBox->Style = csDropDownList;  ComboBox->DropDownCount = Max(ComboBox->DropDownCount, 16);}//---------------------------------------------------------------------------void __fastcall SetShortCutCombo(TComboBox * ComboBox, TShortCut Value){  for (int Index = ComboBox->Items->Count - 1; Index >= 0; Index--)  {    TShortCut AShortCut = TShortCut(ComboBox->Items->Objects[Index]);    if (AShortCut == Value)    {      ComboBox->ItemIndex = Index;      break;    }    else if (AShortCut < Value)    {      DebugAssert(Value != 0);      ComboBox->Items->InsertObject(Index + 1, ShortCutToText(Value),        reinterpret_cast<TObject* >(Value));      ComboBox->ItemIndex = Index + 1;      break;    }    DebugAssert(Index > 0);  }}//---------------------------------------------------------------------------TShortCut __fastcall GetShortCutCombo(TComboBox * ComboBox){  return TShortCut(ComboBox->Items->Objects[ComboBox->ItemIndex]);}//---------------------------------------------------------------------------TShortCut __fastcall NormalizeCustomShortCut(TShortCut ShortCut){  if ((FirstCtrlKeyPadShortCut <= ShortCut) && (ShortCut <= LastCtrlKeyPadShortCut))  {    ShortCut = FirstCtrlNumberShortCut + (ShortCut - FirstCtrlKeyPadShortCut);  }  return ShortCut;}//---------------------------------------------------------------------------bool __fastcall IsCustomShortCut(TShortCut ShortCut){  return    ((FirstCtrlNumberShortCut <= ShortCut) && (ShortCut <= LastCtrlNumberShortCut)) ||    ((FirstShiftCtrlAltLetterShortCut <= ShortCut) && (ShortCut <= LastShiftCtrlAltLetterShortCut));}//---------------------------------------------------------------------------//---------------------------------------------------------------------------class TMasterPasswordDialog : public TCustomDialog{public:  __fastcall TMasterPasswordDialog(bool Current);  bool __fastcall Execute(UnicodeString & CurrentPassword, UnicodeString & NewPassword);protected:  virtual void __fastcall DoValidate();  virtual void __fastcall DoChange(bool & CanSubmit);private:  TPasswordEdit * CurrentEdit;  TPasswordEdit * NewEdit;  TPasswordEdit * ConfirmEdit;};//---------------------------------------------------------------------------__fastcall TMasterPasswordDialog::TMasterPasswordDialog(bool Current) :  TCustomDialog(Current ? HELP_MASTER_PASSWORD_CURRENT : HELP_MASTER_PASSWORD_CHANGE){  Caption = LoadStr(MASTER_PASSWORD_CAPTION);  CurrentEdit = new TPasswordEdit(this);  AddEdit(CurrentEdit, CreateLabel(LoadStr(MASTER_PASSWORD_CURRENT)));  EnableControl(CurrentEdit, Current || WinConfiguration->UseMasterPassword);  CurrentEdit->MaxLength = PasswordMaxLength();  if (!Current)  {    NewEdit = new TPasswordEdit(this);    AddEdit(NewEdit, CreateLabel(LoadStr(MASTER_PASSWORD_NEW)));    NewEdit->MaxLength = CurrentEdit->MaxLength;    if (!WinConfiguration->UseMasterPassword)    {      ActiveControl = NewEdit;    }    ConfirmEdit = new TPasswordEdit(this);    AddEdit(ConfirmEdit, CreateLabel(LoadStr(MASTER_PASSWORD_CONFIRM)));    ConfirmEdit->MaxLength = CurrentEdit->MaxLength;  }  else  {    NewEdit = NULL;    ConfirmEdit = NULL;  }}//---------------------------------------------------------------------------bool __fastcall TMasterPasswordDialog::Execute(  UnicodeString & CurrentPassword, UnicodeString & NewPassword){  bool Result = TCustomDialog::Execute();  if (Result)  {    if (CurrentEdit->Enabled)    {      CurrentPassword = CurrentEdit->Text;    }    if (NewEdit != NULL)    {      NewPassword = NewEdit->Text;    }  }  return Result;}//---------------------------------------------------------------------------void __fastcall TMasterPasswordDialog::DoChange(bool & CanSubmit){  CanSubmit =    (!WinConfiguration->UseMasterPassword || (IsValidPassword(CurrentEdit->Text) >= 0)) &&    ((NewEdit == NULL) || (IsValidPassword(NewEdit->Text) >= 0)) &&    ((ConfirmEdit == NULL) || (IsValidPassword(ConfirmEdit->Text) >= 0));  TCustomDialog::DoChange(CanSubmit);}//---------------------------------------------------------------------------void __fastcall TMasterPasswordDialog::DoValidate(){  TCustomDialog::DoValidate();  if (WinConfiguration->UseMasterPassword &&      !WinConfiguration->ValidateMasterPassword(CurrentEdit->Text))  {    CurrentEdit->SetFocus();    CurrentEdit->SelectAll();    throw Exception(MainInstructions(LoadStr(MASTER_PASSWORD_INCORRECT)));  }  if (NewEdit != NULL)  {    if (NewEdit->Text != ConfirmEdit->Text)    {      ConfirmEdit->SetFocus();      ConfirmEdit->SelectAll();      throw Exception(MainInstructions(LoadStr(MASTER_PASSWORD_DIFFERENT)));    }    int Valid = IsValidPassword(NewEdit->Text);    if (Valid <= 0)    {      DebugAssert(Valid == 0);      if (MessageDialog(LoadStr(MASTER_PASSWORD_SIMPLE2), qtWarning,            qaOK | qaCancel, HELP_MASTER_PASSWORD_SIMPLE) == qaCancel)      {        NewEdit->SetFocus();        NewEdit->SelectAll();        Abort();      }    }  }}//---------------------------------------------------------------------------static bool __fastcall DoMasterPasswordDialog(bool Current,  UnicodeString & NewPassword){  bool Result;  TMasterPasswordDialog * Dialog = new TMasterPasswordDialog(Current);  try  {    UnicodeString CurrentPassword;    Result = Dialog->Execute(CurrentPassword, NewPassword);    if (Result)    {      if ((Current || WinConfiguration->UseMasterPassword) &&          DebugAlwaysTrue(!CurrentPassword.IsEmpty()))      {        WinConfiguration->SetMasterPassword(CurrentPassword);      }    }  }  __finally  {    delete Dialog;  }  return Result;}//---------------------------------------------------------------------------bool __fastcall DoMasterPasswordDialog(){  UnicodeString NewPassword;  bool Result = DoMasterPasswordDialog(true, NewPassword);  DebugAssert(NewPassword.IsEmpty());  return Result;}//---------------------------------------------------------------------------bool __fastcall DoChangeMasterPasswordDialog(UnicodeString & NewPassword){  bool Result = DoMasterPasswordDialog(false, NewPassword);  return Result;}//---------------------------------------------------------------------------void __fastcall MessageWithNoHelp(const UnicodeString & Message){  TMessageParams Params;  Params.AllowHelp = false; // to avoid recursion  if (MessageDialog(LoadStr(HELP_SEND_MESSAGE2), qtConfirmation,        qaOK | qaCancel, HELP_NONE, &Params) == qaOK)  {    SearchHelp(Message);  }}//---------------------------------------------------------------------------void __fastcall CheckLogParam(TProgramParams * Params){  UnicodeString LogFile;  if (Params->FindSwitch(LOG_SWITCH, LogFile) && CheckSafe(Params))  {    Configuration->Usage->Inc(L"ScriptLog");    Configuration->TemporaryLogging(LogFile);  }}//---------------------------------------------------------------------------bool __fastcall CheckXmlLogParam(TProgramParams * Params){  UnicodeString LogFile;  bool Result =    Params->FindSwitch(L"XmlLog", LogFile) &&    CheckSafe(Params);  if (Result)  {    Configuration->Usage->Inc(L"ScriptXmlLog");    Configuration->TemporaryActionsLogging(LogFile);    if (Params->FindSwitch(L"XmlLogRequired"))    {      Configuration->LogActionsRequired = true;    }  }  return Result;}//---------------------------------------------------------------------------bool __fastcall CheckSafe(TProgramParams * Params){  // Originally we warned when the test didn't pass,  // but it would actually be helping hackers, so let's be silent.  // Earlier we tested presence of any URL on command-line.  // That was added to prevent abusing URL handler in 3.8.2 (2006).  // Later in 4.0.4 (2007) an /Unsafe switch was added to URL handler registration.  // So by now, we can check for the switch only and  // do not limit user from combining URL with say  // /rawconfig  return !Params->FindSwitch(UNSAFE_SWITCH);}
 |