585 lines
16 KiB
ObjectPascal
585 lines
16 KiB
ObjectPascal
(* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is mozilla.org.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Netscape Communications Corpotation.
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Takanori Itou <necottie@nesitive.net>
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** *)
|
|
unit nsProfile;
|
|
|
|
interface
|
|
|
|
uses
|
|
nsXPCOM, nsTypes, nsXPCOMGlue;
|
|
|
|
type
|
|
nsProfileDirServiceProvider = interface(nsIDirectoryServiceProvider)
|
|
procedure SetProfileDir(AProfileDir: nsIFile);
|
|
procedure Register;
|
|
procedure Shutdown;
|
|
end;
|
|
|
|
EGeckoProfileError = class(EGeckoError);
|
|
|
|
function NS_NewProfileDirServiceProvider(aNotifyObservers: PRBool): nsProfileDirServiceProvider;
|
|
|
|
resourcestring
|
|
SProfileRegisterError = 'Failed to register profile.';
|
|
SProfileShutdownError = 'Failed to shutdown profile.';
|
|
SSetProfileDirError = 'Failed to register profile directory.';
|
|
SNotADirectory = 'The specified file is not a directory.';
|
|
SProfileInitError = 'Failed to initialize profile.';
|
|
SEnsureProfileDirError = 'Cannot ensure profile directory.';
|
|
|
|
implementation
|
|
|
|
uses
|
|
Windows, SysUtils, nsConsts, nsError, nsGeckoStrings, nsCID;
|
|
|
|
type
|
|
TProfileDirLock = class(TObject)
|
|
FHaveLock: Boolean;
|
|
FLockFileHandle: THandle;
|
|
|
|
constructor Create; overload;
|
|
constructor Create(src: TProfileDirLock); overload;
|
|
destructor Destroy; override;
|
|
|
|
procedure Assign(rhs: TProfileDirLock);
|
|
function Lock(aFile: nsILocalFile): nsresult;
|
|
function Unlock: nsresult;
|
|
end;
|
|
|
|
TProfileDirServiceProvider = class(TInterfacedObject,
|
|
nsProfileDirServiceProvider,
|
|
nsIDirectoryServiceProvider)
|
|
FProfileDir: nsIFile;
|
|
FProfileDirLock: TProfileDirLock;
|
|
FNotifyObservers: PRBool;
|
|
FSharingEnabled: Boolean;
|
|
FNonSharedDirName: IInterfacedString;
|
|
FNonSharedProfileDir: nsIFile;
|
|
function GetFile(const prop: PAnsiChar; out persistent: PRBool): nsIFile; safecall;
|
|
procedure SetProfileDir(AProfileDir: nsIFile);
|
|
procedure Register;
|
|
procedure Shutdown;
|
|
|
|
constructor Create(aNotifyObservers: PRBool = True);
|
|
destructor Destroy; override;
|
|
|
|
procedure Initialize;
|
|
procedure InitProfileDir(profileDir: nsIFile);
|
|
procedure InitNonSharedProfileDir;
|
|
procedure EnsureProfileFileExists(aFile: nsIFile; destDir: nsIFile);
|
|
procedure UndefineFileLocations;
|
|
|
|
function SafeCallException(ExceptObject: TObject; ExceptAddr: Pointer): HResult; override;
|
|
end;
|
|
|
|
constructor TProfileDirLock.Create;
|
|
begin
|
|
inherited Create;
|
|
|
|
FHaveLock := False;
|
|
FLockFileHandle := INVALID_HANDLE_VALUE;
|
|
end;
|
|
|
|
constructor TProfileDirLock.Create(src: TProfileDirLock);
|
|
begin
|
|
inherited Create;
|
|
|
|
Assign(src);
|
|
end;
|
|
|
|
procedure TProfileDirLock.Assign(rhs: TProfileDirLock);
|
|
begin
|
|
Unlock();
|
|
|
|
FHaveLock := rhs.FHaveLock;
|
|
rhs.FHaveLock := False;
|
|
|
|
FLockFileHandle := rhs.FLockFileHandle;
|
|
rhs.FLockFileHandle := INVALID_HANDLE_VALUE;
|
|
end;
|
|
|
|
destructor TProfileDirLock.Destroy;
|
|
begin
|
|
Unlock();
|
|
inherited;
|
|
end;
|
|
|
|
function TProfileDirLock.Lock(aFile: nsILocalFile): nsresult;
|
|
const
|
|
LOCKFILE_NAME = 'parent.lock';
|
|
var
|
|
isDir: PRBool;
|
|
lockFile: nsIFile;
|
|
lockFileName: IInterfacedString;
|
|
filePath: IInterfacedCString;
|
|
begin
|
|
try
|
|
lockFileName := NewString(LOCKFILE_NAME);
|
|
filePath := NewCString;
|
|
|
|
if not FHaveLock then
|
|
begin
|
|
Result := NS_ERROR_UNEXPECTED;
|
|
Exit;
|
|
end;
|
|
|
|
isDir := aFile.IsDirectory();
|
|
|
|
if not isDir then
|
|
begin
|
|
Result := NS_ERROR_FILE_NOT_DIRECTORY;
|
|
Exit;
|
|
end;
|
|
|
|
lockFile := aFile.Clone();
|
|
lockFile.Append(lockFileName.AString);
|
|
lockFile.GetNativePath(filePath.ACString);
|
|
|
|
FLockFileHandle := CreateFileA(PAnsiChar(filePath.ToString),
|
|
GENERIC_READ or GENERIC_WRITE,
|
|
0,
|
|
nil,
|
|
OPEN_ALWAYS,
|
|
FILE_FLAG_DELETE_ON_CLOSE,
|
|
0);
|
|
if FLockFileHandle = INVALID_HANDLE_VALUE then
|
|
begin
|
|
Result := NS_ERROR_FILE_ACCESS_DENIED;
|
|
Exit;
|
|
end;
|
|
FHaveLock := True;
|
|
Result := NS_OK;
|
|
except
|
|
on EOutOfMemory do
|
|
Result := NS_ERROR_OUT_OF_MEMORY;
|
|
on ESafeCallException do
|
|
Result := NS_ERROR_FAILURE;
|
|
else
|
|
Result := NS_ERROR_UNEXPECTED;
|
|
end;
|
|
end;
|
|
|
|
function TProfileDirLock.Unlock: nsresult;
|
|
begin
|
|
Result := NS_OK;
|
|
|
|
if FHaveLock then
|
|
begin
|
|
if FLockFileHandle <> INVALID_HANDLE_VALUE then
|
|
begin
|
|
CloseHandle(FLockFileHandle);
|
|
FLockFileHandle := INVALID_HANDLE_VALUE;
|
|
end;
|
|
FHaveLock := False;
|
|
end;
|
|
end;
|
|
|
|
constructor TProfileDirServiceProvider.Create(aNotifyObservers: PRBool);
|
|
begin
|
|
inherited Create;
|
|
FNotifyObservers := aNotifyObservers;
|
|
end;
|
|
|
|
destructor TProfileDirServiceProvider.Destroy;
|
|
begin
|
|
FProfileDirLock.Free;
|
|
inherited;
|
|
end;
|
|
|
|
procedure TProfileDirServiceProvider.SetProfileDir(aProfileDir: nsIFile);
|
|
var
|
|
{$IFDEF MOZ_PROFILELOCKING}
|
|
dirToLock: nsILocalFile;
|
|
{$ENDIF}
|
|
observerService: nsIObserverService;
|
|
begin
|
|
try
|
|
if Assigned(FProfileDir) then
|
|
begin
|
|
if Assigned(aProfileDir) and
|
|
aProfileDir.Equals(FProfileDir) then
|
|
begin
|
|
Exit;
|
|
end;
|
|
{$IFDEF MOZ_PROFILELOCKING}
|
|
FProfileDirLock.Unlock();
|
|
{$ENDIF}
|
|
UndefineFileLocations;
|
|
end;
|
|
FProfileDir := aProfileDir;
|
|
if not Assigned(FProfileDir) then
|
|
begin
|
|
Exit;
|
|
end;
|
|
|
|
{$IFDEF MOZ_PROFILELOCKING}
|
|
Result := InitProfileDir(FProfileDir);
|
|
if NS_FAILED(Result) then Exit;
|
|
|
|
if FSharingEnabled then
|
|
Result := FNonSharedProfileDir.QueryInterface(nsILocalFile, dirToLock)
|
|
else
|
|
Result := FNonSharedProfileDir.QueryInterface(nsILocalFile, dirToLock);
|
|
if NS_FAILED(Result) then Exit;
|
|
Result := FProfileDirLock.Lock(dirToLock);
|
|
if NS_FAILED(Result) then Exit;
|
|
{$ENDIF}
|
|
|
|
if FNotifyObservers then
|
|
begin
|
|
NS_GetService('@mozilla.org/observer-service;1', nsIObserverService, observerService);
|
|
|
|
observerService.NotifyObservers(nil, 'profile-do-change', 'startup');
|
|
observerService.NotifyObservers(nil, 'profile-after-change', 'startup');
|
|
end;
|
|
|
|
except
|
|
raise EGeckoProfileError.CreateRes(PResStringRec(@SSetProfileDirError));
|
|
end;
|
|
end;
|
|
|
|
procedure TProfileDirServiceProvider.Register;
|
|
var
|
|
directoryService: nsIDirectoryService;
|
|
begin
|
|
NS_GetService(NS_DIRECTORY_SERVICE_CONTRACTID,
|
|
nsIDirectoryService,
|
|
directoryService);
|
|
try
|
|
directoryService.RegisterProvider(Self);
|
|
except
|
|
raise EGeckoProfileError.CreateRes(PResStringRec(@SProfileRegisterError));
|
|
end;
|
|
end;
|
|
|
|
procedure TProfileDirServiceProvider.Shutdown;
|
|
var
|
|
observerService: nsIObserverService;
|
|
begin
|
|
NS_GetService('@mozilla.org/observer-service;1',
|
|
nsIObserverService,
|
|
observerService);
|
|
try
|
|
observerService.NotifyObservers(nil, 'profile-before-change', 'shutdown-persist');
|
|
except
|
|
raise EGeckoProfileError.CreateRes(PResStringRec(@SProfileShutdownError));
|
|
end;
|
|
end;
|
|
|
|
function TProfileDirServiceProvider.GetFile(const prop: PAnsiChar; out persistent: PRBool): nsIFile;
|
|
var
|
|
localFile: nsIFile;
|
|
domainDir: nsIFile;
|
|
appendStr: IInterfacedCString;
|
|
const
|
|
PREFS_FILE_50_NAME =' prefs.js';
|
|
USER_CHROME_DIR_50_NAME = 'chrome';
|
|
LOCAL_STORE_FILE_50_NAME = 'localstore.rdf';
|
|
HISTORY_FILE_50_NAME = 'history.dat';
|
|
PANELS_FILE_50_NAME = 'panels.rdf';
|
|
MIME_TYPES_FILE_50_NAME = 'mimeTypes.rdf';
|
|
BOOKMARKS_FILE_50_NAME = 'bookmark.html';
|
|
DOWNLOADS_FILE_50_NAME = 'downloads.rdf';
|
|
SEARCH_FILE_50_NAME = 'search.rdf';
|
|
MAIL_DIR_50_NAME = 'Mail';
|
|
IMAP_MAIL_DIR_50_NAME = 'ImapMail';
|
|
NEWS_DIR_50_NAME = 'News';
|
|
MSG_FOLDER_CACHE_DIR_50_NAME = 'panacea.dat';
|
|
begin
|
|
appendStr := NewCString;
|
|
|
|
persistent := True;
|
|
domainDir := FProfileDir;
|
|
|
|
Assert(Assigned(domainDir));
|
|
|
|
if prop = NS_APP_PREFS_50_DIR then
|
|
begin
|
|
localFile := domainDir.Clone();
|
|
end else
|
|
if prop = NS_APP_PREFS_50_FILE then
|
|
begin
|
|
localFile := domainDir.Clone();
|
|
appendStr.Assign(PREFS_FILE_50_NAME);
|
|
localFile.AppendNative(appendStr.ACString);
|
|
end else
|
|
if prop = NS_APP_USER_PROFILE_50_DIR then
|
|
begin
|
|
localFile := domainDir.Clone();
|
|
end else
|
|
if prop = NS_APP_USER_CHROME_DIR then
|
|
begin
|
|
localFile := domainDir.Clone();
|
|
appendStr.Assign(USER_CHROME_DIR_50_NAME);
|
|
localFile.AppendNative(appendStr.ACString);
|
|
end else
|
|
if prop = NS_APP_LOCALSTORE_50_FILE then
|
|
begin
|
|
localFile := domainDir.Clone();
|
|
appendStr.Assign(LOCAL_STORE_FILE_50_NAME);
|
|
localFile.AppendNative(appendStr.ACString);
|
|
EnsureProfileFileExists(localFile, domainDir);
|
|
end else
|
|
if prop = NS_APP_HISTORY_50_FILE then
|
|
begin
|
|
localFile := domainDir.Clone();
|
|
appendStr.Assign(HISTORY_FILE_50_NAME);
|
|
localFile.AppendNative(appendStr.ACString);
|
|
end else
|
|
if prop = NS_APP_USER_PANELS_50_FILE then
|
|
begin
|
|
localFile := domainDir.Clone();
|
|
appendStr.Assign(PANELS_FILE_50_NAME);
|
|
localFile.AppendNative(appendStr.ACString);
|
|
EnsureProfileFileExists(localFile, domainDir);
|
|
end else
|
|
if prop = NS_APP_USER_MIMETYPES_50_FILE then
|
|
begin
|
|
localFile := domainDir.Clone();
|
|
appendStr.Assign(MIME_TYPES_FILE_50_NAME);
|
|
localFile.AppendNative(appendStr.ACString);
|
|
EnsureProfileFileExists(localFile, domainDir);
|
|
end else
|
|
if prop = NS_APP_BOOKMARKS_50_FILE then
|
|
begin
|
|
localFile := domainDir.Clone();
|
|
appendStr.Assign(BOOKMARKS_FILE_50_NAME);
|
|
localFile.AppendNative(appendStr.ACString);
|
|
end else
|
|
if prop = NS_APP_DOWNLOADS_50_FILE then
|
|
begin
|
|
localFile := domainDir.Clone();
|
|
appendStr.Assign(DOWNLOADS_FILE_50_NAME);
|
|
localFile.AppendNative(appendStr.ACString);
|
|
end else
|
|
if prop = NS_APP_SEARCH_50_FILE then
|
|
begin
|
|
localFile := domainDir.Clone();
|
|
appendStr.Assign(SEARCH_FILE_50_NAME);
|
|
localFile.AppendNative(appendStr.ACString);
|
|
EnsureProfileFileExists(localFile, domainDir);
|
|
end else
|
|
if prop = NS_APP_MAIL_50_DIR then
|
|
begin
|
|
localFile := domainDir.Clone();
|
|
appendStr.Assign(MAIL_DIR_50_NAME);
|
|
localFile.AppendNative(appendStr.ACString);
|
|
end else
|
|
if prop = NS_APP_IMAP_MAIL_50_DIR then
|
|
begin
|
|
localFile := domainDir.Clone();
|
|
appendStr.Assign(IMAP_MAIL_DIR_50_NAME);
|
|
localFile.AppendNative(appendStr.ACString);
|
|
end else
|
|
if prop = NS_APP_NEWS_50_DIR then
|
|
begin
|
|
localFile := domainDir.Clone();
|
|
appendStr.Assign(NEWS_DIR_50_NAME);
|
|
localFile.AppendNative(appendStr.ACString);
|
|
end else
|
|
if prop = NS_APP_MESSENGER_FOLDER_CACHE_50_DIR then
|
|
begin
|
|
localFile := domainDir.Clone();
|
|
appendStr.Assign(MSG_FOLDER_CACHE_DIR_50_NAME);
|
|
localFile.AppendNative(appendStr.ACString);
|
|
end;
|
|
|
|
if Assigned(localFile) then
|
|
Result := localFile as nsIFile;
|
|
end;
|
|
|
|
procedure TProfileDirServiceProvider.Initialize;
|
|
begin
|
|
{$IFDEF MOZ_PROFILELOCKING}
|
|
FProfileDir := TProfileDirServiceProvider.Create(FNotifyObservers);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TProfileDirServiceProvider.InitProfileDir(profileDir: nsIFile);
|
|
var
|
|
exists: PRBool;
|
|
profileDefaultsDir: nsIFile;
|
|
profileDirParent: nsIFile;
|
|
profileDirName: IInterfacedCString;
|
|
isDir: PRBool;
|
|
begin
|
|
try
|
|
profileDirName := NewCString;
|
|
|
|
exists := profileDir.Exists();
|
|
|
|
if not exists then
|
|
begin
|
|
profileDirParent := profileDir.Parent;
|
|
profileDir.GetNativeLeafName(profileDirName.ACString);
|
|
|
|
try
|
|
profileDefaultsDir := NS_GetSpecialDirectory(NS_APP_PROFILE_DEFAULTS_50_DIR);
|
|
except
|
|
profileDefaultsDir := NS_GetSpecialDirectory(NS_APP_PROFILE_DEFAULTS_NLOC_50_DIR);
|
|
end;
|
|
try
|
|
profileDefaultsDir.CopyToNative(profileDirParent, profileDirName.ACString);
|
|
except
|
|
profileDirParent.AppendNative(profileDirName.ACString);
|
|
profileDirParent.Create(NS_IFILE_DIRECTORY_TYPE, 7 shl 6);
|
|
end;
|
|
end else
|
|
begin
|
|
isDir := profileDir.IsDirectory();
|
|
if not isDir then
|
|
raise EGeckoProfileError.CreateRes(PResStringRec(@SNotADirectory));
|
|
end;
|
|
|
|
if FNonSharedDirName.Length > 0 then
|
|
InitNonSharedProfileDir;
|
|
except
|
|
on EGeckoError do raise
|
|
else raise EGeckoProfileError.CreateRes(PResStringRec(@SProfileInitError));
|
|
end;
|
|
end;
|
|
|
|
procedure TProfileDirServiceProvider.InitNonSharedProfileDir;
|
|
var
|
|
localDir: nsIFile;
|
|
exists: PRBool;
|
|
isDir: PRBool;
|
|
begin
|
|
try
|
|
localDir := FProfileDir.Clone();
|
|
localDir.Append(FNonSharedDirName.AString);
|
|
exists := localDir.Exists();
|
|
if not exists then
|
|
begin
|
|
localDir.Create(NS_IFILE_DIRECTORY_TYPE, 7 shl 6);
|
|
end else
|
|
begin
|
|
isDir := localDir.IsDirectory();
|
|
if not isDir then
|
|
raise EGeckoProfileError.CreateRes(PResStringRec(@SNotADirectory));
|
|
end;
|
|
FNonSharedProfileDir := localDir;
|
|
except
|
|
on EGeckoError do raise
|
|
else raise EGeckoProfileError.CreateRes(PResStringRec(@SProfileInitError));
|
|
end;
|
|
end;
|
|
|
|
procedure TProfileDirServiceProvider.EnsureProfileFileExists(aFile: nsIFile; destDir: nsIFile);
|
|
var
|
|
exists: PRBool;
|
|
defaultsFile: nsIFile;
|
|
leafName: IInterfacedCString;
|
|
begin
|
|
try
|
|
exists := aFile.Exists;
|
|
if exists then
|
|
begin
|
|
Exit;
|
|
end;
|
|
|
|
try
|
|
defaultsFile := NS_GetSpecialDirectory(NS_APP_PROFILE_DEFAULTS_50_DIR);
|
|
except
|
|
defaultsFile := NS_GetSpecialDirectory(NS_APP_PROFILE_DEFAULTS_NLOC_50_DIR);
|
|
end;
|
|
|
|
leafName := NewCString;
|
|
|
|
aFile.GetNativeLeafName(leafName.ACString);
|
|
defaultsFile.AppendNative(leafName.ACString);
|
|
|
|
leafName.Assign('');
|
|
defaultsFile.CopyToNative(destDir, leafName.ACString);
|
|
except
|
|
on EGeckoError do raise
|
|
else raise EGeckoProfileError.CreateRes(PResStringRec(@SEnsureProfileDirError));
|
|
end;
|
|
end;
|
|
|
|
procedure TProfileDirServiceProvider.UndefineFileLocations;
|
|
var
|
|
directoryService : nsIProperties;
|
|
i: Integer;
|
|
const
|
|
NUM_OF_DIRS = 15;
|
|
Dirs: array [1..15] of PAnsiChar = (
|
|
NS_APP_PREFS_50_DIR,
|
|
NS_APP_PREFS_50_FILE,
|
|
NS_APP_USER_PROFILE_50_DIR,
|
|
NS_APP_USER_CHROME_DIR,
|
|
NS_APP_LOCALSTORE_50_FILE,
|
|
NS_APP_HISTORY_50_FILE,
|
|
NS_APP_USER_PANELS_50_FILE,
|
|
NS_APP_USER_MIMETYPES_50_FILE,
|
|
NS_APP_BOOKMARKS_50_FILE,
|
|
NS_APP_DOWNLOADS_50_FILE,
|
|
NS_APP_SEARCH_50_FILE,
|
|
NS_APP_MAIL_50_DIR,
|
|
NS_APP_IMAP_MAIL_50_DIR,
|
|
NS_APP_NEWS_50_DIR,
|
|
NS_APP_MESSENGER_FOLDER_CACHE_50_DIR
|
|
);
|
|
begin
|
|
NS_GetService(NS_DIRECTORY_SERVICE_CONTRACTID,
|
|
nsIProperties,
|
|
directoryService);
|
|
|
|
for I:=1 to NUM_OF_DIRS do
|
|
try
|
|
directoryService.Undefine(Dirs[I]);
|
|
except
|
|
end;
|
|
end;
|
|
|
|
function TProfileDirServiceProvider.SafeCallException(ExceptObject: TObject; ExceptAddr: Pointer): HResult;
|
|
begin
|
|
Result := HResult(NS_ERROR_FAILURE);
|
|
end;
|
|
|
|
function NS_NewProfileDirServiceProvider(aNotifyObservers: PRBool): nsProfileDirServiceProvider;
|
|
var
|
|
prov: TProfileDirServiceProvider;
|
|
begin
|
|
prov := TProfileDirServiceProvider.Create(aNotifyObservers);
|
|
|
|
prov.Initialize;
|
|
Result := prov;
|
|
prov.FNotifyObservers := aNotifyObservers;
|
|
end;
|
|
|
|
end.
|