Files
Mozilla/mozilla/extensions/tridentprofile/src/nsTridentPreferencesWin.cpp

770 lines
24 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** 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 code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* 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 ***** */
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include "nsAppDirectoryServiceDefs.h"
#include "nsCOMPtr.h"
#include "nsNetCID.h"
#include "nsDebug.h"
#include "nsDependentString.h"
#include "nsDirectoryServiceDefs.h"
#include "nsString.h"
#include "nsTridentPreferencesWin.h"
#include "plstr.h"
#include "prio.h"
#include "prmem.h"
#include "prlong.h"
#include "nsICookieManager2.h"
#include "nsIFile.h"
#include "nsILocalFile.h"
#include "nsIPrefService.h"
#include "nsIPrefBranch.h"
#include "nsServiceManagerUtils.h"
#include "nsISimpleEnumerator.h"
#include "nsITridentProfileMigrator.h"
const int sInitialCookieBufferSize = 1024; // but it can grow
const int sUsernameLengthLimit = 80;
const int sHostnameLengthLimit = 255;
//***********************************************************************
//*** windows registry to mozilla prefs data type translation functions
//***********************************************************************
typedef void (*regEntryHandler)(unsigned char *, DWORD, DWORD,
nsIPrefBranch *, char *);
// yes/no string to T/F boolean
void
TranslateYNtoTF(unsigned char *aRegValue, DWORD aRegValueLength,
DWORD aRegValueType,
nsIPrefBranch *prefs, char *aPrefKeyName) {
PRInt32 prefIntValue = 0;
// input type is a string, lowercase "yes" or "no"
if (aRegValueType != REG_SZ)
NS_WARNING("unexpected yes/no data type");
if (aRegValueType == REG_SZ && aRegValue[0] != 0) {
// strcmp is safe; it's bounded by its second parameter
prefIntValue = strcmp(reinterpret_cast<char *>(aRegValue), "yes") == 0;
prefs->SetBoolPref(aPrefKeyName, prefIntValue);
}
}
// yes/no string to F/T boolean
void
TranslateYNtoFT(unsigned char *aRegValue, DWORD aRegValueLength,
DWORD aRegValueType,
nsIPrefBranch *prefs, char *aPrefKeyName) {
PRInt32 prefIntValue = 0;
// input type is a string, lowercase "yes" or "no"
if (aRegValueType != REG_SZ)
NS_WARNING("unexpected yes/no data type");
if (aRegValueType == REG_SZ && aRegValue[0] != 0) {
// strcmp is safe; it's bounded by its second parameter
prefIntValue = strcmp(reinterpret_cast<char *>(aRegValue), "yes") != 0;
prefs->SetBoolPref(aPrefKeyName, prefIntValue);
}
}
// decimal RGB (1,2,3) to hex RGB (#010203)
void
TranslateDRGBtoHRGB(unsigned char *aRegValue, DWORD aRegValueLength,
DWORD aRegValueType,
nsIPrefBranch *prefs, char *aPrefKeyName) {
// clear previous settings with defaults
char prefStringValue[10];
// input type is a string
if (aRegValueType != REG_SZ)
NS_WARNING("unexpected RGB data type");
if (aRegValueType == REG_SZ && aRegValue[0] != 0) {
int red, green, blue;
::sscanf(reinterpret_cast<char *>(aRegValue), "%d,%d,%d",
&red, &green, &blue);
::sprintf(prefStringValue, "#%02X%02X%02X", red, green, blue);
prefs->SetCharPref(aPrefKeyName, prefStringValue);
}
}
// translate a windows registry DWORD int to a mozilla prefs PRInt32
void
TranslateDWORDtoPRInt32(unsigned char *aRegValue, DWORD aRegValueLength,
DWORD aRegValueType,
nsIPrefBranch *prefs, char *aPrefKeyName) {
// clear previous settings with defaults
PRInt32 prefIntValue = 0;
if (aRegValueType != REG_DWORD)
NS_WARNING("unexpected signed int data type");
if (aRegValueType == REG_DWORD) {
prefIntValue = *(reinterpret_cast<DWORD *>(aRegValue));
prefs->SetIntPref(aPrefKeyName, prefIntValue);
}
}
// string copy
void
TranslateString(unsigned char *aRegValue, DWORD aRegValueLength,
DWORD aRegValueType,
nsIPrefBranch *prefs, char *aPrefKeyName) {
if (aRegValueType != REG_SZ)
NS_WARNING("unexpected string data type");
if (aRegValueType == REG_SZ)
prefs->SetCharPref(aPrefKeyName,
reinterpret_cast<char *>(aRegValue));
}
// translate homepage
// (modified string copy)
void
TranslateHomepage(unsigned char *aRegValue, DWORD aRegValueLength,
DWORD aRegValueType,
nsIPrefBranch *prefs, char *aPrefKeyName) {
if (aRegValueType != REG_SZ)
NS_WARNING("unexpected string data type");
if (aRegValueType == REG_SZ) {
// strcmp is safe; it's bounded by its second parameter
if (strcmp(reinterpret_cast<char *>(aRegValue), "about:blank") == 0)
prefs->SetIntPref("browser.startup.page", 0);
else {
prefs->SetIntPref("browser.startup.page", 1);
prefs->SetCharPref(aPrefKeyName,
reinterpret_cast<char *>(aRegValue));
}
}
}
// translate accepted language character set formats
// (modified string copy)
void
TranslateLanglist(unsigned char *aRegValue, DWORD aRegValueLength,
DWORD aRegValueType,
nsIPrefBranch *prefs, char *aPrefKeyName) {
char prefStringValue[MAX_PATH]; // a convenient size, one hopes
if (aRegValueType != REG_SZ)
NS_WARNING("unexpected string data type");
if (aRegValueType != REG_SZ)
return;
// copy source format like "en-us,ar-kw;q=0.7,ar-om;q=0.3" into
// destination format like "en-us, ar-kw, ar-om"
char *source = reinterpret_cast<char *>(aRegValue),
*dest = prefStringValue,
*sourceEnd = source + aRegValueLength,
*destEnd = dest + (MAX_PATH-2); // room for " \0"
PRBool skip = PR_FALSE,
comma = PR_FALSE;
while (source < sourceEnd && *source && dest < destEnd) {
if (*source == ',')
skip = PR_FALSE;
else if (*source == ';')
skip = PR_TRUE;
if (!skip) {
if (comma && *source != ' ')
*dest++ = ' ';
*dest = *source;
}
comma = *source == ',';
++source;
}
*dest = 0;
prefs->SetCharPref(aPrefKeyName, prefStringValue);
}
static int CALLBACK
fontEnumProc(const LOGFONT *aLogFont, const TEXTMETRIC *aMetric,
DWORD aFontType, LPARAM aClosure) {
*((int *) aClosure) = aLogFont->lfPitchAndFamily & FF_ROMAN;
return 0;
}
void
TranslatePropFont(unsigned char *aRegValue, DWORD aRegValueLength,
DWORD aRegValueType,
nsIPrefBranch *prefs, char *aPrefKeyName) {
HDC dc = ::GetDC(0);
LOGFONT lf;
int isSerif = 1;
// serif or sans-serif font?
lf.lfCharSet = DEFAULT_CHARSET;
lf.lfPitchAndFamily = 0;
PL_strncpyz(lf.lfFaceName, reinterpret_cast<char *>(aRegValue),
LF_FACESIZE);
::EnumFontFamiliesEx(dc, &lf, fontEnumProc, (LPARAM) &isSerif, 0);
::ReleaseDC(0, dc);
if (isSerif) {
prefs->SetCharPref("font.name.serif.x-western",
reinterpret_cast<char *>(aRegValue));
prefs->SetCharPref("font.default.x-western", "serif");
} else {
prefs->SetCharPref("font.name.sans-serif.x-western",
reinterpret_cast<char *>(aRegValue));
prefs->SetCharPref("font.default.x-western", "sans-serif");
}
}
//***********************************************************************
//*** master table of registry-to-gecko-pref translations
//***********************************************************************
struct regEntry {
char *regKeyName, // registry key (HKCU\Software ...)
*regValueName; // registry key leaf
char *prefKeyName; // pref name ("javascript.enabled" ...)
regEntryHandler entryHandler; // processing func
};
struct regEntry gRegEntries[] = {
{ "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoComplete",
"AutoSuggest",
"browser.urlbar.autocomplete.enabled",
TranslateYNtoTF },
{ "Software\\Microsoft\\Internet Explorer\\International",
"AcceptLanguage",
"intl.accept_languages",
TranslateLanglist },
{ "Software\\Microsoft\\Internet Explorer\\International\\Scripts\\3",
"IEFixedFontName",
"font.name.monospace.x-western",
TranslateString },
{ 0, // an optimization: 0 means use the previous key
"IEPropFontName",
"", // special-cased in the translation function
TranslatePropFont },
{ "Software\\Microsoft\\Internet Explorer\\Main",
"Use_DlgBox_Colors",
"browser.display.use_system_colors",
TranslateYNtoTF },
{ 0,
"Use FormSuggest",
"wallet.captureForms",
TranslateYNtoTF },
{ 0,
"FormSuggest Passwords",
"signon.rememberSignons",
TranslateYNtoTF },
{ 0,
"Start Page",
"browser.startup.homepage",
TranslateHomepage },
{ "Software\\Microsoft\\Internet Explorer\\Settings",
"Always Use My Colors",
"browser.display.use_document_colors",
TranslateYNtoFT },
{ 0,
"Text Color",
"browser.display.foreground_color",
TranslateDRGBtoHRGB },
{ 0,
"Background Color",
"browser.display.background_color",
TranslateDRGBtoHRGB },
{ 0,
"Anchor Color",
"browser.anchor_color",
TranslateDRGBtoHRGB },
{ 0,
"Anchor Color Visited",
"browser.visited_color",
TranslateDRGBtoHRGB },
{ 0,
"Always Use My Font Face",
"browser.display.use_document_fonts",
TranslateYNtoFT },
{ "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Url History",
"DaysToKeep",
"browser.history_expire_days",
TranslateDWORDtoPRInt32 }
};
#if 0
user_pref("font.size.fixed.x-western", 14);
user_pref("font.size.variable.x-western", 15);
#endif
//*****************************************************************************
//*** factory
//*****************************************************************************
nsTridentPreferences *
MakeTridentPreferences() {
return new nsTridentPreferencesWin();
}
//*****************************************************************************
//*** nsTridentPreferences
//*****************************************************************************
nsTridentPreferences::nsTridentPreferences() {
}
nsTridentPreferences::~nsTridentPreferences() {
}
//*****************************************************************************
//*** nsTridentPreferencesWin
//*****************************************************************************
nsTridentPreferencesWin::nsTridentPreferencesWin() {
}
nsTridentPreferencesWin::~nsTridentPreferencesWin() {
}
// migration entry point
nsresult
nsTridentPreferencesWin::MigrateTridentPreferences(PRUint32 aItems) {
nsresult rv = NS_OK;
if (aItems & nsITridentProfileMigrator::PREFERENCES)
rv = CopyPreferences();
if (NS_SUCCEEDED(rv) && (aItems & nsITridentProfileMigrator::COOKIES))
rv = CopyCookies();
return rv;
}
nsresult
nsTridentPreferencesWin::CopyPreferences() {
HKEY regKey;
PRBool regKeyOpen = PR_FALSE;
struct regEntry *entry,
*endEntry = gRegEntries +
sizeof(gRegEntries)/sizeof(struct regEntry);
DWORD regType;
DWORD regLength;
unsigned char regValue[MAX_PATH]; // a convenient size
nsCOMPtr<nsIPrefBranch> prefs;
{ // scope pserve why not
nsCOMPtr<nsIPrefService> pserve(do_GetService(NS_PREFSERVICE_CONTRACTID));
if (pserve)
pserve->GetBranch("", getter_AddRefs(prefs));
}
if (!prefs)
return NS_ERROR_FAILURE;
// step through gRegEntries table
for (entry = gRegEntries; entry < endEntry; ++entry) {
// a new keyname? close any previous one and open the new one
if (entry->regKeyName) {
if (regKeyOpen) {
::RegCloseKey(regKey);
regKeyOpen = PR_FALSE;
}
regKeyOpen = ::RegOpenKeyEx(HKEY_CURRENT_USER, entry->regKeyName, 0,
KEY_READ, &regKey) == ERROR_SUCCESS;
}
if (regKeyOpen) {
// read registry data
regLength = MAX_PATH;
if (::RegQueryValueEx(regKey, entry->regValueName, 0,
&regType, regValue, &regLength) == ERROR_SUCCESS)
entry->entryHandler(regValue, regLength, regType,
prefs, entry->prefKeyName);
}
}
if (regKeyOpen)
::RegCloseKey(regKey);
return CopyStyleSheet();
}
/* Fetch and translate the current user's cookies.
Return true if successful. */
nsresult
nsTridentPreferencesWin::CopyCookies() {
// IE cookies are stored in files named <username>@domain[n].txt
// (in <username>'s Cookies folder. isn't the naming redundant?)
PRBool rv = NS_OK;
nsCOMPtr<nsIFile> cookiesDir;
nsCOMPtr<nsISimpleEnumerator> cookieFiles;
nsCOMPtr<nsICookieManager2> cookieManager(do_GetService(NS_COOKIEMANAGER_CONTRACTID));
if (!cookieManager)
return NS_ERROR_FAILURE;
// find the cookies directory
NS_GetSpecialDirectory(NS_WIN_COOKIES_DIR, getter_AddRefs(cookiesDir));
if (cookiesDir)
cookiesDir->GetDirectoryEntries(getter_AddRefs(cookieFiles));
if (!cookieFiles)
return NS_ERROR_FAILURE;
// fetch the current user's name from the environment
char username[sUsernameLengthLimit+2];
::GetEnvironmentVariable("USERNAME", username, sizeof(username));
username[sizeof(username)-2] = '\0';
PL_strcat(username, "@");
int usernameLength = PL_strlen(username);
// allocate a buffer into which to read each cookie file
char *fileContents = (char *) PR_Malloc(sInitialCookieBufferSize);
if (!fileContents)
return NS_ERROR_OUT_OF_MEMORY;
PRUint32 fileContentsSize = sInitialCookieBufferSize;
do { // for each file in the cookies directory
// get the next file
PRBool moreFiles = PR_FALSE;
if (NS_FAILED(cookieFiles->HasMoreElements(&moreFiles)) || !moreFiles)
break;
nsCOMPtr<nsISupports> supFile;
cookieFiles->GetNext(getter_AddRefs(supFile));
nsCOMPtr<nsIFile> cookieFile(do_QueryInterface(supFile));
if (!cookieFile) {
rv = NS_ERROR_FAILURE;
break; // unexpected! punt!
}
// is it a cookie file for the current user?
nsCAutoString fileName;
cookieFile->GetNativeLeafName(fileName);
const nsACString &fileOwner = Substring(fileName, 0, usernameLength);
if (!fileOwner.Equals(username, nsCaseInsensitiveCStringComparator()))
continue;
// ensure the contents buffer is large enough to hold the entire file
// plus one byte (see DelimitField())
PRInt64 llFileSize;
if (NS_FAILED(cookieFile->GetFileSize(&llFileSize)))
continue;
PRUint32 fileSize, readSize;
LL_L2UI(fileSize, llFileSize);
if (fileSize >= fileContentsSize) {
PR_Free(fileContents);
fileContents = (char *) PR_Malloc(fileSize+1);
if (!fileContents) {
rv = NS_ERROR_FAILURE;
break; // fatal error
}
fileContentsSize = fileSize;
}
// read the entire cookie file
PRFileDesc *fd;
nsCOMPtr<nsILocalFile> localCookieFile(do_QueryInterface(cookieFile));
if (localCookieFile &&
NS_SUCCEEDED(localCookieFile->OpenNSPRFileDesc(PR_RDONLY, 0444, &fd))) {
readSize = PR_Read(fd, fileContents, fileSize);
PR_Close(fd);
if (fileSize == readSize) { // translate this file's cookies
nsresult onerv;
onerv = CopyCookiesFromBuffer(fileContents, readSize, cookieManager);
if (NS_FAILED(onerv))
rv = onerv;
}
}
} while(1);
if (fileContents)
PR_Free(fileContents);
return rv;
}
/* Fetch cookies from a single IE cookie file.
Return true if successful. */
nsresult
nsTridentPreferencesWin::CopyCookiesFromBuffer(
char *aBuffer,
PRUint32 aBufferLength,
nsICookieManager2 *aCookieManager) {
nsresult rv = NS_OK;
const char *bufferEnd = aBuffer + aBufferLength;
// cookie fields:
char *name,
*value,
*host,
*path,
*flags,
*expirationDate1, *expirationDate2,
*creationDate1, *creationDate2,
*terminator;
int flagsValue;
time_t expirationDate,
creationDate;
char hostCopy[sHostnameLengthLimit+1],
*hostCopyConstructor,
*hostCopyEnd = hostCopy + sHostnameLengthLimit;
do { // for each cookie in the buffer
DelimitField(&aBuffer, bufferEnd, &name);
DelimitField(&aBuffer, bufferEnd, &value);
DelimitField(&aBuffer, bufferEnd, &host);
DelimitField(&aBuffer, bufferEnd, &flags);
DelimitField(&aBuffer, bufferEnd, &expirationDate1);
DelimitField(&aBuffer, bufferEnd, &expirationDate2);
DelimitField(&aBuffer, bufferEnd, &creationDate1);
DelimitField(&aBuffer, bufferEnd, &creationDate2);
DelimitField(&aBuffer, bufferEnd, &terminator);
// it's a cookie if we got one of each
if (terminator >= bufferEnd)
break;
// IE stores deleted cookies with a zero-length value
if (*value == '\0')
continue;
// convert flags to an int, date numbers to useable dates
::sscanf(flags, "%d", &flagsValue);
expirationDate = FileTimeToTimeT(expirationDate1, expirationDate2);
creationDate = FileTimeToTimeT(creationDate1, creationDate2);
// munge host, and separate host from path
hostCopyConstructor = hostCopy;
// first, with a non-null domain, assume it's what Mozilla considers
// a domain cookie. see bug 222343.
if (*host && *host != '.' && *host != '/')
*hostCopyConstructor++ = '.';
// copy the host part and leave path pointing to the path part
for (path = host; *path && *path != '/'; ++path)
;
int hostLength = path - host;
if (hostLength > hostCopyEnd - hostCopyConstructor)
hostLength = hostCopyEnd - hostCopyConstructor;
PL_strncpy(hostCopyConstructor, host, hostLength);
hostCopyConstructor += hostLength;
*hostCopyConstructor = '\0';
nsDependentCString stringName(name),
stringPath(path);
// delete any possible extant matching host cookie
if (hostCopy[0] == '.')
aCookieManager->Remove(nsDependentCString(hostCopy+1),
stringName, stringPath, PR_FALSE);
nsresult onerv;
// Add() makes a new domain cookie
onerv = aCookieManager->Add(nsDependentCString(hostCopy),
stringPath,
stringName,
nsDependentCString(value),
flagsValue & 0x1, // isSecure
PR_FALSE, // isHttpOnly
PR_FALSE, // isSession
PRInt64(expirationDate));
if (NS_FAILED(onerv)) {
rv = onerv;
break;
}
} while(aBuffer < bufferEnd);
return rv;
}
/* Delimit the next field in the IE cookie buffer.
when called:
aBuffer: at the beginning of the next field or preceding whitespace
aBufferEnd: one past the last valid character in the buffer
on return:
aField: at the beginning of the next field, which is null delimited
aBuffer: after the null at the end of the field
the character at which aBufferEnd points must be part of the buffer
so we can set it to \0.
*/
void
nsTridentPreferencesWin::DelimitField(char **aBuffer,
const char *aBufferEnd,
char **aField) {
char *scan = *aBuffer;
*aField = scan;
while (scan < aBufferEnd && (*scan != '\r' && *scan != '\n'))
++scan;
if (scan+1 < aBufferEnd && (*(scan+1) == '\r' || *(scan+1) == '\n') &&
*scan != *(scan+1)) {
*scan = '\0';
scan += 2;
} else {
if (scan <= aBufferEnd) // (1 byte past bufferEnd is guaranteed allocated)
*scan = '\0';
++scan;
}
*aBuffer = scan;
}
// conversion routine. returns 0 (epoch date) if the input is out of range
time_t
nsTridentPreferencesWin::FileTimeToTimeT(const char *aLowDateIntString,
const char *aHighDateIntString) {
FILETIME fileTime;
SYSTEMTIME systemTime;
tm tTime;
time_t rv;
::sscanf(aLowDateIntString, "%ld", &fileTime.dwLowDateTime);
::sscanf(aHighDateIntString, "%ld", &fileTime.dwHighDateTime);
::FileTimeToSystemTime(&fileTime, &systemTime);
tTime.tm_year = systemTime.wYear - 1900;
tTime.tm_mon = systemTime.wMonth-1;
tTime.tm_mday = systemTime.wDay;
tTime.tm_hour = systemTime.wHour;
tTime.tm_min = systemTime.wMinute;
tTime.tm_sec = systemTime.wSecond;
tTime.tm_isdst = -1;
rv = ::mktime(&tTime);
return rv < 0 ? 0 : rv;
}
/* Find the accessibility stylesheet if it exists and replace Mozilla's
with it. Return true if we found and copied a stylesheet. */
nsresult
nsTridentPreferencesWin::CopyStyleSheet() {
nsresult rv = NS_OK; // return failure only if filecopy fails
HKEY regKey;
DWORD regType,
regLength,
regDWordValue;
char tridentFilename[MAX_PATH];
// is there a trident user stylesheet?
if (::RegOpenKeyEx(HKEY_CURRENT_USER,
"Software\\Microsoft\\Internet Explorer\\Styles", 0,
KEY_READ, &regKey) != ERROR_SUCCESS)
return NS_OK;
regLength = sizeof(DWORD);
if (::RegQueryValueEx(regKey, "Use My Stylesheet", 0, &regType,
reinterpret_cast<unsigned char *>(&regDWordValue),
&regLength) == ERROR_SUCCESS &&
regType == REG_DWORD && regDWordValue == 1) {
regLength = MAX_PATH;
if (::RegQueryValueEx(regKey, "User Stylesheet", 0, &regType,
reinterpret_cast<unsigned char *>(tridentFilename),
&regLength)
== ERROR_SUCCESS) {
// tridentFilename is a native path to the specified stylesheet file
// point an nsIFile at it
nsCOMPtr<nsILocalFile> tridentFile(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
if (tridentFile) {
PRBool exists;
tridentFile->InitWithNativePath(nsDependentCString(tridentFilename));
tridentFile->Exists(&exists);
if (exists) {
// now establish our file (userContent.css in the profile/chrome dir)
nsCOMPtr<nsIFile> chromeDir;
NS_GetSpecialDirectory(NS_APP_USER_CHROME_DIR,
getter_AddRefs(chromeDir));
if (chromeDir)
rv = tridentFile->CopyToNative(chromeDir,
nsDependentCString("userContent.css"));
}
}
}
}
::RegCloseKey(regKey);
return rv;
}
void
nsTridentPreferencesWin::GetUserStyleSheetFile(nsIFile **aUserFile) {
nsCOMPtr<nsIFile> userChrome;
*aUserFile = 0;
// establish the chrome directory
NS_GetSpecialDirectory(NS_APP_USER_CHROME_DIR, getter_AddRefs(userChrome));
if (userChrome) {
PRBool exists;
userChrome->Exists(&exists);
if (!exists &&
NS_FAILED(userChrome->Create(nsIFile::DIRECTORY_TYPE, 0755)))
return;
// establish the user content stylesheet file
userChrome->AppendNative(NS_LITERAL_CSTRING("userContent.css"));
*aUserFile = userChrome;
NS_ADDREF(*aUserFile);
}
}