/* Derived from source code of TrueCrypt 7.1a, which is Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed by the TrueCrypt License 3.0. Modifications and additions to the original source code (contained in this file) and all other portions of this file are Copyright (c) 2013-2026 AM Crypto and are governed by the Apache License 2.0 the full text of which is contained in the file License.txt included in VeraCrypt binary and source code distribution packages. */ #include "System.h" #ifdef TC_UNIX #include #include #include #include #endif #include "Common/SecurityToken.h" #include "Platform/SystemLog.h" #include "Platform/SerializerFactory.h" #include "Main/Main.h" #include "Main/Resources.h" #include "Main/Application.h" #include "Main/GraphicUserInterface.h" #include "Main/VolumeHistory.h" #include "Main/Xml.h" #include "MainFrame.h" #include "AboutDialog.h" #include "BenchmarkDialog.h" #include "ChangePasswordDialog.h" #include "EncryptionTestDialog.h" #include "FavoriteVolumesDialog.h" #include "LegalNoticesDialog.h" #include "PreferencesDialog.h" #include "SecurityTokenKeyfilesDialog.h" #include "VolumeCreationWizard.h" #include "VolumePropertiesDialog.h" #ifdef TC_MACOSX #include #include "Core/Unix/MacOSX/CoreMacOSX.h" #endif namespace VeraCrypt { #ifdef TC_MACOSX struct VolumeDiscoveryState { VolumeDiscoveryState (wxEvtHandler *target) : Running (false), Completed (false), Succeeded (false), HasResult (false), Generation (0), ResultGeneration (0), Started (chrono::steady_clock::now()), NotificationTarget (target) { // A kernel-blocked metadata read may outlive GUI shutdown. Retain the // read-only serializer registry until process exit as well as this state; // static teardown must not delete it underneath the detached worker. static const bool registryRetained = [] () { SerializerFactory::Initialize(); return true; } (); (void) registryRetained; } // Constructed on the GUI thread (CoreUnix initializes locale state). CoreMacOSX DiscoveryCore; Mutex AccessMutex; bool Running, Completed, Succeeded, HasResult; uint64 Generation, ResultGeneration; chrono::steady_clock::time_point Started; VolumeDiscoveryResult Result; wxEvtHandler *NotificationTarget; }; class VolumeDiscoveryTask : public Functor { public: VolumeDiscoveryTask (shared_ptr state, uint64 generation) : State (state), Generation (generation) { } virtual void operator() () { VolumeDiscoveryResult result; bool succeeded = false; try { result = State->DiscoveryCore.GetMountedVolumesWithStatus(); succeeded = true; } catch (exception &e) { SystemLog::WriteException (e); } catch (...) { } ScopeLock lock (State->AccessMutex); State->Result = result; State->Succeeded = succeeded; State->HasResult = true; State->ResultGeneration = Generation; State->Completed = true; State->Running = false; // Destruction clears this pointer under the same lock before the // window's event handler is destroyed. Never post to a dead window. if (State->NotificationTarget) wxQueueEvent (State->NotificationTarget, new wxCommandEvent (wxEVT_COMMAND_VOLUME_DISCOVERY_COMPLETED)); } private: shared_ptr State; uint64 Generation; }; #endif DEFINE_EVENT_TYPE(wxEVT_COMMAND_UPDATE_VOLUME_LIST) DEFINE_EVENT_TYPE(wxEVT_COMMAND_PREF_UPDATED) DEFINE_EVENT_TYPE(wxEVT_COMMAND_OPEN_VOLUME_REQUEST) DEFINE_EVENT_TYPE(wxEVT_COMMAND_VOLUME_DISCOVERY_COMPLETED) DEFINE_EVENT_TYPE(wxEVT_COMMAND_SHOW_WARNING) MainFrame::MainFrame (wxWindow* parent) : MainFrameBase (parent), #ifdef HAVE_INDICATORS indicator (NULL), indicator_item_showhide (NULL), indicator_item_mountfavorites (NULL), indicator_item_dismountall (NULL), indicator_item_prefs (NULL), indicator_item_exit (NULL), #endif ListItemRightClickEventPending (false), #ifdef TC_MACOSX VolumeDiscovery (new VolumeDiscoveryState (this)), #endif SelectedItemIndex (-1), SelectedSlotNumber (0), ShowRequestFifo (-1) { wxBusyCursor busy; SetName (Application::GetName()); SetTitle (Application::GetName()); SetIcon (Resources::GetVeraCryptIcon()); #ifdef TC_MACOSX CreateStatusBar(); #endif #if defined(TC_UNIX) && !defined(TC_MACOSX) try { string fifoPath = GetShowRequestFifoPath(); remove (fifoPath.c_str()); throw_sys_if (mkfifo (fifoPath.c_str(), S_IRUSR | S_IWUSR) == -1); ShowRequestFifo = open (fifoPath.c_str(), O_RDONLY | O_NONBLOCK); throw_sys_if (ShowRequestFifo == -1); } catch (...) { #ifdef DEBUG throw; #endif } #endif InitControls(); InitPreferences(); InitTaskBarIcon(); InitEvents(); InitMessageFilter(); InitWindowPrivacy(); if (!GetPreferences().SecurityTokenModule.IsEmpty() && !SecurityToken::IsInitialized()) { try { Gui->InitSecurityTokenLibrary(); } catch (exception &e) { Gui->ShowError (e); } } Connect( wxID_EXIT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainFrame::OnQuit ) ); Connect( wxID_ANY, wxEVT_COMMAND_UPDATE_VOLUME_LIST, wxThreadEventHandler( MainFrame::OnUpdateVolumeList ) ); Connect( wxID_ANY, wxEVT_COMMAND_VOLUME_DISCOVERY_COMPLETED, wxCommandEventHandler( MainFrame::OnVolumeDiscoveryCompleted ) ); Connect( wxID_ANY, wxEVT_COMMAND_PREF_UPDATED, wxCommandEventHandler( MainFrame::OnPreferencesUpdated ) ); Connect( wxID_ANY, wxEVT_COMMAND_OPEN_VOLUME_REQUEST, wxCommandEventHandler( MainFrame::OnOpenVolumeSystemRequest ) ); #ifdef TC_MACOSX Connect( wxID_ANY, wxEVT_MOVE, wxMoveEventHandler( MainFrame::OnMoveHandler ) ); #endif } MainFrame::~MainFrame () { #ifdef TC_MACOSX { ScopeLock lock (VolumeDiscovery->AccessMutex); VolumeDiscovery->NotificationTarget = nullptr; } #endif #if defined(TC_UNIX) && !defined(TC_MACOSX) if (ShowRequestFifo != -1) { try { close (ShowRequestFifo); remove (string (GetShowRequestFifoPath()).c_str()); } catch (...) { } } #endif Disconnect( wxID_EXIT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainFrame::OnQuit ) ); Disconnect( wxID_ANY, wxEVT_COMMAND_UPDATE_VOLUME_LIST, wxThreadEventHandler( MainFrame::OnUpdateVolumeList ) ); Disconnect( wxID_ANY, wxEVT_COMMAND_VOLUME_DISCOVERY_COMPLETED, wxCommandEventHandler( MainFrame::OnVolumeDiscoveryCompleted ) ); Disconnect( wxID_ANY, wxEVT_COMMAND_PREF_UPDATED, wxCommandEventHandler( MainFrame::OnPreferencesUpdated ) ); Disconnect( wxID_ANY, wxEVT_COMMAND_OPEN_VOLUME_REQUEST, wxCommandEventHandler( MainFrame::OnOpenVolumeSystemRequest ) ); #ifdef TC_MACOSX Disconnect( wxID_ANY, wxEVT_MOVE, wxMoveEventHandler( MainFrame::OnMoveHandler ) ); #endif Core->VolumeMountedEvent.Disconnect (this); Core->VolumeDismountedEvent.Disconnect (this); Gui->OpenVolumeSystemRequestEvent.Disconnect (this); Gui->PreferencesUpdatedEvent.Disconnect (this); VolumeHistory::DisconnectComboBox (VolumePathComboBox); #ifdef TC_WINDOWS Hotkey::UnregisterList (this, GetPreferences().Hotkeys); #endif } void MainFrame::AddToFavorites (const VolumeInfoList &volumes) { try { FavoriteVolumeList newFavorites; // Delete duplicates foreach (shared_ptr favorite, FavoriteVolume::LoadList()) { bool mounted = false; foreach_ref (const VolumeInfo &volume, volumes) { if (volume.Path == favorite->Path) { mounted = true; break; } } if (!mounted) newFavorites.push_back (favorite); } size_t newItemCount = 0; foreach_ref (const VolumeInfo &volume, volumes) { newFavorites.push_back (shared_ptr (new FavoriteVolume (volume.Path, volume.MountPoint, volume.SlotNumber, volume.Protection == VolumeProtection::ReadOnly, volume.SystemEncryption))); ++newItemCount; } OrganizeFavorites (newFavorites, newItemCount); } catch (exception &e) { Gui->ShowError (e); } } bool MainFrame::CanExit () const { return Gui->IsTheOnlyTopLevelWindow (this); } void MainFrame::ChangePassword (ChangePasswordDialog::Mode::Enum mode) { if (!CheckVolumePathNotEmpty ()) return; shared_ptr volumePath = GetSelectedVolumePath(); #ifdef TC_WINDOWS if (Core->IsVolumeMounted (*volumePath)) { Gui->ShowInfo (LangString [mode == ChangePasswordDialog::Mode::ChangePkcs5Prf ? "MOUNTED_NO_PKCS5_PRF_CHANGE" : "MOUNTED_NOPWCHANGE"]); return; } #endif #ifdef TC_MACOSX if (Gui->IsInBackgroundMode()) Gui->SetBackgroundMode (false); #endif ChangePasswordDialog dialog (this, volumePath, mode); dialog.ShowModal(); } void MainFrame::CheckFilesystem (bool repair) { shared_ptr selectedVolume = GetSelectedVolume(); if (selectedVolume) { try { #ifdef TC_WINDOWS string mountPoint = selectedVolume->MountPoint; wstring args = StringFormatter (repair ? L"/C echo {0} & chkdsk {1} /F /X & pause" : L"/C echo {0} & chkdsk {1} & pause", StringFormatter (LangString[repair ? "REPAIRING_FS" : "CHECKING_FS"], mountPoint), mountPoint); ShellExecute (static_cast (GetHandle()), L"runas", L"cmd.exe", args.c_str(), nullptr, SW_SHOW); #else # ifdef TC_MACOSX Gui->ShowInfo (LangString[repair ? "MACOSX_REPAIR_FILESYS" : "MACOSX_CHECK_FILESYS"]); # endif Core->CheckFilesystem (selectedVolume, repair); UpdateVolumeList(); #endif } catch (exception &e) { Gui->ShowError (e); } } } bool MainFrame::CheckVolumePathNotEmpty () const { if (VolumePathComboBox->GetValue().empty()) { Gui->ShowInfo ("NO_VOLUME_SELECTED"); return false; } return true; } void MainFrame::DismountVolume (shared_ptr volume) { try { if (!volume) volume = GetSelectedVolume(); if (volume) Gui->DismountVolume (volume); } catch (exception &e) { Gui->ShowError (e); } } bool MainFrame::CanConfirmNoMountedVolumes () const { #ifdef TC_MACOSX // An unacknowledged unconfirmed cleanup must not disappear with the app. return VolumeSnapshot.CanConfirmEmpty (MountedVolumes.empty()) && !Gui->HasUnconfirmedCleanupWarnings(); #else return MountedVolumes.empty(); #endif } shared_ptr MainFrame::GetSelectedVolume () const { #ifdef TC_MACOSX // Keep selection tied to the displayed instance. Core operations validate // its serial and resolve current image ownership again before acting. foreach (shared_ptr volume, MountedVolumes) if (volume->SlotNumber == SelectedSlotNumber) return volume; return shared_ptr (); #else return Core->GetMountedVolume (SelectedSlotNumber); #endif } void MainFrame::InitControls () { LogoBitmap->SetBitmap (Resources::GetLogoBitmap()); list colPermilles; #ifndef TC_WINDOWS SettingsMenu->Remove (HotkeysMenuItem); #endif #ifdef TC_MACOSX SettingsMenu->Remove (PreferencesMenuItem); SettingsMenu->AppendSeparator(); SettingsMenu->Append (PreferencesMenuItem); LowStaticBoxSizer->Detach (HigherButtonSizer); VolumeStaticBoxSizer->Detach (VolumeGridBagSizer); VolumeStaticBoxSizer->Add (VolumeGridBagSizer, 1, wxEXPAND, 0); ExitButton->SetLabel (LangString["IDCLOSE"]); MountAllDevicesButton->SetLabel (LangString["LINUX_MOUNT_ALL_DEV"]); #endif #ifdef TC_WINDOWS SlotListCtrl->InsertColumn (ColumnSlot, LangString["DRIVE"], wxLIST_FORMAT_LEFT, 1); colPermilles.push_back (75); #else SlotListCtrl->InsertColumn (ColumnSlot, LangString["TOKEN_SLOT_ID"], wxLIST_FORMAT_LEFT, 1); colPermilles.push_back (82); #endif SlotListCtrl->InsertColumn (ColumnPath, LangString["VOLUME"], wxLIST_FORMAT_LEFT, 1); #ifdef TC_WINDOWS colPermilles.push_back (487); #else colPermilles.push_back (429); #endif SlotListCtrl->InsertColumn (ColumnSize, LangString["SIZE"], wxLIST_FORMAT_RIGHT, 1); #ifdef TC_WINDOWS colPermilles.push_back (126); #else colPermilles.push_back (130); #endif #ifdef TC_WINDOWS SlotListCtrl->InsertColumn (ColumnEA, LangString["ENCRYPTION_ALGORITHM_LV"], wxLIST_FORMAT_LEFT, 1); colPermilles.push_back (233); #else SlotListCtrl->InsertColumn (ColumnMountPoint, LangString["MOUNT_POINT"], wxLIST_FORMAT_LEFT, 1); colPermilles.push_back (259); #endif SlotListCtrl->InsertColumn (ColumnType, LangString["TYPE"], wxLIST_FORMAT_LEFT, 1); colPermilles.push_back (100); wxImageList *imageList = new wxImageList (16, 12, true); imageList->Add (Resources::GetDriveIconBitmap(), Resources::GetDriveIconMaskBitmap()); SlotListCtrl->AssignImageList (imageList, wxIMAGE_LIST_SMALL); SetMinSize (wxSize (-1, -1)); size_t slotListRowCount = 12; #ifndef TC_WINDOWS int screenHeight = wxSystemSettings::GetMetric (wxSYS_SCREEN_Y); if (screenHeight < 480) slotListRowCount = 1; else if (screenHeight <= 600) slotListRowCount = slotListRowCount * screenHeight / 1000; #endif Gui->SetListCtrlHeight (SlotListCtrl, slotListRowCount); #ifdef __WXGTK__ wxSize size (-1, (int) ((double) Gui->GetCharHeight (this) * 1.53)); CreateVolumeButton->SetMinSize (size); VolumePropertiesButton->SetMinSize (size); WipeCacheButton->SetMinSize (size); VolumePathComboBox->SetMinSize (size); SelectFileButton->SetMinSize (size); SelectDeviceButton->SetMinSize (size); VolumeToolsButton->SetMinSize (size); size = wxSize (-1, 38); VolumeButton->SetMinSize (size); #endif Fit(); Layout(); Center(); VolumePathComboBox->SetMinSize (VolumePathComboBox->GetSize()); VolumePathComboBox->SetMaxSize (VolumePathComboBox->GetSize()); SetMinSize (GetSize()); SetMaxSize (GetSize()); Gui->SetListCtrlColumnWidths (SlotListCtrl, colPermilles); UpdateVolumeList(); UpdateWipeCacheButton(); } void MainFrame::InitEvents () { Core->VolumeMountedEvent.Connect (EventConnector (this, &MainFrame::OnVolumeMounted)); Core->VolumeDismountedEvent.Connect (EventConnector (this, &MainFrame::OnVolumeDismounted)); Gui->OpenVolumeSystemRequestEvent.Connect (EventConnector (this, &MainFrame::OnOpenVolumeSystemRequestEvent)); Gui->PreferencesUpdatedEvent.Connect (EventConnector (this, &MainFrame::OnPreferencesUpdatedEvent)); // Drag & drop class FileDropTarget : public wxFileDropTarget { public: FileDropTarget (MainFrame *frame) : Frame (frame) { } wxDragResult OnDragOver (wxCoord x, wxCoord y, wxDragResult def) { wxPoint p; wxWindow *w = wxFindWindowAtPointer (p); if (w == Frame || wxGetTopLevelParent (w) == Frame) return wxDragLink; return wxDragNone; } bool OnDropFiles (wxCoord x, wxCoord y, const wxArrayString &filenames) { if (!filenames.empty()) Frame->SetVolumePath (wstring (filenames.front())); return true; } MainFrame *Frame; }; SetDropTarget (new FileDropTarget (this)); foreach (wxWindow *c, MainPanel->GetChildren()) c->SetDropTarget (new FileDropTarget (this)); // Volume history VolumeHistory::ConnectComboBox (VolumePathComboBox); #ifdef TC_WINDOWS // Hotkeys Hotkey::RegisterList (this, GetPreferences().Hotkeys); Connect (wxEVT_HOTKEY, wxKeyEventHandler (MainFrame::OnHotkey)); #endif // Timer class Timer : public wxTimer { public: Timer (MainFrame *frame) : Frame (frame) { } void Notify() { Frame->OnTimer(); } MainFrame *Frame; }; mTimer.reset (dynamic_cast (new Timer (this))); mTimer->Start (2000); } #ifdef TC_WINDOWS #include static WNDPROC MainFrameWndProc; static LRESULT CALLBACK MainFrameWndProcFilter (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { if (message == WM_DEVICECHANGE && !Core->IsDeviceChangeInProgress()) { MainFrame *frame = dynamic_cast (Gui->GetMainFrame()); PDEV_BROADCAST_HDR hdr = (PDEV_BROADCAST_HDR) lParam; if (wParam == DBT_DEVICEREMOVECOMPLETE && hdr->dbch_devicetype == DBT_DEVTYP_VOLUME) { PDEV_BROADCAST_VOLUME vol = (PDEV_BROADCAST_VOLUME) lParam; for (wchar_t driveNo = 0; driveNo < 26; ++driveNo) { if (vol->dbcv_unitmask & (1 << driveNo)) frame->OnDeviceChange (wstring (StringFormatter (L"{0}:\\", wchar_t (L'A' + driveNo)))); } } else { frame->OnDeviceChange (); } } return CallWindowProc (MainFrameWndProc, hwnd, message, wParam, lParam); } #endif void MainFrame::InitMessageFilter () { #ifdef TC_WINDOWS HWND mainFrameHwnd = static_cast (GetHandle()); MainFrameWndProc = (WNDPROC) GetWindowLongPtr (mainFrameHwnd, GWL_WNDPROC); SetWindowLongPtr (mainFrameHwnd, GWL_WNDPROC, (LONG_PTR) MainFrameWndProcFilter); #endif } void MainFrame::InitWindowPrivacy () { bool enableContentProtection = !CmdLine->ArgAllowScreencapture; #ifdef TC_MACOSX enableContentProtection = enableContentProtection && !GetPreferences().DisableScreenProtection; #endif Gui->SetContentProtection (enableContentProtection); } void MainFrame::InitPreferences () { try { LoadPreferences(); VolumeSlotNumber lastSelectedSlotNumber = GetPreferences().LastSelectedSlotNumber; if (Core->IsSlotNumberValid (lastSelectedSlotNumber)) { long slotIndex = SlotNumberToItemIndex (lastSelectedSlotNumber); if (slotIndex >= 0) { SlotListCtrl->SetItemState (slotIndex, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); SlotListCtrl->EnsureVisible (slotIndex); } } LoadFavoriteVolumes(); VolumeHistory::Load(); if (VolumePathComboBox->GetValue().empty() && !VolumeHistory::Get().empty()) SetVolumePath (VolumeHistory::Get().front()); } catch (exception &e) { Gui->ShowError (e); Gui->ShowError (LangString["LINUX_ERROR_LOADING_CONFIG"] + wstring (Application::GetConfigFilePath (L""))); } } void MainFrame::InitTaskBarIcon () { class TaskBarIcon : public wxTaskBarIcon { public: TaskBarIcon (MainFrame *frame) : Busy (false), Frame (frame) { Connect (wxEVT_TASKBAR_LEFT_DOWN, wxTaskBarIconEventHandler (TaskBarIcon::OnLeftButtonDown)); } wxMenu *CreatePopupMenu () { unique_ptr popup (new wxMenu); const bool operationsEnabled = !Busy && !Gui->GetWaitDialog(); Gui->AppendToMenu (*popup, LangString[Gui->IsInBackgroundMode() ? "SHOW_TC" : "HIDE_TC"], this, wxCommandEventHandler (TaskBarIcon::OnShowHideMenuItemSelected)); popup->AppendSeparator(); Gui->AppendToMenu (*popup, LangString["IDM_MOUNT_FAVORITE_VOLUMES"], this, wxCommandEventHandler (TaskBarIcon::OnMountAllFavoritesMenuItemSelected))->Enable (operationsEnabled); Gui->AppendToMenu (*popup, LangString["HK_UNMOUNT_ALL"], this, wxCommandEventHandler (TaskBarIcon::OnDismountAllMenuItemSelected))->Enable (operationsEnabled); // Favorite volumes if (Gui->GetPreferences().BackgroundTaskMenuMountItemsEnabled && !Frame->FavoriteVolumesMenuMap.empty()) { popup->AppendSeparator(); typedef pair FavMapPair; foreach (FavMapPair fp, Frame->FavoriteVolumesMenuMap) { //TBH Gui->AppendToMenu (*popup, LangString["MOUNT"] + L" " + wstring (fp.second.Path) + (fp.second.MountPoint.IsEmpty() ? L"" : L" " + wstring (fp.second.MountPoint)), Gui->AppendToMenu (*popup, LangString["MOUNT_BUTTON"] + L" " + wstring (fp.second.Path) + (fp.second.MountPoint.IsEmpty() ? L"" : L" " + wstring (fp.second.MountPoint)), this, wxCommandEventHandler (TaskBarIcon::OnFavoriteVolumeMenuItemSelected), fp.first)->Enable (operationsEnabled); } } // Mounted volumes VolumeInfoList mountedVolumes = Gui->GetMountedVolumesForUI(); if (!mountedVolumes.empty()) { if (Gui->GetPreferences().BackgroundTaskMenuOpenItemsEnabled) { popup->AppendSeparator(); OpenMap.clear(); foreach (shared_ptr volume, mountedVolumes) { if (!volume->MountPoint.IsEmpty()) { wxString label = LangString["OPEN"] + L" " + wstring (volume->MountPoint) + L" (" + wstring (volume->Path) + L")"; wxMenuItem *item = Gui->AppendToMenu (*popup, label, this, wxCommandEventHandler (TaskBarIcon::OnOpenMenuItemSelected)); OpenMap[item->GetId()] = volume; } } } if (Gui->GetPreferences().BackgroundTaskMenuDismountItemsEnabled) { popup->AppendSeparator(); DismountMap.clear(); foreach (shared_ptr volume, mountedVolumes) { wxString label = LangString["UNMOUNT"] + L" "; if (!volume->MountPoint.IsEmpty()) label += wstring (volume->MountPoint) + L" (" + wstring (volume->Path) + L")"; else label += wstring (volume->Path); wxMenuItem *item = Gui->AppendToMenu (*popup, label, this, wxCommandEventHandler (TaskBarIcon::OnDismountMenuItemSelected)); item->Enable (operationsEnabled); DismountMap[item->GetId()] = volume; } } } popup->AppendSeparator(); Gui->AppendToMenu (*popup, LangString["IDM_PREFERENCES"], this, wxCommandEventHandler (TaskBarIcon::OnPreferencesMenuItemSelected))->Enable (operationsEnabled); #ifndef TC_MACOSX popup->AppendSeparator(); Gui->AppendToMenu (*popup, LangString["EXIT"], this, wxCommandEventHandler (TaskBarIcon::OnExitMenuItemSelected))->Enable (!Busy && Frame->CanExit()); #endif return popup.release(); } void OnDismountAllMenuItemSelected (wxCommandEvent& event) { Busy = true; Frame->OnDismountAllButtonClick (event); Busy = false; } void OnDismountMenuItemSelected (wxCommandEvent& event) { Busy = true; Frame->DismountVolume (DismountMap[event.GetId()]); Busy = false; } void OnFavoriteVolumeMenuItemSelected (wxCommandEvent& event) { Busy = true; Frame->OnFavoriteVolumeMenuItemSelected (event); Busy = false; } void OnMountAllFavoritesMenuItemSelected (wxCommandEvent& event) { Busy = true; Frame->MountAllFavorites (); Busy = false; } void OnExitMenuItemSelected (wxCommandEvent& event) { Busy = true; if (Core->GetMountedVolumes().empty() || Gui->AskYesNo (LangString ["CONFIRM_EXIT"], false, true)) Frame->Close (true); Busy = false; } void OnLeftButtonDown (wxTaskBarIconEvent& event) { Gui->SetBackgroundMode (false); } void OnOpenMenuItemSelected (wxCommandEvent& event) { Gui->OpenExplorerWindow (OpenMap[event.GetId()]->MountPoint); } void OnPreferencesMenuItemSelected (wxCommandEvent& event) { Busy = true; Frame->OnPreferencesMenuItemSelected (event); Busy = false; } void OnShowHideMenuItemSelected (wxCommandEvent& event) { Gui->SetBackgroundMode (!Gui->IsInBackgroundMode()); } bool Busy; map < int, shared_ptr > DismountMap; MainFrame *Frame; map < int, shared_ptr > OpenMap; }; mTaskBarIcon.reset (new TaskBarIcon (this)); ShowTaskBarIcon (GetPreferences().BackgroundTaskEnabled); } void MainFrame::LoadFavoriteVolumes () { typedef pair FavMapPair; foreach (FavMapPair p, FavoriteVolumesMenuMap) { FavoritesMenu->Delete (p.first); } FavoriteVolumesMenuMap.clear(); foreach_ref (const FavoriteVolume &favorite, FavoriteVolume::LoadList()) { wstring label = wstring (favorite.Path); if (!favorite.MountPoint.IsEmpty()) label += wstring (L" ") + wstring (favorite.MountPoint); wxMenuItem *item = Gui->AppendToMenu (*FavoritesMenu, label, this, wxCommandEventHandler (MainFrame::OnFavoriteVolumeMenuItemSelected)); FavoriteVolumesMenuMap[item->GetId()] = favorite; } } void MainFrame::LoadPreferences () { UserPreferences prefs; prefs.Load(); Gui->SetPreferences (prefs); NoHistoryCheckBox->SetValue (!prefs.SaveHistory); } void MainFrame::MountAllDevices () { try { MountOptions mountOptions (GetPreferences().DefaultMountOptions); if (CmdLine->ArgHash) { mountOptions.Kdf = CmdLine->ArgHash; } if (CmdLine->ArgPim > 0) { mountOptions.Pim = CmdLine->ArgPim; } if (SlotListCtrl->GetSelectedItemCount() == 1) mountOptions.SlotNumber = SelectedSlotNumber; Gui->MountAllDeviceHostedVolumes (mountOptions); } catch (exception &e) { Gui->ShowError (e); } } void MainFrame::MountAllFavorites () { try { MountOptions mountOptions (GetPreferences().DefaultMountOptions); if (CmdLine->ArgHash) { mountOptions.Kdf = CmdLine->ArgHash; } if (CmdLine->ArgPim > 0) { mountOptions.Pim = CmdLine->ArgPim; } mountOptions.EMVSupportEnabled = GetPreferences().EMVSupportEnabled; Gui->MountAllFavoriteVolumes (mountOptions); } catch (exception &e) { Gui->ShowError (e); } } void MainFrame::MountVolume () { if (!IsFreeSlotSelected()) { Gui->ShowWarning (LangString["LINUX_SELECT_FREE_SLOT"]); return; } if (!CheckVolumePathNotEmpty()) return; MountOptions mountOptions (GetPreferences().DefaultMountOptions); mountOptions.SlotNumber = SelectedSlotNumber; mountOptions.Path = GetSelectedVolumePath(); if (CmdLine->ArgHash) { mountOptions.Kdf = CmdLine->ArgHash; } if (CmdLine->ArgPim > 0) { mountOptions.Pim = CmdLine->ArgPim; } mountOptions.EMVSupportEnabled = GetPreferences().EMVSupportEnabled; try { if (Gui->MountVolume (mountOptions) && GetPreferences().SaveHistory) VolumeHistory::Add (*mountOptions.Path); } catch (exception &e) { Gui->ShowError (e); } } void MainFrame::OnAboutMenuItemSelected (wxCommandEvent& event) { #ifdef TC_MACOSX if (Gui->IsInBackgroundMode()) Gui->SetBackgroundMode (false); EnsureVisible (); #endif AboutDialog dialog (this); dialog.ShowModal(); } void MainFrame::OnActivate (wxActivateEvent& event) { Gui->SetActiveFrame (this); #ifdef TC_MACOSX if (event.GetActive() && Gui->IsInBackgroundMode()) Gui->SetBackgroundMode (false); EnsureVisible(); #endif event.Skip(); } void MainFrame::OnAddAllMountedToFavoritesMenuItemSelected (wxCommandEvent& event) { AddToFavorites (MountedVolumes); } void MainFrame::OnAddToFavoritesMenuItemSelected (wxCommandEvent& event) { shared_ptr selectedVolume = GetSelectedVolume(); if (selectedVolume) { VolumeInfoList volumes; volumes.push_back (selectedVolume); AddToFavorites (volumes); } } void MainFrame::OnBackupVolumeHeadersMenuItemSelected (wxCommandEvent& event) { if (!CheckVolumePathNotEmpty ()) return; try { Gui->BackupVolumeHeaders (GetSelectedVolumePath()); } catch (exception &e) { Gui->ShowError (e); } } void MainFrame::OnBenchmarkMenuItemSelected (wxCommandEvent& event) { #ifdef TC_MACOSX if (Gui->IsInBackgroundMode()) Gui->SetBackgroundMode (false); #endif BenchmarkDialog dialog (this); dialog.ShowModal(); } void MainFrame::OnClearSlotSelectionMenuItemSelected (wxCommandEvent& event) { Gui->ClearListCtrlSelection (SlotListCtrl); UpdateControls(); } void MainFrame::OnClose (wxCloseEvent& event) { // Do not start another core operation from a nested wait event loop. if (Gui->GetWaitDialog()) { if (event.CanVeto()) event.Veto(); return; } if (GetPreferences().WipeCacheOnClose) Core->WipePasswordCache(); #ifdef TC_MACOSX if (!event.CanVeto() && GetPreferences().DismountOnLogOff) { try { Gui->OnLogOff(); } catch (exception &e) { SystemLog::WriteException (e); } catch (...) { SystemLog::WriteException (UnknownException (SRC_POS)); } } #endif if (!Gui->IsTheOnlyTopLevelWindow (this)) { // Bring first frame to foreground wxFrame *frame = nullptr; foreach (wxWindow *window, wxTopLevelWindows) { if (window != this && dynamic_cast (window) && StringConverter::GetTypeName (typeid (*window)).find ("wxTaskBarIcon") == string::npos) { frame = dynamic_cast (window); if (window->IsShown()) break; } } if (frame) { frame->Show(); if (frame->IsIconized()) frame->Iconize(false); frame->Raise(); } } else if (event.CanVeto() && GetPreferences().BackgroundTaskEnabled && (!GetPreferences().CloseBackgroundTaskOnNoVolumes || !CanConfirmNoMountedVolumes())) { // Enter background mode if (!Gui->IsInBackgroundMode()) Gui->SetBackgroundMode (true); } else { #ifdef __WXGTK__ Show(); #endif SavePreferences(); Destroy(); } // Cancel close - veto is not used to prevent aborting log off procedure on Windows return; } void MainFrame::OnCloseAllSecurityTokenSessionsMenuItemSelected (wxCommandEvent& event) { try { { wxBusyCursor busy; SecurityToken::CloseAllSessions(); } Gui->ShowInfo ("ALL_TOKEN_SESSIONS_CLOSED"); } catch (exception &e) { Gui->ShowError (e); } } void MainFrame::OnCreateVolumeButtonClick (wxCommandEvent& event) { try { (new VolumeCreationWizard (nullptr))->Show(); } catch (exception &e) { Gui->ShowError (e); } } void MainFrame::OnDefaultKeyfilesMenuItemSelected (wxCommandEvent& event) { #ifdef TC_MACOSX if (Gui->IsInBackgroundMode()) Gui->SetBackgroundMode (false); #endif PreferencesDialog dialog (this); dialog.SelectPage (dialog.DefaultKeyfilesPage); dialog.ShowModal(); } void MainFrame::OnDefaultMountParametersMenuItemSelected(wxCommandEvent& event) { #ifdef TC_MACOSX if (Gui->IsInBackgroundMode()) Gui->SetBackgroundMode (false); #endif PreferencesDialog dialog (this); dialog.SelectPage (dialog.DefaultMountOptionsPage); dialog.ShowModal(); } void MainFrame::OnDeviceChange (const DirectoryPath &mountPoint) { // Check if any host device has been removed and force dismount of volumes accordingly VolumeInfoList removedVolumes; foreach (shared_ptr volume, Core->GetMountedVolumes()) { // File-hosted volumes if (!volume->Path.IsDevice() && !mountPoint.IsEmpty()) { if (wxString (wstring(volume->Path)).Upper().StartsWith (wstring (mountPoint).c_str())) { removedVolumes.push_back (volume); continue; } } // Device-hosted volumes if (volume->Path.IsDevice() && !Core->IsDevicePresent (volume->Path)) removedVolumes.push_back (volume); } if (!removedVolumes.empty()) Gui->AutoDismountVolumes (removedVolumes, true); } void MainFrame::OnDismountAllButtonClick (wxCommandEvent& event) { Gui->DismountAllVolumes(); } void MainFrame::OnEncryptionTestMenuItemSelected (wxCommandEvent& event) { #ifdef TC_MACOSX if (Gui->IsInBackgroundMode()) Gui->SetBackgroundMode (false); #endif EncryptionTestDialog dialog (this); dialog.ShowModal(); } void MainFrame::OnExitButtonClick (wxCommandEvent& event) { Close(); } void MainFrame::OnFavoriteVolumeMenuItemSelected (wxCommandEvent& event) { FavoriteVolume favorite = FavoriteVolumesMenuMap[event.GetId()]; if (!favorite.Path.IsEmpty()) { SetVolumePath (favorite.Path); MountOptions mountOptions (GetPreferences().DefaultMountOptions); if (CmdLine->ArgHash) { mountOptions.Kdf = CmdLine->ArgHash; } if (CmdLine->ArgPim > 0) { mountOptions.Pim = CmdLine->ArgPim; } favorite.ToMountOptions (mountOptions); shared_ptr volume = Gui->MountVolume (mountOptions); if (volume) SlotListCtrl->EnsureVisible (SlotNumberToItemIndex (volume->SlotNumber)); } } void MainFrame::OnHiddenVolumeProtectionTriggered (shared_ptr protectedVolume) { Gui->ShowWarningTopMost (StringFormatter (LangString["DAMAGE_TO_HIDDEN_VOLUME_PREVENTED"], wstring (protectedVolume->Path))); } void MainFrame::OnHotkey (wxKeyEvent& event) { #ifdef TC_WINDOWS switch (event.GetId()) { case Hotkey::Id::CloseAllSecurityTokenSessions: try { SecurityToken::CloseAllSessions(); Gui->ShowInfo ("ALL_TOKEN_SESSIONS_CLOSED"); } catch (exception &e) { Gui->ShowError (e); } break; case Hotkey::Id::DismountAll: case Hotkey::Id::DismountAllWipeCache: { if (event.GetId() == Hotkey::Id::DismountAllWipeCache) WipeCache(); size_t mountedCount = Core->GetMountedVolumes().size(); Gui->DismountAllVolumes(); size_t newMountedCount = Core->GetMountedVolumes().size(); if (newMountedCount < mountedCount) { if (newMountedCount == 0 && GetPreferences().DisplayMessageAfterHotkeyDismount) Gui->ShowInfo ("MOUNTED_VOLUMES_UNMOUNTED"); else if (GetPreferences().BeepAfterHotkeyMountDismount) MessageBeep((UINT) -1); } } break; case Hotkey::Id::ForceDismountAllWipeCache: case Hotkey::Id::ForceDismountAllWipeCacheExit: { bool mounted = !Core->GetMountedVolumes().empty(); WipeCache(); Gui->DismountAllVolumes (true, true); if (mounted && GetPreferences().DisplayMessageAfterHotkeyDismount) Gui->ShowInfo ("VOLUMES_UNMOUNTED_CACHE_WIPED"); else if (mounted && GetPreferences().BeepAfterHotkeyMountDismount) MessageBeep((UINT) -1); if (event.GetId() == Hotkey::Id::ForceDismountAllWipeCacheExit) Close (true); } break; case Hotkey::Id::MountAllDevices: case Hotkey::Id::MountAllFavorites: { size_t mountedCount = Core->GetMountedVolumes().size(); if (event.GetId() == Hotkey::Id::MountAllDevices) MountAllDevices(); else MountAllFavorites(); if (Core->GetMountedVolumes().size() > mountedCount && GetPreferences().BeepAfterHotkeyMountDismount) MessageBeep((UINT) -1); } break; case Hotkey::Id::ShowHideApplication: Gui->SetBackgroundMode (!Gui->IsInBackgroundMode()); break; case Hotkey::Id::WipeCache: WipeCache(); Gui->ShowInfo ("PASSWORD_CACHE_WIPED"); break; default: assert (false); break; } #endif // TC_WINDOWS } void MainFrame::OnHotkeysMenuItemSelected (wxCommandEvent& event) { #ifdef TC_MACOSX if (Gui->IsInBackgroundMode()) Gui->SetBackgroundMode (false); #endif PreferencesDialog dialog (this); dialog.SelectPage (dialog.HotkeysPage); dialog.ShowModal(); } void MainFrame::OnLanguageMenuItemSelected (wxCommandEvent& event) { #ifdef TC_MACOSX if (Gui->IsInBackgroundMode()) Gui->SetBackgroundMode (false); #endif PreferencesDialog dialog (this); dialog.SelectPage (dialog.LanguagesPage); dialog.ShowModal(); } void MainFrame::OnLegalNoticesMenuItemSelected (wxCommandEvent& event) { #ifdef TC_MACOSX if (Gui->IsInBackgroundMode()) Gui->SetBackgroundMode (false); #endif LegalNoticesDialog dialog (this); dialog.ShowModal(); } void MainFrame::OnListChanged () { OnListItemSelectionChanged(); UpdateControls(); } void MainFrame::OnListItemActivated (wxListEvent& event) { if (IsMountedSlotSelected()) OpenSelectedVolume(); else MountVolume(); } void MainFrame::OnListItemDeleted (long itemIndex) { if (SelectedItemIndex > itemIndex) --SelectedItemIndex; } void MainFrame::OnListItemDeselected (wxListEvent& event) { OnListItemSelectionChanged(); } void MainFrame::OnListItemInserted (long itemIndex) { if (SelectedItemIndex >= itemIndex) ++SelectedItemIndex; } void MainFrame::OnListItemRightClick (wxListEvent& event) { #ifdef TC_MACOSX if (SelectedItemIndex != event.GetIndex()) { SelectedItemIndex = event.GetIndex(); OnListItemSelectionChanged(); } if (!ListItemRightClickEventPending) { ListItemRightClickEventPending = true; SlotListCtrl->GetEventHandler()->AddPendingEvent (event); return; } ListItemRightClickEventPending = false; #endif wxMenu popup; if (IsMountedSlotSelected()) { Gui->AppendToMenu (popup, LangString["UNMOUNT"], this, wxCommandEventHandler (MainFrame::OnDismountVolumeMenuItemSelected)); Gui->AppendToMenu (popup, LangString["OPEN"], this, wxCommandEventHandler (MainFrame::OnOpenVolumeMenuItemSelected)); Gui->AppendToMenu (popup, LangString["LINUX_DESELECT"], this, wxCommandEventHandler (MainFrame::OnClearSlotSelectionMenuItemSelected)); popup.AppendSeparator(); Gui->AppendToMenu (popup, LangString["IDPM_ADD_TO_FAVORITES"], this, wxCommandEventHandler (MainFrame::OnAddToFavoritesMenuItemSelected)); popup.AppendSeparator(); Gui->AppendToMenu (popup, LangString["IDPM_CHECK_FILESYS"], this, wxCommandEventHandler (MainFrame::OnCheckFilesystemMenuItemSelected)); Gui->AppendToMenu (popup, LangString["IDPM_REPAIR_FILESYS"], this, wxCommandEventHandler (MainFrame::OnRepairFilesystemMenuItemSelected)); popup.AppendSeparator(); Gui->AppendToMenu (popup, LangString["IDPM_PROPERTIES"], this, wxCommandEventHandler (MainFrame::OnVolumePropertiesButtonClick)); PopupMenu (&popup); } else if (IsFreeSlotSelected()) { Gui->AppendToMenu (popup, LangString["IDM_MOUNT_VOLUME"], this, wxCommandEventHandler (MainFrame::OnMountVolumeMenuItemSelected)); popup.AppendSeparator(); Gui->AppendToMenu (popup, LangString["SELECT_FILE_AND_MOUNT"], this, wxCommandEventHandler (MainFrame::OnSelectFileAndMountMenuItemSelected)); Gui->AppendToMenu (popup, LangString["SELECT_DEVICE_AND_MOUNT"], this, wxCommandEventHandler (MainFrame::OnSelectDeviceAndMountMenuItemSelected)); popup.AppendSeparator(); Gui->AppendToMenu (popup, LangString["LINUX_DESELECT"], this, wxCommandEventHandler (MainFrame::OnClearSlotSelectionMenuItemSelected)); PopupMenu (&popup); } } void MainFrame::OnListItemSelected (wxListEvent& event) { SelectedItemIndex = event.GetIndex(); OnListItemSelectionChanged(); } void MainFrame::OnListItemSelectionChanged () { if (SlotListCtrl->GetSelectedItemCount() < 1) SelectedItemIndex = -1; if (SelectedItemIndex >= 0) SelectedSlotNumber = (VolumeSlotNumber) SlotListCtrl->GetItemData (SelectedItemIndex); else SelectedSlotNumber = 0; UpdateControls(); } void MainFrame::OnManageSecurityTokenKeyfilesMenuItemSelected (wxCommandEvent& event) { try { #ifdef TC_MACOSX if (Gui->IsInBackgroundMode()) Gui->SetBackgroundMode (false); #endif SecurityTokenKeyfilesDialog dialog (this, false); dialog.ShowModal(); } catch (exception &e) { Gui->ShowError (e); } } void MainFrame::OnMountAllDevicesButtonClick (wxCommandEvent& event) { MountAllDevices(); } void MainFrame::OnMountAllFavoritesMenuItemSelected (wxCommandEvent& event) { MountAllFavorites(); } void MainFrame::OnNoHistoryCheckBoxClick (wxCommandEvent& event) { UserPreferences prefs = GetPreferences(); prefs.SaveHistory = !event.IsChecked(); Gui->SetPreferences (prefs); if (event.IsChecked()) { try { VolumeHistory::Clear(); } catch (exception &e) { Gui->ShowError (e); } } } void MainFrame::OnOrganizeFavoritesMenuItemSelected (wxCommandEvent& event) { try { OrganizeFavorites (FavoriteVolume::LoadList()); } catch (exception &e) { Gui->ShowError (e); } } void MainFrame::OnPreferencesMenuItemSelected (wxCommandEvent& event) { #ifdef TC_MACOSX if (Gui->IsInBackgroundMode()) Gui->SetBackgroundMode (false); #endif PreferencesDialog dialog (this); dialog.ShowModal(); } void MainFrame::OnOpenVolumeSystemRequest (wxCommandEvent& event) { wstring* eventPath = (wstring*) event.GetClientData(); SetVolumePath (*eventPath); delete eventPath; } void MainFrame::OnOpenVolumeSystemRequestEvent (EventArgs &args) { wstring* eventPath = new wstring (dynamic_cast (args).mVolumePath); wxCommandEvent* pEvent = new wxCommandEvent( wxEVT_COMMAND_OPEN_VOLUME_REQUEST,0); pEvent->SetClientData(eventPath); wxQueueEvent (this, pEvent); } void MainFrame::OnPreferencesUpdated (wxCommandEvent& event) { const UserPreferences &prefs = GetPreferences(); NoHistoryCheckBox->SetValue (!prefs.SaveHistory); ShowTaskBarIcon (prefs.BackgroundTaskEnabled); if (Gui->IsInBackgroundMode() && !prefs.BackgroundTaskEnabled) Close (true); InitWindowPrivacy(); SavePreferences(); } void MainFrame::OnRestoreVolumeHeaderMenuItemSelected (wxCommandEvent& event) { if (!CheckVolumePathNotEmpty ()) return; try { Gui->RestoreVolumeHeaders (GetSelectedVolumePath()); } catch (exception &e) { Gui->ShowError (e); } } void MainFrame::OnSecurityTokenPreferencesMenuItemSelected (wxCommandEvent& event) { #ifdef TC_MACOSX if (Gui->IsInBackgroundMode()) Gui->SetBackgroundMode (false); #endif PreferencesDialog dialog (this); dialog.SelectPage (dialog.SecurityTokensPage); dialog.ShowModal(); } void MainFrame::OnSelectDeviceAndMountMenuItemSelected (wxCommandEvent& event) { DevicePath path = Gui->SelectDevice (this); if (!path.IsEmpty()) { SetVolumePath (path); OnMountVolumeMenuItemSelected (event); } } void MainFrame::OnSelectDeviceButtonClick (wxCommandEvent& event) { DevicePath path = Gui->SelectDevice (this); if (!path.IsEmpty()) SetVolumePath (path); } void MainFrame::OnSelectFileAndMountMenuItemSelected (wxCommandEvent& event) { FilePath path = Gui->SelectVolumeFile (this); if (!path.IsEmpty()) { SetVolumePath (path); OnMountVolumeMenuItemSelected (event); } } void MainFrame::OnSelectFileButtonClick (wxCommandEvent& event) { FilePath path = Gui->SelectVolumeFile (this); if (!path.IsEmpty()) SetVolumePath (path); } void MainFrame::OnTimer () { try { UpdateVolumeList(); UpdateWipeCacheButton(); if (GetPreferences().BackgroundTaskEnabled && !Gui->GetWaitDialog()) { // Inactivity auto-dismount if (GetPreferences().DismountOnInactivity #ifdef TC_MACOSX && VolumeSnapshot.IsFresh() #endif ) { VolumeInfoList inactiveVolumes; #ifdef TC_MACOSX wxLongLong currentTime = chrono::duration_cast (chrono::steady_clock::now().time_since_epoch()).count(); #else wxLongLong currentTime = wxGetLocalTimeMillis().GetValue(); #endif map newActivityTimeMap; foreach (shared_ptr volume, MountedVolumes) { #ifdef TC_MACOSX // A retained entry has no current counters. Keep its idle state until // they can be read again: unchanged cumulative counters prove idleness. if (volume->Discovery == VolumeInfo::ControlUnavailable) { map ::const_iterator entry = VolumeActivityMap.find (volume->Path); if (entry != VolumeActivityMap.end() && entry->second.SerialInstanceNumber == volume->SerialInstanceNumber) newActivityTimeMap[volume->Path] = entry->second; continue; } #endif if (VolumeActivityMap.find (volume->Path) != VolumeActivityMap.end() && VolumeActivityMap[volume->Path].SerialInstanceNumber == volume->SerialInstanceNumber) { VolumeActivityMapEntry ae = VolumeActivityMap[volume->Path]; if (volume->TotalDataRead != ae.TotalDataRead || volume->TotalDataWritten != ae.TotalDataWritten) { ae.LastActivityTime = currentTime; ae.TotalDataRead = volume->TotalDataRead; ae.TotalDataWritten = volume->TotalDataWritten; } else if ((currentTime - ae.LastActivityTime) > GetPreferences().MaxVolumeIdleTime * 1000LL * 60) { inactiveVolumes.push_back (volume); } newActivityTimeMap[volume->Path] = ae; } else { newActivityTimeMap[volume->Path] = VolumeActivityMapEntry (*volume, currentTime); } } VolumeActivityMap = newActivityTimeMap; if (!inactiveVolumes.empty()) Gui->AutoDismountVolumes (inactiveVolumes); } // Screen saver auto-dismount if (GetPreferences().DismountOnScreenSaver) { #ifdef TC_WINDOWS bool running; if (SystemParametersInfo (SPI_GETSCREENSAVERRUNNING, 0, &running, 0) != 0) { static bool previousState = false; if (running && !previousState) { previousState = true; Gui->OnAutoDismountAllEvent(); } else { previousState = running; } } #endif } } if (Gui->IsInBackgroundMode()) { if (!GetPreferences().BackgroundTaskEnabled) { Close (true); } else if (CanConfirmNoMountedVolumes() && (GetPreferences().CloseBackgroundTaskOnNoVolumes || Core->IsInPortableMode())) { Close (true); } } #if defined(TC_UNIX) && !defined(TC_MACOSX) try { uint8 buf[128]; if (read (ShowRequestFifo, buf, sizeof (buf)) > 0) Gui->SetBackgroundMode (false); } catch (...) { #ifdef DEBUG throw; #endif } #endif } catch (exception &e) { Gui->ShowError (e); } } void MainFrame::OnVolumeButtonClick (wxCommandEvent& event) { if (IsMountedSlotSelected()) DismountVolume(); else MountVolume(); } void MainFrame::OnVolumePropertiesButtonClick (wxCommandEvent& event) { shared_ptr selectedVolume = GetSelectedVolume(); if (selectedVolume) { #ifdef TC_MACOSX if (Gui->IsInBackgroundMode()) Gui->SetBackgroundMode (false); #endif VolumePropertiesDialog dialog (this, *selectedVolume); dialog.ShowModal(); } } void MainFrame::OnVolumeToolsButtonClick (wxCommandEvent& event) { if (!CheckVolumePathNotEmpty()) return; wxMenu popup; Gui->AppendToMenu (popup, LangString["IDM_CHANGE_PASSWORD"], this, wxCommandEventHandler (MainFrame::OnChangePasswordMenuItemSelected)); popup.AppendSeparator (); Gui->AppendToMenu (popup, LangString["IDM_ADD_REMOVE_VOL_KEYFILES"], this, wxCommandEventHandler (MainFrame::OnChangeKeyfilesMenuItemSelected)); Gui->AppendToMenu (popup, LangString["IDM_REMOVE_ALL_KEYFILES_FROM_VOL"], this, wxCommandEventHandler (MainFrame::OnRemoveKeyfilesMenuItemSelected)); popup.AppendSeparator (); Gui->AppendToMenu (popup, LangString["IDM_CHANGE_SYS_HEADER_KEY_DERIV_ALGO"], this, wxCommandEventHandler (MainFrame::OnChangePkcs5PrfMenuItemSelected)); popup.AppendSeparator (); Gui->AppendToMenu (popup, LangString["IDM_BACKUP_VOL_HEADER"], this, wxCommandEventHandler (MainFrame::OnBackupVolumeHeadersMenuItemSelected)); Gui->AppendToMenu (popup, LangString["IDM_RESTORE_VOL_HEADER"], this, wxCommandEventHandler (MainFrame::OnRestoreVolumeHeaderMenuItemSelected)); PopupMenu (&popup, VolumeToolsButton->GetPosition().x + 2, VolumeToolsButton->GetPosition().y + 2); } void MainFrame::OnWipeCacheButtonClick (wxCommandEvent& event) { WipeCache(); Gui->ShowInfo ("PASSWORD_CACHE_WIPED"); } void MainFrame::OpenSelectedVolume () const { shared_ptr selectedVolume = GetSelectedVolume(); if (selectedVolume) { try { wxBusyCursor busy; Gui->OpenExplorerWindow (selectedVolume->MountPoint); } catch (exception &e) { Gui->ShowError (e); } } } void MainFrame::OrganizeFavorites (const FavoriteVolumeList &favorites, size_t newItemCount) { #ifdef TC_MACOSX if (Gui->IsInBackgroundMode()) Gui->SetBackgroundMode (false); #endif FavoriteVolumesDialog dialog (this, favorites, newItemCount); if (dialog.ShowModal() == wxID_OK) { FavoriteVolume::SaveList (dialog.GetFavorites()); LoadFavoriteVolumes(); } } void MainFrame::SavePreferences () const { try { UserPreferences prefs = GetPreferences(); prefs.LastSelectedSlotNumber = SelectedSlotNumber; prefs.Save(); VolumeHistory::Save(); } catch (exception &e) { if (!Core->IsInPortableMode()) Gui->ShowError (e); } } #ifdef HAVE_INDICATORS void MainFrame::SetBusy (bool busy) { gtk_widget_set_sensitive(indicator_item_mountfavorites, !busy); gtk_widget_set_sensitive(indicator_item_dismountall, !busy); gtk_widget_set_sensitive(indicator_item_prefs, !busy); gtk_widget_set_sensitive(indicator_item_exit, !busy /*&& CanExit()*/); } static void IndicatorOnShowHideMenuItemSelected (GtkWidget *widget, MainFrame *self) { Gui->SetBackgroundMode (!Gui->IsInBackgroundMode()); } static void IndicatorOnMountAllFavoritesMenuItemSelected (GtkWidget *widget, MainFrame *self) { self->SetBusy(true); self->MountAllFavorites (); self->SetBusy(false); } static void IndicatorOnDismountAllMenuItemSelected (GtkWidget *widget, MainFrame *self) { self->SetBusy(true); Gui->DismountAllVolumes(); self->SetBusy(false); } static void IndicatorOnPreferencesMenuItemSelected (GtkWidget *widget, MainFrame *self) { self->SetBusy(true); PreferencesDialog dialog (self); dialog.ShowModal(); self->SetBusy(false); } static void IndicatorOnExitMenuItemSelected (GtkWidget *widget, MainFrame *self) { self->SetBusy(true); if (Core->GetMountedVolumes().empty() || Gui->AskYesNo (LangString ["CONFIRM_EXIT"], false, true)) self->Close (true); self->SetBusy(false); } #endif void MainFrame::ShowTaskBarIcon (bool show) { if (!show && mTaskBarIcon->IsIconInstalled()) { mTaskBarIcon->RemoveIcon(); } else if (show && !mTaskBarIcon->IsIconInstalled()) { #ifndef TC_MACOSX #ifndef HAVE_INDICATORS mTaskBarIcon->SetIcon (Resources::GetVeraCryptIcon(), L"VeraCrypt"); #endif #endif #ifdef HAVE_INDICATORS if (indicator == NULL) { indicator = app_indicator_new ("veracrypt", "veracrypt", APP_INDICATOR_CATEGORY_APPLICATION_STATUS); app_indicator_set_status (indicator, APP_INDICATOR_STATUS_ACTIVE); GtkWidget *menu = gtk_menu_new(); indicator_item_showhide = gtk_menu_item_new_with_label (LangString[Gui->IsInBackgroundMode() ? "SHOW_TC" : "HIDE_TC"].mb_str()); gtk_menu_shell_append (GTK_MENU_SHELL (menu), indicator_item_showhide); g_signal_connect (indicator_item_showhide, "activate", G_CALLBACK (IndicatorOnShowHideMenuItemSelected), this); gtk_menu_shell_append (GTK_MENU_SHELL (menu), gtk_separator_menu_item_new()); indicator_item_mountfavorites = gtk_menu_item_new_with_label (LangString["IDM_MOUNT_FAVORITE_VOLUMES"].mb_str()); gtk_menu_shell_append (GTK_MENU_SHELL (menu), indicator_item_mountfavorites); g_signal_connect (indicator_item_mountfavorites, "activate", G_CALLBACK (IndicatorOnMountAllFavoritesMenuItemSelected), this); indicator_item_dismountall = gtk_menu_item_new_with_label (LangString["HK_UNMOUNT_ALL"].mb_str()); gtk_menu_shell_append (GTK_MENU_SHELL (menu), indicator_item_dismountall); g_signal_connect (indicator_item_dismountall, "activate", G_CALLBACK (IndicatorOnDismountAllMenuItemSelected), this); gtk_menu_shell_append (GTK_MENU_SHELL (menu), gtk_separator_menu_item_new()); indicator_item_prefs = gtk_menu_item_new_with_label (LangString["IDM_PREFERENCES"].mb_str()); gtk_menu_shell_append (GTK_MENU_SHELL (menu), indicator_item_prefs); g_signal_connect (indicator_item_prefs, "activate", G_CALLBACK (IndicatorOnPreferencesMenuItemSelected), this); gtk_menu_shell_append (GTK_MENU_SHELL (menu), gtk_separator_menu_item_new()); indicator_item_exit = gtk_menu_item_new_with_label (LangString["EXIT"].mb_str()); gtk_menu_shell_append (GTK_MENU_SHELL (menu), indicator_item_exit); g_signal_connect (indicator_item_exit, "activate", G_CALLBACK (IndicatorOnExitMenuItemSelected), this); gtk_widget_show_all (menu); app_indicator_set_menu (indicator, GTK_MENU (menu)); } #endif } } long MainFrame::SlotNumberToItemIndex (uint32 slotNumber) const { for (long itemIndex = 0; itemIndex < SlotListCtrl->GetItemCount(); itemIndex++) { wxListItem item; item.SetId (itemIndex); if (slotNumber == (uint32) SlotListCtrl->GetItemData (item)) return itemIndex; } return -1; } void MainFrame::UpdateControls () { bool mounted = IsMountedSlotSelected(); VolumeButton->SetLabel (mounted ? LangString["UNMOUNT_BUTTON"] : LangString["MOUNT_BUTTON"]); VolumePropertiesButton->Enable (mounted); DismountVolumeMenuItem->Enable (mounted); MountVolumeMenuItem->Enable (!mounted); VolumePropertiesMenuItem->Enable (mounted); AddToFavoritesMenuItem->Enable (mounted); AddAllMountedToFavoritesMenuItem->Enable (!MountedVolumes.empty()); UpdateWipeCacheButton(); } void MainFrame::OnUpdateVolumeList (wxThreadEvent& event) { #ifdef TC_MACOSX { ScopeLock lock (VolumeDiscovery->AccessMutex); ++VolumeDiscovery->Generation; } VolumeSnapshot.Invalidate(); VolumeListChange change = event.GetPayload (); MountedVolumes.remove_if ([&change] (shared_ptr volume) { return volume->SerialInstanceNumber == change.Volume->SerialInstanceNumber; }); if (change.Mounted) MountedVolumes.push_back (change.Volume); #endif UpdateVolumeList(); } void MainFrame::OnVolumeDiscoveryCompleted (wxCommandEvent& event) { try { UpdateVolumeList (false); } catch (exception &e) { SystemLog::WriteException (e); } catch (...) { } } void MainFrame::UpdateVolumeList (bool startDiscovery) { static Mutex mutex; ScopeLock lock (mutex); bool listChanged = false; #ifdef TC_MACOSX { ScopeLock discoveryLock (VolumeDiscovery->AccessMutex); auto now = chrono::steady_clock::now(); if (VolumeDiscovery->Completed) { if (VolumeDiscovery->Succeeded && VolumeDiscovery->ResultGeneration == VolumeDiscovery->Generation) { VolumeDiscoveryResult &result = VolumeDiscovery->Result; // Retain the identity of previously seen but now unreadable services. // New unresolved candidates remain separate, without invented slots. foreach (shared_ptr old, MountedVolumes) if (find (result.UnresolvedMounts.begin(), result.UnresolvedMounts.end(), old->AuxMountPoint) != result.UnresolvedMounts.end() && none_of (result.Volumes.begin(), result.Volumes.end(), [&old] (shared_ptr volume) { return volume->SerialInstanceNumber == old->SerialInstanceNumber; })) { shared_ptr unknown = old->Clone(); unknown->Discovery = VolumeInfo::ControlUnavailable; unknown->VirtualDevice = DevicePath(); unknown->MountPoint = DirectoryPath(); result.Volumes.push_back (unknown); } MountedVolumes.swap (result.Volumes); VolumeSnapshot.RecordSample (VolumeDiscovery->Started, result.IsComplete()); } else { VolumeSnapshot.Invalidate(); // A volume event invalidated an in-flight result. Start the // replacement immediately, without waiting for the next timer. if (VolumeDiscovery->ResultGeneration != VolumeDiscovery->Generation) startDiscovery = true; } VolumeDiscovery->Completed = false; } bool stale = !VolumeSnapshot.IsFresh (now); SetStatusText (stale ? LangString[!VolumeDiscovery->HasResult && now - VolumeDiscovery->Started < chrono::seconds (6) ? "VOLUME_DISCOVERY_PENDING" : "VOLUME_DISCOVERY_STALLED"] : (VolumeSnapshot.IsComplete() ? wxString() : LangString["VOLUME_DISCOVERY_PARTIAL"])); if (startDiscovery && !VolumeDiscovery->Running) { VolumeDiscovery->Started = now; VolumeDiscovery->Running = true; unique_ptr task (new VolumeDiscoveryTask (VolumeDiscovery, VolumeDiscovery->Generation)); Thread thread; try { thread.Start (task.get()); } catch (...) { VolumeDiscovery->Running = false; throw; } task.release(); thread.Detach(); } } #else MountedVolumes = Core->GetMountedVolumes(); #endif map < VolumeSlotNumber, shared_ptr > mountedVolumesMap; foreach (shared_ptr volume, MountedVolumes) { // A live replacement may share a slot with a retained unreadable entry. // Keep the visible row and selection on the first (live) instance. mountedVolumesMap.insert (make_pair (volume->SlotNumber, volume)); } VolumeInfoList protectionTriggeredVolumes; // Update list long prevItemIndex = -1; for (VolumeSlotNumber slotNumber = Core->GetFirstSlotNumber(); slotNumber <= Core->GetLastSlotNumber(); ++slotNumber) { long itemIndex = SlotNumberToItemIndex (slotNumber); vector fields (SlotListCtrl->GetColumnCount()); if (mountedVolumesMap.find (slotNumber) != mountedVolumesMap.end()) { shared_ptr volume = mountedVolumesMap[slotNumber]; #ifdef TC_WINDOWS fields[ColumnSlot] = volume->MountPoint; fields[ColumnEA] = volume->EncryptionAlgorithmName; #else fields[ColumnSlot] = StringConverter::FromNumber (slotNumber); fields[ColumnMountPoint] = volume->MountPoint; #ifdef TC_MACOSX if (volume->Discovery == VolumeInfo::DiscoveryUnknown || volume->Discovery == VolumeInfo::ControlUnavailable) fields[ColumnMountPoint] = LangString["VOLUME_STATUS_UNKNOWN"]; else if (volume->Discovery == VolumeInfo::ImageAbsent) fields[ColumnMountPoint] = LangString["VOLUME_IMAGE_ABSENT"]; #endif #endif fields[ColumnPath] = volume->Path; fields[ColumnSize] = Gui->SizeToString (volume->Size); fields[ColumnType] = Gui->VolumeTypeToString (volume->Type, volume->Protection); if (volume->HiddenVolumeProtectionTriggered) { fields[ColumnType] += L"(!)"; } bool slotUpdated = false; if (itemIndex == -1) { Gui->InsertToListCtrl (SlotListCtrl, ++prevItemIndex, fields, 0, (void *)(intptr_t) volume->SlotNumber); OnListItemInserted (prevItemIndex); listChanged |= true; slotUpdated = true; } else { if (Gui->UpdateListCtrlItem (SlotListCtrl, itemIndex, fields)) { listChanged = true; slotUpdated = true; } prevItemIndex = itemIndex; } if (slotUpdated && volume->HiddenVolumeProtectionTriggered) protectionTriggeredVolumes.push_back (volume); } else { #ifdef TC_WINDOWS fields[ColumnSlot] = Core->SlotNumberToMountPoint (slotNumber); #else fields[ColumnSlot] = StringConverter::FromNumber (slotNumber); #endif #ifdef TC_WINDOWS if (Core->IsMountPointAvailable (fields[ColumnSlot])) #else if (true) #endif { if (itemIndex == -1) { Gui->InsertToListCtrl (SlotListCtrl, ++prevItemIndex, fields, 0, (void *)(intptr_t) slotNumber); OnListItemInserted (prevItemIndex); listChanged |= true; } else { listChanged |= Gui->UpdateListCtrlItem (SlotListCtrl, itemIndex, fields); prevItemIndex = itemIndex; } } else if (itemIndex != -1) { SlotListCtrl->DeleteItem (itemIndex); OnListItemDeleted (itemIndex); listChanged = true; } } } if (listChanged) { SlotListCtrl->SetColumnWidth(0, wxLIST_AUTOSIZE); OnListChanged(); } foreach (shared_ptr volume, protectionTriggeredVolumes) OnHiddenVolumeProtectionTriggered (volume); } void MainFrame::UpdateWipeCacheButton () { bool enabled = WipeCacheButton->IsEnabled(); bool empty = Core->IsPasswordCacheEmpty(); if (empty && enabled) { WipeCacheButton->Disable(); WipeCachedPasswordsMenuItem->Enable (false); } else if (!empty && !enabled) { WipeCacheButton->Enable(); WipeCachedPasswordsMenuItem->Enable(); } } void MainFrame::WipeCache () { Core->WipePasswordCache(); UpdateWipeCacheButton(); } #ifdef TC_MACOSX void MainFrame::OnMoveHandler(wxMoveEvent& event) { EnsureVisible (true); } #endif }