File:  [truecrypt] / truecrypt / main / userinterface.cpp
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 16:50:33 2018 UTC (8 years, 3 months ago) by root
Branches: drWhax, MAIN
CVS tags: v5_0a, HEAD
5.0a

/*
 Copyright (c) 2008 TrueCrypt Foundation. All rights reserved.

 Governed by the TrueCrypt License 2.4 the full text of which is contained
 in the file License.txt included in TrueCrypt binary and source code
 distribution packages.
*/

#include "System.h"
#include <set>
#include <typeinfo>
#include <wx/apptrait.h>
#include <wx/cmdline.h>
#include "Platform/PlatformTest.h"
#ifdef TC_UNIX
#include "Platform/Unix/Process.h"
#endif
#include "Volume/EncryptionTest.h"
#include "Application.h"
#include "FavoriteVolume.h"
#include "UserInterface.h"

namespace TrueCrypt
{
	UserInterface::UserInterface ()
	{
	}

	UserInterface::~UserInterface ()
	{
		Core->WarningEvent.Disconnect (this);
		Core->VolumeMountedEvent.Disconnect (this);
	}

	void UserInterface::CloseExplorerWindows (shared_ptr <VolumeInfo> mountedVolume) const
	{
#ifdef TC_WINDOWS
		struct Args
		{
			HWND ExplorerWindow;
			string DriveRootPath;
		};

		struct Enumerator
		{
			static BOOL CALLBACK ChildWindows (HWND hwnd, LPARAM argsLP)
			{
				Args *args = reinterpret_cast <Args *> (argsLP);
				
				char s[4096];
				SendMessageA (hwnd, WM_GETTEXT, sizeof (s), (LPARAM) s);

				if (strstr (s, args->DriveRootPath.c_str()) != NULL)
				{
					PostMessage (args->ExplorerWindow, WM_CLOSE, 0, 0);
					return FALSE;
				}

				return TRUE;
			}

			static BOOL CALLBACK TopLevelWindows (HWND hwnd, LPARAM argsLP)
			{
				Args *args = reinterpret_cast <Args *> (argsLP);

				char s[4096];
				GetClassNameA (hwnd, s, sizeof s);
				if (strcmp (s, "CabinetWClass") == 0)
				{
					GetWindowTextA (hwnd, s, sizeof s);
					if (strstr (s, args->DriveRootPath.c_str()) != NULL)
					{
						PostMessage (hwnd, WM_CLOSE, 0, 0);
						return TRUE;
					}

					args->ExplorerWindow = hwnd;
					EnumChildWindows (hwnd, ChildWindows, argsLP);
				}

				return TRUE;
			}
		};

		Args args;

		string mountPoint = mountedVolume->MountPoint;
		if (mountPoint.size() < 2 || mountPoint[1] != ':')
			return;

		args.DriveRootPath = string() + mountPoint[0] + string (":\\");
		
		EnumWindows (Enumerator::TopLevelWindows, (LPARAM) &args);
#endif
	}

	void UserInterface::DismountAllVolumes (bool ignoreOpenFiles, bool interactive) const
	{
		try
		{
			VolumeInfoList mountedVolumes = Core->GetMountedVolumes();

			if (mountedVolumes.size() < 1)
				ShowInfo (LangString["NO_VOLUMES_MOUNTED"]);

			BusyScope busy (this);
			DismountVolumes (mountedVolumes, ignoreOpenFiles, interactive);
		}
		catch (exception &e)
		{
			ShowError (e);
		}
	}

	void UserInterface::DismountVolume (shared_ptr <VolumeInfo> volume, bool ignoreOpenFiles, bool interactive) const
	{
		VolumeInfoList volumes;
		volumes.push_back (volume);

		DismountVolumes (volumes, ignoreOpenFiles, interactive);
	}

	void UserInterface::DismountVolumes (VolumeInfoList volumes, bool ignoreOpenFiles, bool interactive) const
	{
		BusyScope busy (this);

		wxString message;
		bool twoPassMode = volumes.size() > 1;
		bool volumesInUse = false;
		bool firstPass = true;

#ifdef TC_WINDOWS
		if (Preferences.CloseExplorerWindowsOnDismount)
		{
			foreach (shared_ptr <VolumeInfo> volume, volumes)
				CloseExplorerWindows (volume);
		}
#endif
		while (!volumes.empty())
		{
			VolumeInfoList volumesLeft;
			foreach (shared_ptr <VolumeInfo> volume, volumes)
			{
				try
				{
					BusyScope busy (this);
					Core->DismountVolume (volume, ignoreOpenFiles);
				}
				catch (MountedVolumeInUse&)
				{
					if (!firstPass)
						throw;

					if (twoPassMode || !interactive)
					{
						volumesInUse = true;
						volumesLeft.push_back (volume);
						continue;
					}
					else
					{
						if (AskYesNo (StringFormatter (LangString["UNMOUNT_LOCK_FAILED"], wstring (volume->Path)), true, true))
						{
							BusyScope busy (this);
							Core->DismountVolume (volume, true);
						}
						else
							throw UserAbort (SRC_POS);
					}
				}
				catch (...)
				{
					if (twoPassMode && firstPass)
						volumesLeft.push_back (volume);
					else
						throw;
				}

				if (volume->HiddenVolumeProtectionTriggered)
					ShowWarning (StringFormatter (LangString["DAMAGE_TO_HIDDEN_VOLUME_PREVENTED"], wstring (volume->Path)));

				if (Preferences.Verbose)
				{
					if (!message.IsEmpty())
						message += L'\n';
					message += StringFormatter (_("Volume \"{0}\" has been dismounted."), wstring (volume->Path));
				}
			}

			if (twoPassMode && firstPass)
			{
				volumes = volumesLeft;

				if (volumesInUse && interactive)
				{
					if (AskYesNo (LangString["UNMOUNTALL_LOCK_FAILED"], true, true))
						ignoreOpenFiles = true;
					else
						throw UserAbort (SRC_POS);
				}
			}
			else
				break;

			firstPass = false;
		}

		if (Preferences.Verbose && !message.IsEmpty())
			ShowInfo (message);
	}
	
	wxString UserInterface::ExceptionToMessage (const exception &ex) const
	{
		wxString message;
		
		const Exception *e = dynamic_cast <const Exception *> (&ex);
		if (e)
		{
			message = ExceptionToString (*e);

			// System exception
			const SystemException *sysEx = dynamic_cast <const SystemException *> (&ex);
			if (sysEx)
			{
				if (!message.IsEmpty())
				{
					message += L"\n\n";
				}

				message += wxString (sysEx->SystemText()).Trim (true);
			}

			if (!message.IsEmpty())
			{
				// Subject
				if (!e->GetSubject().empty())
				{
					message = message.Trim (true);

					if (message.EndsWith (L"."))
						message.Truncate (message.size() - 1);

					if (!message.EndsWith (L":"))
						message << L":\n";
					else
						message << L"\n";

					message << e->GetSubject();
				}
#ifdef DEBUG
				if (sysEx && sysEx->what())
					message << L"\n\n" << StringConverter::ToWide (sysEx->what());
#endif
				return message;
			}
		}

		// bad_alloc
		const bad_alloc *outOfMemory = dynamic_cast <const bad_alloc *> (&ex);
		if (outOfMemory)
			return _("Out of memory.");

		// Unresolved exceptions
		string typeName (StringConverter::GetTypeName (typeid (ex)));
		size_t pos = typeName.find ("TrueCrypt::");
		if (pos != string::npos)
		{
			return StringConverter::ToWide (typeName.substr (pos + string ("TrueCrypt::").size()))
				+ L" at " + StringConverter::ToWide (ex.what());
		}

		return StringConverter::ToWide (typeName) + L" at " + StringConverter::ToWide (ex.what());
	}

	wxString UserInterface::ExceptionToString (const Exception &ex) const
	{
		// Error messages
		const ErrorMessage *errMsgEx = dynamic_cast <const ErrorMessage *> (&ex);
		if (errMsgEx)
			return wstring (*errMsgEx).c_str();

		// ExecutedProcessFailed
		const ExecutedProcessFailed *execEx = dynamic_cast <const ExecutedProcessFailed *> (&ex);
		if (execEx)
		{
			wstring errOutput;

			// ElevationFailed
			if (dynamic_cast <const ElevationFailed*> (&ex))
				errOutput += wxString (_("Failed to obtain administrator privileges")) + (StringConverter::Trim (execEx->GetErrorOutput()).empty() ? L". " : L": ");

			errOutput += StringConverter::ToWide (execEx->GetErrorOutput());

			if (errOutput.empty())
				return errOutput + StringFormatter (_("Command \"{0}\" returned error {1}."), execEx->GetCommand(), execEx->GetExitCode());

			return wxString (errOutput).Trim (true);
		}

		// PasswordIncorrect 
		if (dynamic_cast <const PasswordIncorrect *> (&ex))
		{
			wxString message = ExceptionTypeToString (typeid (ex));

			if (wxGetKeyState (WXK_CAPITAL))
				message += wxString (L"\n\n") + LangString["CAPSLOCK_ON"];

			return message;
		}

		// Other library exceptions
		return ExceptionTypeToString (typeid (ex));
	}

	wxString UserInterface::ExceptionTypeToString (const std::type_info &ex) const
	{
#define EX2MSG(exception, message) do { if (ex == typeid (exception)) return (message); } while (false)
		EX2MSG (DriveLetterUnavailable,				LangString["DRIVE_LETTER_UNAVAILABLE"]);
		EX2MSG (ExternalException,					LangString["EXCEPTION_OCCURRED"]);
		EX2MSG (InsufficientData,					_("Not enough data available."));
		EX2MSG (HigherVersionRequired,				LangString["NEW_VERSION_REQUIRED"]);
		EX2MSG (MissingArgument,					_("A required argument is missing."));
		EX2MSG (MissingVolumeData,					_("Volume data missing."));
		EX2MSG (MountPointRequired,					_("Mount point required."));
		EX2MSG (MountPointUnavailable,				_("Mount point is already in use."));
		EX2MSG (NoDriveLetterAvailable,				LangString["NO_FREE_DRIVES"]);
		EX2MSG (NoLoopbackDeviceAvailable,			_("No loopback device available."));
		EX2MSG (PasswordEmpty,						_("No password or keyfile specified."));
		EX2MSG (PasswordIncorrect,					LangString["PASSWORD_WRONG"]);
		EX2MSG (PasswordKeyfilesIncorrect,			LangString["PASSWORD_OR_KEYFILE_WRONG"]);
		EX2MSG (PasswordTooLong,					StringFormatter (_("Password is longer than {0} characters."), VolumePassword::MaxSize));
		EX2MSG (ProtectionPasswordIncorrect,		_("Incorrect keyfile(s) and/or password to the protected hidden volume or the hidden volume does not exist."));
		EX2MSG (ProtectionPasswordKeyfilesIncorrect,	_("Incorrect password to the protected hidden volume or the hidden volume does not exist."));
		EX2MSG (RootDeviceUnavailable,				LangString["NODRIVER"]);
		EX2MSG (StringConversionFailed,				_("Invalid characters encountered."));
		EX2MSG (StringFormatterException,			_("Error while parsing formatted string."));
		EX2MSG (UnportablePassword,					LangString["UNSUPPORTED_CHARS_IN_PWD"]);
		EX2MSG (UnsupportedSectorSize,					LangString["LARGE_SECTOR_UNSUPPORTED"]);
		EX2MSG (VolumeAlreadyMounted,				LangString["VOL_ALREADY_MOUNTED"]);
		EX2MSG (VolumeHostInUse,					_("The host file/device is already in use."));
		EX2MSG (VolumeSlotUnavailable,				_("Volume slot unavailable."));

#undef EX2MSG
		return L"";
	}

	void UserInterface::Init ()
	{
		SetAppName (Application::GetName());
		SetClassName (Application::GetName());

		LangString.Init();
		Core->Init();

		wxCmdLineParser parser;
		parser.SetCmdLine (argc, argv);
		CmdLine.reset (new CommandLineInterface (parser, InterfaceType));
		SetPreferences (CmdLine->Preferences);

		Core->SetApplicationExecutablePath (Application::GetExecutablePath());

		if (!Preferences.NonInteractive)
		{
			Core->SetAdminPasswordCallback (GetAdminPasswordRequestHandler());
		}
		else
		{
			struct AdminPasswordRequestHandler : public GetStringFunctor
			{
				virtual string operator() ()
				{
					throw ElevationFailed (SRC_POS, "sudo", 1, "");
				}
			};

			Core->SetAdminPasswordCallback (shared_ptr <GetStringFunctor> (new AdminPasswordRequestHandler));
		}

		Core->WarningEvent.Connect (EventConnector <UserInterface> (this, &UserInterface::OnWarning));
		Core->VolumeMountedEvent.Connect (EventConnector <UserInterface> (this, &UserInterface::OnVolumeMounted));
	}
	
	void UserInterface::ListMountedVolumes (const VolumeInfoList &volumes) const
	{
		if (volumes.size() < 1)
			throw_err (LangString["NO_VOLUMES_MOUNTED"]);

		wxString message;

		foreach_ref (const VolumeInfo &volume, volumes)
		{
			message << volume.SlotNumber << L": " << StringConverter::QuoteSpaces (volume.Path);

			if (!volume.VirtualDevice.IsEmpty())
				message << L' ' << wstring (volume.VirtualDevice);
			else
				message << L" - ";

			if (!volume.MountPoint.IsEmpty())
				message << L' ' << StringConverter::QuoteSpaces (volume.MountPoint);
			else
				message << L" - ";

			if (Preferences.Verbose)
				message << L' ' << SizeToString (volume.Size);

			message << L'\n';
		}

		ShowString (message);
	}
	
	VolumeInfoList UserInterface::MountAllDeviceHostedVolumes (MountOptions &options) const
	{
		BusyScope busy (this);

		VolumeInfoList newMountedVolumes;

		if (!options.MountPoint)
			options.MountPoint.reset (new DirectoryPath);

		Core->CoalesceSlotNumberAndMountPoint (options);

		bool sharedAccessAllowed = options.SharedAccessAllowed;
		bool someVolumesShared = false;

		HostDeviceList devices;
		foreach (shared_ptr <HostDevice> device, Core->GetHostDevices (true))
		{
			devices.push_back (device);

			foreach (shared_ptr <HostDevice> partition, device->Partitions)
				devices.push_back (partition);
		}

		set <wstring> mountedVolumes;
		foreach_ref (const VolumeInfo &v, Core->GetMountedVolumes())
			mountedVolumes.insert (v.Path);

		bool protectedVolumeMounted = false;
		bool legacyVolumeMounted = false;

		foreach_ref (const HostDevice &device, devices)
		{
			if (mountedVolumes.find (wstring (device.Path)) != mountedVolumes.end())
				continue;

			Yield();
			options.SlotNumber = Core->GetFirstFreeSlotNumber (options.SlotNumber);
			options.MountPoint.reset (new DirectoryPath);
			options.Path.reset (new VolumePath (device.Path));

			try
			{
				try
				{
					options.SharedAccessAllowed = sharedAccessAllowed;
					newMountedVolumes.push_back (Core->MountVolume (options));
				}
				catch (VolumeHostInUse&)
				{
					if (!sharedAccessAllowed)
					{
						try
						{
							options.SharedAccessAllowed = true;
							newMountedVolumes.push_back (Core->MountVolume (options));
							someVolumesShared = true;
						}
						catch (VolumeHostInUse&)
						{
							continue;
						}
					}
					else
						continue;
				}

				if (newMountedVolumes.back()->Protection == VolumeProtection::HiddenVolumeReadOnly)
					protectedVolumeMounted = true;

				if (newMountedVolumes.back()->EncryptionAlgorithmMinBlockSize == 8)
					legacyVolumeMounted = true;
			}
			catch (DriverError&) { }
			catch (MissingVolumeData&) { }
			catch (PasswordException&) { }
			catch (SystemException&) { }
		}

		if (newMountedVolumes.empty())
		{
			ShowWarning (LangString [options.Keyfiles && !options.Keyfiles->empty() ? "PASSWORD_OR_KEYFILE_WRONG_AUTOMOUNT" : "PASSWORD_WRONG_AUTOMOUNT"]);
		}
		else
		{
			if (someVolumesShared)
				ShowWarning ("DEVICE_IN_USE_INFO");

			if (legacyVolumeMounted)
				ShowWarning ("WARN_64_BIT_BLOCK_CIPHER");

			if (protectedVolumeMounted)
				ShowInfo (LangString[newMountedVolumes.size() > 1 ? "HIDVOL_PROT_WARN_AFTER_MOUNT_PLURAL" : "HIDVOL_PROT_WARN_AFTER_MOUNT"]);
		}

		return newMountedVolumes;
	}

	VolumeInfoList UserInterface::MountAllFavoriteVolumes (MountOptions &options) const
	{
		BusyScope busy (this);
		
		VolumeInfoList newMountedVolumes;
		foreach_ref (const FavoriteVolume &favorite, FavoriteVolume::LoadList())
		{
			shared_ptr <VolumeInfo> mountedVolume = Core->GetMountedVolume (favorite.Path);
			if (mountedVolume)
			{
				if (mountedVolume->MountPoint != favorite.MountPoint)
					ShowInfo (StringFormatter (LangString["VOLUME_ALREADY_MOUNTED"], wstring (favorite.Path)));
				continue;
			}

			favorite.ToMountOptions (options);

			if (Preferences.NonInteractive)
			{
				BusyScope busy (this);
				newMountedVolumes.push_back (Core->MountVolume (options));
			}
			else
			{
				try
				{
					BusyScope busy (this);
					newMountedVolumes.push_back (Core->MountVolume (options));
				}
				catch (...)
				{
					shared_ptr <VolumeInfo> volume = MountVolume (options);
					if (!volume)
						break;
					newMountedVolumes.push_back (volume);
				}
			}
		}

		return newMountedVolumes;
	}

	shared_ptr <VolumeInfo> UserInterface::MountVolume (MountOptions &options) const
	{
		shared_ptr <VolumeInfo> volume;

		try
		{
			volume = Core->MountVolume (options);
		}
		catch (VolumeHostInUse&)
		{
			if (options.SharedAccessAllowed)
				throw_err (LangString["FILE_IN_USE_FAILED"]);

			if (!AskYesNo (StringFormatter (LangString["VOLUME_HOST_IN_USE"], wstring (*options.Path)), false, true))
				throw UserAbort (SRC_POS);

			try
			{
				options.SharedAccessAllowed = true;
				volume = Core->MountVolume (options);
			}
			catch (VolumeHostInUse&)
			{
				throw_err (LangString["FILE_IN_USE_FAILED"]);
			}
		}

		if (volume->EncryptionAlgorithmMinBlockSize == 8)
			ShowWarning ("WARN_64_BIT_BLOCK_CIPHER");

		if (VolumeHasUnrecommendedExtension (*options.Path))
			ShowWarning ("EXE_FILE_EXTENSION_MOUNT_WARNING");

		if (options.Protection == VolumeProtection::HiddenVolumeReadOnly)
			ShowInfo ("HIDVOL_PROT_WARN_AFTER_MOUNT");

		return volume;
	}

	void UserInterface::OnUnhandledException ()
	{
		try
		{
			throw;
		}
		catch (UserAbort&)
		{
		}
		catch (exception &e)
		{
			ShowError (e);
		}
		catch (...)
		{
			ShowError (_("Unknown exception occurred."));
		}

		Yield();
		Application::SetExitCode (1);
	}

	void UserInterface::OnVolumeMounted (EventArgs &args)
	{
		shared_ptr <VolumeInfo> mountedVolume = (dynamic_cast <VolumeEventArgs &> (args)).mVolume;

		if (Preferences.OpenExplorerWindowAfterMount && !mountedVolume->MountPoint.IsEmpty())
			OpenExplorerWindow (mountedVolume->MountPoint);
	}
	
	void UserInterface::OnWarning (EventArgs &args)
	{
		ExceptionEventArgs &e = dynamic_cast <ExceptionEventArgs &> (args);
		ShowWarning (e.mException);
	}

	void UserInterface::OpenExplorerWindow (const DirectoryPath &path)
	{
		if (path.IsEmpty())
			return;

		list <string> args;

#ifdef TC_WINDOWS

		wstring p (Directory::AppendSeparator (path));
		SHFILEINFO fInfo;
		SHGetFileInfo (p.c_str(), 0, &fInfo, sizeof (fInfo), 0); // Force explorer to discover the drive
		ShellExecute (GetTopWindow() ? static_cast <HWND> (GetTopWindow()->GetHandle()) : nullptr, L"open", p.c_str(), nullptr, nullptr, SW_SHOWNORMAL);

#elif defined (TC_MACOSX)

		args.push_back (string (path));
		Process::Execute ("open", args);

#else
		// MIME handler for directory seems to be unavailable through wxWidgets
		if (GetTraits()->GetDesktopEnvironment() == L"GNOME")
		{
			args.push_back ("--no-default-window");
			args.push_back ("--no-desktop");
			args.push_back (string (path));
			try
			{
				Process::Execute ("nautilus", args, 2000);
			}
			catch (TimeOut&) { }
		}
		else if (GetTraits()->GetDesktopEnvironment() == L"KDE")
		{
			args.push_back ("openURL");
			args.push_back (string (path));
			try
			{
				Process::Execute ("kfmclient", args, 2000);
			}
			catch (TimeOut&) { }
		}
#endif
	}

	bool UserInterface::ProcessCommandLine ()
	{
		CommandLineInterface &cmdLine = *CmdLine;

		switch (cmdLine.ArgCommand)
		{
		case CommandId::None:
			return false;

		case CommandId::AutoMountDevices:
		case CommandId::AutoMountFavorites:
		case CommandId::AutoMountDevicesFavorites:
		case CommandId::MountVolume:
			{
				cmdLine.ArgMountOptions.Path = cmdLine.ArgVolumePath;
				cmdLine.ArgMountOptions.MountPoint = cmdLine.ArgMountPoint;
				cmdLine.ArgMountOptions.Password = cmdLine.ArgPassword;
				cmdLine.ArgMountOptions.Keyfiles = cmdLine.ArgKeyfiles;
				cmdLine.ArgMountOptions.SharedAccessAllowed = cmdLine.ArgForce;

				VolumeInfoList mountedVolumes;
				switch (cmdLine.ArgCommand)
				{
				case CommandId::AutoMountDevices:
				case CommandId::AutoMountFavorites:
				case CommandId::AutoMountDevicesFavorites:
					{
						if (cmdLine.ArgCommand == CommandId::AutoMountDevices || cmdLine.ArgCommand == CommandId::AutoMountDevicesFavorites)
						{
							if (Preferences.NonInteractive)
								mountedVolumes = UserInterface::MountAllDeviceHostedVolumes (cmdLine.ArgMountOptions);
							else
								mountedVolumes = MountAllDeviceHostedVolumes (cmdLine.ArgMountOptions);
						}

						if (cmdLine.ArgCommand == CommandId::AutoMountFavorites || cmdLine.ArgCommand == CommandId::AutoMountDevicesFavorites)
						{
							foreach (shared_ptr <VolumeInfo> v, MountAllFavoriteVolumes(cmdLine.ArgMountOptions))
								mountedVolumes.push_back (v);
						}
					}
					break;


					break;

				case CommandId::MountVolume:
					if (Preferences.OpenExplorerWindowAfterMount)
					{
						// Open explorer window for an already mounted volume
						shared_ptr <VolumeInfo> mountedVolume = Core->GetMountedVolume (*cmdLine.ArgMountOptions.Path);
						if (mountedVolume && !mountedVolume->MountPoint.IsEmpty())
						{
							OpenExplorerWindow (mountedVolume->MountPoint);
							break;
						}
					}

					if (Preferences.NonInteractive)
					{
						// Volume path
						if (!cmdLine.ArgMountOptions.Path)
							throw MissingArgument (SRC_POS);

						mountedVolumes.push_back (Core->MountVolume (cmdLine.ArgMountOptions));
					}
					else
					{
						shared_ptr <VolumeInfo> volume = MountVolume (cmdLine.ArgMountOptions);
						if (!volume)
						{
							Application::SetExitCode (1);
							throw UserAbort (SRC_POS);
						}
						mountedVolumes.push_back (volume);
					}
					break;

				default:
					throw ParameterIncorrect (SRC_POS);
				}

				if (Preferences.Verbose && !mountedVolumes.empty())
				{
					wxString message;
					foreach_ref (const VolumeInfo &volume, mountedVolumes)
					{
						if (!message.IsEmpty())
							message += L'\n';
						message += StringFormatter (_("Volume \"{0}\" has been mounted."), wstring (volume.Path));
					}
					ShowInfo (message);
				}
			}
			return true;

		case CommandId::ChangePassword:
			ChangePassword (cmdLine.ArgVolumePath, cmdLine.ArgPassword, cmdLine.ArgKeyfiles, cmdLine.ArgNewPassword, cmdLine.ArgNewKeyfiles);
			return true;

		case CommandId::DismountVolumes:
			DismountVolumes (cmdLine.ArgVolumes, cmdLine.ArgForce, !Preferences.NonInteractive);
			return true;

		case CommandId::DisplayVersion:
			ShowString (Application::GetName() + L" " + StringConverter::ToWide (Version::String()) + L"\n");
			return true;

		case CommandId::Help:
			ShowString (L"\nExamples:\n\nMount a volume:\ntruecrypt volume.tc /media/truecrypt1\n\n"
					L"Dismount a volume:\ntruecrypt -d volume.tc\n\n"
					L"Dismount all mounted volumes:\ntruecrypt -d\n\n"
					);
			return true;

		case CommandId::ListVolumes:
			ListMountedVolumes (cmdLine.ArgVolumes);
			return true;

		case CommandId::Test:
			Test();
			return true;

		default:
			throw ParameterIncorrect (SRC_POS);
		}

		return false;
	}

	void UserInterface::SetPreferences (const UserPreferences &preferences)
	{
		Preferences = preferences;
		PreferencesUpdatedEvent.Raise();
	}

	void UserInterface::ShowError (const exception &ex) const
	{
		if (!dynamic_cast <const UserAbort*> (&ex))
			DoShowError (ExceptionToMessage (ex));
	}

	wxString UserInterface::SizeToString (uint64 size) const
	{
		wstringstream s;
		if (size > 1024ULL*1024*1024*1024*1024*99)
			s << size/1024/1024/1024/1024/1024 << L" " << LangString["PB"].c_str();
		else if (size > 1024ULL*1024*1024*1024*1024)
			return wxString::Format (L"%.1f %s", (double)(size/1024.0/1024/1024/1024/1024), LangString["PB"].c_str());
		else if (size > 1024ULL*1024*1024*1024*99)
			s << size/1024/1024/1024/1024 << L" " << LangString["TB"].c_str();
		else if (size > 1024ULL*1024*1024*1024)
			return wxString::Format (L"%.1f %s", (double)(size/1024.0/1024/1024/1024), LangString["TB"].c_str());
		else if (size > 1024ULL*1024*1024*99)
			s << size/1024/1024/1024 << L" " << LangString["GB"].c_str();
		else if (size > 1024ULL*1024*1024)
			return wxString::Format (L"%.1f %s", (double)(size/1024.0/1024/1024), LangString["GB"].c_str());
		else if (size > 1024ULL*1024*99)
			s << size/1024/1024 << L" " << LangString["MB"].c_str();
		else if (size > 1024ULL*1024)
			return wxString::Format (L"%.1f %s", (double)(size/1024.0/1024), LangString["MB"].c_str());
		else if (size > 1024ULL)
			s << size/1024 << L" " << LangString["KB"].c_str();
		else
			s << size << L" " << LangString["BYTE"].c_str();

		return s.str();
	}

	wxString UserInterface::SpeedToString (uint64 speed) const
	{
		wstringstream s;

		if (speed > 1024ULL*1024*1024*1024*1024*99)
			s << speed/1024/1024/1024/1024/1024 << L" " << LangString["PB_PER_SEC"].c_str();
		else if (speed > 1024ULL*1024*1024*1024*1024)
			return wxString::Format (L"%.1f %s", (double)(speed/1024.0/1024/1024/1024/1024), LangString["PB_PER_SEC"].c_str());
		else if (speed > 1024ULL*1024*1024*1024*99)
			s << speed/1024/1024/1024/1024 << L" " << LangString["TB"].c_str();
		else if (speed > 1024ULL*1024*1024*1024)
			return wxString::Format (L"%.1f %s", (double)(speed/1024.0/1024/1024/1024), LangString["TB_PER_SEC"].c_str());
		else if (speed > 1024ULL*1024*1024*99)
			s << speed/1024/1024/1024 << L" " << LangString["GB"].c_str();
		else if (speed > 1024ULL*1024*1024)
			return wxString::Format (L"%.1f %s", (double)(speed/1024.0/1024/1024), LangString["GB_PER_SEC"].c_str());
		else if (speed > 1024ULL*1024*99)
			s << speed/1024/1024 << L" " << LangString["MB"].c_str();
		else if (speed > 1024ULL*1024)
			return wxString::Format (L"%.1f %s", (double)(speed/1024.0/1024), LangString["MB_PER_SEC"].c_str());
		else if (speed > 1024ULL)
			s << speed/1024 << L" " << LangString["KB_PER_SEC"].c_str();
		else
			s << speed << L" " << LangString["B_PER_SEC"].c_str();

		return s.str();
	}

	void UserInterface::Test () const
	{
		if (!PlatformTest::TestAll())
			throw TestFailed (SRC_POS);

		EncryptionTest::TestAll();

		// StringFormatter
		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}")
			throw TestFailed (SRC_POS);
		try
		{
			StringFormatter (L"{0} {1}", 1);
			throw TestFailed (SRC_POS);
		}
		catch (StringFormatterException&) { }

		try
		{
			StringFormatter (L"{0} {1} {1}", 1, 2, 3);
			throw TestFailed (SRC_POS);
		}
		catch (StringFormatterException&) { }

		try
		{
			StringFormatter (L"{0} 1}", 1, 2);
			throw TestFailed (SRC_POS);
		}
		catch (StringFormatterException&) { }

		try
		{
			StringFormatter (L"{0} {1", 1, 2);
			throw TestFailed (SRC_POS);
		}
		catch (StringFormatterException&) { }

		ShowInfo ("TESTS_PASSED");
	}
	
	bool UserInterface::VolumeHasUnrecommendedExtension (const VolumePath &path) const
	{
		wxString ext = wxFileName (wxString (wstring (path)).Lower()).GetExt();
		return ext.IsSameAs (L"exe") || ext.IsSameAs (L"sys") || ext.IsSameAs (L"dll");
	}

	wxString UserInterface::VolumeTimeToString (VolumeTime volumeTime) const
	{
		wxString dateStr = VolumeTimeToDateTime (volumeTime).Format();

#ifdef TC_WINDOWS

		FILETIME ft;
		*(unsigned __int64 *)(&ft) = volumeTime;
		SYSTEMTIME st;
		FileTimeToSystemTime (&ft, &st);

		wchar_t wstr[1024];
		if (GetDateFormat (LOCALE_USER_DEFAULT, 0, &st, 0, wstr, array_capacity (wstr)) != 0)
		{
			dateStr = wstr;
			GetTimeFormat (LOCALE_USER_DEFAULT, 0, &st, 0, wstr, array_capacity (wstr));
			dateStr += wxString (L" ") + wstr;
		}
#endif
		return dateStr;
	}

	wxString UserInterface::VolumeTypeToString (VolumeType::Enum type, VolumeProtection::Enum protection) const
	{
		switch (type)
		{
		case VolumeType::Normal:
			return LangString[protection == VolumeProtection::HiddenVolumeReadOnly ? "OUTER" : "NORMAL"];

		case VolumeType::Hidden:
			return LangString["HIDDEN"];

		default:
			return L"?";
		}
	}
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.