"Fossies" - the Fresh Open Source Software Archive

Member "src/Main/GraphicUserInterface.cpp" (10 Oct 2018, 51859 Bytes) of package /windows/misc/VeraCrypt_1.23-Hotfix-2_Source.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "GraphicUserInterface.cpp" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.22_Source_vs_1.23_Source.

    1 /*
    2  Derived from source code of TrueCrypt 7.1a, which is
    3  Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed
    4  by the TrueCrypt License 3.0.
    5 
    6  Modifications and additions to the original source code (contained in this file)
    7  and all other portions of this file are Copyright (c) 2013-2017 IDRIX
    8  and are governed by the Apache License 2.0 the full text of which is
    9  contained in the file License.txt included in VeraCrypt binary and source
   10  code distribution packages.
   11 */
   12 
   13 #include "System.h"
   14 
   15 #ifdef TC_UNIX
   16 #include <wx/mimetype.h>
   17 #include <wx/sckipc.h>
   18 #include <fcntl.h>
   19 #include <signal.h>
   20 #include <unistd.h>
   21 #include <sys/stat.h>
   22 #include <sys/types.h>
   23 #include <sys/utsname.h>
   24 #include "Platform/Unix/Process.h"
   25 #endif
   26 
   27 #include "Common/SecurityToken.h"
   28 #include "Application.h"
   29 #include "GraphicUserInterface.h"
   30 #include "FatalErrorHandler.h"
   31 #include "Forms/DeviceSelectionDialog.h"
   32 #include "Forms/KeyfileGeneratorDialog.h"
   33 #include "Forms/MainFrame.h"
   34 #include "Forms/MountOptionsDialog.h"
   35 #include "Forms/RandomPoolEnrichmentDialog.h"
   36 #include "Forms/SecurityTokenKeyfilesDialog.h"
   37 
   38 namespace VeraCrypt
   39 {
   40 #ifdef TC_MACOSX
   41     int GraphicUserInterface::g_customIdCmdV = 0;
   42     int GraphicUserInterface::g_customIdCmdA = 0;
   43 #endif
   44 
   45     GraphicUserInterface::GraphicUserInterface () :
   46         ActiveFrame (nullptr),
   47         BackgroundMode (false),
   48         mMainFrame (nullptr),
   49         mWaitDialog (nullptr)
   50     {
   51 #ifdef TC_UNIX
   52         signal (SIGHUP, OnSignal);
   53         signal (SIGINT, OnSignal);
   54         signal (SIGQUIT, OnSignal);
   55         signal (SIGTERM, OnSignal);
   56 #endif
   57 
   58 #ifdef TC_MACOSX
   59         g_customIdCmdV = wxNewId();
   60         g_customIdCmdA = wxNewId();
   61         wxApp::s_macHelpMenuTitleName = _("&Help");
   62 #endif
   63     }
   64 
   65     GraphicUserInterface::~GraphicUserInterface ()
   66     {
   67         try
   68         {
   69             if (RandomNumberGenerator::IsRunning())
   70                 RandomNumberGenerator::Stop();
   71         }
   72         catch (...) { }
   73 
   74         FatalErrorHandler::Deregister();
   75 
   76 #ifdef TC_UNIX
   77         signal (SIGHUP, SIG_DFL);
   78         signal (SIGINT, SIG_DFL);
   79         signal (SIGQUIT, SIG_DFL);
   80         signal (SIGTERM, SIG_DFL);
   81 #endif
   82     }
   83 
   84     void GraphicUserInterface::AppendToListCtrl (wxListCtrl *listCtrl, const vector <wstring> &itemFields, int imageIndex, void *itemDataPtr) const
   85     {
   86         InsertToListCtrl (listCtrl, listCtrl->GetItemCount(), itemFields, imageIndex, itemDataPtr);
   87     }
   88 
   89     wxMenuItem *GraphicUserInterface::AppendToMenu (wxMenu &menu, const wxString &label, wxEvtHandler *handler, wxObjectEventFunction handlerFunction, int itemId) const
   90     {
   91         wxMenuItem *item = new wxMenuItem (&menu, itemId, label);
   92         menu.Append (item);
   93 
   94         if (handler)
   95             handler->Connect (item->GetId(), wxEVT_COMMAND_MENU_SELECTED, handlerFunction);
   96 
   97         return item;
   98     }
   99 
  100     bool GraphicUserInterface::AskYesNo (const wxString &message, bool defaultYes, bool warning) const
  101     {
  102         return ShowMessage (message,
  103             wxYES_NO | (warning ? wxICON_EXCLAMATION : wxICON_QUESTION) | (defaultYes ? wxYES_DEFAULT : wxNO_DEFAULT)
  104             ) == wxYES;
  105     }
  106 
  107     void GraphicUserInterface::AutoDismountVolumes (VolumeInfoList mountedVolumes, bool alwaysForce)
  108     {
  109         size_t mountedVolumeCount = Core->GetMountedVolumes().size();
  110         try
  111         {
  112             wxBusyCursor busy;
  113             DismountVolumes (mountedVolumes, alwaysForce ? true : GetPreferences().ForceAutoDismount, false);
  114         }
  115         catch (...) { }
  116 
  117         if (Core->GetMountedVolumes().size() < mountedVolumeCount)
  118             OnVolumesAutoDismounted();
  119     }
  120 
  121     void GraphicUserInterface::BackupVolumeHeaders (shared_ptr <VolumePath> volumePath) const
  122     {
  123         wxWindow *parent = GetActiveWindow();
  124 
  125         if (!volumePath || volumePath->IsEmpty())
  126             volumePath = make_shared <VolumePath> (SelectVolumeFile (GetActiveWindow()));
  127 
  128         if (volumePath->IsEmpty())
  129             throw UserAbort (SRC_POS);
  130 
  131 #ifdef TC_WINDOWS
  132         if (Core->IsVolumeMounted (*volumePath))
  133         {
  134             ShowInfo ("DISMOUNT_FIRST");
  135             return;
  136         }
  137 #endif
  138 
  139 #ifdef TC_UNIX
  140         // Temporarily take ownership of a device if the user is not an administrator
  141         UserId origDeviceOwner ((uid_t) -1);
  142 
  143         if (!Core->HasAdminPrivileges() && volumePath->IsDevice())
  144         {
  145             origDeviceOwner = FilesystemPath (wstring (*volumePath)).GetOwner();
  146             Core->SetFileOwner (*volumePath, UserId (getuid()));
  147         }
  148 
  149         finally_do_arg2 (FilesystemPath, *volumePath, UserId, origDeviceOwner,
  150         {
  151             if (finally_arg2.SystemId != (uid_t) -1)
  152                 Core->SetFileOwner (finally_arg, finally_arg2);
  153         });
  154 #endif
  155 
  156         ShowInfo ("EXTERNAL_VOL_HEADER_BAK_FIRST_INFO");
  157 
  158         shared_ptr <Volume> normalVolume;
  159         shared_ptr <Volume> hiddenVolume;
  160 
  161         MountOptions normalVolumeMountOptions;
  162         MountOptions hiddenVolumeMountOptions;
  163 
  164         normalVolumeMountOptions.Path = volumePath;
  165         hiddenVolumeMountOptions.Path = volumePath;
  166 
  167         VolumeType::Enum volumeType = VolumeType::Normal;
  168 
  169         // Open both types of volumes
  170         while (true)
  171         {
  172             shared_ptr <Volume> volume;
  173             MountOptions *options = (volumeType == VolumeType::Hidden ? &hiddenVolumeMountOptions : &normalVolumeMountOptions);
  174 
  175             MountOptionsDialog dialog (parent, *options,
  176                 LangString[volumeType == VolumeType::Hidden ? "ENTER_HIDDEN_VOL_PASSWORD" : "ENTER_NORMAL_VOL_PASSWORD"],
  177                 true);
  178 
  179             while (!volume)
  180             {
  181                 dialog.Hide();
  182                 if (dialog.ShowModal() != wxID_OK)
  183                     return;
  184 
  185                 try
  186                 {
  187                     wxBusyCursor busy;
  188                     OpenVolumeThreadRoutine routine(
  189                         options->Path,
  190                         options->PreserveTimestamps,
  191                         options->Password,
  192                         options->Pim,
  193                         options->Kdf,
  194                         false,
  195                         options->Keyfiles,
  196                         options->Protection,
  197                         options->ProtectionPassword,
  198                         options->ProtectionPim,
  199                         options->ProtectionKdf,
  200                         options->ProtectionKeyfiles,
  201                         true,
  202                         volumeType,
  203                         options->UseBackupHeaders
  204                         );
  205 
  206                         ExecuteWaitThreadRoutine (parent, &routine);
  207                         volume = routine.m_pVolume;
  208                 }
  209                 catch (PasswordException &e)
  210                 {
  211                     bool bFailed = true;
  212                     if (!options->UseBackupHeaders)
  213                     {
  214                         try
  215                         {
  216                             OpenVolumeThreadRoutine routine2(
  217                                 options->Path,
  218                                 options->PreserveTimestamps,
  219                                 options->Password,
  220                                 options->Pim,
  221                                 options->Kdf,
  222                                 false,
  223                                 options->Keyfiles,
  224                                 options->Protection,
  225                                 options->ProtectionPassword,
  226                                 options->ProtectionPim,
  227                                 options->ProtectionKdf,
  228                                 options->ProtectionKeyfiles,
  229                                 true,
  230                                 volumeType,
  231                                 true
  232                             );
  233 
  234                             ExecuteWaitThreadRoutine (parent, &routine2);
  235                             volume = routine2.m_pVolume;
  236                             bFailed = false;
  237                         }
  238                         catch (...)
  239                         {
  240                         }
  241                     }
  242 
  243                     if (bFailed)
  244                         ShowWarning (e);
  245                     else
  246                         ShowWarning ("HEADER_DAMAGED_AUTO_USED_HEADER_BAK");
  247                 }
  248             }
  249 
  250             if (volumeType == VolumeType::Hidden)
  251                 hiddenVolume = volume;
  252             else
  253                 normalVolume = volume;
  254 
  255             // Ask whether a hidden volume is present
  256             if (volumeType == VolumeType::Normal)
  257             {
  258                 wxArrayString choices;
  259                 choices.Add (LangString["VOLUME_CONTAINS_HIDDEN"]);
  260                 choices.Add (LangString["VOLUME_DOES_NOT_CONTAIN_HIDDEN"]);
  261 
  262                 wxSingleChoiceDialog choiceDialog (parent, LangString["DOES_VOLUME_CONTAIN_HIDDEN"], Application::GetName(), choices);
  263                 choiceDialog.SetSize (wxSize (Gui->GetCharWidth (&choiceDialog) * 60, -1));
  264                 choiceDialog.SetSelection (0);
  265 
  266                 if (choiceDialog.ShowModal() != wxID_OK)
  267                     return;
  268 
  269                 switch (choiceDialog.GetSelection())
  270                 {
  271                 case 0:
  272                     volumeType = VolumeType::Hidden;
  273                     continue;
  274 
  275                 case 1:
  276                     break;
  277 
  278                 default:
  279                     return;
  280                 }
  281             }
  282 
  283             break;
  284         }
  285 
  286         if (hiddenVolume)
  287         {
  288             if (typeid (*normalVolume->GetLayout()) == typeid (VolumeLayoutV1Normal))
  289                 throw ParameterIncorrect (SRC_POS);
  290 
  291             if (typeid (*normalVolume->GetLayout()) == typeid (VolumeLayoutV2Normal) && typeid (*hiddenVolume->GetLayout()) != typeid (VolumeLayoutV2Hidden))
  292                 throw ParameterIncorrect (SRC_POS);
  293         }
  294 
  295         // Ask user to select backup file path
  296         wxString confirmMsg = LangString["CONFIRM_VOL_HEADER_BAK"];
  297 
  298         if (!AskYesNo (wxString::Format (confirmMsg, wstring (*volumePath).c_str()), true))
  299             return;
  300 
  301         FilePathList files = SelectFiles (parent, wxEmptyString, true, false);
  302         if (files.empty())
  303             return;
  304 
  305         File backupFile;
  306         backupFile.Open (*files.front(), File::CreateWrite);
  307 
  308         RandomNumberGenerator::Start();
  309         /* force the display of the random enriching interface */
  310         RandomNumberGenerator::SetEnrichedByUserStatus (false);
  311         UserEnrichRandomPool (nullptr);
  312 
  313         {
  314             wxBusyCursor busy;
  315 
  316             // Re-encrypt volume header
  317             SecureBuffer newHeaderBuffer (normalVolume->GetLayout()->GetHeaderSize());
  318             ReEncryptHeaderThreadRoutine routine(newHeaderBuffer, normalVolume->GetHeader(), normalVolumeMountOptions.Password, normalVolumeMountOptions.Pim, normalVolumeMountOptions.Keyfiles);
  319 
  320             ExecuteWaitThreadRoutine (parent, &routine);
  321 
  322             backupFile.Write (newHeaderBuffer);
  323 
  324             if (hiddenVolume)
  325             {
  326                 // Re-encrypt hidden volume header
  327                 ReEncryptHeaderThreadRoutine hiddenRoutine(newHeaderBuffer, hiddenVolume->GetHeader(), hiddenVolumeMountOptions.Password, hiddenVolumeMountOptions.Pim, hiddenVolumeMountOptions.Keyfiles);
  328 
  329                 ExecuteWaitThreadRoutine (parent, &hiddenRoutine);
  330             }
  331             else
  332             {
  333                 // Store random data in place of hidden volume header
  334                 shared_ptr <EncryptionAlgorithm> ea = normalVolume->GetEncryptionAlgorithm();
  335                 Core->RandomizeEncryptionAlgorithmKey (ea);
  336                 ea->Encrypt (newHeaderBuffer);
  337             }
  338 
  339             backupFile.Write (newHeaderBuffer);
  340         }
  341 
  342         ShowWarning ("VOL_HEADER_BACKED_UP");
  343     }
  344 
  345     void GraphicUserInterface::BeginInteractiveBusyState (wxWindow *window)
  346     {
  347         static auto_ptr <wxCursor> arrowWaitCursor;
  348 
  349         if (arrowWaitCursor.get() == nullptr)
  350             arrowWaitCursor.reset (new wxCursor (wxCURSOR_ARROWWAIT));
  351 
  352         window->SetCursor (*arrowWaitCursor);
  353     }
  354 
  355     void GraphicUserInterface::CreateKeyfile (shared_ptr <FilePath> keyfilePath) const
  356     {
  357         try
  358         {
  359             KeyfileGeneratorDialog dialog (GetActiveWindow());
  360             dialog.ShowModal();
  361         }
  362         catch (exception &e)
  363         {
  364             ShowError (e);
  365         }
  366     }
  367 
  368     void GraphicUserInterface::ClearListCtrlSelection (wxListCtrl *listCtrl) const
  369     {
  370         foreach (long item, GetListCtrlSelectedItems (listCtrl))
  371             listCtrl->SetItemState (item, 0, wxLIST_STATE_SELECTED);
  372     }
  373 
  374     wxHyperlinkCtrl *GraphicUserInterface::CreateHyperlink (wxWindow *parent, const wxString &linkUrl, const wxString &linkText) const
  375     {
  376         wxHyperlinkCtrl *hyperlink = new wxHyperlinkCtrl (parent, wxID_ANY, linkText, linkUrl, wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE);
  377 
  378         wxColour color = wxSystemSettings::GetColour (wxSYS_COLOUR_WINDOWTEXT);
  379         hyperlink->SetHoverColour (color);
  380         hyperlink->SetNormalColour (color);
  381         hyperlink->SetVisitedColour (color);
  382 
  383         return hyperlink;
  384     }
  385 
  386     void GraphicUserInterface::DoShowError (const wxString &message) const
  387     {
  388         ShowMessage (message, wxOK | wxICON_ERROR);
  389     }
  390 
  391     void GraphicUserInterface::DoShowInfo (const wxString &message) const
  392     {
  393         ShowMessage (message, wxOK | wxICON_INFORMATION);
  394     }
  395 
  396     void GraphicUserInterface::DoShowString (const wxString &str) const
  397     {
  398         ShowMessage (str, wxOK);
  399     }
  400 
  401     void GraphicUserInterface::DoShowWarning (const wxString &message) const
  402     {
  403         ShowMessage (message, wxOK
  404 #ifndef TC_MACOSX
  405             | wxICON_EXCLAMATION
  406 #endif
  407             );
  408     }
  409 
  410     void GraphicUserInterface::EndInteractiveBusyState (wxWindow *window) const
  411     {
  412         static auto_ptr <wxCursor> arrowCursor;
  413 
  414         if (arrowCursor.get() == nullptr)
  415             arrowCursor.reset (new wxCursor (wxCURSOR_ARROW));
  416 
  417         window->SetCursor (*arrowCursor);
  418     }
  419 
  420     wxTopLevelWindow *GraphicUserInterface::GetActiveWindow () const
  421     {
  422 #ifdef TC_WINDOWS
  423         return dynamic_cast <wxTopLevelWindow *> (wxGetActiveWindow());
  424 #endif
  425 
  426 #ifdef __WXGTK__
  427         // GTK for some reason unhides a hidden window if it is a parent of a new window
  428         if (IsInBackgroundMode())
  429             return nullptr;
  430 #endif
  431         if (wxTopLevelWindows.size() == 1)
  432             return dynamic_cast <wxTopLevelWindow *> (wxTopLevelWindows.front());
  433 
  434 #ifdef __WXGTK__
  435         wxLongLong startTime = wxGetLocalTimeMillis();
  436         do
  437         {
  438 #endif
  439             foreach (wxWindow *window, wxTopLevelWindows)
  440             {
  441                 wxTopLevelWindow *topLevelWin = dynamic_cast <wxTopLevelWindow *> (window);
  442                 if (topLevelWin && topLevelWin->IsActive() && topLevelWin->IsShown())
  443                     return topLevelWin;
  444             }
  445 #ifdef __WXGTK__
  446             Yield(); // GTK does a lot of operations asynchronously, which makes it prone to many race conditions
  447         } while (wxGetLocalTimeMillis() - startTime < 500);
  448 #endif
  449 
  450         return dynamic_cast <wxTopLevelWindow *> (ActiveFrame ? ActiveFrame : GetTopWindow());
  451     }
  452 
  453     shared_ptr <GetStringFunctor> GraphicUserInterface::GetAdminPasswordRequestHandler ()
  454     {
  455         struct AdminPasswordRequestHandler : public GetStringFunctor
  456         {
  457             virtual void operator() (string &passwordStr)
  458             {
  459 
  460                 wxString sValue;
  461                 if (Gui->GetWaitDialog())
  462                 {
  463                     Gui->GetWaitDialog()->RequestAdminPassword(sValue);
  464                     if (sValue.IsEmpty())
  465                         throw UserAbort (SRC_POS);
  466                 }
  467                 else
  468                 {
  469                     wxPasswordEntryDialog dialog (Gui->GetActiveWindow(), _("Enter your user password or administrator password:"), _("Administrator privileges required"));
  470                     if (dialog.ShowModal() != wxID_OK)
  471                         throw UserAbort (SRC_POS);
  472                     sValue = dialog.GetValue();
  473                 }
  474                 wstring wPassword (sValue); // A copy of the password is created here by wxWidgets, which cannot be erased
  475                 finally_do_arg (wstring *, &wPassword, { StringConverter::Erase (*finally_arg); });
  476 
  477                 StringConverter::ToSingle (wPassword, passwordStr);
  478             }
  479         };
  480 
  481         return shared_ptr <GetStringFunctor> (new AdminPasswordRequestHandler);
  482     }
  483 
  484     int GraphicUserInterface::GetCharHeight (wxWindow *window) const
  485     {
  486         int width;
  487         int height;
  488         window->GetTextExtent (L"a", &width, &height);
  489 
  490         if (height < 1)
  491             return 14;
  492 
  493         return height;
  494     }
  495 
  496     int GraphicUserInterface::GetCharWidth (wxWindow *window) const
  497     {
  498         int width;
  499         int height;
  500         window->GetTextExtent (L"a", &width, &height);
  501 
  502         if (width < 1)
  503             return 7;
  504 
  505         return width;
  506     }
  507 
  508     wxFont GraphicUserInterface::GetDefaultBoldFont (wxWindow *window) const
  509     {
  510         return wxFont (
  511 #ifdef __WXGTK__
  512             9
  513 #elif defined(TC_MACOSX)
  514             13
  515 #else
  516             10
  517 #endif
  518             * GetCharHeight (window) / 13, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
  519 #ifdef __WXGTK__
  520             wxFONTWEIGHT_BOLD, false);
  521 #elif defined(TC_MACOSX)
  522             wxFONTWEIGHT_NORMAL, false);
  523 #else
  524             wxFONTWEIGHT_BOLD, false, L"Arial");
  525 #endif
  526     }
  527 
  528     list <long> GraphicUserInterface::GetListCtrlSelectedItems (wxListCtrl *listCtrl) const
  529     {
  530         list <long> selectedItems;
  531 
  532         long item = -1;
  533         while ((item = listCtrl->GetNextItem (item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)) != -1)
  534             selectedItems.push_back (item);
  535 
  536         return selectedItems;
  537     }
  538 
  539     wxString GraphicUserInterface::GetListCtrlSubItemText (wxListCtrl *listCtrl, long itemIndex, int columnIndex) const
  540     {
  541         wxListItem item;
  542         item.SetId (itemIndex);
  543         item.SetColumn (columnIndex);
  544         item.SetText (L"");
  545 
  546         if (!listCtrl->GetItem (item))
  547             throw ParameterIncorrect (SRC_POS);
  548 
  549         return item.GetText();
  550     }
  551 
  552     int GraphicUserInterface::GetScrollbarWidth (wxWindow *window, bool noScrollBar) const
  553     {
  554         int offset = 0;
  555 #ifdef TC_WINDOWS
  556         offset = 4;
  557 #elif defined (__WXGTK__)
  558         offset = 7;
  559 #elif defined (TC_MACOSX)
  560         offset = 9;
  561 #endif
  562         if (noScrollBar)
  563             return offset;
  564 
  565         int width = wxSystemSettings::GetMetric (wxSYS_VSCROLL_X, window);
  566 
  567         if (width == -1)
  568             return 24;
  569 
  570         return width + offset;
  571     }
  572 
  573     void GraphicUserInterface::InitSecurityTokenLibrary () const
  574     {
  575         if (Preferences.SecurityTokenModule.IsEmpty())
  576             throw_err (LangString ["NO_PKCS11_MODULE_SPECIFIED"]);
  577 
  578         struct PinRequestHandler : public GetPinFunctor
  579         {
  580             virtual void operator() (string &passwordStr)
  581             {
  582                 if (CmdLine->ArgTokenPin && CmdLine->ArgTokenPin->IsAllocated ())
  583                 {
  584                     passwordStr.clear();
  585                     passwordStr.insert (0, (char*) CmdLine->ArgTokenPin->Ptr (), CmdLine->ArgTokenPin->Size());
  586                     return;
  587                 }
  588 
  589                 if (Gui->GetPreferences().NonInteractive)
  590                     throw MissingArgument (SRC_POS);
  591 
  592                 wxString sValue;
  593                 if (Gui->GetWaitDialog())
  594                 {
  595                     sValue = StringConverter::ToWide (passwordStr).c_str();
  596                     Gui->GetWaitDialog()->RequestPin (sValue);
  597                     if (sValue.IsEmpty ())
  598                         throw UserAbort (SRC_POS);
  599                 }
  600                 else
  601                 {
  602                     wxPasswordEntryDialog dialog (Gui->GetActiveWindow(), wxString::Format (LangString["ENTER_TOKEN_PASSWORD"], StringConverter::ToWide (passwordStr).c_str()), LangString["IDD_TOKEN_PASSWORD"]);
  603                     dialog.SetSize (wxSize (Gui->GetCharWidth (&dialog) * 50, -1));
  604 
  605                     if (dialog.ShowModal() != wxID_OK)
  606                         throw UserAbort (SRC_POS);
  607                     sValue = dialog.GetValue();
  608                 }
  609 
  610                 wstring wPassword (sValue); // A copy of the password is created here by wxWidgets, which cannot be erased
  611                 finally_do_arg (wstring *, &wPassword, { StringConverter::Erase (*finally_arg); });
  612 
  613                 StringConverter::ToSingle (wPassword, passwordStr);
  614             }
  615 
  616             virtual void notifyIncorrectPin ()
  617             {
  618                 if (CmdLine->ArgTokenPin && CmdLine->ArgTokenPin->IsAllocated ())
  619                 {
  620                     CmdLine->ArgTokenPin->Free ();
  621                 }
  622             }
  623         };
  624 
  625         struct WarningHandler : public SendExceptionFunctor
  626         {
  627             virtual void operator() (const Exception &e)
  628             {
  629                 Gui->ShowError (e);
  630             }
  631         };
  632 
  633         try
  634         {
  635             SecurityToken::InitLibrary (Preferences.SecurityTokenModule, auto_ptr <GetPinFunctor> (new PinRequestHandler), auto_ptr <SendExceptionFunctor> (new WarningHandler));
  636         }
  637         catch (Exception &e)
  638         {
  639             ShowError (e);
  640             throw_err (LangString ["PKCS11_MODULE_INIT_FAILED"]);
  641         }
  642     }
  643 
  644     void GraphicUserInterface::InsertToListCtrl (wxListCtrl *listCtrl, long itemIndex, const vector <wstring> &itemFields, int imageIndex, void *itemDataPtr) const
  645     {
  646         wxListItem item;
  647         item.SetData (itemDataPtr);
  648         item.SetId (itemIndex);
  649         item.SetImage (imageIndex);
  650         int col = 0;
  651         foreach (wxString field, itemFields)
  652         {
  653             item.SetColumn (col++);
  654             item.SetText (field);
  655             if (col == 1)
  656             {
  657                 throw_sys_if (listCtrl->InsertItem (item) == -1);
  658                 item.SetImage (-1);
  659                 continue;
  660             }
  661 
  662             listCtrl->SetItem (item);
  663         }
  664     }
  665 
  666     bool GraphicUserInterface::IsTheOnlyTopLevelWindow (const wxWindow *window) const
  667     {
  668         foreach (wxWindow *w, wxTopLevelWindows)
  669         {
  670             if (w != window
  671                 && (dynamic_cast <const wxFrame *> (w) || dynamic_cast <const wxDialog *> (w))
  672                 && StringConverter::GetTypeName (typeid (*w)).find ("wxTaskBarIcon") == string::npos)
  673             {
  674                 return false;
  675             }
  676         }
  677         return true;
  678     }
  679 
  680     void GraphicUserInterface::ListSecurityTokenKeyfiles () const
  681     {
  682         SecurityTokenKeyfilesDialog dialog (nullptr);
  683         dialog.ShowModal();
  684     }
  685 
  686 #ifdef TC_MACOSX
  687     void GraphicUserInterface::MacOpenFiles (const wxArrayString &fileNames)
  688     {
  689         if (fileNames.GetCount() > 0)
  690         {
  691             // we can only put one volume path at a time on the text field
  692             // so we take the first on the list
  693             OpenVolumeSystemRequestEventArgs eventArgs (fileNames[0]);
  694             OpenVolumeSystemRequestEvent.Raise (eventArgs);
  695         }
  696     }
  697 
  698     void GraphicUserInterface::MacReopenApp ()
  699     {
  700         SetBackgroundMode (false);
  701     }
  702     
  703     bool GraphicUserInterface::HandlePasswordEntryCustomEvent (wxEvent& event)
  704     {
  705         bool bHandled = false;
  706         if (    (event.GetEventType() == wxEVT_MENU)
  707             &&  ((event.GetId() == g_customIdCmdV) || (event.GetId() == g_customIdCmdA)))
  708         {
  709             wxWindow* focusedCtrl = wxWindow::FindFocus();
  710             if (focusedCtrl 
  711                 && (focusedCtrl->IsKindOf(wxCLASSINFO(wxTextCtrl)))
  712                 && (focusedCtrl->GetWindowStyle() & wxTE_PASSWORD))
  713             {
  714                 wxTextCtrl* passwordCtrl = (wxTextCtrl*) focusedCtrl;
  715                 if (event.GetId() == g_customIdCmdV)
  716                     passwordCtrl->Paste ();
  717                 else if (event.GetId() == g_customIdCmdA)
  718                     passwordCtrl->SelectAll ();
  719                 bHandled = true;
  720             }
  721         }
  722         
  723         return bHandled;
  724     }
  725     
  726     void GraphicUserInterface::InstallPasswordEntryCustomKeyboardShortcuts (wxWindow* window)
  727     {
  728         // we manually handle CMD+V and CMD+A on password fields in order to support
  729         // pasting password values into them. By default, wxWidgets doesn't handle this
  730         // for password entry fields.
  731         wxAcceleratorEntry entries[2];
  732         entries[0].Set(wxACCEL_CMD, (int) 'V', g_customIdCmdV);
  733         entries[1].Set(wxACCEL_CMD, (int) 'A', g_customIdCmdA);
  734         wxAcceleratorTable accel(sizeof(entries) / sizeof(wxAcceleratorEntry), entries);
  735         window->SetAcceleratorTable(accel);
  736     }
  737 #endif
  738 
  739     void GraphicUserInterface::MoveListCtrlItem (wxListCtrl *listCtrl, long itemIndex, long newItemIndex) const
  740     {
  741         if (itemIndex == newItemIndex || newItemIndex < 0
  742             || (newItemIndex > itemIndex && newItemIndex == listCtrl->GetItemCount()))
  743             return;
  744 
  745         wxListItem item;
  746         item.SetId (itemIndex);
  747         item.SetData ((void *) nullptr);
  748         item.SetImage (-1);
  749 
  750         if (!listCtrl->GetItem (item))
  751             throw ParameterIncorrect (SRC_POS);
  752 
  753         int itemState = listCtrl->GetItemState (itemIndex, wxLIST_STATE_SELECTED);
  754 
  755         vector <wstring> itemFields (listCtrl->GetColumnCount());
  756         for (size_t col = 0; col < itemFields.size(); ++col)
  757         {
  758             itemFields[col] = GetListCtrlSubItemText (listCtrl, itemIndex, col);
  759         }
  760 
  761         listCtrl->DeleteItem (itemIndex);
  762 
  763         if (newItemIndex > listCtrl->GetItemCount() - 1)
  764             AppendToListCtrl (listCtrl, itemFields, item.GetImage(), (void *) item.GetData());
  765         else
  766             InsertToListCtrl (listCtrl, newItemIndex, itemFields, item.GetImage(), (void *) item.GetData());
  767 
  768         item.SetId (newItemIndex);
  769         listCtrl->SetItemState (item, itemState, wxLIST_STATE_SELECTED);
  770     }
  771 
  772     VolumeInfoList GraphicUserInterface::MountAllDeviceHostedVolumes (MountOptions &options) const
  773     {
  774         MountOptionsDialog dialog (GetTopWindow(), options);
  775         while (true)
  776         {
  777             options.Path.reset();
  778 
  779             if (dialog.ShowModal() != wxID_OK)
  780                 return VolumeInfoList();
  781 
  782             VolumeInfoList mountedVolumes = UserInterface::MountAllDeviceHostedVolumes (options);
  783 
  784             if (!mountedVolumes.empty())
  785                 return mountedVolumes;
  786         }
  787     }
  788 
  789     shared_ptr <VolumeInfo> GraphicUserInterface::MountVolume (MountOptions &options) const
  790     {
  791         CheckRequirementsForMountingVolume();
  792 
  793         shared_ptr <VolumeInfo> volume;
  794 
  795         if (!options.Path || options.Path->IsEmpty())
  796             options.Path = make_shared <VolumePath> (SelectVolumeFile (GetActiveWindow()));
  797 
  798         if (options.Path->IsEmpty())
  799             throw UserAbort (SRC_POS);
  800 
  801         if (Core->IsVolumeMounted (*options.Path))
  802         {
  803             ShowInfo (StringFormatter (LangString["VOLUME_ALREADY_MOUNTED"], wstring (*options.Path)));
  804             return volume;
  805         }
  806 
  807         try
  808         {
  809             if ((!options.Password || options.Password->IsEmpty())
  810                 && (!options.Keyfiles || options.Keyfiles->empty())
  811                 && !Core->IsPasswordCacheEmpty())
  812             {
  813                 // Cached password
  814                 try
  815                 {
  816                     wxBusyCursor busy;
  817                     return UserInterface::MountVolume (options);
  818                 }
  819                 catch (PasswordException&) { }
  820             }
  821 
  822             if (!options.Keyfiles && GetPreferences().UseKeyfiles && !GetPreferences().DefaultKeyfiles.empty())
  823                 options.Keyfiles = make_shared <KeyfileList> (GetPreferences().DefaultKeyfiles);
  824 
  825             if ((options.Password && !options.Password->IsEmpty())
  826                 || (options.Keyfiles && !options.Keyfiles->empty() && (options.TrueCryptMode || options.Password)))
  827             {
  828                 try
  829                 {
  830                     wxBusyCursor busy;
  831                     return UserInterface::MountVolume (options);
  832                 }
  833                 catch (PasswordException&) { }
  834             }
  835 
  836             VolumePassword password;
  837             KeyfileList keyfiles;
  838 
  839             MountOptionsDialog dialog (GetTopWindow(), options);
  840             int incorrectPasswordCount = 0;
  841 
  842             while (!volume)
  843             {
  844                 dialog.Hide();
  845                 if (dialog.ShowModal() != wxID_OK)
  846                     return volume;
  847 
  848                 try
  849                 {
  850                     wxBusyCursor busy;
  851                     volume = UserInterface::MountVolume (options);
  852                 }
  853                 catch (PasswordIncorrect &e)
  854                 {
  855                     if (++incorrectPasswordCount > 2 && !options.UseBackupHeaders)
  856                     {
  857                         // Try to mount the volume using the backup header
  858                         options.UseBackupHeaders = true;
  859 
  860                         try
  861                         {
  862                             volume = UserInterface::MountVolume (options);
  863                             ShowWarning ("HEADER_DAMAGED_AUTO_USED_HEADER_BAK");
  864                         }
  865                         catch (...)
  866                         {
  867                             options.UseBackupHeaders = false;
  868                             ShowWarning (e);
  869                         }
  870                     }
  871                     else
  872                         ShowWarning (e);
  873                 }
  874                 catch (PasswordException &e)
  875                 {
  876                     ShowWarning (e);
  877                 }
  878             }
  879         }
  880         catch (exception &e)
  881         {
  882             ShowError (e);
  883         }
  884 
  885 #ifdef TC_LINUX
  886         if (volume && !Preferences.NonInteractive && !Preferences.DisableKernelEncryptionModeWarning
  887             && volume->EncryptionModeName != L"XTS"
  888             && !AskYesNo (LangString["ENCRYPTION_MODE_NOT_SUPPORTED_BY_KERNEL"] + _("\n\nDo you want to show this message next time you mount such a volume?"), true, true))
  889         {
  890             UserPreferences prefs = GetPreferences();
  891             prefs.DisableKernelEncryptionModeWarning = true;
  892             Gui->SetPreferences (prefs);
  893         }
  894 #endif
  895         return volume;
  896     }
  897 
  898     void GraphicUserInterface::OnAutoDismountAllEvent ()
  899     {
  900         VolumeInfoList mountedVolumes = Core->GetMountedVolumes();
  901 
  902         if (!mountedVolumes.empty())
  903         {
  904             wxBusyCursor busy;
  905             AutoDismountVolumes (mountedVolumes);
  906         }
  907     }
  908 
  909     bool GraphicUserInterface::OnInit ()
  910     {
  911         Gui = this;
  912         InterfaceType = UserInterfaceType::Graphic;
  913         try
  914         {
  915             FatalErrorHandler::Register();
  916             Init();
  917 
  918             if (ProcessCommandLine() && !CmdLine->StartBackgroundTask)
  919             {
  920                 Yield();
  921                 Application::SetExitCode (0);
  922                 return false;
  923             }
  924 
  925             // Check if another instance is already running and bring its windows to foreground
  926 #ifndef TC_MACOSX
  927 #ifdef TC_WINDOWS
  928             const wxString serverName = Application::GetName() + L"-" + wxGetUserId();
  929             class Connection : public wxDDEConnection
  930             {
  931             public:
  932                 Connection () { }
  933 
  934                 bool OnExecute (const wxString& topic, wxChar *data, int size, wxIPCFormat format)
  935                 {
  936                     if (topic == L"raise")
  937                     {
  938                         if (Gui->IsInBackgroundMode())
  939                             Gui->SetBackgroundMode (false);
  940 
  941                         Gui->mMainFrame->Show (true);
  942                         Gui->mMainFrame->Raise ();
  943                         return true;
  944                     }
  945                     return false;
  946                 }
  947             };
  948 #endif
  949 
  950             wxLogLevel logLevel = wxLog::GetLogLevel();
  951             wxLog::SetLogLevel (wxLOG_Error);
  952 
  953             const wxString instanceCheckerName = wxString (L".") + Application::GetName() + L"-lock-" + wxGetUserId();
  954             SingleInstanceChecker.reset (new wxSingleInstanceChecker (instanceCheckerName));
  955 
  956             wxLog::SetLogLevel (logLevel);
  957 
  958             if (SingleInstanceChecker->IsAnotherRunning())
  959             {
  960 #ifdef TC_WINDOWS
  961                 class Client: public wxDDEClient
  962                 {
  963                 public:
  964                     Client() {};
  965                     wxConnectionBase *OnMakeConnection () { return new Connection; }
  966                 };
  967 
  968                 auto_ptr <wxDDEClient> client (new Client);
  969                 auto_ptr <wxConnectionBase> connection (client->MakeConnection (L"localhost", serverName, L"raise"));
  970 
  971                 if (connection.get() && connection->Execute (nullptr))
  972                 {
  973                     connection->Disconnect();
  974                     Application::SetExitCode (0);
  975                     return false;
  976                 }
  977 #endif
  978 
  979 #if defined(TC_UNIX) && !defined(TC_MACOSX)
  980                 try
  981                 {
  982                     int showFifo = open (string (MainFrame::GetShowRequestFifoPath()).c_str(), O_WRONLY | O_NONBLOCK);
  983                     throw_sys_if (showFifo == -1);
  984 
  985                     byte buf[1] = { 1 };
  986                     if (write (showFifo, buf, 1) == 1)
  987                     {
  988                         close (showFifo);
  989                         Gui->ShowInfo (_("VeraCrypt is already running."));
  990                         Application::SetExitCode (0);
  991                         return false;
  992                     }
  993 
  994                     close (showFifo);
  995                 }
  996                 catch (...)
  997                 {
  998 #ifdef DEBUG
  999                     throw;
 1000 #endif
 1001                 }
 1002 
 1003                 // This is a false positive as VeraCrypt is not running (pipe not available)
 1004                 // we continue running after cleaning the lock file
 1005                 // and creating a new instance of the checker
 1006                 wxString lockFileName = wxGetHomeDir();
 1007                 if ( lockFileName.Last() != wxT('/') )
 1008                 {
 1009                     lockFileName += wxT('/');
 1010                 }
 1011                 lockFileName << instanceCheckerName;
 1012 
 1013                 if (wxRemoveFile (lockFileName))
 1014                 {
 1015                     SingleInstanceChecker.reset (new wxSingleInstanceChecker (instanceCheckerName));
 1016                 }
 1017 #else
 1018 
 1019                 wxLog::FlushActive();
 1020                 Application::SetExitCode (1);
 1021                 Gui->ShowInfo (_("VeraCrypt is already running."));
 1022                 return false;
 1023 #endif
 1024             }
 1025 
 1026 #ifdef TC_WINDOWS
 1027             class Server : public wxDDEServer
 1028             {
 1029             public:
 1030                 wxConnectionBase *OnAcceptConnection (const wxString &topic)
 1031                 {
 1032                     if (topic == L"raise")
 1033                         return new Connection;
 1034                     return nullptr;
 1035                 }
 1036             };
 1037 
 1038             DDEServer.reset (new Server);
 1039             if (!DDEServer->Create (serverName))
 1040                 wxLog::FlushActive();
 1041 #endif
 1042 #endif // !TC_MACOSX
 1043 
 1044             Connect (wxEVT_END_SESSION, wxCloseEventHandler (GraphicUserInterface::OnEndSession));
 1045 #ifdef wxHAS_POWER_EVENTS
 1046             Gui->Connect (wxEVT_POWER_SUSPENDING, wxPowerEventHandler (GraphicUserInterface::OnPowerSuspending));
 1047 #endif
 1048 
 1049             mMainFrame = new MainFrame (nullptr);
 1050 
 1051             if (CmdLine->StartBackgroundTask)
 1052             {
 1053                 UserPreferences prefs = GetPreferences ();
 1054                 prefs.BackgroundTaskEnabled = true;
 1055                 SetPreferences (prefs);
 1056                 mMainFrame->Close();
 1057             }
 1058             else
 1059             {
 1060                 mMainFrame->Show (true);
 1061             }
 1062 
 1063             SetTopWindow (mMainFrame);
 1064         }
 1065         catch (exception &e)
 1066         {
 1067             ShowError (e);
 1068             return false;
 1069         }
 1070 
 1071         return true;
 1072     }
 1073 
 1074     void GraphicUserInterface::OnLogOff ()
 1075     {
 1076         VolumeInfoList mountedVolumes = Core->GetMountedVolumes();
 1077         if (GetPreferences().BackgroundTaskEnabled && GetPreferences().DismountOnLogOff
 1078             && !mountedVolumes.empty())
 1079         {
 1080             wxLongLong startTime = wxGetLocalTimeMillis();
 1081             bool timeOver = false;
 1082 
 1083             wxBusyCursor busy;
 1084             while (!timeOver && !mountedVolumes.empty())
 1085             {
 1086                 try
 1087                 {
 1088                     timeOver = (wxGetLocalTimeMillis() - startTime >= 4000);
 1089 
 1090                     DismountVolumes (mountedVolumes, !timeOver ? false : GetPreferences().ForceAutoDismount, timeOver);
 1091                     OnVolumesAutoDismounted();
 1092 
 1093                     break;
 1094                 }
 1095                 catch (UserAbort&)
 1096                 {
 1097                     return;
 1098                 }
 1099                 catch (...)
 1100                 {
 1101                     Thread::Sleep (500);
 1102                 }
 1103 
 1104                 VolumeInfoList mountedVolumes = Core->GetMountedVolumes();
 1105             }
 1106 
 1107         }
 1108     }
 1109 
 1110 #ifdef wxHAS_POWER_EVENTS
 1111     void GraphicUserInterface::OnPowerSuspending (wxPowerEvent& event)
 1112     {
 1113         size_t volumeCount = Core->GetMountedVolumes().size();
 1114         if (GetPreferences().BackgroundTaskEnabled && GetPreferences().DismountOnPowerSaving && volumeCount > 0)
 1115         {
 1116             OnAutoDismountAllEvent();
 1117 
 1118             if (Core->GetMountedVolumes().size() < volumeCount)
 1119                 ShowInfoTopMost (LangString["MOUNTED_VOLUMES_AUTO_DISMOUNTED"]);
 1120         }
 1121     }
 1122 #endif
 1123 
 1124     void GraphicUserInterface::OnSignal (int signal)
 1125     {
 1126 #ifdef TC_UNIX
 1127         Gui->SingleInstanceChecker.reset();
 1128         _exit (1);
 1129 #endif
 1130     }
 1131 
 1132     void GraphicUserInterface::OnVolumesAutoDismounted ()
 1133     {
 1134         if (GetPreferences().WipeCacheOnAutoDismount)
 1135         {
 1136             Core->WipePasswordCache();
 1137             SecurityToken::CloseAllSessions();
 1138         }
 1139     }
 1140 
 1141     void GraphicUserInterface::OpenDocument (wxWindow *parent, const wxFileName &document)
 1142     {
 1143         if (!document.FileExists())
 1144             throw ParameterIncorrect (SRC_POS);
 1145 
 1146 #ifdef TC_WINDOWS
 1147 
 1148         if (int (ShellExecute (GetTopWindow() ? static_cast <HWND> (GetTopWindow()->GetHandle()) : nullptr, L"open",
 1149         document.GetFullPath().c_str(), nullptr, nullptr, SW_SHOWNORMAL)) >= 32)
 1150         return;
 1151 
 1152 #else
 1153         wxMimeTypesManager mimeMgr;
 1154         wxFileType *fileType = mimeMgr.GetFileTypeFromExtension (document.GetExt());
 1155         if (fileType)
 1156         {
 1157             try
 1158             {
 1159                 if (wxExecute (fileType->GetOpenCommand (document.GetFullPath())) != 0)
 1160                     return;
 1161             }
 1162             catch (TimeOut&) { }
 1163         }
 1164 #endif
 1165     }
 1166 
 1167     wxString GraphicUserInterface::GetHomepageLinkURL (const wxString &linkId, const wxString &extraVars) const
 1168     {
 1169         wxString url = wxString (TC_APPLINK);
 1170         bool buildUrl = true;
 1171 
 1172         if (linkId == L"donate")
 1173         {
 1174             url = L"Donation.html";
 1175         }
 1176         else if (linkId == L"main")
 1177         {
 1178             url = wxString (TC_HOMEPAGE);
 1179             buildUrl = false;
 1180         }
 1181         else if (linkId == L"onlinehelp")
 1182         {
 1183             url = L"https://www.veracrypt.fr/en/Documentation.html";
 1184             buildUrl = false;
 1185         }
 1186         else if (linkId == L"localizations")
 1187         {
 1188             url = L"Language Packs.html";
 1189         }
 1190         else if (linkId == L"beginnerstutorial" || linkId == L"tutorial")
 1191         {
 1192             url = L"Beginner's Tutorial.html";
 1193         }
 1194         else if (linkId == L"releasenotes" || linkId == L"history")
 1195         {
 1196             url = L"Release Notes.html";
 1197         }
 1198         else if (linkId == L"hwacceleration")
 1199         {
 1200             url = L"Hardware Acceleration.html";
 1201         }
 1202         else if (linkId == L"parallelization")
 1203         {
 1204             url = L"Parallelization.html";
 1205         }
 1206         else if (linkId == L"help")
 1207         {
 1208             url = L"Documentation.html";
 1209         }
 1210         else if (linkId == L"keyfiles")
 1211         {
 1212             url = L"Keyfiles.html";
 1213         }
 1214         else if (linkId == L"introcontainer")
 1215         {
 1216             url = L"Creating New Volumes.html";
 1217         }
 1218         else if (linkId == L"introsysenc")
 1219         {
 1220             url = L"System Encryption.html";
 1221         }
 1222         else if (linkId == L"hiddensysenc")
 1223         {
 1224             url = L"VeraCrypt Hidden Operating System.html";
 1225         }
 1226         else if (linkId == L"sysencprogressinfo")
 1227         {
 1228             url = L"System Encryption.html";
 1229         }
 1230         else if (linkId == L"hiddenvolume")
 1231         {
 1232             url = L"Hidden Volume.html";
 1233         }
 1234         else if (linkId == L"aes")
 1235         {
 1236             url = L"AES.html";
 1237         }
 1238         else if (linkId == L"serpent")
 1239         {
 1240             url = L"Serpent.html";
 1241         }
 1242         else if (linkId == L"twofish")
 1243         {
 1244             url = L"Twofish.html";
 1245         }
 1246         else if (linkId == L"camellia")
 1247         {
 1248             url = L"Camellia.html";
 1249         }
 1250         else if (linkId == L"kuznyechik")
 1251         {
 1252             url = L"Kuznyechik.html";
 1253         }
 1254         else if (linkId == L"cascades")
 1255         {
 1256             url = L"Cascades.html";
 1257         }
 1258         else if (linkId == L"hashalgorithms")
 1259         {
 1260             url = L"Hash Algorithms.html";
 1261         }
 1262         else if (linkId == L"isoburning")
 1263         {
 1264             url = L"https://cdburnerxp.se/en/home";
 1265             buildUrl = false;
 1266         }
 1267         else if (linkId == L"sysfavorites")
 1268         {
 1269             url = L"System Favorite Volumes.html";
 1270         }
 1271         else if (linkId == L"favorites")
 1272         {
 1273             url = L"Favorite Volumes.html";
 1274         }
 1275         else if (linkId == L"hiddenvolprotection")
 1276         {
 1277             url = L"Protection of Hidden Volumes.html";
 1278         }
 1279         else if (linkId == L"faq")
 1280         {
 1281             url = L"FAQ.html";
 1282         }
 1283         else if (linkId == L"downloads")
 1284         {
 1285             url = L"Downloads.html";
 1286         }
 1287         else if (linkId == L"news")
 1288         {
 1289             url = L"News.html";
 1290         }
 1291         else if (linkId == L"contact")
 1292         {
 1293             url = L"Contact.html";
 1294         }
 1295         else
 1296         {
 1297             buildUrl = false;
 1298         }
 1299         
 1300         if (buildUrl)
 1301         {
 1302             wxString htmlPath = wstring (Application::GetExecutableDirectory());
 1303             bool localFile = true;
 1304 
 1305 #ifdef TC_RESOURCE_DIR
 1306             htmlPath = StringConverter::ToWide (string (TC_TO_STRING (TC_RESOURCE_DIR)) + "/doc/HTML/");
 1307 #elif defined (TC_WINDOWS)
 1308             htmlPath += L"\\docs\\html\\en\\";
 1309 #elif defined (TC_MACOSX)
 1310             htmlPath += L"/../Resources/doc/HTML/";
 1311 #elif defined (TC_UNIX)
 1312             htmlPath = L"/usr/share/veracrypt/doc/HTML/";
 1313 #else
 1314             localFile = false;
 1315 #endif
 1316             if (localFile)
 1317             {
 1318                 /* check if local file exists */
 1319                 wxFileName htmlFile = htmlPath + url;
 1320                 htmlFile.Normalize();
 1321                 localFile = htmlFile.FileExists();
 1322             }
 1323 
 1324             if (!localFile)
 1325             {
 1326                 htmlPath = L"https://www.veracrypt.fr/en/";
 1327             }
 1328             else
 1329             {
 1330                 htmlPath = L"file://" + htmlPath;
 1331             }
 1332             url.Replace (L" ", L"%20");
 1333             url.Replace (L"'", L"%27");
 1334 
 1335             url = htmlPath + url;
 1336         }
 1337 
 1338         return url;
 1339     }
 1340 
 1341     void GraphicUserInterface::OpenHomepageLink (wxWindow *parent, const wxString &linkId, const wxString &extraVars)
 1342     {
 1343         wxString url;
 1344 
 1345         BeginInteractiveBusyState (parent);
 1346         wxLaunchDefaultBrowser (GetHomepageLinkURL (linkId, extraVars), wxBROWSER_NEW_WINDOW);
 1347         Thread::Sleep (200);
 1348         EndInteractiveBusyState (parent);
 1349     }
 1350 
 1351     void GraphicUserInterface::OpenOnlineHelp (wxWindow *parent)
 1352     {
 1353         OpenHomepageLink (parent, L"onlinehelp");
 1354     }
 1355 
 1356     void GraphicUserInterface::OpenUserGuide (wxWindow *parent)
 1357     {
 1358         OpenHomepageLink (parent, L"help");
 1359     }
 1360 
 1361     void GraphicUserInterface::RestoreVolumeHeaders (shared_ptr <VolumePath> volumePath) const
 1362     {
 1363         wxWindow *parent = GetActiveWindow();
 1364 
 1365         if (!volumePath || volumePath->IsEmpty())
 1366             volumePath = make_shared <VolumePath> (SelectVolumeFile (GetActiveWindow()));
 1367 
 1368         if (volumePath->IsEmpty())
 1369             throw UserAbort (SRC_POS);
 1370 
 1371 #ifdef TC_WINDOWS
 1372         if (Core->IsVolumeMounted (*volumePath))
 1373         {
 1374             ShowInfo ("DISMOUNT_FIRST");
 1375             return;
 1376         }
 1377 #endif
 1378 
 1379 #ifdef TC_UNIX
 1380         // Temporarily take ownership of a device if the user is not an administrator
 1381         UserId origDeviceOwner ((uid_t) -1);
 1382 
 1383         if (!Core->HasAdminPrivileges() && volumePath->IsDevice())
 1384         {
 1385             origDeviceOwner = FilesystemPath (wstring (*volumePath)).GetOwner();
 1386             Core->SetFileOwner (*volumePath, UserId (getuid()));
 1387         }
 1388 
 1389         finally_do_arg2 (FilesystemPath, *volumePath, UserId, origDeviceOwner,
 1390         {
 1391             if (finally_arg2.SystemId != (uid_t) -1)
 1392                 Core->SetFileOwner (finally_arg, finally_arg2);
 1393         });
 1394 #endif
 1395 
 1396         // Ask whether to restore internal or external backup
 1397         bool restoreInternalBackup;
 1398         wxArrayString choices;
 1399         choices.Add (LangString["HEADER_RESTORE_INTERNAL"]);
 1400         choices.Add (LangString["HEADER_RESTORE_EXTERNAL"]);
 1401 
 1402         wxSingleChoiceDialog choiceDialog (parent, LangString["HEADER_RESTORE_EXTERNAL_INTERNAL"], Application::GetName(), choices);
 1403         choiceDialog.SetSize (wxSize (Gui->GetCharWidth (&choiceDialog) * 80, -1));
 1404         choiceDialog.SetSelection (0);
 1405 
 1406         if (choiceDialog.ShowModal() != wxID_OK)
 1407             return;
 1408 
 1409         switch (choiceDialog.GetSelection())
 1410         {
 1411         case 0:
 1412             restoreInternalBackup = true;
 1413             break;
 1414 
 1415         case 1:
 1416             restoreInternalBackup = false;
 1417             break;
 1418 
 1419         default:
 1420             return;
 1421         }
 1422 
 1423         /* force the display of the random enriching interface */
 1424         RandomNumberGenerator::SetEnrichedByUserStatus (false);
 1425 
 1426         if (restoreInternalBackup)
 1427         {
 1428             // Restore header from the internal backup
 1429             shared_ptr <Volume> volume;
 1430             MountOptions options;
 1431             options.Path = volumePath;
 1432 
 1433             MountOptionsDialog dialog (parent, options, wxEmptyString, true);
 1434 
 1435             while (!volume)
 1436             {
 1437                 dialog.Hide();
 1438                 if (dialog.ShowModal() != wxID_OK)
 1439                     return;
 1440 
 1441                 try
 1442                 {
 1443                     wxBusyCursor busy;
 1444                     OpenVolumeThreadRoutine routine(
 1445                         options.Path,
 1446                         options.PreserveTimestamps,
 1447                         options.Password,
 1448                         options.Pim,
 1449                         options.Kdf,
 1450                         options.TrueCryptMode,
 1451                         options.Keyfiles,
 1452                         options.Protection,
 1453                         options.ProtectionPassword,
 1454                         options.ProtectionPim,
 1455                         options.ProtectionKdf,
 1456                         options.ProtectionKeyfiles,
 1457                         options.SharedAccessAllowed,
 1458                         VolumeType::Unknown,
 1459                         true
 1460                         );
 1461 
 1462                         ExecuteWaitThreadRoutine (parent, &routine);
 1463                         volume = routine.m_pVolume;
 1464                 }
 1465                 catch (PasswordException &e)
 1466                 {
 1467                     ShowWarning (e);
 1468                 }
 1469             }
 1470 
 1471             shared_ptr <VolumeLayout> layout = volume->GetLayout();
 1472             if (typeid (*layout) == typeid (VolumeLayoutV1Normal))
 1473             {
 1474                 ShowError ("VOLUME_HAS_NO_BACKUP_HEADER");
 1475                 return;
 1476             }
 1477 
 1478             RandomNumberGenerator::Start();
 1479             UserEnrichRandomPool (nullptr);
 1480 
 1481             // Re-encrypt volume header
 1482             wxBusyCursor busy;
 1483             SecureBuffer newHeaderBuffer (volume->GetLayout()->GetHeaderSize());
 1484             ReEncryptHeaderThreadRoutine routine(newHeaderBuffer, volume->GetHeader(), options.Password, options.Pim, options.Keyfiles);
 1485 
 1486             ExecuteWaitThreadRoutine (parent, &routine);
 1487 
 1488             // Write volume header
 1489             int headerOffset = volume->GetLayout()->GetHeaderOffset();
 1490             shared_ptr <File> volumeFile = volume->GetFile();
 1491 
 1492             if (headerOffset >= 0)
 1493                 volumeFile->SeekAt (headerOffset);
 1494             else
 1495                 volumeFile->SeekEnd (headerOffset);
 1496 
 1497             volumeFile->Write (newHeaderBuffer);
 1498         }
 1499         else
 1500         {
 1501             // Restore header from an external backup
 1502 
 1503             wxString confirmMsg = LangString["CONFIRM_VOL_HEADER_RESTORE"];
 1504 
 1505             if (!AskYesNo (wxString::Format (confirmMsg, wstring (*volumePath).c_str()), true, true))
 1506                 return;
 1507 
 1508             FilePathList files = SelectFiles (parent, wxEmptyString, false, false);
 1509             if (files.empty())
 1510                 return;
 1511 
 1512             File backupFile;
 1513             backupFile.Open (*files.front(), File::OpenRead);
 1514 
 1515             bool legacyBackup;
 1516 
 1517             // Determine the format of the backup file
 1518             switch (backupFile.Length())
 1519             {
 1520             case TC_VOLUME_HEADER_GROUP_SIZE:
 1521                 legacyBackup = false;
 1522                 break;
 1523 
 1524             case TC_VOLUME_HEADER_SIZE_LEGACY * 2:
 1525                 legacyBackup = true;
 1526                 break;
 1527 
 1528             default:
 1529                 ShowError ("HEADER_BACKUP_SIZE_INCORRECT");
 1530                 return;
 1531             }
 1532 
 1533             // Open the volume header stored in the backup file
 1534             MountOptions options;
 1535 
 1536             MountOptionsDialog dialog (parent, options, LangString["ENTER_HEADER_BACKUP_PASSWORD"], true);
 1537             shared_ptr <VolumeLayout> decryptedLayout;
 1538 
 1539             while (!decryptedLayout)
 1540             {
 1541                 dialog.Hide();
 1542                 if (dialog.ShowModal() != wxID_OK)
 1543                     return;
 1544 
 1545                 try
 1546                 {
 1547                     wxBusyCursor busy;
 1548 
 1549                     // Test volume layouts
 1550                     foreach (shared_ptr <VolumeLayout> layout, VolumeLayout::GetAvailableLayouts ())
 1551                     {
 1552                         if (layout->HasDriveHeader())
 1553                             continue;
 1554 
 1555                         if (!legacyBackup && (typeid (*layout) == typeid (VolumeLayoutV1Normal)))
 1556                             continue;
 1557 
 1558                         if (legacyBackup && (typeid (*layout) == typeid (VolumeLayoutV2Normal) || typeid (*layout) == typeid (VolumeLayoutV2Hidden)))
 1559                             continue;
 1560 
 1561                         SecureBuffer headerBuffer (layout->GetHeaderSize());
 1562                         backupFile.ReadAt (headerBuffer, layout->GetType() == VolumeType::Hidden ? layout->GetHeaderSize() : 0);
 1563 
 1564                         // Decrypt header
 1565                         shared_ptr <VolumePassword> passwordKey = Keyfile::ApplyListToPassword (options.Keyfiles, options.Password);
 1566                         Pkcs5KdfList keyDerivationFunctions = layout->GetSupportedKeyDerivationFunctions(options.TrueCryptMode);
 1567                         EncryptionAlgorithmList encryptionAlgorithms = layout->GetSupportedEncryptionAlgorithms();
 1568                         EncryptionModeList encryptionModes = layout->GetSupportedEncryptionModes();
 1569 
 1570                         DecryptThreadRoutine decryptRoutine(layout->GetHeader(), headerBuffer, *passwordKey, options.Pim, options.Kdf, options.TrueCryptMode, keyDerivationFunctions, encryptionAlgorithms, encryptionModes);
 1571 
 1572                         ExecuteWaitThreadRoutine (parent, &decryptRoutine);
 1573 
 1574                         if (decryptRoutine.m_bResult)
 1575                         {
 1576                             decryptedLayout = layout;
 1577                             break;
 1578                         }
 1579                     }
 1580 
 1581                     if (!decryptedLayout)
 1582                         throw PasswordIncorrect (SRC_POS);
 1583                 }
 1584                 catch (PasswordException &e)
 1585                 {
 1586                     ShowWarning (e);
 1587                 }
 1588             }
 1589 
 1590             File volumeFile;
 1591             volumeFile.Open (*volumePath, File::OpenReadWrite, File::ShareNone, File::PreserveTimestamps);
 1592 
 1593             RandomNumberGenerator::Start();
 1594             UserEnrichRandomPool (nullptr);
 1595 
 1596             // Re-encrypt volume header
 1597             wxBusyCursor busy;
 1598             SecureBuffer newHeaderBuffer (decryptedLayout->GetHeaderSize());
 1599             ReEncryptHeaderThreadRoutine routine(newHeaderBuffer, decryptedLayout->GetHeader(), options.Password, options.Pim, options.Keyfiles);
 1600 
 1601             ExecuteWaitThreadRoutine (parent, &routine);
 1602 
 1603             // Write volume header
 1604             int headerOffset = decryptedLayout->GetHeaderOffset();
 1605             if (headerOffset >= 0)
 1606                 volumeFile.SeekAt (headerOffset);
 1607             else
 1608                 volumeFile.SeekEnd (headerOffset);
 1609 
 1610             volumeFile.Write (newHeaderBuffer);
 1611 
 1612             if (decryptedLayout->HasBackupHeader())
 1613             {
 1614                 // Re-encrypt backup volume header
 1615                 ReEncryptHeaderThreadRoutine backupRoutine(newHeaderBuffer, decryptedLayout->GetHeader(), options.Password, options.Pim, options.Keyfiles);
 1616 
 1617                 ExecuteWaitThreadRoutine (parent, &backupRoutine);
 1618 
 1619                 // Write backup volume header
 1620                 headerOffset = decryptedLayout->GetBackupHeaderOffset();
 1621                 if (headerOffset >= 0)
 1622                     volumeFile.SeekAt (headerOffset);
 1623                 else
 1624                     volumeFile.SeekEnd (headerOffset);
 1625 
 1626                 volumeFile.Write (newHeaderBuffer);
 1627             }
 1628         }
 1629 
 1630         ShowInfo ("VOL_HEADER_RESTORED");
 1631     }
 1632 
 1633     DevicePath GraphicUserInterface::SelectDevice (wxWindow *parent) const
 1634     {
 1635         try
 1636         {
 1637             DeviceSelectionDialog dialog (parent);
 1638             if (dialog.ShowModal() == wxID_OK)
 1639             {
 1640                 return dialog.SelectedDevice.Path;
 1641             }
 1642         }
 1643         catch (exception &e)
 1644         {
 1645             Gui->ShowError (e);
 1646         }
 1647 
 1648         return DevicePath();
 1649     }
 1650 
 1651     DirectoryPath GraphicUserInterface::SelectDirectory (wxWindow *parent, const wxString &message, bool existingOnly) const
 1652     {
 1653         /* Avoid OS leaking previously used directory when user choose not to save history */
 1654         wxString defaultPath;
 1655         if (!GetPreferences().SaveHistory)
 1656             defaultPath = wxGetHomeDir ();
 1657 
 1658         return DirectoryPath (::wxDirSelector (!message.empty() ? message :
 1659 #ifdef __WXGTK__
 1660             wxDirSelectorPromptStr,
 1661 #else
 1662             L"",
 1663 #endif
 1664             defaultPath, wxDD_DEFAULT_STYLE | (existingOnly ? wxDD_DIR_MUST_EXIST : 0), wxDefaultPosition, parent).wc_str());
 1665     }
 1666 
 1667     FilePathList GraphicUserInterface::SelectFiles (wxWindow *parent, const wxString &caption, bool saveMode, bool allowMultiple, const list < pair <wstring, wstring> > &fileExtensions, const DirectoryPath &directory) const
 1668     {
 1669         FilePathList files;
 1670 
 1671         long style;
 1672         if (saveMode)
 1673             style = wxFD_SAVE | wxFD_OVERWRITE_PROMPT;
 1674         else
 1675             style = wxFD_OPEN | wxFD_FILE_MUST_EXIST | (allowMultiple ? wxFD_MULTIPLE : 0);
 1676 
 1677         wxString wildcards = L"*.*";
 1678 
 1679 #ifndef __WXGTK__
 1680         if (!fileExtensions.empty())
 1681 #endif
 1682         {
 1683             wildcards = LangString["ALL_FILES"] +
 1684 #ifdef TC_WINDOWS
 1685                 L" (*.*)|*.*";
 1686 #else
 1687                 L"|*";
 1688 #endif
 1689             typedef pair <wstring, wstring> StringPair;
 1690             foreach (StringPair p, fileExtensions)
 1691             {
 1692                 if (p.first == L"*" || p.first == L"*.*")
 1693                 {
 1694                     wildcards += L"|" + wildcards.substr (0, wildcards.find (L"*|") + 1);
 1695                     wildcards = wildcards.substr (wildcards.find (L"*|") + 2);
 1696                     continue;
 1697                 }
 1698 
 1699                 wildcards += wxString (L"|") + p.second + L" (*." + p.first + L")|*." + p.first;
 1700             }
 1701         }
 1702 
 1703         /* Avoid OS leaking previously used directory when user choose not to save history */
 1704         wxString defaultDir = wstring (directory);
 1705         if (defaultDir.IsEmpty () && !GetPreferences().SaveHistory)
 1706             defaultDir = wxGetHomeDir ();
 1707 
 1708         wxFileDialog dialog (parent, !caption.empty() ? caption : LangString ["OPEN_TITLE"], defaultDir, wxString(), wildcards, style);
 1709 
 1710         if (dialog.ShowModal() == wxID_OK)
 1711         {
 1712             if (!allowMultiple)
 1713                 files.push_back (make_shared <FilePath> (dialog.GetPath().wc_str()));
 1714             else
 1715             {
 1716                 wxArrayString paths;
 1717                 dialog.GetPaths (paths);
 1718 
 1719                 foreach (const wxString &path, paths)
 1720                     files.push_back (make_shared <FilePath> (path.wc_str()));
 1721             }
 1722         }
 1723 
 1724         return files;
 1725     }
 1726 
 1727     FilePath GraphicUserInterface::SelectVolumeFile (wxWindow *parent, bool saveMode, const DirectoryPath &directory) const
 1728     {
 1729         list < pair <wstring, wstring> > extensions;
 1730         extensions.push_back (make_pair (L"hc", LangString["TC_VOLUMES"].ToStdWstring()));
 1731 
 1732         FilePathList selFiles = Gui->SelectFiles (parent, LangString[saveMode ? "OPEN_NEW_VOLUME" : "OPEN_VOL_TITLE"], saveMode, false, extensions, directory);
 1733 
 1734         if (!selFiles.empty())
 1735             return *selFiles.front();
 1736         else
 1737             return FilePath();
 1738     }
 1739 
 1740     void GraphicUserInterface::SetBackgroundMode (bool state)
 1741     {
 1742 #ifdef TC_MACOSX
 1743         // Hiding an iconized window on OS X apparently cannot be reversed
 1744         if (state && mMainFrame->IsIconized())
 1745             mMainFrame->Iconize (false);
 1746 #endif
 1747         mMainFrame->Show (!state);
 1748         if (!state)
 1749         {
 1750             if (mMainFrame->IsIconized())
 1751                 mMainFrame->Iconize (false);
 1752 
 1753             mMainFrame->Raise();
 1754         }
 1755 
 1756         BackgroundMode = state;
 1757     }
 1758 
 1759     void GraphicUserInterface::SetListCtrlColumnWidths (wxListCtrl *listCtrl, list <int> columnWidthPermilles, bool hasVerticalScrollbar) const
 1760     {
 1761 #ifdef TC_MACOSX
 1762         hasVerticalScrollbar = true;
 1763 #endif
 1764         int listWidth = listCtrl->GetSize().GetWidth();
 1765         int minListWidth = listCtrl->GetMinSize().GetWidth();
 1766         if (minListWidth > listWidth)
 1767             listWidth = minListWidth;
 1768 
 1769         listWidth -= GetScrollbarWidth (listCtrl, !hasVerticalScrollbar);
 1770 
 1771         int col = 0;
 1772         int totalColWidth = 0;
 1773         foreach (int colWidth, columnWidthPermilles)
 1774         {
 1775             int width = listWidth * colWidth / 1000;
 1776             totalColWidth += width;
 1777 
 1778             if (col == listCtrl->GetColumnCount() - 1)
 1779                 width += listWidth - totalColWidth;
 1780 
 1781             listCtrl->SetColumnWidth (col++, width);
 1782         }
 1783     }
 1784 
 1785     void GraphicUserInterface::SetListCtrlHeight (wxListCtrl *listCtrl, size_t rowCount) const
 1786     {
 1787         wxRect itemRect;
 1788         if (listCtrl->GetItemCount() == 0)
 1789         {
 1790             bool addedCols = false;
 1791             if (listCtrl->GetColumnCount() == 0)
 1792             {
 1793                 listCtrl->InsertColumn (0, L".", wxLIST_FORMAT_LEFT, 1);
 1794                 addedCols = true;
 1795             }
 1796             vector <wstring> f;
 1797             f.push_back (L".");
 1798             AppendToListCtrl (listCtrl, f);
 1799             listCtrl->GetItemRect (0, itemRect);
 1800 
 1801             if (addedCols)
 1802                 listCtrl->ClearAll();
 1803             else
 1804                 listCtrl->DeleteAllItems();
 1805         }
 1806         else
 1807             listCtrl->GetItemRect (0, itemRect);
 1808 
 1809         int headerHeight = itemRect.y;
 1810 #ifdef TC_WINDOWS
 1811         headerHeight += 4;
 1812 #elif defined (TC_MACOSX)
 1813         headerHeight += 7;
 1814 #elif defined (__WXGTK__)
 1815         headerHeight += 5;
 1816 #endif
 1817         int rowHeight = itemRect.height;
 1818 #ifdef TC_MACOSX
 1819         rowHeight += 1;
 1820 #endif
 1821         listCtrl->SetMinSize (wxSize (listCtrl->GetMinSize().GetWidth(), rowHeight * rowCount + headerHeight));
 1822     }
 1823 
 1824     void GraphicUserInterface::SetListCtrlWidth (wxListCtrl *listCtrl, size_t charCount, bool hasVerticalScrollbar) const
 1825     {
 1826         int width = GetCharWidth (listCtrl) * charCount;
 1827 #ifdef TC_MACOSX
 1828         if (!hasVerticalScrollbar)
 1829             width += GetScrollbarWidth (listCtrl);
 1830 #endif
 1831         listCtrl->SetMinSize (wxSize (width, listCtrl->GetMinSize().GetHeight()));
 1832     }
 1833 
 1834     void GraphicUserInterface::ShowErrorTopMost (const wxString &message) const
 1835     {
 1836         ShowMessage (message, wxOK | wxICON_ERROR, true);
 1837     }
 1838 
 1839     void GraphicUserInterface::ShowInfoTopMost (const wxString &message) const
 1840     {
 1841         ShowMessage (message, wxOK | wxICON_INFORMATION, true);
 1842     }
 1843 
 1844     int GraphicUserInterface::ShowMessage (const wxString &message, long style, bool topMost) const
 1845     {
 1846         wxString caption = Application::GetName();
 1847         wxString subMessage = message;
 1848 
 1849 #ifdef TC_MACOSX
 1850         size_t p = message.find (L"\n");
 1851         if (p != string::npos)
 1852         {
 1853             // Divide message to caption and info message
 1854             caption = message.substr (0, p);
 1855 
 1856             p = message.find_first_not_of (L'\n', p);
 1857             if (p != string::npos)
 1858                 subMessage = message.substr (p);
 1859             else
 1860                 subMessage.clear();
 1861 
 1862             if (subMessage.EndsWith (L"?"))
 1863             {
 1864                 // Move question to caption
 1865                 caption += wstring (L" ");
 1866                 p = subMessage.find_last_of (L".\n");
 1867                 if (p != string::npos)
 1868                 {
 1869                     if (caption.EndsWith (L": "))
 1870                         caption[caption.size() - 2] = L'.';
 1871 
 1872                     caption += subMessage.substr (subMessage.find_first_not_of (L"\n ", p + 1));
 1873                     subMessage = subMessage.substr (0, p + 1);
 1874                 }
 1875                 else
 1876                 {
 1877                     caption += subMessage.substr (subMessage.find_first_not_of (L"\n"));
 1878                     subMessage.clear();
 1879                 }
 1880             }
 1881         }
 1882         else if (message.size() < 160)
 1883         {
 1884             caption = message;
 1885             subMessage.clear();
 1886         }
 1887         else
 1888         {
 1889             if (style & wxICON_EXCLAMATION)
 1890                 caption = wxString (_("Warning")) + L':';
 1891             else if (style & wxICON_ERROR || style & wxICON_HAND)
 1892                 caption = wxString (_("Error")) + L':';
 1893             else
 1894                 caption.clear();
 1895         }
 1896 #endif
 1897         if (mWaitDialog)
 1898         {
 1899             return mWaitDialog->RequestShowMessage(subMessage, caption, style, topMost);
 1900         }
 1901         else
 1902         {
 1903             if (topMost)
 1904             {
 1905                 if (!IsActive())
 1906                     mMainFrame->RequestUserAttention (wxUSER_ATTENTION_ERROR);
 1907 
 1908                 style |= wxSTAY_ON_TOP;
 1909             }
 1910 
 1911             return wxMessageBox (subMessage, caption, style, GetActiveWindow());
 1912         }
 1913     }
 1914 
 1915     void GraphicUserInterface::ShowWarningTopMost (const wxString &message) const
 1916     {
 1917         ShowMessage (message, wxOK
 1918 #ifndef TC_MACOSX
 1919             | wxICON_EXCLAMATION
 1920 #endif
 1921             , true);
 1922     }
 1923 
 1924     void GraphicUserInterface::ThrowTextModeRequired () const
 1925     {
 1926         Gui->ShowError (_("This feature is currently supported only in text mode."));
 1927         throw UserAbort (SRC_POS);
 1928     }
 1929 
 1930     bool GraphicUserInterface::UpdateListCtrlItem (wxListCtrl *listCtrl, long itemIndex, const vector <wstring> &itemFields) const
 1931     {
 1932         bool changed = false;
 1933         wxListItem item;
 1934         item.SetId (itemIndex);
 1935         item.SetText (L"");
 1936 
 1937         int col = 0;
 1938         foreach (wxString field, itemFields)
 1939         {
 1940             item.SetColumn (col++);
 1941 
 1942             if (!listCtrl->GetItem (item))
 1943                 throw ParameterIncorrect (SRC_POS);
 1944 
 1945             if (item.GetText() != field)
 1946             {
 1947                 item.SetText (field);
 1948                 listCtrl->SetItem (item);
 1949                 if (item.GetColumn() == 3 || item.GetColumn() == 4)
 1950                     listCtrl->SetColumnWidth(item.GetColumn(), wxLIST_AUTOSIZE);
 1951                 changed = true;
 1952             }
 1953         }
 1954         return changed;
 1955     }
 1956 
 1957     void GraphicUserInterface::UserEnrichRandomPool (wxWindow *parent, shared_ptr <Hash> hash) const
 1958     {
 1959         RandomNumberGenerator::Start();
 1960 
 1961         if (hash)
 1962             RandomNumberGenerator::SetHash (hash);
 1963 
 1964         if (!RandomNumberGenerator::IsEnrichedByUser())
 1965         {
 1966             RandomPoolEnrichmentDialog dialog (parent);
 1967             RandomNumberGenerator::SetEnrichedByUserStatus (dialog.ShowModal() == wxID_OK);
 1968         }
 1969     }
 1970 
 1971     void GraphicUserInterface::Yield () const
 1972     {
 1973 #ifndef TC_WINDOWS
 1974         wxSafeYield (nullptr, true);
 1975 #endif
 1976     }
 1977 
 1978     shared_ptr <VolumeInfo> GraphicUserInterface::MountVolumeThread (MountOptions &options) const
 1979     {
 1980         MountThreadRoutine routine(options);
 1981 
 1982         ExecuteWaitThreadRoutine(GetTopWindow(), &routine);
 1983         return routine.m_pVolume;
 1984     }
 1985 
 1986     void GraphicUserInterface::ExecuteWaitThreadRoutine (wxWindow *parent, WaitThreadRoutine *pRoutine) const
 1987     {
 1988         WaitDialog dlg(parent, LangString["IDT_STATIC_MODAL_WAIT_DLG_INFO"], pRoutine);
 1989         mWaitDialog = &dlg;
 1990         finally_do_arg (WaitDialog**, &mWaitDialog, { *finally_arg = nullptr; });
 1991         dlg.Run();
 1992     }
 1993 
 1994     DEFINE_EVENT_TYPE (TC_EVENT_THREAD_EXITING);
 1995 
 1996     GraphicUserInterface *Gui = nullptr;
 1997 }