(*
    Tux Commander - UConfig - Configuration saving/restoring, various constants
    Copyright (C) 2008 Tomas Bzatek <tbzatek@users.sourceforge.net>
    Check for updates on tuxcmd.sourceforge.net

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*)
unit UConfig;

interface                   

uses Classes, ULocale;

resourcestring
  ConstAppTitle = 'Tux Commander';
  ConstAboutVersion = '0.6.70-dev';
  ConstAboutBuildDate = '2009-11-15';
  
{$IFDEF FPC}
  {$INCLUDE fpcver.inc}
{$ENDIF}

const ConfDefaultNormalItemFGColor = '#000000';
      ConfDefaultActiveItemFGColor = '#FFFFFF';
      ConfDefaultInactiveItemFGColor = '#000000';
      ConfDefaultSelectedItemFGColor = '#FF0000';
      ConfDefaultLinkItemFGColor = '#A0A0A0';
      ConfDefaultDotFileItemFGColor = '#606060';
      ConfDefaultNormalItemBGColor = '#FFFFFF';
      ConfDefaultActiveItemBGColor = '#000000';
      ConfDefaultInactiveItemBGColor = '#D0D0D0';

      ConfSelItemsDelim = ';';
      ConfDefaultPanelFont = 'Sans 10';
      ConfDefaultSettingsDir = '.tuxcmd';      //  Also has to be changed in UGTKLoader
      ConfDblClickDelay = 500;
      ConfQuickRenameDelay = ConfDblClickDelay + 250;
      ConfInactiveTimerDelay = 0;
      ConfEditViewFileSizeLimit = 10*1024*1024;   //  10 MB
      ConfAppNA = '---';
      ConfDefaultRowHeight = 16;
      ConstInternalProgressTimer = 25;    //  default = 25ms
      ConstRemoteWaitDialogDelay = 800;   //  default = 800ms
      ConstFileListTipsDelay = 400;
      ConstFileListTipsDelayNeighbour = 95;
      ConstNumPanelColumns = 10;
      ConstFullPathFormatStr = '%s#%s';
      ConstConnMgrXORKey = 65;

      ConstTerminalCommand_xterm = 'xterm -T "TuxCommand" -e sh -c ''%s ; echo -n Press ENTER to exit... ; read''';
      ConstTerminalCommand_rxvt = 'rxvt -T "TuxCommand" -e sh -c ''%s ; echo -n Press ENTER to exit... ; read''';
      ConstTerminalCommand_rxvt2 = 'rxvt +si +sw -sl 1000 -g 130x50 -bg black -fg grey -T "TuxCommand" -e sh -c ''%s ; echo -n Press ENTER to exit... ; read''';
      ConstTerminalCommand_gnometerminal = 'gnome-terminal -t "TuxCommand" --geometry=110x40 --working-directory=%cwd -x sh -c ''%s ; echo -n Press ENTER to exit... ; read''';
      ConfViewersApps: array[1..6] of string = ('gedit', 'gvim', 'less', 'emacs', 'nano', 'vi');
      ConfEditorApps: array[1..5] of string = ('gedit', 'gvim', 'emacs', 'nano', 'vi');
      ConfTerminalApps: array[1..4] of string = (ConstTerminalCommand_xterm, ConstTerminalCommand_rxvt, ConstTerminalCommand_rxvt2, ConstTerminalCommand_gnometerminal);
      ConfTerminalAppsWParam: array[1..4] of string = ('xterm', 'rxvt', 'rxvt', 'gnome-terminal');


const SMOOTH_SCROLL_STEPS = 5;
      SMOOTH_SCROLL_DURATION = 45;
      SMOOTH_SCROLL_STEPS_PAGE = 10;
      SMOOTH_SCROLL_DURATION_PAGE = 120;

const tuxcmd_rc_file = 'style "treeview-style" {'#10 +
                       '  GtkTreeView::horizontal_separator = 0'#10 +
                       '  GtkTreeView::vertical_separator = 0'#10 +
                       '}'#10 +
                       'class "GtkTreeView" style "treeview-style"';


var ConfPanelSep, ConfRowHeight, ConfRowHeightReal, ConfNumHistoryItems,
    ConfMainWindowWidth, ConfMainWindowHeight, ConfMainWindowPosLeft, ConfMainWindowPosTop, ConfMainWindowState,
    ConfMainWindowLeftSortColumn, ConfMainWindowLeftSortType, ConfMainWindowRightSortColumn, ConfMainWindowRightSortType,
    ConfSizeFormat, ConfSizeGroupPrecision, ConfCmdLineTerminalBehaviour, ConfViewerTerminalBehaviour,
    ConfEditorTerminalBehaviour, ConfLeftTabBarTabIndex, ConfRightTabBarTabIndex, ConfSwitchOtherPanelBehaviour,
    ConfTabMaxLength, ConfDateFormat, ConfTimeFormat, ConfDateTimeFormat, ConfQuickSearchActivationKey: integer;

    ConfLeftPath, ConfRightPath, ConfPanelFont, ConfProfileName, ConfViewer, ConfEditor, ConfTerminalCommand,
    ConfNormalItemFGColor, ConfActiveItemFGColor, ConfInactiveItemFGColor, ConfSelectedItemFGColor, ConfLinkItemFGColor,
    ConfDotFileItemFGColor, ConfNormalItemBGColor, ConfActiveItemBGColor, ConfInactiveItemBGColor,
    ParamLeftDir, ParamRightDir, ConfCustomDateFormat, ConfCustomTimeFormat: string;

    ParamDebug, ConfShowDotFiles, ConfClearReadOnlyAttr, ConfDisableMouseRename, ConfUseSystemFont, ConfUseFileTypeIcons,
    ConfFocusRefresh, ConfNewStyleAltO, ConfDirsInBold, ConfDisableDirectoryBrackets, ParamDisableGnome, ConfWMCompatMode,
    ConfUseLibcSystem, ConfUseInternalViewer, ParamDisablePlugins: boolean;
    ConfNormalItemDefaultColors, ConfCursorDefaultColors, ConfInactiveItemDefaultColors, ConfSelectedItemDefaultColors,
    ConfLinkItemDefaultColors, ConfDotFileItemDefaultColors, ConfLynxLikeMotion, ConfSizeGroupRequestZeroDigits,
    ConfDisableFileTips, ConfInsMoveDown, ConfSpaceMovesDown, ConfShowFuncButtons, ConfSelectAllDirs, ConfOctalPerm: boolean;
    ConfMounterUseFSTab, ConfShowTextUIDs, ConfMounterPushDown, ConfSavePanelTabs, ConfDuplicateTabWarning,
    ConfOpenConnectionsWarning, ConfSortDirectoriesLikeFiles, ConfQuickRenameSkipExt, ConfRightClickSelect,
    ConfSearchFilterCaseSensitive, ConfSearchOtherFS, ConfSearchArchives, ConfSearchTextCaseSensitive,
    ConfMakeSymlinkRelative, ConfReplaceConnectionWarning, ConfWarnUnsavedConnection: boolean;

    ConfShowMounterBar: integer;
    ConfColumnSizes, ConfColumnIDs: array[1..ConstNumPanelColumns] of integer;
    ConfColumnVisible: array[1..ConstNumPanelColumns] of boolean;
    ConfUseURI: boolean;
    ConfColumnTitlesLong, ConfColumnTitlesShort: array[1..ConstNumPanelColumns] of string;
    ConfParamForceLang: string;
    ConfTempPath: string;
    ConfUseSmoothScrolling: boolean;

    ApplicationShuttingDown: boolean;
    ConfConnMgrActiveItem, ConfConnMgrSortColumn, ConfConnMgrSortType, ConfConnMgrColumn1Width: integer;
    ConfConnMgrDoNotSavePasswords, ConfConnMgrDoNotSynchronizeKeyring: boolean;
    ConfQuickConnectPluginID: string;




procedure SetDefaults;
procedure ReadMainSettings;
procedure WriteMainSettings;
procedure ReadMainGUISettings;
procedure WriteMainGUISettings;
procedure ReadAssoc;
procedure WriteAssoc;
procedure ReadBookmarks;
procedure WriteBookmarks;
procedure ReadMounter;
procedure WriteMounter;
procedure ReadTabs(const LeftPanel: boolean; TabList: TStringList; TabSortIDs, TabSortTypes: TList);
procedure WriteTabs(const LeftPanel: boolean; TabList: TStringList; TabSortIDs, TabSortTypes: TList);
procedure ReadConnections;
procedure WriteConnections;
procedure SearchForDefaultApps;
function CheckConfFilesMod(var ChangedMainGUI, ChangedAssoc, ChangedBookmarks, ChangedMounter, ChangedConnections: boolean): boolean;
//   Returns True if something has changed

implementation

uses ULibc, glib2, SysUtils, UCoreUtils, UCore, UFileAssoc, UCoreClasses, UGnome, UVFSCore;

var InternalQuickExit, InternalDeleteHistory: boolean;
    InternalMainGUIConfmtime, InternalBookmarksConfmtime, InternalFAssocConfmtime, InternalMounterConfmtime,
    InternalConnMgrConfmtime: Longint;


function GetFileTime(FileName: string): time_t; forward;

(********************************************************************************************************************************)
(********************************************************************************************************************************)
procedure SetDefaults;
var i: integer;
begin
  InternalMainGUIConfmtime := -1;
  InternalBookmarksConfmtime := -1;
  InternalFAssocConfmtime := -1;
  InternalMounterConfmtime := -1;
  InternalConnMgrConfmtime := -1;
  InternalQuickExit := False;
  ConfPanelSep := 50;
  ConfLeftPath := '/';
  ConfRightPath := '/';
  ConfColumnSizes[1] := 150;   //  Name
  ConfColumnSizes[2] := 190;   //  Name + Extension
  ConfColumnSizes[3] := 40;    //  Extension
  ConfColumnSizes[4] := 90;    //  Size
  ConfColumnSizes[5] := 75;    //  Date + Time
  ConfColumnSizes[6] := 40;    //  Date
  ConfColumnSizes[7] := 40;    //  Time
  ConfColumnSizes[8] := 40;    //  User
  ConfColumnSizes[9] := 40;    //  Group
  ConfColumnSizes[10] := 70;   //  Attributes
  for i := 1 to ConstNumPanelColumns do ConfColumnIDs[i] := i;
  ConfColumnVisible[1] := True;
  ConfColumnVisible[2] := False;
  ConfColumnVisible[3] := True;
  ConfColumnVisible[4] := True;
  ConfColumnVisible[5] := True;
  ConfColumnVisible[6] := False;
  ConfColumnVisible[7] := False;
  ConfColumnVisible[8] := False;
  ConfColumnVisible[9] := False;
  ConfColumnVisible[10] := True;
  ConfRowHeight := -1;
  ConfRowHeightReal := ConfDefaultRowHeight;
  ConfPanelFont := ConfDefaultPanelFont;
  ConfProfileName := 'Profile_Default';
  ParamDebug := False;
  ConfShowDotFiles := False;
  ConfClearReadOnlyAttr := True;
  ConfViewer := ConfAppNA;
  ConfEditor := ConfAppNA;
  ConfTerminalCommand := ConfAppNA;
  ConfNumHistoryItems := 20;
  ConfDisableMouseRename := False;
  InternalDeleteHistory := False;
  ConfUseSystemFont := True;
  ConfUseFileTypeIcons := True;
  ConfMainWindowWidth := 800;
  ConfMainWindowHeight := 600;
  ConfMainWindowPosLeft := -1;
  ConfMainWindowPosTop := -1;
  ConfMainWindowState := 0;
  ConfMainWindowLeftSortColumn := 0;
  ConfMainWindowLeftSortType := 0;   //  soAscending
  ConfMainWindowRightSortColumn := 0;
  ConfMainWindowRightSortType := 0;
  ConfFocusRefresh := False;
  ConfLynxLikeMotion := False;
  ConfSizeFormat := 0;
  ConfSizeGroupPrecision := 2;
  ConfSizeGroupRequestZeroDigits := True;
  ConfNewStyleAltO := True;
  ConfDirsInBold := False;
  ConfDisableDirectoryBrackets := False;
  ParamDisableGnome := False;
  ConfWMCompatMode := False;
  ConfDisableFileTips := False;
  ConfInsMoveDown := True;
  ConfSpaceMovesDown := False;
  ConfShowFuncButtons := True;
  ConfSelectAllDirs := True;
  ConfOctalPerm := False;
  ConfCmdLineTerminalBehaviour := 0;    //  0 = Autodetect, 1 = Terminal, 2 = no term.
  ConfViewerTerminalBehaviour := 0;
  ConfEditorTerminalBehaviour := 0;
  ConfUseLibcSystem := False;
  ConfUseInternalViewer := False;
  ConfMounterUseFSTab := True;
  ConfShowMounterBar := 1;              //  0 = No mounter bar, 1 = one mounter bar, 2 = two mounter bars above the panels
  ConfShowTextUIDs := True;
  ConfMounterPushDown := False;
  ConfUseURI := False;
  ParamDisablePlugins := False;
  ParamLeftDir := '';
  ParamRightDir := '';
  ConfLeftTabBarTabIndex := -1;
  ConfRightTabBarTabIndex := -1;
  ConfSavePanelTabs := True;
  ConfParamForceLang := '';
  ConfSwitchOtherPanelBehaviour := -1;
  ConfDuplicateTabWarning := True;
  ConfOpenConnectionsWarning := True;
  ConfTabMaxLength := 25;
  ConfTempPath := '/tmp';
  ConfUseSmoothScrolling := False;
  ConfDateFormat := 0;
  ConfTimeFormat := 0;
  ConfDateTimeFormat := 0;
  ConfCustomDateFormat := '%x';
  ConfCustomTimeFormat := '%X';
  ConfQuickSearchActivationKey := 0;
  ConfSortDirectoriesLikeFiles := False;
  ConfQuickRenameSkipExt := True;
  ConfConnMgrActiveItem := 0;
  ConfRightClickSelect := False;
  ConfConnMgrDoNotSavePasswords := False;
  ConfConnMgrDoNotSynchronizeKeyring := False;
  ConfQuickConnectPluginID := '';
  ConfConnMgrSortColumn := -1;
  ConfConnMgrSortType := 2;
  ConfConnMgrColumn1Width := 230;
  ConfSearchFilterCaseSensitive := False;
  ConfSearchOtherFS := False;
  ConfSearchArchives := False;
  ConfSearchTextCaseSensitive := False;
  ConfMakeSymlinkRelative := False;
  ConfReplaceConnectionWarning := True;
  ConfWarnUnsavedConnection := True;


  //  Setup default values for colors
  ConfNormalItemFGColor := ConfDefaultNormalItemFGColor;
  ConfNormalItemBGColor := ConfDefaultNormalItemBGColor;
  ConfActiveItemFGColor := ConfDefaultActiveItemFGColor;
  ConfActiveItemBGColor := ConfDefaultActiveItemBGColor;
  ConfInactiveItemFGColor := ConfDefaultInactiveItemFGColor;
  ConfInactiveItemBGColor := ConfDefaultInactiveItemBGColor;
  ConfSelectedItemFGColor := ConfDefaultSelectedItemFGColor;
  ConfLinkItemFGColor := ConfDefaultLinkItemFGColor;
  ConfDotFileItemFGColor := ConfDefaultDotFileItemFGColor;
  ConfNormalItemDefaultColors := False;
  ConfCursorDefaultColors := False;
  ConfInactiveItemDefaultColors := False;
  ConfSelectedItemDefaultColors := False;
  ConfLinkItemDefaultColors := False;
  ConfDotFileItemDefaultColors := False;
  SetupColors;
end;

procedure ReadMainSettings;
var s: string;
    IniFile: TMyIniFile;
    i, j: integer;
begin
  try
  s := IncludeTrailingPathDelimiter(GetHomePath) + ConfDefaultSettingsDir;
  if not DirectoryExists(s) then
    if not ForceDirectories(s) then begin
      DebugMsg(['*** Error: Cannot read user settings']);
      Exit;
    end;

  DebugMsg(['Using profile ''', ConfProfileName, '''']);
  IniFile := TMyIniFile.Create(IncludeTrailingPathDelimiter(s) + 'options', True);
  try
    if ParamLeftDir <> '' then ConfLeftPath := ParamLeftDir else
      ConfLeftPath := IniFile.ReadString(ConfProfileName, 'LeftPath', ConfLeftPath);
    if ParamRightDir <> '' then ConfRightPath := ParamRightDir else
      ConfRightPath := IniFile.ReadString(ConfProfileName, 'RightPath', ConfRightPath);
    ConfShowDotFiles := IniFile.ReadBool(ConfProfileName, 'ShowDotFiles', ConfShowDotFiles);
    ConfPanelSep := IniFile.ReadInteger(ConfProfileName, 'PanelSep', ConfPanelSep);
    ConfMainWindowWidth := IniFile.ReadInteger(ConfProfileName, 'MainWindowWidth', ConfMainWindowWidth);
    ConfMainWindowHeight := IniFile.ReadInteger(ConfProfileName, 'MainWindowHeight', ConfMainWindowHeight);
    ConfMainWindowPosLeft := IniFile.ReadInteger(ConfProfileName, 'MainWindowPosLeft', ConfMainWindowPosLeft);
    ConfMainWindowPosTop := IniFile.ReadInteger(ConfProfileName, 'MainWindowPosTop', ConfMainWindowPosTop);
    ConfMainWindowState := IniFile.ReadInteger(ConfProfileName, 'MainWindowState', ConfMainWindowState);
    for i := 1 to ConstNumPanelColumns do begin
      ConfColumnSizes[i] := IniFile.ReadInteger(ConfProfileName, Format('ColumnSize[%d]', [i]), ConfColumnSizes[i]);
      ConfColumnIDs[i] := IniFile.ReadInteger(ConfProfileName, Format('ColumnIDs[%d]', [i]), ConfColumnIDs[i]);
      ConfColumnVisible[i] := IniFile.ReadBool(ConfProfileName, Format('ColumnVisible[%d]', [i]), ConfColumnVisible[i]);
    end;
    ConfMainWindowLeftSortColumn := IniFile.ReadInteger(ConfProfileName, 'MainWindowLeftSortColumn', ConfMainWindowLeftSortColumn);
    ConfMainWindowLeftSortType := IniFile.ReadInteger(ConfProfileName, 'MainWindowLeftSortType', ConfMainWindowLeftSortType);
    ConfMainWindowRightSortColumn := IniFile.ReadInteger(ConfProfileName, 'MainWindowRightSortColumn', ConfMainWindowRightSortColumn);
    ConfMainWindowRightSortType := IniFile.ReadInteger(ConfProfileName, 'MainWindowRightSortType', ConfMainWindowRightSortType);
    if not InternalDeleteHistory then begin
      i := IniFile.ReadInteger('CommandLineHistory', 'NumItems', 0);
      if i > 0 then
        for j := 0 to i - 1 do
          CommandLineHistory.Add(IniFile.ReadString('CommandLineHistory', Format('Item%d', [j]), ''));
      i := IniFile.ReadInteger('SelectHistory', 'NumItems', 0);
      if i > 0 then
        for j := 0 to i - 1 do begin
          s := IniFile.ReadString('SelectHistory', Format('Item%d', [j]), '');
          if s <> '*.*' then SelectHistory.Add(s);
        end;
      i := IniFile.ReadInteger('SearchHistory', 'NumItems', 0);
      if i > 0 then
        for j := 0 to i - 1 do
          SearchHistory.Add(IniFile.ReadString('SearchHistory', Format('Item%d', [j]), ''));
      i := IniFile.ReadInteger('SearchTextHistory', 'NumItems', 0);
      if i > 0 then
        for j := 0 to i - 1 do
          SearchTextHistory.Add(IniFile.ReadString('SearchTextHistory', Format('Item%d', [j]), ''));
    end;
    ConfShowMounterBar := IniFile.ReadInteger(ConfProfileName, 'ShowMounterBar', ConfShowMounterBar);
    ConfSearchFilterCaseSensitive := IniFile.ReadBool(ConfProfileName, 'SearchFilterCaseSensitive', ConfSearchFilterCaseSensitive);
    ConfSearchOtherFS := IniFile.ReadBool(ConfProfileName, 'SearchOtherFS', ConfSearchOtherFS);
    ConfSearchArchives := IniFile.ReadBool(ConfProfileName, 'SearchArchives', ConfSearchArchives);
    ConfSearchTextCaseSensitive := IniFile.ReadBool(ConfProfileName, 'SearchTextCaseSensitive', ConfSearchTextCaseSensitive);
    ConfMakeSymlinkRelative := IniFile.ReadBool(ConfProfileName, 'MakeSymlinkRelative', ConfMakeSymlinkRelative);

  finally
    try IniFile.Free; except end;
  end;
  except end;
end;

procedure WriteMainSettings;
var s: string;
    IniFile: TMyIniFile;
    i: integer;
begin
  if InternalQuickExit then Exit;
  ConfLeftPath := LeftLocalEngine.Path;
  ConfRightPath := RightLocalEngine.Path;
  try
  s := IncludeTrailingPathDelimiter(GetHomePath) + ConfDefaultSettingsDir;
  if not DirectoryExists(s) then
    if not ForceDirectories(s) then begin
      DebugMsg(['*** Error: Cannot save user settings']);
      Exit;
    end;

  IniFile := TMyIniFile.Create(IncludeTrailingPathDelimiter(s) + 'options', False);
  try try
    IniFile.WriteString(ConfProfileName, 'LeftPath', ConfLeftPath);
    IniFile.WriteString(ConfProfileName, 'RightPath', ConfRightPath);
    IniFile.WriteBool(ConfProfileName, 'ShowDotFiles', ConfShowDotFiles);
    IniFile.WriteInteger(ConfProfileName, 'PanelSep', ConfPanelSep);
    IniFile.WriteInteger(ConfProfileName, 'MainWindowState', ConfMainWindowState);
    if ConfMainWindowState <> 4 then begin
      IniFile.WriteInteger(ConfProfileName, 'MainWindowWidth', ConfMainWindowWidth);
      IniFile.WriteInteger(ConfProfileName, 'MainWindowHeight', ConfMainWindowHeight);
      IniFile.WriteInteger(ConfProfileName, 'MainWindowPosLeft', ConfMainWindowPosLeft);
      IniFile.WriteInteger(ConfProfileName, 'MainWindowPosTop', ConfMainWindowPosTop);
    end;
    for i := 1 to ConstNumPanelColumns do begin
      IniFile.WriteInteger(ConfProfileName, Format('ColumnSize[%d]', [i]), ConfColumnSizes[i]);
      IniFile.WriteInteger(ConfProfileName, Format('ColumnIDs[%d]', [i]), ConfColumnIDs[i]);
      IniFile.WriteBool(ConfProfileName, Format('ColumnVisible[%d]', [i]), ConfColumnVisible[i]);
    end;
    IniFile.WriteInteger(ConfProfileName, 'MainWindowLeftSortColumn', ConfMainWindowLeftSortColumn);
    IniFile.WriteInteger(ConfProfileName, 'MainWindowLeftSortType', ConfMainWindowLeftSortType);
    IniFile.WriteInteger(ConfProfileName, 'MainWindowRightSortColumn', ConfMainWindowRightSortColumn);
    IniFile.WriteInteger(ConfProfileName, 'MainWindowRightSortType', ConfMainWindowRightSortType);
    IniFile.WriteInteger('CommandLineHistory', 'NumItems', CommandLineHistory.Count);
    IniFile.WriteInteger('SelectHistory', 'NumItems', SelectHistory.Count);
    IniFile.WriteInteger('SearchHistory', 'NumItems', SearchHistory.Count);
    IniFile.WriteInteger('SearchTextHistory', 'NumItems', SearchTextHistory.Count);
    if CommandLineHistory.Count > 0 then
      for i := 0 to CommandLineHistory.Count - 1 do
        IniFile.WriteString('CommandLineHistory', Format('Item%d', [i]), CommandLineHistory[i]);
    if SelectHistory.Count > 0 then
      for i := 0 to SelectHistory.Count - 1 do
        IniFile.WriteString('SelectHistory', Format('Item%d', [i]), SelectHistory[i]);
    if SearchHistory.Count > 0 then
      for i := 0 to SearchHistory.Count - 1 do
        IniFile.WriteString('SearchHistory', Format('Item%d', [i]), SearchHistory[i]);
    if SearchTextHistory.Count > 0 then
      for i := 0 to SearchTextHistory.Count - 1 do
        IniFile.WriteString('SearchTextHistory', Format('Item%d', [i]), SearchTextHistory[i]);
    IniFile.WriteInteger(ConfProfileName, 'ShowMounterBar', ConfShowMounterBar);
    IniFile.WriteBool(ConfProfileName, 'SearchFilterCaseSensitive', ConfSearchFilterCaseSensitive);
    IniFile.WriteBool(ConfProfileName, 'SearchOtherFS', ConfSearchOtherFS);
    IniFile.WriteBool(ConfProfileName, 'SearchArchives', ConfSearchArchives);
    IniFile.WriteBool(ConfProfileName, 'SearchTextCaseSensitive', ConfSearchTextCaseSensitive);
    IniFile.WriteBool(ConfProfileName, 'MakeSymlinkRelative', ConfMakeSymlinkRelative);

  except
    on E: Exception do DebugMsg(['*** Error: Cannot save user settings (', E.ClassName, '): ', E.Message]);
  end;
  finally
    IniFile.Free;
  end;
  except end;
end;

(********************************************************************************************************************************)
(********************************************************************************************************************************)
procedure ReadMainGUISettings;
var s: string;
    IniFile: TMyIniFile;
begin
  SearchForDefaultApps;
  try
  s := IncludeTrailingPathDelimiter(GetHomePath) + ConfDefaultSettingsDir;
  if not DirectoryExists(s) then
    if not ForceDirectories(s) then begin
      DebugMsg(['*** Error: Cannot read user settings']);
      Exit;
    end;

  IniFile := TMyIniFile.Create(IncludeTrailingPathDelimiter(s) + 'gui', True);
  try
    ConfPanelFont := IniFile.ReadString(ConfProfileName, 'PanelFont', ConfDefaultPanelFont);
    ConfRowHeight := IniFile.ReadInteger(ConfProfileName, 'RowHeight', ConfRowHeight);
    if ConfRowHeight > 0 then ConfRowHeightReal := ConfRowHeight;
    ConfClearReadOnlyAttr := IniFile.ReadBool(ConfProfileName, 'ClearReadOnlyAttr', ConfClearReadOnlyAttr);
    ConfViewer := IniFile.ReadString(ConfProfileName, 'Viewer', ConfViewer);
    ConfEditor := IniFile.ReadString(ConfProfileName, 'Editor', ConfEditor);
    ConfTerminalCommand := IniFile.ReadString(ConfProfileName, 'TerminalCommand', ConfTerminalCommand);
    ConfNumHistoryItems := IniFile.ReadInteger('General', 'NumHistoryItems', ConfNumHistoryItems);
    ConfDisableMouseRename := IniFile.ReadBool(ConfProfileName, 'DisableMouseRename', ConfDisableMouseRename);
    ConfUseSystemFont := IniFile.ReadBool(ConfProfileName, 'UseSystemFont', ConfUseSystemFont);
    ConfUseFileTypeIcons := IniFile.ReadBool(ConfProfileName, 'UseFileTypeIcons', ConfUseFileTypeIcons);
    //  Read color settings
    ConfNormalItemFGColor := IniFile.ReadString(ConfProfileName, 'NormalItemFGColor', ConfNormalItemFGColor);
    ConfNormalItemBGColor := IniFile.ReadString(ConfProfileName, 'NormalItemBGColor', ConfNormalItemBGColor);
    ConfActiveItemFGColor := IniFile.ReadString(ConfProfileName, 'ActiveItemFGColor', ConfActiveItemFGColor);
    ConfActiveItemBGColor := IniFile.ReadString(ConfProfileName, 'ActiveItemBGColor', ConfActiveItemBGColor);
    ConfInactiveItemFGColor := IniFile.ReadString(ConfProfileName, 'InactiveItemFGColor', ConfInactiveItemFGColor);
    ConfInactiveItemBGColor := IniFile.ReadString(ConfProfileName, 'InactiveItemBGColor', ConfInactiveItemBGColor);
    ConfSelectedItemFGColor := IniFile.ReadString(ConfProfileName, 'SelectedItemFGColor', ConfSelectedItemFGColor);
    ConfLinkItemFGColor := IniFile.ReadString(ConfProfileName, 'LinkItemFGColor', ConfLinkItemFGColor);
    ConfDotFileItemFGColor := IniFile.ReadString(ConfProfileName, 'DotFileItemFGColor', ConfDotFileItemFGColor);
    ConfNormalItemDefaultColors := IniFile.ReadBool(ConfProfileName, 'NormalItemDefaultColors', ConfNormalItemDefaultColors);
    ConfCursorDefaultColors := IniFile.ReadBool(ConfProfileName, 'CursorDefaultColors', ConfCursorDefaultColors);
    ConfInactiveItemDefaultColors := IniFile.ReadBool(ConfProfileName, 'InactiveItemDefaultColors', ConfInactiveItemDefaultColors);
    ConfSelectedItemDefaultColors := IniFile.ReadBool(ConfProfileName, 'SelectedItemDefaultColors', ConfSelectedItemDefaultColors);
    ConfLinkItemDefaultColors := IniFile.ReadBool(ConfProfileName, 'LinkItemDefaultColors', ConfLinkItemDefaultColors);
    ConfDotFileItemDefaultColors := IniFile.ReadBool(ConfProfileName, 'DotFileItemDefaultColors', ConfDotFileItemDefaultColors);
    ConfLynxLikeMotion := IniFile.ReadBool(ConfProfileName, 'LynxLikeMotion', ConfLynxLikeMotion);
    ConfDirsInBold := IniFile.ReadBool(ConfProfileName, 'DirsInBold', ConfDirsInBold);
    ConfNewStyleAltO := IniFile.ReadBool(ConfProfileName, 'NewStyleAltO', ConfNewStyleAltO);
    ConfWMCompatMode := IniFile.ReadBool(ConfProfileName, 'WMCompatibilityMode', ConfWMCompatMode);
    ConfDisableFileTips := IniFile.ReadBool(ConfProfileName, 'DisableFileTips', ConfDisableFileTips);
    ConfDisableDirectoryBrackets := IniFile.ReadBool(ConfProfileName, 'DisableDirectoryBrackets', ConfDisableDirectoryBrackets);
    ConfInsMoveDown := IniFile.ReadBool(ConfProfileName, 'InsMoveDown', ConfInsMoveDown);
    ConfSpaceMovesDown := IniFile.ReadBool(ConfProfileName, 'SpaceMovesDown', ConfSpaceMovesDown);
    ConfSelectAllDirs := IniFile.ReadBool(ConfProfileName, 'SelectAllDirs', ConfSelectAllDirs);
    ConfShowFuncButtons := IniFile.ReadBool(ConfProfileName, 'ShowFuncButtons', ConfShowFuncButtons);
    ConfOctalPerm := IniFile.ReadBool(ConfProfileName, 'OctalPerm', ConfOctalPerm);
    ConfFocusRefresh := IniFile.ReadBool(ConfProfileName, 'FocusRefresh', ConfFocusRefresh);
    ConfSizeFormat := IniFile.ReadInteger(ConfProfileName, 'SizeFormat', ConfSizeFormat);
    ConfSizeGroupPrecision := IniFile.ReadInteger(ConfProfileName, 'SizeGroupPrecision', ConfSizeGroupPrecision);
    ConfSizeGroupRequestZeroDigits := IniFile.ReadBool(ConfProfileName, 'SizeGroupRequestZeroDigits', ConfSizeGroupRequestZeroDigits);
    ConfCmdLineTerminalBehaviour := IniFile.ReadInteger(ConfProfileName, 'CmdLineTerminalBehaviour', ConfCmdLineTerminalBehaviour);
    ConfViewerTerminalBehaviour := IniFile.ReadInteger(ConfProfileName, 'ViewerTerminalBehaviour', ConfViewerTerminalBehaviour);
    ConfEditorTerminalBehaviour := IniFile.ReadInteger(ConfProfileName, 'EditorTerminalBehaviour', ConfEditorTerminalBehaviour);
    ConfUseLibcSystem := IniFile.ReadBool(ConfProfileName, 'CompatUseLibcSystem', ConfUseLibcSystem);
    ConfUseInternalViewer := IniFile.ReadBool(ConfProfileName, 'UseInternalViewer', ConfUseInternalViewer);
    ConfSwitchOtherPanelBehaviour := IniFile.ReadInteger(ConfProfileName, 'SwitchOtherPanelBehaviour', ConfSwitchOtherPanelBehaviour);
    ConfDuplicateTabWarning := IniFile.ReadBool(ConfProfileName, 'DuplicateTabWarning', ConfDuplicateTabWarning);
    ConfOpenConnectionsWarning := IniFile.ReadBool(ConfProfileName, 'OpenConnectionsWarning', ConfOpenConnectionsWarning);
    ConfShowTextUIDs := IniFile.ReadBool(ConfProfileName, 'ShowTextUIDs', ConfShowTextUIDs);


    (*********************************************  NEW !!!! *************************************************)
    ConfSavePanelTabs := IniFile.ReadBool(ConfProfileName, 'SavePanelTabs', ConfSavePanelTabs);
    ConfTabMaxLength := IniFile.ReadInteger(ConfProfileName, 'TabMaxLength', ConfTabMaxLength);
    ConfTempPath := IniFile.ReadString(ConfProfileName, 'TempPath', ConfTempPath);
    ConfUseSmoothScrolling := IniFile.ReadBool(ConfProfileName, 'UseSmoothScrolling', ConfUseSmoothScrolling);
    ConfDateFormat := IniFile.ReadInteger(ConfProfileName, 'DateFormat', ConfDateFormat);
    ConfTimeFormat := IniFile.ReadInteger(ConfProfileName, 'TimeFormat', ConfTimeFormat);
    ConfDateTimeFormat := IniFile.ReadInteger(ConfProfileName, 'DateTimeFormat', ConfDateTimeFormat);
    ConfCustomDateFormat := IniFile.ReadString(ConfProfileName, 'CustomDateFormat', ConfCustomDateFormat);
    ConfCustomTimeFormat := IniFile.ReadString(ConfProfileName, 'CustomTimeFormat', ConfCustomTimeFormat);
    ConfQuickSearchActivationKey := IniFile.ReadInteger(ConfProfileName, 'QuickSearchActivationKey', ConfQuickSearchActivationKey);
    ConfSortDirectoriesLikeFiles := IniFile.ReadBool(ConfProfileName, 'SortDirectoriesLikeFiles', ConfSortDirectoriesLikeFiles);
    ConfQuickRenameSkipExt := IniFile.ReadBool(ConfProfileName, 'QuickRenameSkipExt', ConfQuickRenameSkipExt);

    (*********************************************  NEW SINCE 0.6.55 *************************************************)
    ConfRightClickSelect := IniFile.ReadBool(ConfProfileName, 'RightClickSelect', ConfRightClickSelect);
    ConfReplaceConnectionWarning := IniFile.ReadBool(ConfProfileName, 'ReplaceConnectionWarning', ConfReplaceConnectionWarning);
    ConfWarnUnsavedConnection := IniFile.ReadBool(ConfProfileName, 'WarnUnsavedConnection', ConfWarnUnsavedConnection);


    SearchForDefaultApps;
  finally
    try IniFile.Free; except end;
    InternalMainGUIConfmtime := GetFileTime(IncludeTrailingPathDelimiter(s) + 'gui');
  end;
  except end;
end;

procedure WriteMainGUISettings;
var s: string;
    IniFile: TMyIniFile;
begin
  if InternalQuickExit then Exit;
  try
  s := IncludeTrailingPathDelimiter(GetHomePath) + ConfDefaultSettingsDir;
  if not DirectoryExists(s) then
    if not ForceDirectories(s) then begin
      DebugMsg(['*** Error: Cannot save user settings']);
      Exit;
    end;

  IniFile := TMyIniFile.Create(IncludeTrailingPathDelimiter(s) + 'gui', False);
  try try
    IniFile.WriteString(ConfProfileName, 'PanelFont', ConfPanelFont);
    IniFile.WriteInteger(ConfProfileName, 'RowHeight', ConfRowHeight);
    IniFile.WriteBool(ConfProfileName, 'ClearReadOnlyAttr', ConfClearReadOnlyAttr);
    IniFile.WriteString(ConfProfileName, 'Viewer', ConfViewer);
    IniFile.WriteString(ConfProfileName, 'Editor', ConfEditor);
    IniFile.WriteString(ConfProfileName, 'TerminalCommand', ConfTerminalCommand);
    IniFile.WriteInteger('General', 'NumHistoryItems', ConfNumHistoryItems);
    IniFile.WriteBool(ConfProfileName, 'DisableMouseRename', ConfDisableMouseRename);
    IniFile.WriteBool(ConfProfileName, 'UseSystemFont', ConfUseSystemFont);
    IniFile.WriteBool(ConfProfileName, 'UseFileTypeIcons', ConfUseFileTypeIcons);

    //  Save color settings
    IniFile.WriteString(ConfProfileName, 'NormalItemFGColor', ConfNormalItemFGColor);
    IniFile.WriteString(ConfProfileName, 'NormalItemBGColor', ConfNormalItemBGColor);
    IniFile.WriteString(ConfProfileName, 'ActiveItemFGColor', ConfActiveItemFGColor);
    IniFile.WriteString(ConfProfileName, 'ActiveItemBGColor', ConfActiveItemBGColor);
    IniFile.WriteString(ConfProfileName, 'InactiveItemFGColor', ConfInactiveItemFGColor);
    IniFile.WriteString(ConfProfileName, 'InactiveItemBGColor', ConfInactiveItemBGColor);
    IniFile.WriteString(ConfProfileName, 'SelectedItemFGColor', ConfSelectedItemFGColor);
    IniFile.WriteString(ConfProfileName, 'LinkItemFGColor', ConfLinkItemFGColor);
    IniFile.WriteString(ConfProfileName, 'DotFileItemFGColor', ConfDotFileItemFGColor);
    IniFile.WriteBool(ConfProfileName, 'NormalItemDefaultColors', ConfNormalItemDefaultColors);
    IniFile.WriteBool(ConfProfileName, 'CursorDefaultColors', ConfCursorDefaultColors);
    IniFile.WriteBool(ConfProfileName, 'InactiveItemDefaultColors', ConfInactiveItemDefaultColors);
    IniFile.WriteBool(ConfProfileName, 'SelectedItemDefaultColors', ConfSelectedItemDefaultColors);
    IniFile.WriteBool(ConfProfileName, 'LinkItemDefaultColors', ConfLinkItemDefaultColors);
    IniFile.WriteBool(ConfProfileName, 'DotFileItemDefaultColors', ConfDotFileItemDefaultColors);
    IniFile.WriteBool(ConfProfileName, 'LynxLikeMotion', ConfLynxLikeMotion);
    IniFile.WriteInteger(ConfProfileName, 'SizeFormat', ConfSizeFormat);
    IniFile.WriteInteger(ConfProfileName, 'SizeGroupPrecision', ConfSizeGroupPrecision);
    IniFile.WriteBool(ConfProfileName, 'SizeGroupRequestZeroDigits', ConfSizeGroupRequestZeroDigits);
    IniFile.WriteBool(ConfProfileName, 'NewStyleAltO', ConfNewStyleAltO);
    IniFile.WriteBool(ConfProfileName, 'DirsInBold', ConfDirsInBold);
    IniFile.WriteBool(ConfProfileName, 'DisableDirectoryBrackets', ConfDisableDirectoryBrackets);
    IniFile.WriteBool(ConfProfileName, 'WMCompatibilityMode', ConfWMCompatMode);
    IniFile.WriteBool(ConfProfileName, 'DisableFileTips', ConfDisableFileTips);
    IniFile.WriteBool(ConfProfileName, 'InsMoveDown', ConfInsMoveDown);
    IniFile.WriteBool(ConfProfileName, 'SpaceMovesDown', ConfSpaceMovesDown);
    IniFile.WriteBool(ConfProfileName, 'ShowFuncButtons', ConfShowFuncButtons);
    IniFile.WriteBool(ConfProfileName, 'SelectAllDirs', ConfSelectAllDirs);
    IniFile.WriteBool(ConfProfileName, 'OctalPerm', ConfOctalPerm);
    IniFile.WriteBool(ConfProfileName, 'FocusRefresh', ConfFocusRefresh);
    IniFile.WriteInteger(ConfProfileName, 'CmdLineTerminalBehaviour', ConfCmdLineTerminalBehaviour);
    IniFile.WriteInteger(ConfProfileName, 'ViewerTerminalBehaviour', ConfViewerTerminalBehaviour);
    IniFile.WriteInteger(ConfProfileName, 'EditorTerminalBehaviour', ConfEditorTerminalBehaviour);
    IniFile.WriteBool(ConfProfileName, 'CompatUseLibcSystem', ConfUseLibcSystem);
    IniFile.WriteBool(ConfProfileName, 'UseInternalViewer', ConfUseInternalViewer);
    IniFile.WriteInteger(ConfProfileName, 'SwitchOtherPanelBehaviour', ConfSwitchOtherPanelBehaviour);
    IniFile.WriteBool(ConfProfileName, 'DuplicateTabWarning', ConfDuplicateTabWarning);
    IniFile.WriteBool(ConfProfileName, 'OpenConnectionsWarning', ConfOpenConnectionsWarning);
    IniFile.WriteBool(ConfProfileName, 'ShowTextUIDs', ConfShowTextUIDs);

    (*********************************************  NEW !!!! *************************************************)
    IniFile.WriteBool(ConfProfileName, 'SavePanelTabs', ConfSavePanelTabs);
    IniFile.WriteInteger(ConfProfileName, 'TabMaxLength', ConfTabMaxLength);
    IniFile.WriteString(ConfProfileName, 'TempPath', ConfTempPath);
    IniFile.WriteBool(ConfProfileName, 'UseSmoothScrolling', ConfUseSmoothScrolling);
    IniFile.WriteInteger(ConfProfileName, 'DateFormat', ConfDateFormat);
    IniFile.WriteInteger(ConfProfileName, 'TimeFormat', ConfTimeFormat);
    IniFile.WriteInteger(ConfProfileName, 'DateTimeFormat', ConfDateTimeFormat);
    IniFile.WriteString(ConfProfileName, 'CustomDateFormat', ConfCustomDateFormat);
    IniFile.WriteString(ConfProfileName, 'CustomTimeFormat', ConfCustomTimeFormat);
    IniFile.WriteInteger(ConfProfileName, 'QuickSearchActivationKey', ConfQuickSearchActivationKey);
    IniFile.WriteBool(ConfProfileName, 'SortDirectoriesLikeFiles', ConfSortDirectoriesLikeFiles);
    IniFile.WriteBool(ConfProfileName, 'QuickRenameSkipExt', ConfQuickRenameSkipExt);

    (*********************************************  NEW SINCE 0.6.55 *************************************************)
    IniFile.WriteBool(ConfProfileName, 'RightClickSelect', ConfRightClickSelect);
    IniFile.WriteBool(ConfProfileName, 'ReplaceConnectionWarning', ConfReplaceConnectionWarning);
    IniFile.WriteBool(ConfProfileName, 'WarnUnsavedConnection', ConfWarnUnsavedConnection);

  except
    on E: Exception do DebugMsg(['*** Error: Cannot save user settings (', E.ClassName, '): ', E.Message]);
  end;

  finally
    IniFile.Free;
    InternalMainGUIConfmtime := GetFileTime(IncludeTrailingPathDelimiter(s) + 'gui');
  end;
  except end;
end;

(********************************************************************************************************************************)
(********************************************************************************************************************************)
procedure ReadAssoc;
var s: string;
    IniFile: TMyIniFile;
    Sections: TStringList;
    i, j, cnt: integer;
    Item: TFileAssoc;
    Action: TAssocAction;
begin
  try
  s := IncludeTrailingPathDelimiter(GetHomePath) + ConfDefaultSettingsDir;
  if not DirectoryExists(s) then
    if not ForceDirectories(s) then begin
      DebugMsg(['*** Error: Cannot read file association settings']);
      Exit;
    end;

  try
    if not Assigned(AssocList) then AssocList := TList.Create else
      if AssocList.Count > 0 then for i := 0 to AssocList.Count - 1 do TFileAssoc(AssocList[i]).Free;
  except end;
  AssocList.Clear;

  IniFile := TMyIniFile.Create(IncludeTrailingPathDelimiter(s) + 'filetypes', True);
  try
    Sections := TStringList.Create;
    IniFile.ReadSections(Sections);
    if Sections.Count > 0 then
      for i := 0 to Sections.Count - 1 do
        if Sections[i] <> 'General' then begin
          Item := TFileAssoc.Create;
          with Item do begin
            if (Sections[i] = ConstFTAMetaDirectory) or (Sections[i] = ConstFTAMetaFile)
              then SetLength(Extensions, 0)
              else ParseString(Sections[i], ';', Extensions);
            FileTypeName := IniFile.ReadString(Sections[i], 'FileTypeName', '');
            DefaultAction := IniFile.ReadInteger(Sections[i], 'DefaultAction', 0);
            cnt := IniFile.ReadInteger(Sections[i], 'NumActions', 0);
            FileTypeIcon := IniFile.ReadString(Sections[i], 'FileTypeIcon', '');
            ColorString := IniFile.ReadString(Sections[i], 'ColorString', '');
            if cnt > 0 then
              for j := 0 to cnt - 1 do begin
                Action := TAssocAction.Create;
                with Action do begin
                  ActionName := IniFile.ReadString(Sections[i],  Format('Action%dName', [j]), '');
                  ActionCommand := IniFile.ReadString(Sections[i],  Format('Action%dCommand', [j]), '');
                  RunInTerminal := IniFile.ReadBool(Sections[i],  Format('Action%dRunInTerminal', [j]), False);
                  AutodetectGUI := IniFile.ReadBool(Sections[i],  Format('Action%dAutodetectGUI', [j]), True);
                end;
                if (Action.ActionName <> '') {and (Action.ActionCommand <> '')} then  ActionList.Add(Action);
              end;
          end;
        {if Length(Trim(Item.Extensions)) > 0 then} AssocList.Add(Item);
      end;
    Sections.Free;
    AddDefaultItems(AssocList);
    if Assigned(FileIcon) then RecreateIcons(AssocList);
  finally
    try IniFile.Free; except end;
    InternalFAssocConfmtime := GetFileTime(IncludeTrailingPathDelimiter(s) + 'filetypes');
  end;
  except end;
end;

procedure WriteAssoc;
var i, j: integer;
    IniFile: TMyIniFile;
    s, SectionTitle: string;
begin
  if InternalQuickExit then Exit;
  try
  s := IncludeTrailingPathDelimiter(GetHomePath) + ConfDefaultSettingsDir;
  if not DirectoryExists(s) then
    if not ForceDirectories(s) then begin
      DebugMsg(['*** Error: Cannot save file association settings']);
      Exit;
    end;
  s := IncludeTrailingPathDelimiter(s) + 'filetypes';
  if access(PChar(s), R_OK) = 0 then libc_remove(PChar(s));

  IniFile := TMyIniFile.Create(s, False);
  try try
    if AssocList.Count > 0 then
      for i := 0 to AssocList.Count - 1 do
        with TFileAssoc(AssocList[i]) do begin
          if (FileTypeName = ConstFTAMetaDirectory) or (FileTypeName = ConstFTAMetaFile)
            then SectionTitle := FileTypeName
            else SectionTitle := MakeString(';', Extensions);
          IniFile.EraseSection(SectionTitle);
          IniFile.WriteString(SectionTitle, 'FileTypeName', FileTypeName);
          IniFile.WriteString(SectionTitle, 'FileTypeIcon', FileTypeIcon);
          IniFile.WriteInteger(SectionTitle, 'DefaultAction', DefaultAction);
          IniFile.WriteInteger(SectionTitle, 'NumActions', ActionList.Count);
          IniFile.WriteString(SectionTitle, 'ColorString', ColorString);
          if ActionList.Count > 0 then
            for j := 0 to ActionList.Count - 1 do begin
              IniFile.WriteString(SectionTitle, Format('Action%dName', [j]), TAssocAction(ActionList[j]).ActionName);
              IniFile.WriteString(SectionTitle, Format('Action%dCommand', [j]), TAssocAction(ActionList[j]).ActionCommand);
              IniFile.WriteBool(SectionTitle, Format('Action%dRunInTerminal', [j]), TAssocAction(ActionList[j]).RunInTerminal);
              IniFile.WriteBool(SectionTitle, Format('Action%dAutodetectGUI', [j]), TAssocAction(ActionList[j]).AutodetectGUI);
            end;
        end;
  except
    on E: Exception do DebugMsg(['*** Error: Cannot save file association settings (', E.ClassName, '): ', E.Message]);
  end;
  finally
    IniFile.Free;
    InternalFAssocConfmtime := GetFileTime(s);
  end;
  except end;
end;

(********************************************************************************************************************************)
(********************************************************************************************************************************)
procedure ReadBookmarks;
var s: string;
    i: integer;
begin
  try
    s := IncludeTrailingPathDelimiter(IncludeTrailingPathDelimiter(GetHomePath) + ConfDefaultSettingsDir) + 'bookmarks';
    Bookmarks.LoadFromFile(s);
    InternalBookmarksConfmtime := GetFileTime(s);
    if Bookmarks.Count > 0 then
      for i := Bookmarks.Count - 1 downto 0 do
        if Length(Trim(Bookmarks[i])) = 0 then Bookmarks.Delete(i);
  except
  end;
end;

procedure WriteBookmarks;
var s: string;
    i: integer;
begin
  if InternalQuickExit then Exit;
  try
    s := IncludeTrailingPathDelimiter(IncludeTrailingPathDelimiter(GetHomePath) + ConfDefaultSettingsDir) + 'bookmarks';
    if Bookmarks.Count > 0 then
      for i := Bookmarks.Count - 1 downto 0 do
        if Length(Trim(Bookmarks[i])) = 0 then Bookmarks.Delete(i);
    Bookmarks.SaveToFile(s);
    InternalBookmarksConfmtime := GetFileTime(s);
  except
  end;
end;

(********************************************************************************************************************************)
(********************************************************************************************************************************)
procedure ReadMounter;
var s: string;
    IniFile: TMyIniFile;
    Sections: TStringList;
    i: integer;
    Item: TMounterItem;
begin
  try
  s := IncludeTrailingPathDelimiter(GetHomePath) + ConfDefaultSettingsDir;
  if not DirectoryExists(s) then
    if not ForceDirectories(s) then begin
      DebugMsg(['*** Error: Cannot read file association settings']);
      Exit;
    end;

  try
    if not Assigned(MounterList) then MounterList := TList.Create else
      if MounterList.Count > 0 then for i := 0 to MounterList.Count - 1 do TMounterItem(MounterList[i]).Free;
  except end;
  MounterList.Clear;

  IniFile := TMyIniFile.Create(IncludeTrailingPathDelimiter(s) + 'mounter', True);
  try
    Sections := TStringList.Create;
    IniFile.ReadSections(Sections);
    if Sections.Count > 0 then
      for i := 0 to Sections.Count - 1 do
        if Sections[i] = 'General' then begin
          ConfMounterUseFSTab := IniFile.ReadBool('General', 'MounterUseFSTab', ConfMounterUseFSTab);
          ConfMounterPushDown := IniFile.ReadBool('General', 'MounterPushDown', ConfMounterPushDown);
      end else begin
        Item := TMounterItem.Create;
        with Item do begin
          Device := Sections[i];
          DisplayText := IniFile.ReadString(Sections[i], 'DisplayText', '');
          MountPath := IniFile.ReadString(Sections[i], 'MountPath', '');
          IconPath := IniFile.ReadString(Sections[i], 'IconPath', '');
          MountCommand := IniFile.ReadString(Sections[i], 'MountCommand', '');
          UmountCommand := IniFile.ReadString(Sections[i], 'UmountCommand', '');
          DeviceType := IniFile.ReadInteger(Sections[i], 'DeviceType', 0);
        end;
        MounterList.Add(Item);
      end;
    Sections.Free;
  finally
    try IniFile.Free; except end;
    InternalMounterConfmtime := GetFileTime(IncludeTrailingPathDelimiter(s) + 'mounter');
  end;
  except end;
end;

procedure WriteMounter;
var i: integer;
    IniFile: TMyIniFile;
    s, SectionTitle: string;
begin
  if InternalQuickExit then Exit;
  try
  s := IncludeTrailingPathDelimiter(GetHomePath) + ConfDefaultSettingsDir;
  if not DirectoryExists(s) then
    if not ForceDirectories(s) then begin
      DebugMsg(['*** Error: Cannot save file association settings']);
      Exit;
    end;
  s := IncludeTrailingPathDelimiter(s) + 'mounter';
  if access(PChar(s), R_OK) = 0 then libc_remove(PChar(s));

  IniFile := TMyIniFile.Create(s, False);
  try try
    IniFile.WriteBool('General', 'MounterUseFSTab', ConfMounterUseFSTab);
    IniFile.WriteBool('General', 'MounterPushDown', ConfMounterPushDown);
    if MounterList.Count > 0 then
      for i := 0 to MounterList.Count - 1 do
        with TMounterItem(MounterList[i]) do begin
          SectionTitle := Device;
          IniFile.EraseSection(SectionTitle);
          IniFile.WriteString(SectionTitle, 'DisplayText', DisplayText);
          IniFile.WriteString(SectionTitle, 'MountPath', MountPath);
          IniFile.WriteString(SectionTitle, 'IconPath', IconPath);
          IniFile.WriteString(SectionTitle, 'MountCommand', MountCommand);
          IniFile.WriteString(SectionTitle, 'UmountCommand', UmountCommand);
          IniFile.WriteInteger(SectionTitle, 'DeviceType', DeviceType);
        end;
  except
    on E: Exception do DebugMsg(['*** Error: Cannot save file association settings (', E.ClassName, '): ', E.Message]);
  end;
  finally
    IniFile.Free;
    InternalMounterConfmtime := GetFileTime(s);
  end;
  except end;
end;


(********************************************************************************************************************************)
(********************************************************************************************************************************)
procedure ReadTabs(const LeftPanel: boolean; TabList: TStringList; TabSortIDs, TabSortTypes: TList);
const PanelPrefixes: array[boolean] of string = ('Left', 'Right');
var s, Section: string;
    IniFile: TMyIniFile;
    i, j: integer;
    NumItems: integer;
begin
  try
  s := IncludeTrailingPathDelimiter(GetHomePath) + ConfDefaultSettingsDir;
  if not DirectoryExists(s) then
    if not ForceDirectories(s) then begin
      DebugMsg(['*** Error: Cannot read panel tabs']);
      Exit;
    end;

  IniFile := TMyIniFile.Create(IncludeTrailingPathDelimiter(s) + 'tabs', True);
  try
    Section := Format('%s_%spanel', [ConfProfileName, PanelPrefixes[LeftPanel]]);
    NumItems := IniFile.ReadInteger(Section, 'NumTabs', 0);
    if LeftPanel then ConfLeftTabBarTabIndex := IniFile.ReadInteger(Section, 'TabIndex', ConfLeftTabBarTabIndex)
                 else ConfRightTabBarTabIndex := IniFile.ReadInteger(Section, 'TabIndex', ConfRightTabBarTabIndex);
    if NumItems > 0 then
      for i := 0 to NumItems - 1 do begin
        s := IniFile.ReadString(Section, Format('Tab%d', [i]), '');
        if Length(s) > 0 then TabList.Add(s);
        j := IniFile.ReadInteger(Section, Format('Tab%d_SortID', [i]), 0);
        TabSortIDs.Add(Pointer(j));
        j := IniFile.ReadInteger(Section, Format('Tab%d_SortType', [i]), 0);
        TabSortTypes.Add(Pointer(j));
      end;
    if (TabList.Count <> TabSortIDs.Count) or (TabList.Count <> TabSortTypes.Count) or (TabList.Count = 1) then begin
      //  Something went wrong, tab list is corrupt, let's remove all tabs
      TabList.Clear;
      TabSortIDs.Clear;
      TabSortTypes.Clear;
    end;
  finally
    try IniFile.Free; except end;
  end;
  except end;
end;

procedure WriteTabs(const LeftPanel: boolean; TabList: TStringList; TabSortIDs, TabSortTypes: TList);
const PanelPrefixes: array[boolean] of string = ('Left', 'Right');
var s, Section: string;
    IniFile: TMyIniFile;
    i: integer;
begin
  if InternalQuickExit then Exit;
  try
  s := IncludeTrailingPathDelimiter(GetHomePath) + ConfDefaultSettingsDir;
  if not DirectoryExists(s) then
    if not ForceDirectories(s) then begin
      DebugMsg(['*** Error: Cannot save panel tabs']);
      Exit;
    end;

  IniFile := TMyIniFile.Create(IncludeTrailingPathDelimiter(s) + 'tabs', False);
  try try
    Section := Format('%s_%spanel', [ConfProfileName, PanelPrefixes[LeftPanel]]);
    IniFile.EraseSection(Section);
    IniFile.WriteInteger(Section, 'NumTabs', TabList.Count);
    if LeftPanel then IniFile.WriteInteger(Section, 'TabIndex', ConfLeftTabBarTabIndex)
                 else IniFile.WriteInteger(Section, 'TabIndex', ConfRightTabBarTabIndex);
    if TabList.Count > 0 then
      for i := 0 to TabList.Count - 1 do begin
        IniFile.WriteString(Section, Format('Tab%d', [i]), TabList[i]);
        IniFile.WriteInteger(Section, Format('Tab%d_SortID', [i]), Integer(TabSortIDs[i]));
        IniFile.WriteInteger(Section, Format('Tab%d_SortType', [i]), Integer(TabSortTypes[i]));
      end;
  except
    on E: Exception do DebugMsg(['*** Error: Cannot save panel tabs settings (', E.ClassName, '): ', E.Message]);
  end;
  finally
    IniFile.Free;
  end;
  except end;
end;


(********************************************************************************************************************************)
(********************************************************************************************************************************)
procedure ReadConnections;
var s: string;
    IniFile: TMyIniFile;
    Sections: TStringList;
    i, j, k: integer;
    Item: TConnMgrItem;
begin
  try
  s := IncludeTrailingPathDelimiter(GetHomePath) + ConfDefaultSettingsDir;
  if not DirectoryExists(s) then
    if not ForceDirectories(s) then begin
      DebugMsg(['*** Error: Cannot read connection manager settings']);
      Exit;
    end;

  try
    if not Assigned(ConnectionMgrList) then ConnectionMgrList := TList.Create else
      if ConnectionMgrList.Count > 0 then for i := 0 to ConnectionMgrList.Count - 1 do TConnMgrItem(ConnectionMgrList[i]).Free;
  except end;
  ConnectionMgrList.Clear;

  IniFile := TMyIniFile.Create(IncludeTrailingPathDelimiter(s) + 'connmgr', True);
  try
    Sections := TStringList.Create;
    IniFile.ReadSections(Sections);
    if Sections.Count > 0 then
      for i := 0 to Sections.Count - 1 do
        if Sections[i] = '__General' then begin
          ConfConnMgrActiveItem := IniFile.ReadInteger('__General', 'ConnMgrActiveItem', ConfConnMgrActiveItem);
          ConfConnMgrDoNotSavePasswords := IniFile.ReadBool('__General', 'ConnMgrDoNotSavePasswords', ConfConnMgrDoNotSavePasswords);
          ConfConnMgrDoNotSynchronizeKeyring := IniFile.ReadBool('__General', 'ConnMgrDoNotSynchronizeKeyring', ConfConnMgrDoNotSynchronizeKeyring);
          ConfQuickConnectPluginID := IniFile.ReadString('__General', 'QuickConnectPluginID', ConfQuickConnectPluginID);
          ConfConnMgrSortColumn := IniFile.ReadInteger('__General', 'ConnMgrSortColumn', ConfConnMgrSortColumn);
          ConfConnMgrSortType := IniFile.ReadInteger('__General', 'ConnMgrSortType', ConfConnMgrSortType);
          ConfConnMgrColumn1Width := IniFile.ReadInteger('__General', 'ConnMgrColumn1Width', ConfConnMgrColumn1Width);
        end else
        if Sections[i] = '__QuickConnectHistory' then begin
          QuickConnectHistory.Clear;
          if not InternalDeleteHistory then begin
            j := IniFile.ReadInteger('__QuickConnectHistory', 'NumItems', 0);
            if j > 0 then
              for k := 0 to j - 1 do
                QuickConnectHistory.Add(IniFile.ReadString('__QuickConnectHistory', Format('Item%d', [k]), ''));
          end;
        end else begin
          Item := TConnMgrItem.Create;
          with Item do begin
            ConnectionName := IniFile.ReadString(Sections[i], 'ConnectionName', '');
            ServiceType := IniFile.ReadString(Sections[i], 'ServiceType', '');
            Server := IniFile.ReadString(Sections[i], 'Server', '');
            Username := IniFile.ReadString(Sections[i], 'Username', '');
            Password := XORStr(IniFile.ReadString(Sections[i], 'Password', ''), ConstConnMgrXORKey);
            TargetDir := IniFile.ReadString(Sections[i], 'TargetDir', '');
            PluginID := IniFile.ReadString(Sections[i], 'PluginID', '');
          end;
          ConnectionMgrList.Add(Item);
        end;
    Sections.Free;
  finally
    try IniFile.Free; except end;
    InternalConnMgrConfmtime := GetFileTime(IncludeTrailingPathDelimiter(s) + 'connmgr');
  end;
  except end;
end;

procedure WriteConnections;
var i: integer;
    IniFile: TMyIniFile;
    s, SectionTitle: string;
begin
  if InternalQuickExit then Exit;
  try
  s := IncludeTrailingPathDelimiter(GetHomePath) + ConfDefaultSettingsDir;
  if not DirectoryExists(s) then
    if not ForceDirectories(s) then begin
      DebugMsg(['*** Error: Cannot save connection manager settings']);
      Exit;
    end;
  s := IncludeTrailingPathDelimiter(s) + 'connmgr';
  if access(PChar(s), R_OK) = 0 then libc_remove(PChar(s));

  IniFile := TMyIniFile.Create(s, False);
  try try
    IniFile.WriteInteger('__General', 'ConnMgrActiveItem', ConfConnMgrActiveItem);
    IniFile.WriteBool('__General', 'ConnMgrDoNotSavePasswords', ConfConnMgrDoNotSavePasswords);
    IniFile.WriteBool('__General', 'ConnMgrDoNotSynchronizeKeyring', ConfConnMgrDoNotSynchronizeKeyring);
    IniFile.WriteString('__General', 'QuickConnectPluginID', ConfQuickConnectPluginID);
    IniFile.WriteInteger('__General', 'ConnMgrSortColumn', ConfConnMgrSortColumn);
    IniFile.WriteInteger('__General', 'ConnMgrSortType', ConfConnMgrSortType);
    IniFile.WriteInteger('__General', 'ConnMgrColumn1Width', ConfConnMgrColumn1Width);
    IniFile.WriteInteger('__QuickConnectHistory', 'NumItems', QuickConnectHistory.Count);
    if QuickConnectHistory.Count > 0 then
      for i := 0 to QuickConnectHistory.Count - 1 do
        IniFile.WriteString('__QuickConnectHistory', Format('Item%d', [i]), QuickConnectHistory[i]);
    if ConnectionMgrList.Count > 0 then
      for i := 0 to ConnectionMgrList.Count - 1 do
        with TConnMgrItem(ConnectionMgrList[i]) do begin
          SectionTitle := Format('%d_%d_%d', [g_str_hash(PChar(ConnectionName)), i, g_str_hash(PChar(GetURI(False)))]);
          IniFile.EraseSection(SectionTitle);
          IniFile.WriteString(SectionTitle, 'ConnectionName', ConnectionName);
          IniFile.WriteString(SectionTitle, 'ServiceType', ServiceType);
          IniFile.WriteString(SectionTitle, 'Server', Server);
          IniFile.WriteString(SectionTitle, 'Username', Username);
          if not ConfConnMgrDoNotSavePasswords then IniFile.WriteString(SectionTitle, 'Password', XORStr(Password, ConstConnMgrXORKey))
                                               else IniFile.WriteString(SectionTitle, 'Password', '');
          IniFile.WriteString(SectionTitle, 'TargetDir', TargetDir);
          IniFile.WriteString(SectionTitle, 'PluginID', PluginID);
        end;
  except
    on E: Exception do DebugMsg(['*** Error: Cannot save connection manager settings (', E.ClassName, '): ', E.Message]);
  end;
  finally
    IniFile.Free;
    InternalConnMgrConfmtime := GetFileTime(s);
  end;
  except end;
end;


(********************************************************************************************************************************)
(********************************************************************************************************************************)
procedure SearchForDefaultApps;
var i: integer;
    PATH: string;
begin
  PATH := GetEnvironmentVariable('PATH');
  if ConfViewer = ConfAppNA then
    for i := 1 to Length(ConfViewersApps) do
      if FileSearch(ConfViewersApps[i], PATH) <> '' then begin
        ConfViewer := ConfViewersApps[i];
        Break;
      end;
  if ConfEditor = ConfAppNA then
    for i := 1 to Length(ConfEditorApps) do
      if FileSearch(ConfEditorApps[i], PATH) <> '' then begin
        ConfEditor := ConfEditorApps[i];
        Break;
      end;
  if ConfTerminalCommand = ConfAppNA then
    for i := Length(ConfTerminalAppsWParam) downto 1 do
      if FileSearch(ConfTerminalAppsWParam[i], PATH) <> '' then begin
        ConfTerminalCommand := ConfTerminalApps[i];
        Break;
      end;
end;

(********************************************************************************************************************************)
(********************************************************************************************************************************)
function GetFileTime(FileName: string): time_t;
var StatBuf: Pstat64;
begin
  Result := -1;
  StatBuf := malloc(sizeof(Tstat64));
  memset(StatBuf, 0, sizeof(Tstat64));
  if lstat64(PChar(FileName), StatBuf) = 0 then Result := StatBuf^.st_mtime;
  libc_free(StatBuf);
end;

function CheckConfFilesMod(var ChangedMainGUI, ChangedAssoc, ChangedBookmarks, ChangedMounter, ChangedConnections: boolean): boolean;
var s: string;
begin
  s := IncludeTrailingPathDelimiter(IncludeTrailingPathDelimiter(GetHomePath) + ConfDefaultSettingsDir);
  ChangedMainGUI := (GetFileTime(s + 'gui') > 0) and (GetFileTime(s + 'gui') > InternalMainGUIConfmtime);
  ChangedAssoc := (GetFileTime(s + 'filetypes') > 0) and (GetFileTime(s + 'filetypes') > InternalFAssocConfmtime);
  ChangedBookmarks := (GetFileTime(s + 'bookmarks') > 0) and (GetFileTime(s + 'bookmarks') > InternalBookmarksConfmtime);
  ChangedMounter := (GetFileTime(s + 'mounter') > 0) and (GetFileTime(s + 'mounter') > InternalMounterConfmtime);
  ChangedConnections := (GetFileTime(s + 'connmgr') > 0) and (GetFileTime(s + 'connmgr') > InternalConnMgrConfmtime);
  Result := ChangedMainGUI or ChangedAssoc or ChangedBookmarks or ChangedMounter or ChangedConnections;
  InternalMainGUIConfmtime := GetFileTime(s + 'gui');
  InternalFAssocConfmtime := GetFileTime(s + 'filetypes');
  InternalBookmarksConfmtime := GetFileTime(s + 'bookmarks');
  InternalMounterConfmtime := GetFileTime(s + 'mounter');
  InternalConnMgrConfmtime := GetFileTime(s + 'connmgr');
end;

(********************************************************************************************************************************)
(********************************************************************************************************************************)
procedure SetMiscLocaleStrings;
begin
  ConfColumnTitlesLong[1] := LANGColumns_TitlesLongName;
  ConfColumnTitlesLong[2] := LANGColumns_TitlesLongNameExt;
  ConfColumnTitlesLong[3] := LANGColumns_TitlesLongExt;
  ConfColumnTitlesLong[4] := LANGColumns_TitlesLongSize;
  ConfColumnTitlesLong[5] := LANGColumns_TitlesLongDateTime;
  ConfColumnTitlesLong[6] := LANGColumns_TitlesLongDate;
  ConfColumnTitlesLong[7] := LANGColumns_TitlesLongTime;
  ConfColumnTitlesLong[8] := LANGColumns_TitlesLongUser;
  ConfColumnTitlesLong[9] := LANGColumns_TitlesLongGroup;
  ConfColumnTitlesLong[10] := LANGColumns_TitlesLongAttr;
  ConfColumnTitlesShort[1] := LANGColumns_TitlesShortName;
  ConfColumnTitlesShort[2] := LANGColumns_TitlesShortNameExt;
  ConfColumnTitlesShort[3] := LANGColumns_TitlesShortExt;
  ConfColumnTitlesShort[4] := LANGColumns_TitlesShortSize;
  ConfColumnTitlesShort[5] := LANGColumns_TitlesShortDateTime;
  ConfColumnTitlesShort[6] := LANGColumns_TitlesShortDate;
  ConfColumnTitlesShort[7] := LANGColumns_TitlesShortTime;
  ConfColumnTitlesShort[8] := LANGColumns_TitlesShortUser;
  ConfColumnTitlesShort[9] := LANGColumns_TitlesShortGroup;
  ConfColumnTitlesShort[10] := LANGColumns_TitlesShortAttr;
end;



(********************************************************************************************************************************)
(********************************************************************************************************************************)
procedure ParseCMDLine;
var i: integer;
    s: string;
begin
  if ParamCount > 0 then
    for i := 1 to ParamCount do begin
      s := UpperCase(ParamStr(i));
      if s = '--DEBUG' then ParamDebug := True else
      if s = '--DISABLE-GNOME' then ParamDisableGnome := True else
      if s = '--DELETE-HISTORY' then InternalDeleteHistory := True else
      if s = '--ENABLE-URI' then ConfUseURI := True else
      if s = '--DISABLE-PLUGINS' then ParamDisablePlugins := True else
      if Pos('--PROFILE=', s) = 1 then begin
        ConfProfileName := 'Profile_' + Trim(Copy(ParamStr(i), 11, Length(s) - 10));
        if ConfProfileName = '' then ConfProfileName := 'Default';
      end else
      if Pos('--LEFT=', s) = 1 then ParamLeftDir := Copy(ParamStr(i), 8, Length(s) - 7) else
      if Pos('--RIGHT=', s) = 1 then ParamRightDir := Copy(ParamStr(i), 9, Length(s) - 8) else
      if Pos('--LANG=', s) = 1 then ConfParamForceLang := Copy(ParamStr(i), 8, Length(s) - 7) else
      if (s = '--HELP') or (s = '-H') then begin
        WriteLn('Tux Commander v', ConstAboutVersion, ' [built ', ConstAboutBuildDate, ']');
        WriteLn('Copyright (c) 2009 Tomas Bzatek');
        WriteLn('Website: tuxcmd.sourceforge.net');
        WriteLn;
        WriteLn('Usage: tuxcmd [options...]');
        WriteLn;
        WriteLn('Options:');
        WriteLn('  --debug                    Enable debug messages');
        WriteLn('  --profile=<profilename>    Use different configuration profile');
        WriteLn('  --delete-history           Delete command-line, selection and search history');
        WriteLn('                               (use in case of locale problems)');
        WriteLn('  --disable-gnome            Don''t load GNOME libraries');
        WriteLn('  --disable-plugins          Don''t load VFS modules');
        WriteLn('  --left=<path>              Start left panel at <path>');
        WriteLn('  --right=<path>             Start right panel at <path>');
        WriteLn('  --lang=<language>          Force GUI language (the string <language> is');
        WriteLn('                             standard two-char language id');
        InternalQuickExit := True;
        Halt(1);
      end else WriteLn('tuxcmd: Unknown commandline option: ', ParamStr(i));
    end;
end;



initialization
  ApplicationShuttingDown := False;
  SetDefaults;
  ParseCMDLine;
  {$IFDEF FPC}
    DebugMsg(['Tux Commander v', ConstAboutVersion, ' [', ConstAboutBuildDate, ']   FreePascal build ',
              '(version ', ConstFPCVersionString, ' ', ConstFPCDateString, ', define ',
              {$IFDEF CPU64} {$IFDEF ENDIAN_LITTLE}'x86_64'{$ELSE}'ppc64'{$ENDIF} {$ELSE} {$IFNDEF CPUPOWERPC}'i386'{$ELSE}'ppc' {$ENDIF} {$ENDIF},
              ', compiled on ', ConstFPCCompilerOSString, '/', ConstFPCCompilerHostProcessorString,
              ' for ', ConstFPCTargetOSString, '/', ConstFPCTargetProcessorString, ')']);
  {$ELSE}
    DebugMsg(['Tux Commander v', ConstAboutVersion, ' [', ConstAboutBuildDate, ']   Kylix build']);
  {$ENDIF}
  //  Load GNOME libs
  if not ParamDisableGnome then LoadGnomeLibs;
  //  Create basic objects
  CommandLineHistory := TStringList.Create;
  CommandLineHistory.CaseSensitive := True;
  Bookmarks := TStringList.Create;
  Bookmarks.CaseSensitive := True;
  QuickConnectHistory := TStringList.Create;
  QuickConnectHistory.CaseSensitive := True;
  //  Initialize the modules
  DoInitPlugins;
  //  Initialize locales
  SetTranslationTexts(ConfParamForceLang);
  SetMiscLocaleStrings;
  //  Load the settings
  ReadMainSettings;
  ReadMainGUISettings;
  ReadAssoc;
  ReadBookmarks;
  ReadMounter;

  //  Apply the settings
  LoadIcons;
  RecreateIcons(AssocList);
finalization
  //  Save the settings
  WriteBookmarks;
  WriteMainSettings;
  if ConfSavePanelTabs then begin
    WriteTabs(True, LeftPanelTabs, LeftTabSortIDs, LeftTabSortTypes);
    WriteTabs(False, RightPanelTabs, RightTabSortIDs, RightTabSortTypes);
  end;
  //  Destroy the objects
  LeftLocalEngine.Free;
  RightLocalEngine.Free;
  CommandLineHistory.Free;
  QuickConnectHistory.Free;
  Bookmarks.Free;
end.
