|
|
1.1 ! root 1: /* ! 2: Copyright (c) 2008 TrueCrypt Foundation. All rights reserved. ! 3: ! 4: Governed by the TrueCrypt License 2.4 the full text of which is contained ! 5: in the file License.txt included in TrueCrypt binary and source code ! 6: distribution packages. ! 7: */ ! 8: ! 9: #include "System.h" ! 10: #include <set> ! 11: #include <typeinfo> ! 12: #include <wx/apptrait.h> ! 13: #include <wx/cmdline.h> ! 14: #include "Platform/PlatformTest.h" ! 15: #ifdef TC_UNIX ! 16: #include "Platform/Unix/Process.h" ! 17: #endif ! 18: #include "Volume/EncryptionTest.h" ! 19: #include "Application.h" ! 20: #include "FavoriteVolume.h" ! 21: #include "UserInterface.h" ! 22: ! 23: namespace TrueCrypt ! 24: { ! 25: UserInterface::UserInterface () ! 26: { ! 27: } ! 28: ! 29: UserInterface::~UserInterface () ! 30: { ! 31: Core->WarningEvent.Disconnect (this); ! 32: Core->VolumeMountedEvent.Disconnect (this); ! 33: } ! 34: ! 35: void UserInterface::CloseExplorerWindows (shared_ptr <VolumeInfo> mountedVolume) const ! 36: { ! 37: #ifdef TC_WINDOWS ! 38: struct Args ! 39: { ! 40: HWND ExplorerWindow; ! 41: string DriveRootPath; ! 42: }; ! 43: ! 44: struct Enumerator ! 45: { ! 46: static BOOL CALLBACK ChildWindows (HWND hwnd, LPARAM argsLP) ! 47: { ! 48: Args *args = reinterpret_cast <Args *> (argsLP); ! 49: ! 50: char s[4096]; ! 51: SendMessageA (hwnd, WM_GETTEXT, sizeof (s), (LPARAM) s); ! 52: ! 53: if (strstr (s, args->DriveRootPath.c_str()) != NULL) ! 54: { ! 55: PostMessage (args->ExplorerWindow, WM_CLOSE, 0, 0); ! 56: return FALSE; ! 57: } ! 58: ! 59: return TRUE; ! 60: } ! 61: ! 62: static BOOL CALLBACK TopLevelWindows (HWND hwnd, LPARAM argsLP) ! 63: { ! 64: Args *args = reinterpret_cast <Args *> (argsLP); ! 65: ! 66: char s[4096]; ! 67: GetClassNameA (hwnd, s, sizeof s); ! 68: if (strcmp (s, "CabinetWClass") == 0) ! 69: { ! 70: GetWindowTextA (hwnd, s, sizeof s); ! 71: if (strstr (s, args->DriveRootPath.c_str()) != NULL) ! 72: { ! 73: PostMessage (hwnd, WM_CLOSE, 0, 0); ! 74: return TRUE; ! 75: } ! 76: ! 77: args->ExplorerWindow = hwnd; ! 78: EnumChildWindows (hwnd, ChildWindows, argsLP); ! 79: } ! 80: ! 81: return TRUE; ! 82: } ! 83: }; ! 84: ! 85: Args args; ! 86: ! 87: string mountPoint = mountedVolume->MountPoint; ! 88: if (mountPoint.size() < 2 || mountPoint[1] != ':') ! 89: return; ! 90: ! 91: args.DriveRootPath = string() + mountPoint[0] + string (":\\"); ! 92: ! 93: EnumWindows (Enumerator::TopLevelWindows, (LPARAM) &args); ! 94: #endif ! 95: } ! 96: ! 97: void UserInterface::DismountAllVolumes (bool ignoreOpenFiles, bool interactive) const ! 98: { ! 99: try ! 100: { ! 101: VolumeInfoList mountedVolumes = Core->GetMountedVolumes(); ! 102: ! 103: if (mountedVolumes.size() < 1) ! 104: ShowInfo (LangString["NO_VOLUMES_MOUNTED"]); ! 105: ! 106: BusyScope busy (this); ! 107: DismountVolumes (mountedVolumes, ignoreOpenFiles, interactive); ! 108: } ! 109: catch (exception &e) ! 110: { ! 111: ShowError (e); ! 112: } ! 113: } ! 114: ! 115: void UserInterface::DismountVolume (shared_ptr <VolumeInfo> volume, bool ignoreOpenFiles, bool interactive) const ! 116: { ! 117: VolumeInfoList volumes; ! 118: volumes.push_back (volume); ! 119: ! 120: DismountVolumes (volumes, ignoreOpenFiles, interactive); ! 121: } ! 122: ! 123: void UserInterface::DismountVolumes (VolumeInfoList volumes, bool ignoreOpenFiles, bool interactive) const ! 124: { ! 125: BusyScope busy (this); ! 126: ! 127: wxString message; ! 128: bool twoPassMode = volumes.size() > 1; ! 129: bool volumesInUse = false; ! 130: bool firstPass = true; ! 131: ! 132: #ifdef TC_WINDOWS ! 133: if (Preferences.CloseExplorerWindowsOnDismount) ! 134: { ! 135: foreach (shared_ptr <VolumeInfo> volume, volumes) ! 136: CloseExplorerWindows (volume); ! 137: } ! 138: #endif ! 139: while (!volumes.empty()) ! 140: { ! 141: VolumeInfoList volumesLeft; ! 142: foreach (shared_ptr <VolumeInfo> volume, volumes) ! 143: { ! 144: try ! 145: { ! 146: BusyScope busy (this); ! 147: Core->DismountVolume (volume, ignoreOpenFiles); ! 148: } ! 149: catch (MountedVolumeInUse&) ! 150: { ! 151: if (!firstPass) ! 152: throw; ! 153: ! 154: if (twoPassMode || !interactive) ! 155: { ! 156: volumesInUse = true; ! 157: volumesLeft.push_back (volume); ! 158: continue; ! 159: } ! 160: else ! 161: { ! 162: if (AskYesNo (StringFormatter (LangString["UNMOUNT_LOCK_FAILED"], wstring (volume->Path)), true, true)) ! 163: { ! 164: BusyScope busy (this); ! 165: Core->DismountVolume (volume, true); ! 166: } ! 167: else ! 168: throw UserAbort (SRC_POS); ! 169: } ! 170: } ! 171: catch (...) ! 172: { ! 173: if (twoPassMode && firstPass) ! 174: volumesLeft.push_back (volume); ! 175: else ! 176: throw; ! 177: } ! 178: ! 179: if (volume->HiddenVolumeProtectionTriggered) ! 180: ShowWarning (StringFormatter (LangString["DAMAGE_TO_HIDDEN_VOLUME_PREVENTED"], wstring (volume->Path))); ! 181: ! 182: if (Preferences.Verbose) ! 183: { ! 184: if (!message.IsEmpty()) ! 185: message += L'\n'; ! 186: message += StringFormatter (_("Volume \"{0}\" has been dismounted."), wstring (volume->Path)); ! 187: } ! 188: } ! 189: ! 190: if (twoPassMode && firstPass) ! 191: { ! 192: volumes = volumesLeft; ! 193: ! 194: if (volumesInUse && interactive) ! 195: { ! 196: if (AskYesNo (LangString["UNMOUNTALL_LOCK_FAILED"], true, true)) ! 197: ignoreOpenFiles = true; ! 198: else ! 199: throw UserAbort (SRC_POS); ! 200: } ! 201: } ! 202: else ! 203: break; ! 204: ! 205: firstPass = false; ! 206: } ! 207: ! 208: if (Preferences.Verbose && !message.IsEmpty()) ! 209: ShowInfo (message); ! 210: } ! 211: ! 212: wxString UserInterface::ExceptionToMessage (const exception &ex) const ! 213: { ! 214: wxString message; ! 215: ! 216: const Exception *e = dynamic_cast <const Exception *> (&ex); ! 217: if (e) ! 218: { ! 219: message = ExceptionToString (*e); ! 220: ! 221: // System exception ! 222: const SystemException *sysEx = dynamic_cast <const SystemException *> (&ex); ! 223: if (sysEx) ! 224: { ! 225: if (!message.IsEmpty()) ! 226: { ! 227: message += L"\n\n"; ! 228: } ! 229: ! 230: message += wxString (sysEx->SystemText()).Trim (true); ! 231: } ! 232: ! 233: if (!message.IsEmpty()) ! 234: { ! 235: // Subject ! 236: if (!e->GetSubject().empty()) ! 237: { ! 238: message = message.Trim (true); ! 239: ! 240: if (message.EndsWith (L".")) ! 241: message.Truncate (message.size() - 1); ! 242: ! 243: if (!message.EndsWith (L":")) ! 244: message << L":\n"; ! 245: else ! 246: message << L"\n"; ! 247: ! 248: message << e->GetSubject(); ! 249: } ! 250: #ifdef DEBUG ! 251: if (sysEx && sysEx->what()) ! 252: message << L"\n\n" << StringConverter::ToWide (sysEx->what()); ! 253: #endif ! 254: return message; ! 255: } ! 256: } ! 257: ! 258: // bad_alloc ! 259: const bad_alloc *outOfMemory = dynamic_cast <const bad_alloc *> (&ex); ! 260: if (outOfMemory) ! 261: return _("Out of memory."); ! 262: ! 263: // Unresolved exceptions ! 264: string typeName (StringConverter::GetTypeName (typeid (ex))); ! 265: size_t pos = typeName.find ("TrueCrypt::"); ! 266: if (pos != string::npos) ! 267: { ! 268: return StringConverter::ToWide (typeName.substr (pos + string ("TrueCrypt::").size())) ! 269: + L" at " + StringConverter::ToWide (ex.what()); ! 270: } ! 271: ! 272: return StringConverter::ToWide (typeName) + L" at " + StringConverter::ToWide (ex.what()); ! 273: } ! 274: ! 275: wxString UserInterface::ExceptionToString (const Exception &ex) const ! 276: { ! 277: // Error messages ! 278: const ErrorMessage *errMsgEx = dynamic_cast <const ErrorMessage *> (&ex); ! 279: if (errMsgEx) ! 280: return wstring (*errMsgEx).c_str(); ! 281: ! 282: // ExecutedProcessFailed ! 283: const ExecutedProcessFailed *execEx = dynamic_cast <const ExecutedProcessFailed *> (&ex); ! 284: if (execEx) ! 285: { ! 286: wstring errOutput; ! 287: ! 288: // ElevationFailed ! 289: if (dynamic_cast <const ElevationFailed*> (&ex)) ! 290: errOutput += wxString (_("Failed to obtain administrator privileges")) + (StringConverter::Trim (execEx->GetErrorOutput()).empty() ? L". " : L": "); ! 291: ! 292: errOutput += StringConverter::ToWide (execEx->GetErrorOutput()); ! 293: ! 294: if (errOutput.empty()) ! 295: return errOutput + StringFormatter (_("Command \"{0}\" returned error {1}."), execEx->GetCommand(), execEx->GetExitCode()); ! 296: ! 297: return wxString (errOutput).Trim (true); ! 298: } ! 299: ! 300: // PasswordIncorrect ! 301: if (dynamic_cast <const PasswordIncorrect *> (&ex)) ! 302: { ! 303: wxString message = ExceptionTypeToString (typeid (ex)); ! 304: ! 305: if (wxGetKeyState (WXK_CAPITAL)) ! 306: message += wxString (L"\n\n") + LangString["CAPSLOCK_ON"]; ! 307: ! 308: return message; ! 309: } ! 310: ! 311: // Other library exceptions ! 312: return ExceptionTypeToString (typeid (ex)); ! 313: } ! 314: ! 315: wxString UserInterface::ExceptionTypeToString (const std::type_info &ex) const ! 316: { ! 317: #define EX2MSG(exception, message) do { if (ex == typeid (exception)) return (message); } while (false) ! 318: EX2MSG (DriveLetterUnavailable, LangString["DRIVE_LETTER_UNAVAILABLE"]); ! 319: EX2MSG (ExternalException, LangString["EXCEPTION_OCCURRED"]); ! 320: EX2MSG (InsufficientData, _("Not enough data available.")); ! 321: EX2MSG (HigherVersionRequired, LangString["NEW_VERSION_REQUIRED"]); ! 322: EX2MSG (MissingArgument, _("A required argument is missing.")); ! 323: EX2MSG (MissingVolumeData, _("Volume data missing.")); ! 324: EX2MSG (MountPointRequired, _("Mount point required.")); ! 325: EX2MSG (MountPointUnavailable, _("Mount point is already in use.")); ! 326: EX2MSG (NoDriveLetterAvailable, LangString["NO_FREE_DRIVES"]); ! 327: EX2MSG (NoLoopbackDeviceAvailable, _("No loopback device available.")); ! 328: EX2MSG (PasswordEmpty, _("No password or keyfile specified.")); ! 329: EX2MSG (PasswordIncorrect, LangString["PASSWORD_WRONG"]); ! 330: EX2MSG (PasswordKeyfilesIncorrect, LangString["PASSWORD_OR_KEYFILE_WRONG"]); ! 331: EX2MSG (PasswordTooLong, StringFormatter (_("Password is longer than {0} characters."), VolumePassword::MaxSize)); ! 332: EX2MSG (ProtectionPasswordIncorrect, _("Incorrect keyfile(s) and/or password to the protected hidden volume or the hidden volume does not exist.")); ! 333: EX2MSG (ProtectionPasswordKeyfilesIncorrect, _("Incorrect password to the protected hidden volume or the hidden volume does not exist.")); ! 334: EX2MSG (RootDeviceUnavailable, LangString["NODRIVER"]); ! 335: EX2MSG (StringConversionFailed, _("Invalid characters encountered.")); ! 336: EX2MSG (StringFormatterException, _("Error while parsing formatted string.")); ! 337: EX2MSG (UnportablePassword, LangString["UNSUPPORTED_CHARS_IN_PWD"]); ! 338: EX2MSG (UnsupportedSectorSize, LangString["LARGE_SECTOR_UNSUPPORTED"]); ! 339: EX2MSG (VolumeAlreadyMounted, LangString["VOL_ALREADY_MOUNTED"]); ! 340: EX2MSG (VolumeHostInUse, _("The host file/device is already in use.")); ! 341: EX2MSG (VolumeSlotUnavailable, _("Volume slot unavailable.")); ! 342: ! 343: #undef EX2MSG ! 344: return L""; ! 345: } ! 346: ! 347: void UserInterface::Init () ! 348: { ! 349: SetAppName (Application::GetName()); ! 350: SetClassName (Application::GetName()); ! 351: ! 352: LangString.Init(); ! 353: Core->Init(); ! 354: ! 355: wxCmdLineParser parser; ! 356: parser.SetCmdLine (argc, argv); ! 357: CmdLine.reset (new CommandLineInterface (parser, InterfaceType)); ! 358: SetPreferences (CmdLine->Preferences); ! 359: ! 360: Core->SetApplicationExecutablePath (Application::GetExecutablePath()); ! 361: ! 362: if (!Preferences.NonInteractive) ! 363: { ! 364: Core->SetAdminPasswordCallback (GetAdminPasswordRequestHandler()); ! 365: } ! 366: else ! 367: { ! 368: struct AdminPasswordRequestHandler : public GetStringFunctor ! 369: { ! 370: virtual string operator() () ! 371: { ! 372: throw ElevationFailed (SRC_POS, "sudo", 1, ""); ! 373: } ! 374: }; ! 375: ! 376: Core->SetAdminPasswordCallback (shared_ptr <GetStringFunctor> (new AdminPasswordRequestHandler)); ! 377: } ! 378: ! 379: Core->WarningEvent.Connect (EventConnector <UserInterface> (this, &UserInterface::OnWarning)); ! 380: Core->VolumeMountedEvent.Connect (EventConnector <UserInterface> (this, &UserInterface::OnVolumeMounted)); ! 381: } ! 382: ! 383: void UserInterface::ListMountedVolumes (const VolumeInfoList &volumes) const ! 384: { ! 385: if (volumes.size() < 1) ! 386: throw_err (LangString["NO_VOLUMES_MOUNTED"]); ! 387: ! 388: wxString message; ! 389: ! 390: foreach_ref (const VolumeInfo &volume, volumes) ! 391: { ! 392: message << volume.SlotNumber << L": " << StringConverter::QuoteSpaces (volume.Path); ! 393: ! 394: if (!volume.VirtualDevice.IsEmpty()) ! 395: message << L' ' << wstring (volume.VirtualDevice); ! 396: else ! 397: message << L" - "; ! 398: ! 399: if (!volume.MountPoint.IsEmpty()) ! 400: message << L' ' << StringConverter::QuoteSpaces (volume.MountPoint); ! 401: else ! 402: message << L" - "; ! 403: ! 404: if (Preferences.Verbose) ! 405: message << L' ' << SizeToString (volume.Size); ! 406: ! 407: message << L'\n'; ! 408: } ! 409: ! 410: ShowString (message); ! 411: } ! 412: ! 413: VolumeInfoList UserInterface::MountAllDeviceHostedVolumes (MountOptions &options) const ! 414: { ! 415: BusyScope busy (this); ! 416: ! 417: VolumeInfoList newMountedVolumes; ! 418: ! 419: if (!options.MountPoint) ! 420: options.MountPoint.reset (new DirectoryPath); ! 421: ! 422: Core->CoalesceSlotNumberAndMountPoint (options); ! 423: ! 424: bool sharedAccessAllowed = options.SharedAccessAllowed; ! 425: bool someVolumesShared = false; ! 426: ! 427: HostDeviceList devices; ! 428: foreach (shared_ptr <HostDevice> device, Core->GetHostDevices (true)) ! 429: { ! 430: devices.push_back (device); ! 431: ! 432: foreach (shared_ptr <HostDevice> partition, device->Partitions) ! 433: devices.push_back (partition); ! 434: } ! 435: ! 436: set <wstring> mountedVolumes; ! 437: foreach_ref (const VolumeInfo &v, Core->GetMountedVolumes()) ! 438: mountedVolumes.insert (v.Path); ! 439: ! 440: bool protectedVolumeMounted = false; ! 441: bool legacyVolumeMounted = false; ! 442: ! 443: foreach_ref (const HostDevice &device, devices) ! 444: { ! 445: if (mountedVolumes.find (wstring (device.Path)) != mountedVolumes.end()) ! 446: continue; ! 447: ! 448: Yield(); ! 449: options.SlotNumber = Core->GetFirstFreeSlotNumber (options.SlotNumber); ! 450: options.MountPoint.reset (new DirectoryPath); ! 451: options.Path.reset (new VolumePath (device.Path)); ! 452: ! 453: try ! 454: { ! 455: try ! 456: { ! 457: options.SharedAccessAllowed = sharedAccessAllowed; ! 458: newMountedVolumes.push_back (Core->MountVolume (options)); ! 459: } ! 460: catch (VolumeHostInUse&) ! 461: { ! 462: if (!sharedAccessAllowed) ! 463: { ! 464: try ! 465: { ! 466: options.SharedAccessAllowed = true; ! 467: newMountedVolumes.push_back (Core->MountVolume (options)); ! 468: someVolumesShared = true; ! 469: } ! 470: catch (VolumeHostInUse&) ! 471: { ! 472: continue; ! 473: } ! 474: } ! 475: else ! 476: continue; ! 477: } ! 478: ! 479: if (newMountedVolumes.back()->Protection == VolumeProtection::HiddenVolumeReadOnly) ! 480: protectedVolumeMounted = true; ! 481: ! 482: if (newMountedVolumes.back()->EncryptionAlgorithmMinBlockSize == 8) ! 483: legacyVolumeMounted = true; ! 484: } ! 485: catch (DriverError&) { } ! 486: catch (MissingVolumeData&) { } ! 487: catch (PasswordException&) { } ! 488: catch (SystemException&) { } ! 489: } ! 490: ! 491: if (newMountedVolumes.empty()) ! 492: { ! 493: ShowWarning (LangString [options.Keyfiles && !options.Keyfiles->empty() ? "PASSWORD_OR_KEYFILE_WRONG_AUTOMOUNT" : "PASSWORD_WRONG_AUTOMOUNT"]); ! 494: } ! 495: else ! 496: { ! 497: if (someVolumesShared) ! 498: ShowWarning ("DEVICE_IN_USE_INFO"); ! 499: ! 500: if (legacyVolumeMounted) ! 501: ShowWarning ("WARN_64_BIT_BLOCK_CIPHER"); ! 502: ! 503: if (protectedVolumeMounted) ! 504: ShowInfo (LangString[newMountedVolumes.size() > 1 ? "HIDVOL_PROT_WARN_AFTER_MOUNT_PLURAL" : "HIDVOL_PROT_WARN_AFTER_MOUNT"]); ! 505: } ! 506: ! 507: return newMountedVolumes; ! 508: } ! 509: ! 510: VolumeInfoList UserInterface::MountAllFavoriteVolumes (MountOptions &options) const ! 511: { ! 512: BusyScope busy (this); ! 513: ! 514: VolumeInfoList newMountedVolumes; ! 515: foreach_ref (const FavoriteVolume &favorite, FavoriteVolume::LoadList()) ! 516: { ! 517: shared_ptr <VolumeInfo> mountedVolume = Core->GetMountedVolume (favorite.Path); ! 518: if (mountedVolume) ! 519: { ! 520: if (mountedVolume->MountPoint != favorite.MountPoint) ! 521: ShowInfo (StringFormatter (LangString["VOLUME_ALREADY_MOUNTED"], wstring (favorite.Path))); ! 522: continue; ! 523: } ! 524: ! 525: favorite.ToMountOptions (options); ! 526: ! 527: if (Preferences.NonInteractive) ! 528: { ! 529: BusyScope busy (this); ! 530: newMountedVolumes.push_back (Core->MountVolume (options)); ! 531: } ! 532: else ! 533: { ! 534: try ! 535: { ! 536: BusyScope busy (this); ! 537: newMountedVolumes.push_back (Core->MountVolume (options)); ! 538: } ! 539: catch (...) ! 540: { ! 541: shared_ptr <VolumeInfo> volume = MountVolume (options); ! 542: if (!volume) ! 543: break; ! 544: newMountedVolumes.push_back (volume); ! 545: } ! 546: } ! 547: } ! 548: ! 549: return newMountedVolumes; ! 550: } ! 551: ! 552: shared_ptr <VolumeInfo> UserInterface::MountVolume (MountOptions &options) const ! 553: { ! 554: shared_ptr <VolumeInfo> volume; ! 555: ! 556: try ! 557: { ! 558: volume = Core->MountVolume (options); ! 559: } ! 560: catch (VolumeHostInUse&) ! 561: { ! 562: if (options.SharedAccessAllowed) ! 563: throw_err (LangString["FILE_IN_USE_FAILED"]); ! 564: ! 565: if (!AskYesNo (StringFormatter (LangString["VOLUME_HOST_IN_USE"], wstring (*options.Path)), false, true)) ! 566: throw UserAbort (SRC_POS); ! 567: ! 568: try ! 569: { ! 570: options.SharedAccessAllowed = true; ! 571: volume = Core->MountVolume (options); ! 572: } ! 573: catch (VolumeHostInUse&) ! 574: { ! 575: throw_err (LangString["FILE_IN_USE_FAILED"]); ! 576: } ! 577: } ! 578: ! 579: if (volume->EncryptionAlgorithmMinBlockSize == 8) ! 580: ShowWarning ("WARN_64_BIT_BLOCK_CIPHER"); ! 581: ! 582: if (VolumeHasUnrecommendedExtension (*options.Path)) ! 583: ShowWarning ("EXE_FILE_EXTENSION_MOUNT_WARNING"); ! 584: ! 585: if (options.Protection == VolumeProtection::HiddenVolumeReadOnly) ! 586: ShowInfo ("HIDVOL_PROT_WARN_AFTER_MOUNT"); ! 587: ! 588: return volume; ! 589: } ! 590: ! 591: void UserInterface::OnUnhandledException () ! 592: { ! 593: try ! 594: { ! 595: throw; ! 596: } ! 597: catch (UserAbort&) ! 598: { ! 599: } ! 600: catch (exception &e) ! 601: { ! 602: ShowError (e); ! 603: } ! 604: catch (...) ! 605: { ! 606: ShowError (_("Unknown exception occurred.")); ! 607: } ! 608: ! 609: Yield(); ! 610: Application::SetExitCode (1); ! 611: } ! 612: ! 613: void UserInterface::OnVolumeMounted (EventArgs &args) ! 614: { ! 615: shared_ptr <VolumeInfo> mountedVolume = (dynamic_cast <VolumeEventArgs &> (args)).mVolume; ! 616: ! 617: if (Preferences.OpenExplorerWindowAfterMount && !mountedVolume->MountPoint.IsEmpty()) ! 618: OpenExplorerWindow (mountedVolume->MountPoint); ! 619: } ! 620: ! 621: void UserInterface::OnWarning (EventArgs &args) ! 622: { ! 623: ExceptionEventArgs &e = dynamic_cast <ExceptionEventArgs &> (args); ! 624: ShowWarning (e.mException); ! 625: } ! 626: ! 627: void UserInterface::OpenExplorerWindow (const DirectoryPath &path) ! 628: { ! 629: if (path.IsEmpty()) ! 630: return; ! 631: ! 632: list <string> args; ! 633: ! 634: #ifdef TC_WINDOWS ! 635: ! 636: wstring p (Directory::AppendSeparator (path)); ! 637: SHFILEINFO fInfo; ! 638: SHGetFileInfo (p.c_str(), 0, &fInfo, sizeof (fInfo), 0); // Force explorer to discover the drive ! 639: ShellExecute (GetTopWindow() ? static_cast <HWND> (GetTopWindow()->GetHandle()) : nullptr, L"open", p.c_str(), nullptr, nullptr, SW_SHOWNORMAL); ! 640: ! 641: #elif defined (TC_MACOSX) ! 642: ! 643: args.push_back (string (path)); ! 644: Process::Execute ("open", args); ! 645: ! 646: #else ! 647: // MIME handler for directory seems to be unavailable through wxWidgets ! 648: if (GetTraits()->GetDesktopEnvironment() == L"GNOME") ! 649: { ! 650: args.push_back ("--no-default-window"); ! 651: args.push_back ("--no-desktop"); ! 652: args.push_back (string (path)); ! 653: try ! 654: { ! 655: Process::Execute ("nautilus", args, 2000); ! 656: } ! 657: catch (TimeOut&) { } ! 658: } ! 659: else if (GetTraits()->GetDesktopEnvironment() == L"KDE") ! 660: { ! 661: args.push_back ("openURL"); ! 662: args.push_back (string (path)); ! 663: try ! 664: { ! 665: Process::Execute ("kfmclient", args, 2000); ! 666: } ! 667: catch (TimeOut&) { } ! 668: } ! 669: #endif ! 670: } ! 671: ! 672: bool UserInterface::ProcessCommandLine () ! 673: { ! 674: CommandLineInterface &cmdLine = *CmdLine; ! 675: ! 676: switch (cmdLine.ArgCommand) ! 677: { ! 678: case CommandId::None: ! 679: return false; ! 680: ! 681: case CommandId::AutoMountDevices: ! 682: case CommandId::AutoMountFavorites: ! 683: case CommandId::AutoMountDevicesFavorites: ! 684: case CommandId::MountVolume: ! 685: { ! 686: cmdLine.ArgMountOptions.Path = cmdLine.ArgVolumePath; ! 687: cmdLine.ArgMountOptions.MountPoint = cmdLine.ArgMountPoint; ! 688: cmdLine.ArgMountOptions.Password = cmdLine.ArgPassword; ! 689: cmdLine.ArgMountOptions.Keyfiles = cmdLine.ArgKeyfiles; ! 690: cmdLine.ArgMountOptions.SharedAccessAllowed = cmdLine.ArgForce; ! 691: ! 692: VolumeInfoList mountedVolumes; ! 693: switch (cmdLine.ArgCommand) ! 694: { ! 695: case CommandId::AutoMountDevices: ! 696: case CommandId::AutoMountFavorites: ! 697: case CommandId::AutoMountDevicesFavorites: ! 698: { ! 699: if (cmdLine.ArgCommand == CommandId::AutoMountDevices || cmdLine.ArgCommand == CommandId::AutoMountDevicesFavorites) ! 700: { ! 701: if (Preferences.NonInteractive) ! 702: mountedVolumes = UserInterface::MountAllDeviceHostedVolumes (cmdLine.ArgMountOptions); ! 703: else ! 704: mountedVolumes = MountAllDeviceHostedVolumes (cmdLine.ArgMountOptions); ! 705: } ! 706: ! 707: if (cmdLine.ArgCommand == CommandId::AutoMountFavorites || cmdLine.ArgCommand == CommandId::AutoMountDevicesFavorites) ! 708: { ! 709: foreach (shared_ptr <VolumeInfo> v, MountAllFavoriteVolumes(cmdLine.ArgMountOptions)) ! 710: mountedVolumes.push_back (v); ! 711: } ! 712: } ! 713: break; ! 714: ! 715: ! 716: break; ! 717: ! 718: case CommandId::MountVolume: ! 719: if (Preferences.OpenExplorerWindowAfterMount) ! 720: { ! 721: // Open explorer window for an already mounted volume ! 722: shared_ptr <VolumeInfo> mountedVolume = Core->GetMountedVolume (*cmdLine.ArgMountOptions.Path); ! 723: if (mountedVolume && !mountedVolume->MountPoint.IsEmpty()) ! 724: { ! 725: OpenExplorerWindow (mountedVolume->MountPoint); ! 726: break; ! 727: } ! 728: } ! 729: ! 730: if (Preferences.NonInteractive) ! 731: { ! 732: // Volume path ! 733: if (!cmdLine.ArgMountOptions.Path) ! 734: throw MissingArgument (SRC_POS); ! 735: ! 736: mountedVolumes.push_back (Core->MountVolume (cmdLine.ArgMountOptions)); ! 737: } ! 738: else ! 739: { ! 740: shared_ptr <VolumeInfo> volume = MountVolume (cmdLine.ArgMountOptions); ! 741: if (!volume) ! 742: { ! 743: Application::SetExitCode (1); ! 744: throw UserAbort (SRC_POS); ! 745: } ! 746: mountedVolumes.push_back (volume); ! 747: } ! 748: break; ! 749: ! 750: default: ! 751: throw ParameterIncorrect (SRC_POS); ! 752: } ! 753: ! 754: if (Preferences.Verbose && !mountedVolumes.empty()) ! 755: { ! 756: wxString message; ! 757: foreach_ref (const VolumeInfo &volume, mountedVolumes) ! 758: { ! 759: if (!message.IsEmpty()) ! 760: message += L'\n'; ! 761: message += StringFormatter (_("Volume \"{0}\" has been mounted."), wstring (volume.Path)); ! 762: } ! 763: ShowInfo (message); ! 764: } ! 765: } ! 766: return true; ! 767: ! 768: case CommandId::ChangePassword: ! 769: ChangePassword (cmdLine.ArgVolumePath, cmdLine.ArgPassword, cmdLine.ArgKeyfiles, cmdLine.ArgNewPassword, cmdLine.ArgNewKeyfiles); ! 770: return true; ! 771: ! 772: case CommandId::DismountVolumes: ! 773: DismountVolumes (cmdLine.ArgVolumes, cmdLine.ArgForce, !Preferences.NonInteractive); ! 774: return true; ! 775: ! 776: case CommandId::DisplayVersion: ! 777: ShowString (Application::GetName() + L" " + StringConverter::ToWide (Version::String()) + L"\n"); ! 778: return true; ! 779: ! 780: case CommandId::Help: ! 781: ShowString (L"\nExamples:\n\nMount a volume:\ntruecrypt volume.tc /media/truecrypt1\n\n" ! 782: L"Dismount volume:\ntruecrypt -d volume.tc\n" ! 783: ); ! 784: return true; ! 785: ! 786: case CommandId::ListVolumes: ! 787: ListMountedVolumes (cmdLine.ArgVolumes); ! 788: return true; ! 789: ! 790: case CommandId::Test: ! 791: Test(); ! 792: return true; ! 793: ! 794: default: ! 795: throw ParameterIncorrect (SRC_POS); ! 796: } ! 797: ! 798: return false; ! 799: } ! 800: ! 801: void UserInterface::SetPreferences (const UserPreferences &preferences) ! 802: { ! 803: Preferences = preferences; ! 804: PreferencesUpdatedEvent.Raise(); ! 805: } ! 806: ! 807: void UserInterface::ShowError (const exception &ex) const ! 808: { ! 809: if (!dynamic_cast <const UserAbort*> (&ex)) ! 810: DoShowError (ExceptionToMessage (ex)); ! 811: } ! 812: ! 813: wxString UserInterface::SizeToString (uint64 size) const ! 814: { ! 815: wstringstream s; ! 816: if (size > 1024ULL*1024*1024*1024*1024*99) ! 817: s << size/1024/1024/1024/1024/1024 << L" " << LangString["PB"].c_str(); ! 818: else if (size > 1024ULL*1024*1024*1024*1024) ! 819: return wxString::Format (L"%.1f %s", (double)(size/1024.0/1024/1024/1024/1024), LangString["PB"].c_str()); ! 820: else if (size > 1024ULL*1024*1024*1024*99) ! 821: s << size/1024/1024/1024/1024 << L" " << LangString["TB"].c_str(); ! 822: else if (size > 1024ULL*1024*1024*1024) ! 823: return wxString::Format (L"%.1f %s", (double)(size/1024.0/1024/1024/1024), LangString["TB"].c_str()); ! 824: else if (size > 1024ULL*1024*1024*99) ! 825: s << size/1024/1024/1024 << L" " << LangString["GB"].c_str(); ! 826: else if (size > 1024ULL*1024*1024) ! 827: return wxString::Format (L"%.1f %s", (double)(size/1024.0/1024/1024), LangString["GB"].c_str()); ! 828: else if (size > 1024ULL*1024*99) ! 829: s << size/1024/1024 << L" " << LangString["MB"].c_str(); ! 830: else if (size > 1024ULL*1024) ! 831: return wxString::Format (L"%.1f %s", (double)(size/1024.0/1024), LangString["MB"].c_str()); ! 832: else if (size > 1024ULL) ! 833: s << size/1024 << L" " << LangString["KB"].c_str(); ! 834: else ! 835: s << size << L" " << LangString["BYTE"].c_str(); ! 836: ! 837: return s.str(); ! 838: } ! 839: ! 840: wxString UserInterface::SpeedToString (uint64 speed) const ! 841: { ! 842: wstringstream s; ! 843: ! 844: if (speed > 1024ULL*1024*1024*1024*1024*99) ! 845: s << speed/1024/1024/1024/1024/1024 << L" " << LangString["PB_PER_SEC"].c_str(); ! 846: else if (speed > 1024ULL*1024*1024*1024*1024) ! 847: return wxString::Format (L"%.1f %s", (double)(speed/1024.0/1024/1024/1024/1024), LangString["PB_PER_SEC"].c_str()); ! 848: else if (speed > 1024ULL*1024*1024*1024*99) ! 849: s << speed/1024/1024/1024/1024 << L" " << LangString["TB"].c_str(); ! 850: else if (speed > 1024ULL*1024*1024*1024) ! 851: return wxString::Format (L"%.1f %s", (double)(speed/1024.0/1024/1024/1024), LangString["TB_PER_SEC"].c_str()); ! 852: else if (speed > 1024ULL*1024*1024*99) ! 853: s << speed/1024/1024/1024 << L" " << LangString["GB"].c_str(); ! 854: else if (speed > 1024ULL*1024*1024) ! 855: return wxString::Format (L"%.1f %s", (double)(speed/1024.0/1024/1024), LangString["GB_PER_SEC"].c_str()); ! 856: else if (speed > 1024ULL*1024*99) ! 857: s << speed/1024/1024 << L" " << LangString["MB"].c_str(); ! 858: else if (speed > 1024ULL*1024) ! 859: return wxString::Format (L"%.1f %s", (double)(speed/1024.0/1024), LangString["MB_PER_SEC"].c_str()); ! 860: else if (speed > 1024ULL) ! 861: s << speed/1024 << L" " << LangString["KB_PER_SEC"].c_str(); ! 862: else ! 863: s << speed << L" " << LangString["B_PER_SEC"].c_str(); ! 864: ! 865: return s.str(); ! 866: } ! 867: ! 868: void UserInterface::Test () const ! 869: { ! 870: if (!PlatformTest::TestAll()) ! 871: throw TestFailed (SRC_POS); ! 872: ! 873: EncryptionTest::TestAll(); ! 874: ! 875: // StringFormatter ! 876: if (StringFormatter (L"{9} {8} {7} {6} {5} {4} {3} {2} {1} {0} {{0}}", "1", L"2", '3', L'4', 5, 6, 7, 8, 9, 10) != L"10 9 8 7 6 5 4 3 2 1 {0}") ! 877: throw TestFailed (SRC_POS); ! 878: try ! 879: { ! 880: StringFormatter (L"{0} {1}", 1); ! 881: throw TestFailed (SRC_POS); ! 882: } ! 883: catch (StringFormatterException&) { } ! 884: ! 885: try ! 886: { ! 887: StringFormatter (L"{0} {1} {1}", 1, 2, 3); ! 888: throw TestFailed (SRC_POS); ! 889: } ! 890: catch (StringFormatterException&) { } ! 891: ! 892: try ! 893: { ! 894: StringFormatter (L"{0} 1}", 1, 2); ! 895: throw TestFailed (SRC_POS); ! 896: } ! 897: catch (StringFormatterException&) { } ! 898: ! 899: try ! 900: { ! 901: StringFormatter (L"{0} {1", 1, 2); ! 902: throw TestFailed (SRC_POS); ! 903: } ! 904: catch (StringFormatterException&) { } ! 905: ! 906: ShowInfo ("TESTS_PASSED"); ! 907: } ! 908: ! 909: bool UserInterface::VolumeHasUnrecommendedExtension (const VolumePath &path) const ! 910: { ! 911: wxString ext = wxFileName (wxString (wstring (path)).Lower()).GetExt(); ! 912: return ext.IsSameAs (L"exe") || ext.IsSameAs (L"sys") || ext.IsSameAs (L"dll"); ! 913: } ! 914: ! 915: wxString UserInterface::VolumeTimeToString (VolumeTime volumeTime) const ! 916: { ! 917: wxString dateStr = VolumeTimeToDateTime (volumeTime).Format(); ! 918: ! 919: #ifdef TC_WINDOWS ! 920: ! 921: FILETIME ft; ! 922: *(unsigned __int64 *)(&ft) = volumeTime; ! 923: SYSTEMTIME st; ! 924: FileTimeToSystemTime (&ft, &st); ! 925: ! 926: wchar_t wstr[1024]; ! 927: if (GetDateFormat (LOCALE_USER_DEFAULT, 0, &st, 0, wstr, array_capacity (wstr)) != 0) ! 928: { ! 929: dateStr = wstr; ! 930: GetTimeFormat (LOCALE_USER_DEFAULT, 0, &st, 0, wstr, array_capacity (wstr)); ! 931: dateStr += wxString (L" ") + wstr; ! 932: } ! 933: #endif ! 934: return dateStr; ! 935: } ! 936: ! 937: wxString UserInterface::VolumeTypeToString (VolumeType::Enum type, VolumeProtection::Enum protection) const ! 938: { ! 939: switch (type) ! 940: { ! 941: case VolumeType::Normal: ! 942: return LangString[protection == VolumeProtection::HiddenVolumeReadOnly ? "OUTER" : "NORMAL"]; ! 943: ! 944: case VolumeType::Hidden: ! 945: return LangString["HIDDEN"]; ! 946: ! 947: default: ! 948: return L"?"; ! 949: } ! 950: } ! 951: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.