|
|
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"
1.1.1.2 ! root 782: L"Dismount a volume:\ntruecrypt -d volume.tc\n\n"
! 783: L"Dismount all mounted volumes:\ntruecrypt -d\n\n"
1.1 root 784: );
785: return true;
786:
787: case CommandId::ListVolumes:
788: ListMountedVolumes (cmdLine.ArgVolumes);
789: return true;
790:
791: case CommandId::Test:
792: Test();
793: return true;
794:
795: default:
796: throw ParameterIncorrect (SRC_POS);
797: }
798:
799: return false;
800: }
801:
802: void UserInterface::SetPreferences (const UserPreferences &preferences)
803: {
804: Preferences = preferences;
805: PreferencesUpdatedEvent.Raise();
806: }
807:
808: void UserInterface::ShowError (const exception &ex) const
809: {
810: if (!dynamic_cast <const UserAbort*> (&ex))
811: DoShowError (ExceptionToMessage (ex));
812: }
813:
814: wxString UserInterface::SizeToString (uint64 size) const
815: {
816: wstringstream s;
817: if (size > 1024ULL*1024*1024*1024*1024*99)
818: s << size/1024/1024/1024/1024/1024 << L" " << LangString["PB"].c_str();
819: else if (size > 1024ULL*1024*1024*1024*1024)
820: return wxString::Format (L"%.1f %s", (double)(size/1024.0/1024/1024/1024/1024), LangString["PB"].c_str());
821: else if (size > 1024ULL*1024*1024*1024*99)
822: s << size/1024/1024/1024/1024 << L" " << LangString["TB"].c_str();
823: else if (size > 1024ULL*1024*1024*1024)
824: return wxString::Format (L"%.1f %s", (double)(size/1024.0/1024/1024/1024), LangString["TB"].c_str());
825: else if (size > 1024ULL*1024*1024*99)
826: s << size/1024/1024/1024 << L" " << LangString["GB"].c_str();
827: else if (size > 1024ULL*1024*1024)
828: return wxString::Format (L"%.1f %s", (double)(size/1024.0/1024/1024), LangString["GB"].c_str());
829: else if (size > 1024ULL*1024*99)
830: s << size/1024/1024 << L" " << LangString["MB"].c_str();
831: else if (size > 1024ULL*1024)
832: return wxString::Format (L"%.1f %s", (double)(size/1024.0/1024), LangString["MB"].c_str());
833: else if (size > 1024ULL)
834: s << size/1024 << L" " << LangString["KB"].c_str();
835: else
836: s << size << L" " << LangString["BYTE"].c_str();
837:
838: return s.str();
839: }
840:
841: wxString UserInterface::SpeedToString (uint64 speed) const
842: {
843: wstringstream s;
844:
845: if (speed > 1024ULL*1024*1024*1024*1024*99)
846: s << speed/1024/1024/1024/1024/1024 << L" " << LangString["PB_PER_SEC"].c_str();
847: else if (speed > 1024ULL*1024*1024*1024*1024)
848: return wxString::Format (L"%.1f %s", (double)(speed/1024.0/1024/1024/1024/1024), LangString["PB_PER_SEC"].c_str());
849: else if (speed > 1024ULL*1024*1024*1024*99)
850: s << speed/1024/1024/1024/1024 << L" " << LangString["TB"].c_str();
851: else if (speed > 1024ULL*1024*1024*1024)
852: return wxString::Format (L"%.1f %s", (double)(speed/1024.0/1024/1024/1024), LangString["TB_PER_SEC"].c_str());
853: else if (speed > 1024ULL*1024*1024*99)
854: s << speed/1024/1024/1024 << L" " << LangString["GB"].c_str();
855: else if (speed > 1024ULL*1024*1024)
856: return wxString::Format (L"%.1f %s", (double)(speed/1024.0/1024/1024), LangString["GB_PER_SEC"].c_str());
857: else if (speed > 1024ULL*1024*99)
858: s << speed/1024/1024 << L" " << LangString["MB"].c_str();
859: else if (speed > 1024ULL*1024)
860: return wxString::Format (L"%.1f %s", (double)(speed/1024.0/1024), LangString["MB_PER_SEC"].c_str());
861: else if (speed > 1024ULL)
862: s << speed/1024 << L" " << LangString["KB_PER_SEC"].c_str();
863: else
864: s << speed << L" " << LangString["B_PER_SEC"].c_str();
865:
866: return s.str();
867: }
868:
869: void UserInterface::Test () const
870: {
871: if (!PlatformTest::TestAll())
872: throw TestFailed (SRC_POS);
873:
874: EncryptionTest::TestAll();
875:
876: // StringFormatter
877: 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}")
878: throw TestFailed (SRC_POS);
879: try
880: {
881: StringFormatter (L"{0} {1}", 1);
882: throw TestFailed (SRC_POS);
883: }
884: catch (StringFormatterException&) { }
885:
886: try
887: {
888: StringFormatter (L"{0} {1} {1}", 1, 2, 3);
889: throw TestFailed (SRC_POS);
890: }
891: catch (StringFormatterException&) { }
892:
893: try
894: {
895: StringFormatter (L"{0} 1}", 1, 2);
896: throw TestFailed (SRC_POS);
897: }
898: catch (StringFormatterException&) { }
899:
900: try
901: {
902: StringFormatter (L"{0} {1", 1, 2);
903: throw TestFailed (SRC_POS);
904: }
905: catch (StringFormatterException&) { }
906:
907: ShowInfo ("TESTS_PASSED");
908: }
909:
910: bool UserInterface::VolumeHasUnrecommendedExtension (const VolumePath &path) const
911: {
912: wxString ext = wxFileName (wxString (wstring (path)).Lower()).GetExt();
913: return ext.IsSameAs (L"exe") || ext.IsSameAs (L"sys") || ext.IsSameAs (L"dll");
914: }
915:
916: wxString UserInterface::VolumeTimeToString (VolumeTime volumeTime) const
917: {
918: wxString dateStr = VolumeTimeToDateTime (volumeTime).Format();
919:
920: #ifdef TC_WINDOWS
921:
922: FILETIME ft;
923: *(unsigned __int64 *)(&ft) = volumeTime;
924: SYSTEMTIME st;
925: FileTimeToSystemTime (&ft, &st);
926:
927: wchar_t wstr[1024];
928: if (GetDateFormat (LOCALE_USER_DEFAULT, 0, &st, 0, wstr, array_capacity (wstr)) != 0)
929: {
930: dateStr = wstr;
931: GetTimeFormat (LOCALE_USER_DEFAULT, 0, &st, 0, wstr, array_capacity (wstr));
932: dateStr += wxString (L" ") + wstr;
933: }
934: #endif
935: return dateStr;
936: }
937:
938: wxString UserInterface::VolumeTypeToString (VolumeType::Enum type, VolumeProtection::Enum protection) const
939: {
940: switch (type)
941: {
942: case VolumeType::Normal:
943: return LangString[protection == VolumeProtection::HiddenVolumeReadOnly ? "OUTER" : "NORMAL"];
944:
945: case VolumeType::Hidden:
946: return LangString["HIDDEN"];
947:
948: default:
949: return L"?";
950: }
951: }
952: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.