GenerateUrl.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include "VCLCommon.h"
  5. #include "GenerateUrl.h"
  6. #include "CoreMain.h"
  7. #include "WinConfiguration.h"
  8. #include <StrUtils.hpp>
  9. #include <Tools.h>
  10. #include <PuttyTools.h>
  11. #include <TextsWin.h>
  12. //---------------------------------------------------------------------------
  13. #pragma package(smart_init)
  14. #ifndef NO_RESOURCES
  15. #pragma resource "*.dfm"
  16. #endif
  17. //---------------------------------------------------------------------------
  18. void __fastcall DoGenerateUrlDialog(TSessionData * Data, TStrings * Paths)
  19. {
  20. std::unique_ptr<TGenerateUrlDialog> Dialog(new TGenerateUrlDialog(GetFormOwner(), Data, Paths));
  21. Dialog->Execute();
  22. }
  23. //---------------------------------------------------------------------------
  24. __fastcall TGenerateUrlDialog::TGenerateUrlDialog(
  25. TComponent * Owner, TSessionData * Data, TStrings * Paths)
  26. : TForm(Owner)
  27. {
  28. UseSystemSettings(this);
  29. FData = Data;
  30. FPaths = Paths;
  31. FChanging = false;
  32. ReadOnlyControl(ResultMemo);
  33. }
  34. //---------------------------------------------------------------------------
  35. bool __fastcall TGenerateUrlDialog::IsFileUrl()
  36. {
  37. return (FPaths != NULL);
  38. }
  39. //---------------------------------------------------------------------------
  40. UnicodeString __fastcall TGenerateUrlDialog::GenerateUrl(UnicodeString Path)
  41. {
  42. UnicodeString Url =
  43. FData->GenerateSessionUrl(
  44. FLAGMASK(WinSCPSpecificCheck->Checked, sufSpecific) |
  45. FLAGMASK(UserNameCheck->Enabled && UserNameCheck->Checked, sufUserName) |
  46. FLAGMASK(PasswordCheck->Enabled && PasswordCheck->Checked, sufPassword) |
  47. FLAGMASK(HostKeyCheck->Enabled && HostKeyCheck->Checked, sufHostKey));
  48. if ((RemoteDirectoryCheck->Enabled && RemoteDirectoryCheck->Checked) ||
  49. IsFileUrl())
  50. {
  51. if (StartsStr(L"/", Path));
  52. {
  53. Path.Delete(1, 1);
  54. }
  55. Url += EncodeUrlPath(Path);
  56. }
  57. if (SaveExtensionCheck->Enabled && SaveExtensionCheck->Checked)
  58. {
  59. Url += UnicodeString(UrlParamSeparator) + UrlSaveParamName;
  60. }
  61. return Url;
  62. }
  63. //---------------------------------------------------------------------------
  64. static UnicodeString __fastcall RtfColorEntry(int Color)
  65. {
  66. return FORMAT(L"\\red%d\\green%d\\blue%d;", ((Color & 0xFF0000) >> 16, (Color & 0x00FF00) >> 8, (Color & 0x0000FF) >> 0));
  67. }
  68. //---------------------------------------------------------------------
  69. static UnicodeString __fastcall RtfScriptComment(const UnicodeString & Text)
  70. {
  71. return RtfColorItalicText(6, Text);
  72. }
  73. //---------------------------------------------------------------------------
  74. void __fastcall TGenerateUrlDialog::UpdateControls()
  75. {
  76. if (!FChanging)
  77. {
  78. UnicodeString ExeName = Application->ExeName;
  79. Caption = LoadStr(IsFileUrl() ? GENERATE_URL_FILE_TITLE : GENERATE_URL_SESSION_TITLE);
  80. ScriptSheet->TabVisible = !IsFileUrl();
  81. AssemblySheet->TabVisible = !IsFileUrl();
  82. bool HostKeyUnknown = FData->UsesSsh && FData->HostKey.IsEmpty();
  83. UnicodeString ResultGroupCaption;
  84. if (OptionsPageControl->ActivePage == UrlSheet)
  85. {
  86. ResultGroupCaption = LoadStr(GENERATE_URL_URL);
  87. }
  88. else if (OptionsPageControl->ActivePage == ScriptSheet)
  89. {
  90. UnicodeString ScriptDescription;
  91. if (ScriptFormatCombo->ItemIndex == sfCommandLine)
  92. {
  93. ResultGroupCaption = LoadStr(GENERATE_URL_COMMANDLINE_LABEL);
  94. ScriptDescription = FMTLOAD(GENERATE_URL_COMMANDLINE_DESC, (FORMAT("\"%s\"", (ExeName)))) + L"\n";
  95. }
  96. else
  97. {
  98. ResultGroupCaption = ScriptFormatCombo->Items->Strings[ScriptFormatCombo->ItemIndex];
  99. }
  100. if (HostKeyUnknown)
  101. {
  102. ScriptDescription += LoadStr(GENERATE_URL_HOSTKEY_UNKNOWN) + L"\n";
  103. }
  104. ScriptDescriptionLabel->Caption = ScriptDescription;
  105. }
  106. else if (DebugAlwaysTrue(OptionsPageControl->ActivePage == AssemblySheet))
  107. {
  108. ResultGroupCaption = LoadStr(GENERATE_URL_CODE);
  109. UnicodeString AssemblyDescription;
  110. if (HostKeyUnknown)
  111. {
  112. AssemblyDescription += LoadStr(GENERATE_URL_HOSTKEY_UNKNOWN) + L"\n";
  113. }
  114. AssemblyDescriptionLabel->Caption = AssemblyDescription;
  115. }
  116. ResultGroup->Caption = ResultGroupCaption;
  117. EnableControl(UserNameCheck, !FData->UserNameExpanded.IsEmpty());
  118. bool UserNameIncluded = UserNameCheck->Enabled && UserNameCheck->Checked;
  119. EnableControl(PasswordCheck, UserNameIncluded && FData->HasPassword());
  120. EnableControl(HostKeyCheck, UserNameIncluded && !FData->HostKey.IsEmpty());
  121. EnableControl(RemoteDirectoryCheck, !FData->RemoteDirectory.IsEmpty() && !IsFileUrl());
  122. EnableControl(SaveExtensionCheck, !IsFileUrl());
  123. UnicodeString Result;
  124. bool WordWrap = false;
  125. bool FixedWidth = false;
  126. FPlainResult = L"";
  127. if (OptionsPageControl->ActivePage == UrlSheet)
  128. {
  129. if (!IsFileUrl())
  130. {
  131. UnicodeString Path = FData->RemoteDirectory;
  132. if (!Path.IsEmpty() && !EndsStr(L"/", Path))
  133. {
  134. Path += L"/";
  135. }
  136. FPlainResult = GenerateUrl(Path);
  137. Result = RtfText(FPlainResult);
  138. }
  139. else
  140. {
  141. for (int Index = 0; Index < FPaths->Count; Index++)
  142. {
  143. UnicodeString Url = GenerateUrl(FPaths->Strings[Index]);
  144. Result += RtfText(Url) + RtfPara;
  145. FPlainResult +=
  146. Url +
  147. // What CopyToClipboard would have done could we pass in ResultMemo->Lines
  148. ((FPaths->Count > 0) ? L"\n" : L"");
  149. }
  150. }
  151. WordWrap = true;
  152. }
  153. else if (OptionsPageControl->ActivePage == ScriptSheet)
  154. {
  155. UnicodeString BaseExeName = ExtractFileBaseName(ExeName);
  156. UnicodeString OpenCommand = FData->GenerateOpenCommandArgs();
  157. UnicodeString CommandPlaceholder1 = FMTLOAD(GENERATE_URL_COMMAND, (1));
  158. UnicodeString CommandPlaceholder2 = FMTLOAD(GENERATE_URL_COMMAND, (2));
  159. if (ScriptFormatCombo->ItemIndex == sfScriptFile)
  160. {
  161. Result =
  162. FORMAT(
  163. RtfKeyword(L"open") + L" %s" + RtfPara +
  164. RtfPara +
  165. RtfScriptComment("# %s") + RtfPara +
  166. RtfScriptComment("# %s") + RtfPara +
  167. RtfPara +
  168. RtfKeyword(L"exit") + RtfPara,
  169. (OpenCommand, CommandPlaceholder1, CommandPlaceholder2));
  170. WordWrap = false;
  171. FixedWidth = true;
  172. }
  173. else if (ScriptFormatCombo->ItemIndex == sfBatchFile)
  174. {
  175. UnicodeString ComExeName = ChangeFileExt(ExeName, L".com");
  176. Result =
  177. RtfScriptComment(L"@echo off") + RtfPara +
  178. RtfPara +
  179. RtfText(L"\"" + ComExeName + "\" ") + RtfParameter(L"/log") + RtfText(L"=" + BaseExeName + L".log ") + RtfParameter(L"/ini") + RtfText(L"=nul ") + RtfParameter(L"/command") + RtfText(L" ^") + RtfPara +
  180. RtfText(L" \"") + RtfKeyword(L"open") + RtfText(L" ") + EscapeParam(ReplaceStr(OpenCommand, L"%", L"%%")) + RtfText(L"\" ^") + RtfPara +
  181. RtfText(L" \"") + RtfScriptComment(CommandPlaceholder1) + RtfText(L"\" ^") + RtfPara +
  182. RtfText(L" \"") + RtfScriptComment(CommandPlaceholder2) + RtfText(L"\" ^") + RtfPara +
  183. RtfText(L" \"") + RtfKeyword(L"exit") + RtfText(L"\"") + RtfPara +
  184. RtfPara +
  185. RtfKeyword(L"set") + RtfText(L" WINSCP_RESULT=%ERRORLEVEL%") + RtfPara +
  186. RtfKeyword(L"if") + RtfText(L" %WINSCP_RESULT% ") + RtfKeyword(L"equ") + RtfText(L" 0 (") + RtfPara +
  187. RtfText(L" ") + RtfKeyword(L"echo") + RtfText(L" Success") + RtfPara +
  188. RtfText(L") ") + RtfKeyword(L"else") + RtfText(L" (") + RtfPara +
  189. RtfText(L" ") + RtfKeyword(L"echo") + RtfText(L" Error") + RtfPara +
  190. RtfText(L")") + RtfPara +
  191. RtfPara +
  192. RtfKeyword(L"exit") + RtfText(L" /b %WINSCP_RESULT%") + RtfPara;
  193. WordWrap = false;
  194. FixedWidth = true;
  195. }
  196. else if (ScriptFormatCombo->ItemIndex == sfCommandLine)
  197. {
  198. Result =
  199. RtfParameter(L"/log") + RtfText(L"=" + BaseExeName + L".log ") +
  200. RtfParameter(L"/ini") + RtfText(L"=nul ") +
  201. RtfParameter(L"/command") + RtfText(L" ") +
  202. RtfText(L"\"") + RtfKeyword(L"open") + RtfText(L" ") + EscapeParam(OpenCommand) + RtfText(L"\" ") +
  203. RtfText(L"\"") + RtfScriptComment(CommandPlaceholder1) + RtfText(L"\" ") +
  204. RtfText(L"\"") + RtfScriptComment(CommandPlaceholder2) + RtfText(L"\" ") +
  205. RtfText(L"\"") + RtfKeyword(L"exit") + RtfText(L"\"");
  206. WordWrap = true;
  207. FixedWidth = false;
  208. }
  209. }
  210. else if (DebugAlwaysTrue(OptionsPageControl->ActivePage == AssemblySheet))
  211. {
  212. Result = FData->GenerateAssemblyCode(static_cast<TAssemblyLanguage>(AssemblyLanguageCombo->ItemIndex));
  213. WordWrap = false;
  214. FixedWidth = true;
  215. }
  216. if (FixedWidth)
  217. {
  218. ResultMemo->Font->Name = CustomWinConfiguration->DefaultFixedWidthFontName;
  219. ResultMemo->DefAttributes->Color = clWindowText;
  220. }
  221. else
  222. {
  223. ResultMemo->ParentFont = true;
  224. }
  225. Result =
  226. L"{\\rtf1\n"
  227. "{\\colortbl ;" +
  228. // The same RGB as on wiki
  229. RtfColorEntry(0x008000) + // cde comment (green)
  230. RtfColorEntry(0x008080) + // class (teal)
  231. RtfColorEntry(0x800000) + // string (maroon)
  232. RtfColorEntry(0x0000FF) + // keyword (blue)
  233. RtfColorEntry(0x993333) + // command-line argument (reddish)
  234. RtfColorEntry(0x808080) + // script command (gray)
  235. L"}\n"
  236. "{\\fonttbl{\\f0\\fnil\\fcharset0 " + ResultMemo->Font->Name + L";}}\n"
  237. "\\f0\\fs" + IntToStr(ResultMemo->Font->Size * 2) + L" " +
  238. Result +
  239. L"}";
  240. ResultMemo->WordWrap = WordWrap;
  241. ResultMemo->ScrollBars = WordWrap ? ssVertical : ssBoth;
  242. std::unique_ptr<TMemoryStream> Stream(new TMemoryStream());
  243. UTF8String ResultUtf = Result;
  244. Stream->Write(ResultUtf.c_str(), ResultUtf.Length());
  245. Stream->Position = 0;
  246. Stream->SaveToFile(L"b:\\rtf\\code.rtf");
  247. Stream->Position = 0;
  248. ResultMemo->Lines->LoadFromStream(Stream.get(), TEncoding::UTF8);
  249. }
  250. }
  251. //---------------------------------------------------------------------------
  252. void __fastcall TGenerateUrlDialog::Execute()
  253. {
  254. int Components = WinConfiguration->GenerateUrlComponents;
  255. if (Components < 0)
  256. {
  257. Components = UserNameCheck->Tag | RemoteDirectoryCheck->Tag;
  258. }
  259. TGenerateUrlCodeTarget Target = WinConfiguration->GenerateUrlCodeTarget;
  260. {
  261. TAutoFlag ChangingFlag(FChanging);
  262. if (IsFileUrl())
  263. {
  264. OptionsPageControl->ActivePage = UrlSheet;
  265. }
  266. else
  267. {
  268. switch (Target)
  269. {
  270. case guctUrl:
  271. OptionsPageControl->ActivePage = UrlSheet;
  272. break;
  273. case guctScript:
  274. OptionsPageControl->ActivePage = ScriptSheet;
  275. break;
  276. case guctAssembly:
  277. OptionsPageControl->ActivePage = AssemblySheet;
  278. break;
  279. default:
  280. DebugFail();
  281. }
  282. }
  283. for (int Index = 0; Index < UrlSheet->ControlCount; Index++)
  284. {
  285. TCheckBox * CheckBox = dynamic_cast<TCheckBox *>(UrlSheet->Controls[Index]);
  286. if (DebugAlwaysTrue((CheckBox != NULL) && (CheckBox->Tag != 0)))
  287. {
  288. CheckBox->Checked = FLAGSET(Components, CheckBox->Tag);
  289. }
  290. }
  291. ScriptFormatCombo->ItemIndex = WinConfiguration->GenerateUrlScriptFormat;
  292. AssemblyLanguageCombo->ItemIndex = WinConfiguration->GenerateUrlAssemblyLanguage;
  293. }
  294. UpdateControls();
  295. ShowModal();
  296. // Do not save the selection for files as the "URL" was selected implicitly
  297. if (!IsFileUrl())
  298. {
  299. if (OptionsPageControl->ActivePage == UrlSheet)
  300. {
  301. Target = guctUrl;
  302. }
  303. else if (OptionsPageControl->ActivePage == ScriptSheet)
  304. {
  305. Target = guctScript;
  306. }
  307. else if (OptionsPageControl->ActivePage == AssemblySheet)
  308. {
  309. Target = guctAssembly;
  310. }
  311. else
  312. {
  313. DebugFail();
  314. }
  315. WinConfiguration->GenerateUrlCodeTarget = Target;
  316. }
  317. if (Target == guctUrl)
  318. {
  319. Components = 0;
  320. for (int Index = 0; Index < UrlSheet->ControlCount; Index++)
  321. {
  322. TCheckBox * CheckBox = dynamic_cast<TCheckBox *>(UrlSheet->Controls[Index]);
  323. if (DebugAlwaysTrue((CheckBox != NULL) && (CheckBox->Tag != 0)) &&
  324. CheckBox->Checked)
  325. {
  326. Components |= CheckBox->Tag;
  327. }
  328. }
  329. WinConfiguration->GenerateUrlComponents = Components;
  330. }
  331. else if (Target == guctScript)
  332. {
  333. WinConfiguration->GenerateUrlScriptFormat = static_cast<TScriptFormat>(ScriptFormatCombo->ItemIndex);
  334. }
  335. else if (Target == guctAssembly)
  336. {
  337. WinConfiguration->GenerateUrlAssemblyLanguage = static_cast<TAssemblyLanguage>(AssemblyLanguageCombo->ItemIndex);
  338. }
  339. }
  340. //---------------------------------------------------------------------------
  341. void __fastcall TGenerateUrlDialog::ControlChange(TObject * /*Sender*/)
  342. {
  343. UpdateControls();
  344. }
  345. //---------------------------------------------------------------------------
  346. void __fastcall TGenerateUrlDialog::ClipboardButtonClick(TObject * /*Sender*/)
  347. {
  348. TInstantOperationVisualizer Visualizer;
  349. if (ResultMemo->WordWrap)
  350. {
  351. // Cannot read the text from ResultMemo->Lines as TRichEdit (as opposite to TMemo)
  352. // breaks wrapped lines
  353. if (!FPlainResult.IsEmpty())
  354. {
  355. CopyToClipboard(FPlainResult);
  356. }
  357. else
  358. {
  359. // We get here with command-line only,
  360. // where we know to have a single line only
  361. DebugAssert((OptionsPageControl->ActivePage == ScriptSheet) && (ScriptFormatCombo->ItemIndex == sfCommandLine));
  362. UnicodeString Text;
  363. for (int Index = 0; Index < ResultMemo->Lines->Count; Index++)
  364. {
  365. Text += ResultMemo->Lines->Strings[Index];
  366. }
  367. CopyToClipboard(Text);
  368. }
  369. }
  370. else
  371. {
  372. // On the other hand, the FResult contains RTF markup
  373. // in which case we want to use ResultMemo->Lines
  374. CopyToClipboard(ResultMemo->Lines);
  375. }
  376. }
  377. //---------------------------------------------------------------------------
  378. void __fastcall TGenerateUrlDialog::HelpButtonClick(TObject * /*Sender*/)
  379. {
  380. FormHelp(this);
  381. }
  382. //---------------------------------------------------------------------------
  383. void __fastcall TGenerateUrlDialog::WMNCCreate(TWMNCCreate & Message)
  384. {
  385. // bypass TForm::WMNCCreate to prevent disabling "resize"
  386. // (which is done for bsDialog, see comments in CreateParams)
  387. DefaultHandler(&Message);
  388. }
  389. //---------------------------------------------------------------------------
  390. void __fastcall TGenerateUrlDialog::Dispatch(void * AMessage)
  391. {
  392. TMessage & Message = *reinterpret_cast<TMessage *>(AMessage);
  393. if (Message.Msg == WM_NCCREATE)
  394. {
  395. WMNCCreate(*reinterpret_cast<TWMNCCreate *>(AMessage));
  396. }
  397. else
  398. {
  399. TForm::Dispatch(AMessage);
  400. }
  401. }
  402. //---------------------------------------------------------------------------
  403. void __fastcall TGenerateUrlDialog::CreateParams(TCreateParams & Params)
  404. {
  405. TForm::CreateParams(Params);
  406. // Allow resizing of the window, even if this is bsDialog.
  407. // This makes it more close to bsSizeable, but bsSizeable cannot for some
  408. // reason receive focus, if window is shown atop non-main window
  409. // (like editor)
  410. Params.Style = Params.Style | WS_THICKFRAME;
  411. }
  412. //---------------------------------------------------------------------------
  413. void __fastcall TGenerateUrlDialog::ResultMemoContextPopup(TObject * Sender,
  414. TPoint & MousePos, bool & Handled)
  415. {
  416. MenuPopup(Sender, MousePos, Handled);
  417. }
  418. //---------------------------------------------------------------------------