Back to index

lightning-sunbird  0.9+nobinonly
nsTridentPreferencesWin.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2002
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include <stdio.h>
00039 #include <string.h>
00040 #include <windows.h>
00041 #include "nsAppDirectoryServiceDefs.h"
00042 #include "nsCOMPtr.h"
00043 #include "nsNetCID.h"
00044 #include "nsDebug.h"
00045 #include "nsDependentString.h"
00046 #include "nsDirectoryServiceDefs.h"
00047 #include "nsString.h"
00048 #include "nsTridentPreferencesWin.h"
00049 #include "plstr.h"
00050 #include "prio.h"
00051 #include "prmem.h"
00052 #include "prlong.h"
00053 #include "nsICookieManager2.h"
00054 #include "nsIFile.h"
00055 #include "nsILocalFile.h"
00056 #include "nsIPrefService.h"
00057 #include "nsIPrefBranch.h"
00058 #include "nsServiceManagerUtils.h"
00059 #include "nsISimpleEnumerator.h"
00060 #include "nsITridentProfileMigrator.h"
00061 
00062 const int sInitialCookieBufferSize = 1024; // but it can grow
00063 const int sUsernameLengthLimit     = 80;
00064 const int sHostnameLengthLimit     = 255;
00065 
00066 //***********************************************************************
00067 //*** windows registry to mozilla prefs data type translation functions
00068 //***********************************************************************
00069 
00070 typedef void (*regEntryHandler)(unsigned char *, DWORD, DWORD,
00071                                 nsIPrefBranch *, char *);
00072 
00073 // yes/no string to T/F boolean
00074 void
00075 TranslateYNtoTF(unsigned char *aRegValue, DWORD aRegValueLength,
00076                 DWORD aRegValueType,
00077                 nsIPrefBranch *prefs, char *aPrefKeyName) {
00078 
00079   PRInt32 prefIntValue = 0;
00080 
00081   // input type is a string, lowercase "yes" or "no"
00082   if (aRegValueType != REG_SZ)
00083     NS_WARNING("unexpected yes/no data type");
00084 
00085   if (aRegValueType == REG_SZ && aRegValue[0] != 0) {
00086     // strcmp is safe; it's bounded by its second parameter
00087     prefIntValue = strcmp(NS_REINTERPRET_CAST(char *, aRegValue), "yes") == 0;
00088     prefs->SetBoolPref(aPrefKeyName, prefIntValue);
00089   }
00090 }
00091 
00092 // yes/no string to F/T boolean
00093 void
00094 TranslateYNtoFT(unsigned char *aRegValue, DWORD aRegValueLength,
00095                 DWORD aRegValueType,
00096                 nsIPrefBranch *prefs, char *aPrefKeyName) {
00097 
00098   PRInt32 prefIntValue = 0;
00099 
00100   // input type is a string, lowercase "yes" or "no"
00101   if (aRegValueType != REG_SZ)
00102     NS_WARNING("unexpected yes/no data type");
00103 
00104   if (aRegValueType == REG_SZ && aRegValue[0] != 0) {
00105     // strcmp is safe; it's bounded by its second parameter
00106     prefIntValue = strcmp(NS_REINTERPRET_CAST(char *, aRegValue), "yes") != 0;
00107     prefs->SetBoolPref(aPrefKeyName, prefIntValue);
00108   }
00109 }
00110 
00111 // decimal RGB (1,2,3) to hex RGB (#010203)
00112 void
00113 TranslateDRGBtoHRGB(unsigned char *aRegValue, DWORD aRegValueLength,
00114                     DWORD aRegValueType,
00115                     nsIPrefBranch *prefs, char *aPrefKeyName) {
00116 
00117   // clear previous settings with defaults
00118   char prefStringValue[10];
00119 
00120   // input type is a string
00121   if (aRegValueType != REG_SZ)
00122     NS_WARNING("unexpected RGB data type");
00123 
00124   if (aRegValueType == REG_SZ && aRegValue[0] != 0) {
00125     int red, green, blue;
00126     ::sscanf(NS_REINTERPRET_CAST(char *, aRegValue), "%d,%d,%d",
00127              &red, &green, &blue);
00128     ::sprintf(prefStringValue, "#%02X%02X%02X", red, green, blue);
00129     prefs->SetCharPref(aPrefKeyName, prefStringValue);
00130   }
00131 }
00132 
00133 // translate a windows registry DWORD int to a mozilla prefs PRInt32
00134 void
00135 TranslateDWORDtoPRInt32(unsigned char *aRegValue, DWORD aRegValueLength,
00136                         DWORD aRegValueType,
00137                         nsIPrefBranch *prefs, char *aPrefKeyName) {
00138 
00139   // clear previous settings with defaults
00140   PRInt32 prefIntValue = 0;
00141 
00142   if (aRegValueType != REG_DWORD)
00143     NS_WARNING("unexpected signed int data type");
00144 
00145   if (aRegValueType == REG_DWORD) {
00146     prefIntValue = *(NS_REINTERPRET_CAST(DWORD *, aRegValue));
00147     prefs->SetIntPref(aPrefKeyName, prefIntValue);
00148   }
00149 }
00150 
00151 // string copy
00152 void
00153 TranslateString(unsigned char *aRegValue, DWORD aRegValueLength,
00154                 DWORD aRegValueType,
00155                 nsIPrefBranch *prefs, char *aPrefKeyName) {
00156 
00157   if (aRegValueType != REG_SZ)
00158     NS_WARNING("unexpected string data type");
00159 
00160   if (aRegValueType == REG_SZ)
00161     prefs->SetCharPref(aPrefKeyName,
00162                        NS_REINTERPRET_CAST(char *, aRegValue));
00163 }
00164 
00165 // translate homepage
00166 // (modified string copy)
00167 void
00168 TranslateHomepage(unsigned char *aRegValue, DWORD aRegValueLength,
00169                   DWORD aRegValueType,
00170                   nsIPrefBranch *prefs, char *aPrefKeyName) {
00171 
00172   if (aRegValueType != REG_SZ)
00173     NS_WARNING("unexpected string data type");
00174 
00175   if (aRegValueType == REG_SZ) {
00176     // strcmp is safe; it's bounded by its second parameter
00177     if (strcmp(NS_REINTERPRET_CAST(char *, aRegValue), "about:blank") == 0)
00178       prefs->SetIntPref("browser.startup.page", 0);
00179     else {
00180       prefs->SetIntPref("browser.startup.page", 1);
00181       prefs->SetCharPref(aPrefKeyName,
00182                         NS_REINTERPRET_CAST(char *, aRegValue));
00183     }
00184   }
00185 }
00186 
00187 // translate accepted language character set formats
00188 // (modified string copy)
00189 void
00190 TranslateLanglist(unsigned char *aRegValue, DWORD aRegValueLength,
00191                   DWORD aRegValueType,
00192                   nsIPrefBranch *prefs, char *aPrefKeyName) {
00193 
00194   char prefStringValue[MAX_PATH]; // a convenient size, one hopes
00195 
00196   if (aRegValueType != REG_SZ)
00197     NS_WARNING("unexpected string data type");
00198 
00199   if (aRegValueType != REG_SZ)
00200     return;
00201 
00202   // copy source format like "en-us,ar-kw;q=0.7,ar-om;q=0.3" into
00203   // destination format like "en-us, ar-kw, ar-om"
00204 
00205   char   *source = NS_REINTERPRET_CAST(char *, aRegValue),
00206          *dest = prefStringValue,
00207          *sourceEnd = source + aRegValueLength,
00208          *destEnd = dest + (MAX_PATH-2); // room for " \0"
00209   PRBool  skip = PR_FALSE,
00210           comma = PR_FALSE;
00211 
00212   while (source < sourceEnd && *source && dest < destEnd) {
00213     if (*source == ',')
00214       skip = PR_FALSE;
00215     else if (*source == ';')
00216       skip = PR_TRUE;
00217     if (!skip) {
00218       if (comma && *source != ' ')
00219         *dest++ = ' ';
00220       *dest = *source;
00221     }
00222     comma = *source == ',';
00223     ++source;
00224   }
00225   *dest = 0;
00226 
00227   prefs->SetCharPref(aPrefKeyName, prefStringValue);
00228 }
00229 
00230 static int CALLBACK
00231 fontEnumProc(const LOGFONT *aLogFont, const TEXTMETRIC *aMetric,
00232              DWORD aFontType, LPARAM aClosure) {
00233   *((int *) aClosure) = aLogFont->lfPitchAndFamily & FF_ROMAN;
00234   return 0;
00235 }
00236 void
00237 TranslatePropFont(unsigned char *aRegValue, DWORD aRegValueLength,
00238                   DWORD aRegValueType,
00239                   nsIPrefBranch *prefs, char *aPrefKeyName) {
00240 
00241   HDC     dc = ::GetDC(0);
00242   LOGFONT lf;
00243   int     isSerif = 1;
00244 
00245   // serif or sans-serif font?
00246   lf.lfCharSet = DEFAULT_CHARSET;
00247   lf.lfPitchAndFamily = 0;
00248   PL_strncpyz(lf.lfFaceName, NS_REINTERPRET_CAST(char *, aRegValue),
00249               LF_FACESIZE);
00250   ::EnumFontFamiliesEx(dc, &lf, fontEnumProc, (LPARAM) &isSerif, 0);
00251   ::ReleaseDC(0, dc);
00252 
00253   if (isSerif) {
00254     prefs->SetCharPref("font.name.serif.x-western",
00255                        NS_REINTERPRET_CAST(char *, aRegValue));
00256     prefs->SetCharPref("font.default.x-western", "serif");
00257   } else {
00258     prefs->SetCharPref("font.name.sans-serif.x-western",
00259                        NS_REINTERPRET_CAST(char *, aRegValue));
00260     prefs->SetCharPref("font.default.x-western", "sans-serif");
00261   }
00262 }
00263 
00264 //***********************************************************************
00265 //*** master table of registry-to-gecko-pref translations
00266 //***********************************************************************
00267 
00268 struct regEntry {
00269   char            *regKeyName,     // registry key (HKCU\Software ...)
00270                   *regValueName;   // registry key leaf
00271   char            *prefKeyName;    // pref name ("javascript.enabled" ...)
00272   regEntryHandler  entryHandler;   // processing func
00273 };
00274 struct regEntry gRegEntries[] = {
00275   { "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoComplete",
00276      "AutoSuggest",
00277      "browser.urlbar.autocomplete.enabled",
00278      TranslateYNtoTF },
00279   { "Software\\Microsoft\\Internet Explorer\\International",
00280     "AcceptLanguage",
00281     "intl.accept_languages",
00282     TranslateLanglist },
00283   { "Software\\Microsoft\\Internet Explorer\\International\\Scripts\\3",
00284     "IEFixedFontName",
00285     "font.name.monospace.x-western",
00286     TranslateString },
00287   { 0, // an optimization: 0 means use the previous key
00288     "IEPropFontName",
00289     "", // special-cased in the translation function
00290     TranslatePropFont },
00291   { "Software\\Microsoft\\Internet Explorer\\Main",
00292     "Use_DlgBox_Colors",
00293     "browser.display.use_system_colors",
00294     TranslateYNtoTF },
00295   { 0,
00296     "Use FormSuggest",
00297     "wallet.captureForms",
00298     TranslateYNtoTF },
00299   { 0,
00300     "FormSuggest Passwords",
00301     "signon.rememberSignons",
00302     TranslateYNtoTF },
00303   { 0,
00304     "Start Page",
00305     "browser.startup.homepage",
00306     TranslateHomepage },
00307   { "Software\\Microsoft\\Internet Explorer\\Settings",
00308     "Always Use My Colors",
00309     "browser.display.use_document_colors",
00310     TranslateYNtoFT },
00311   { 0,
00312     "Text Color",
00313     "browser.display.foreground_color",
00314     TranslateDRGBtoHRGB },
00315   { 0,
00316     "Background Color",
00317     "browser.display.background_color",
00318     TranslateDRGBtoHRGB },
00319   { 0,
00320     "Anchor Color",
00321     "browser.anchor_color",
00322     TranslateDRGBtoHRGB },
00323   { 0,
00324     "Anchor Color Visited",
00325     "browser.visited_color",
00326     TranslateDRGBtoHRGB },
00327   { 0,
00328     "Always Use My Font Face",
00329     "browser.display.use_document_fonts",
00330     TranslateYNtoFT },
00331   { "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Url History",
00332     "DaysToKeep",
00333     "browser.history_expire_days",
00334     TranslateDWORDtoPRInt32 }
00335 };
00336 
00337 #if 0
00338 user_pref("font.size.fixed.x-western", 14);
00339 user_pref("font.size.variable.x-western", 15);
00340 #endif
00341 
00342 //*****************************************************************************
00343 //*** factory
00344 //*****************************************************************************
00345 
00346 nsTridentPreferences *
00347 MakeTridentPreferences() {
00348   return new nsTridentPreferencesWin();
00349 }
00350 
00351 //*****************************************************************************
00352 //*** nsTridentPreferences
00353 //*****************************************************************************
00354 
00355 nsTridentPreferences::nsTridentPreferences() {
00356 }
00357 
00358 nsTridentPreferences::~nsTridentPreferences() {
00359 }
00360 
00361 //*****************************************************************************
00362 //*** nsTridentPreferencesWin
00363 //*****************************************************************************
00364 
00365 nsTridentPreferencesWin::nsTridentPreferencesWin() {
00366 }
00367 
00368 nsTridentPreferencesWin::~nsTridentPreferencesWin() {
00369 }
00370 
00371 // migration entry point
00372 nsresult
00373 nsTridentPreferencesWin::MigrateTridentPreferences(PRUint32 aItems) {
00374 
00375   nsresult rv = NS_OK;
00376 
00377   if (aItems & nsITridentProfileMigrator::PREFERENCES)
00378     rv = CopyPreferences();
00379   if (NS_SUCCEEDED(rv) && (aItems & nsITridentProfileMigrator::COOKIES))
00380     rv = CopyCookies();
00381 
00382   return rv;
00383 }
00384 
00385 nsresult
00386 nsTridentPreferencesWin::CopyPreferences() {
00387 
00388   HKEY            regKey;
00389   PRBool          regKeyOpen = PR_FALSE;
00390   struct regEntry *entry,
00391                   *endEntry = gRegEntries +
00392                               sizeof(gRegEntries)/sizeof(struct regEntry);
00393   DWORD           regType;
00394   DWORD           regLength;
00395   unsigned char   regValue[MAX_PATH];  // a convenient size
00396 
00397   nsCOMPtr<nsIPrefBranch> prefs;
00398 
00399   { // scope pserve why not
00400     nsCOMPtr<nsIPrefService> pserve(do_GetService(NS_PREFSERVICE_CONTRACTID));
00401     if (pserve)
00402       pserve->GetBranch("", getter_AddRefs(prefs));
00403   }
00404   if (!prefs)
00405     return NS_ERROR_FAILURE;
00406 
00407   // step through gRegEntries table
00408   
00409   for (entry = gRegEntries; entry < endEntry; ++entry) {
00410 
00411     // a new keyname? close any previous one and open the new one
00412     if (entry->regKeyName) {
00413       if (regKeyOpen) {
00414         ::RegCloseKey(regKey);
00415         regKeyOpen = PR_FALSE;
00416       }
00417       regKeyOpen = ::RegOpenKeyEx(HKEY_CURRENT_USER, entry->regKeyName, 0,
00418                                   KEY_READ, &regKey) == ERROR_SUCCESS;
00419     }
00420 
00421     if (regKeyOpen) {
00422       // read registry data
00423       regLength = MAX_PATH;
00424       if (::RegQueryValueEx(regKey, entry->regValueName, 0,
00425           &regType, regValue, &regLength) == ERROR_SUCCESS)
00426 
00427         entry->entryHandler(regValue, regLength, regType,
00428                             prefs, entry->prefKeyName);
00429     }
00430   }
00431 
00432   if (regKeyOpen)
00433     ::RegCloseKey(regKey);
00434 
00435   return CopyStyleSheet();
00436 }
00437 
00438 /* Fetch and translate the current user's cookies.
00439    Return true if successful. */
00440 nsresult
00441 nsTridentPreferencesWin::CopyCookies() {
00442 
00443   // IE cookies are stored in files named <username>@domain[n].txt
00444   // (in <username>'s Cookies folder. isn't the naming redundant?)
00445 
00446   PRBool rv = NS_OK;
00447 
00448   nsCOMPtr<nsIFile> cookiesDir;
00449   nsCOMPtr<nsISimpleEnumerator> cookieFiles;
00450 
00451   nsCOMPtr<nsICookieManager2> cookieManager(do_GetService(NS_COOKIEMANAGER_CONTRACTID));
00452   if (!cookieManager)
00453     return NS_ERROR_FAILURE;
00454 
00455   // find the cookies directory
00456   NS_GetSpecialDirectory(NS_WIN_COOKIES_DIR, getter_AddRefs(cookiesDir));
00457   if (cookiesDir)
00458     cookiesDir->GetDirectoryEntries(getter_AddRefs(cookieFiles));
00459   if (!cookieFiles)
00460     return NS_ERROR_FAILURE;
00461 
00462   // fetch the current user's name from the environment
00463   char username[sUsernameLengthLimit+2];
00464   ::GetEnvironmentVariable("USERNAME", username, sizeof(username));
00465   username[sizeof(username)-2] = '\0';
00466   PL_strcat(username, "@");
00467   int usernameLength = PL_strlen(username);
00468 
00469   // allocate a buffer into which to read each cookie file
00470   char *fileContents = (char *) PR_Malloc(sInitialCookieBufferSize);
00471   if (!fileContents)
00472     return NS_ERROR_OUT_OF_MEMORY;
00473   PRUint32 fileContentsSize = sInitialCookieBufferSize;
00474 
00475   do { // for each file in the cookies directory
00476     // get the next file
00477     PRBool moreFiles = PR_FALSE;
00478     if (NS_FAILED(cookieFiles->HasMoreElements(&moreFiles)) || !moreFiles)
00479       break;
00480 
00481     nsCOMPtr<nsISupports> supFile;
00482     cookieFiles->GetNext(getter_AddRefs(supFile));
00483     nsCOMPtr<nsIFile> cookieFile(do_QueryInterface(supFile));
00484     if (!cookieFile) {
00485       rv = NS_ERROR_FAILURE;
00486       break; // unexpected! punt!
00487     }
00488 
00489     // is it a cookie file for the current user?
00490     nsCAutoString fileName;
00491     cookieFile->GetNativeLeafName(fileName);
00492     const nsACString &fileOwner = Substring(fileName, 0, usernameLength);
00493     if (!fileOwner.Equals(username, nsCaseInsensitiveCStringComparator()))
00494       continue;
00495 
00496     // ensure the contents buffer is large enough to hold the entire file
00497     // plus one byte (see DelimitField())
00498     PRInt64 llFileSize;
00499     if (NS_FAILED(cookieFile->GetFileSize(&llFileSize)))
00500       continue;
00501 
00502     PRUint32 fileSize, readSize;
00503     LL_L2UI(fileSize, llFileSize);
00504     if (fileSize >= fileContentsSize) {
00505       PR_Free(fileContents);
00506       fileContents = (char *) PR_Malloc(fileSize+1);
00507       if (!fileContents) {
00508         rv = NS_ERROR_FAILURE;
00509         break; // fatal error
00510       }
00511       fileContentsSize = fileSize;
00512     }
00513 
00514     // read the entire cookie file
00515     PRFileDesc *fd;
00516     nsCOMPtr<nsILocalFile> localCookieFile(do_QueryInterface(cookieFile));
00517     if (localCookieFile &&
00518         NS_SUCCEEDED(localCookieFile->OpenNSPRFileDesc(PR_RDONLY, 0444, &fd))) {
00519 
00520       readSize = PR_Read(fd, fileContents, fileSize);
00521       PR_Close(fd);
00522 
00523       if (fileSize == readSize) { // translate this file's cookies
00524         nsresult onerv;
00525         onerv = CopyCookiesFromBuffer(fileContents, readSize, cookieManager);
00526         if (NS_FAILED(onerv))
00527           rv = onerv;
00528       }
00529     }
00530   } while(1);
00531 
00532   if (fileContents)
00533     PR_Free(fileContents);
00534   return rv;
00535 }
00536 
00537 /* Fetch cookies from a single IE cookie file.
00538    Return true if successful. */
00539 nsresult
00540 nsTridentPreferencesWin::CopyCookiesFromBuffer(
00541                            char *aBuffer,
00542                            PRUint32 aBufferLength,
00543                            nsICookieManager2 *aCookieManager) {
00544 
00545   nsresult  rv = NS_OK;
00546 
00547   const char *bufferEnd = aBuffer + aBufferLength;
00548   // cookie fields:
00549   char    *name,
00550           *value,
00551           *host,
00552           *path,
00553           *flags,
00554           *expirationDate1, *expirationDate2,
00555           *creationDate1, *creationDate2,
00556           *terminator;
00557   int      flagsValue;
00558   time_t   expirationDate,
00559            creationDate;
00560   char     hostCopy[sHostnameLengthLimit+1],
00561           *hostCopyConstructor,
00562           *hostCopyEnd = hostCopy + sHostnameLengthLimit;
00563 
00564   do { // for each cookie in the buffer
00565     DelimitField(&aBuffer, bufferEnd, &name);
00566     DelimitField(&aBuffer, bufferEnd, &value);
00567     DelimitField(&aBuffer, bufferEnd, &host);
00568     DelimitField(&aBuffer, bufferEnd, &flags);
00569     DelimitField(&aBuffer, bufferEnd, &expirationDate1);
00570     DelimitField(&aBuffer, bufferEnd, &expirationDate2);
00571     DelimitField(&aBuffer, bufferEnd, &creationDate1);
00572     DelimitField(&aBuffer, bufferEnd, &creationDate2);
00573     DelimitField(&aBuffer, bufferEnd, &terminator);
00574 
00575     // it's a cookie if we got one of each
00576     if (terminator >= bufferEnd)
00577       break;
00578 
00579     // IE stores deleted cookies with a zero-length value
00580     if (*value == '\0')
00581       continue;
00582 
00583     // convert flags to an int, date numbers to useable dates
00584     ::sscanf(flags, "%d", &flagsValue);
00585     expirationDate = FileTimeToTimeT(expirationDate1, expirationDate2);
00586     creationDate = FileTimeToTimeT(creationDate1, creationDate2);
00587 
00588     // munge host, and separate host from path
00589 
00590     hostCopyConstructor = hostCopy;
00591 
00592     // first, with a non-null domain, assume it's what Mozilla considers
00593     // a domain cookie. see bug 222343.
00594     if (*host && *host != '.' && *host != '/')
00595       *hostCopyConstructor++ = '.';
00596 
00597     // copy the host part and leave path pointing to the path part
00598     for (path = host; *path && *path != '/'; ++path)
00599       ;
00600     int hostLength = path - host;
00601     if (hostLength > hostCopyEnd - hostCopyConstructor)
00602       hostLength = hostCopyEnd - hostCopyConstructor;
00603     PL_strncpy(hostCopyConstructor, host, hostLength);
00604     hostCopyConstructor += hostLength;
00605 
00606     *hostCopyConstructor = '\0';
00607 
00608     nsDependentCString stringName(name),
00609                        stringPath(path);
00610 
00611     // delete any possible extant matching host cookie
00612     if (hostCopy[0] == '.')
00613       aCookieManager->Remove(nsDependentCString(hostCopy+1),
00614                              stringName, stringPath, PR_FALSE);
00615 
00616     nsresult onerv;
00617     // Add() makes a new domain cookie
00618     onerv = aCookieManager->Add(nsDependentCString(hostCopy),
00619                                 stringPath,
00620                                 stringName,
00621                                 nsDependentCString(value),
00622                                 flagsValue & 0x1,
00623                                 PR_FALSE,
00624                                 PRInt64(expirationDate));
00625     if (NS_FAILED(onerv)) {
00626       rv = onerv;
00627       break;
00628     }
00629 
00630   } while(aBuffer < bufferEnd);
00631 
00632   return rv;
00633 }
00634 
00635 /* Delimit the next field in the IE cookie buffer.
00636    when called:
00637     aBuffer: at the beginning of the next field or preceding whitespace
00638     aBufferEnd: one past the last valid character in the buffer
00639    on return:
00640     aField: at the beginning of the next field, which is null delimited
00641     aBuffer: after the null at the end of the field
00642 
00643    the character at which aBufferEnd points must be part of the buffer
00644    so we can set it to \0.
00645 */
00646 void
00647 nsTridentPreferencesWin::DelimitField(char **aBuffer,
00648                                       const char *aBufferEnd,
00649                                       char **aField) {
00650 
00651   char *scan = *aBuffer;
00652   *aField = scan;
00653   while (scan < aBufferEnd && (*scan != '\r' && *scan != '\n'))
00654     ++scan;
00655   if (scan+1 < aBufferEnd && (*(scan+1) == '\r' || *(scan+1) == '\n') &&
00656                              *scan != *(scan+1)) {
00657     *scan = '\0';
00658     scan += 2;
00659   } else {
00660     if (scan <= aBufferEnd) // (1 byte past bufferEnd is guaranteed allocated)
00661       *scan = '\0';
00662     ++scan;
00663   }
00664   *aBuffer = scan;
00665 }
00666 
00667 // conversion routine. returns 0 (epoch date) if the input is out of range
00668 time_t
00669 nsTridentPreferencesWin::FileTimeToTimeT(const char *aLowDateIntString,
00670                                          const char *aHighDateIntString) {
00671 
00672   FILETIME   fileTime;
00673   SYSTEMTIME systemTime;
00674   tm         tTime;
00675   time_t     rv;
00676 
00677   ::sscanf(aLowDateIntString, "%ld", &fileTime.dwLowDateTime);
00678   ::sscanf(aHighDateIntString, "%ld", &fileTime.dwHighDateTime);
00679   ::FileTimeToSystemTime(&fileTime, &systemTime);
00680   tTime.tm_year = systemTime.wYear - 1900;
00681   tTime.tm_mon = systemTime.wMonth-1;
00682   tTime.tm_mday = systemTime.wDay;
00683   tTime.tm_hour = systemTime.wHour;
00684   tTime.tm_min = systemTime.wMinute;
00685   tTime.tm_sec = systemTime.wSecond;
00686   tTime.tm_isdst = -1;
00687   rv = ::mktime(&tTime);
00688   return rv < 0 ? 0 : rv;
00689 }
00690 
00691 /* Find the accessibility stylesheet if it exists and replace Mozilla's
00692    with it. Return true if we found and copied a stylesheet. */
00693 nsresult
00694 nsTridentPreferencesWin::CopyStyleSheet() {
00695 
00696   nsresult rv = NS_OK; // return failure only if filecopy fails
00697   HKEY     regKey;
00698   DWORD    regType,
00699            regLength,
00700            regDWordValue;
00701   char     tridentFilename[MAX_PATH];
00702 
00703   // is there a trident user stylesheet?
00704   if (::RegOpenKeyEx(HKEY_CURRENT_USER,
00705                  "Software\\Microsoft\\Internet Explorer\\Styles", 0,
00706                  KEY_READ, &regKey) != ERROR_SUCCESS)
00707     return NS_OK;
00708   
00709   regLength = sizeof(DWORD);
00710   if (::RegQueryValueEx(regKey, "Use My Stylesheet", 0, &regType,
00711                         NS_REINTERPRET_CAST(unsigned char *, &regDWordValue),
00712                         &regLength) == ERROR_SUCCESS &&
00713       regType == REG_DWORD && regDWordValue == 1) {
00714 
00715     regLength = MAX_PATH;
00716     if (::RegQueryValueEx(regKey, "User Stylesheet", 0, &regType,
00717                           NS_REINTERPRET_CAST(unsigned char *, tridentFilename),
00718                           &regLength)
00719         == ERROR_SUCCESS) {
00720 
00721       // tridentFilename is a native path to the specified stylesheet file
00722       // point an nsIFile at it
00723       nsCOMPtr<nsILocalFile> tridentFile(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
00724       if (tridentFile) {
00725         PRBool exists;
00726 
00727         tridentFile->InitWithNativePath(nsDependentCString(tridentFilename));
00728         tridentFile->Exists(&exists);
00729         if (exists) {
00730           // now establish our file (userContent.css in the profile/chrome dir)
00731           nsCOMPtr<nsIFile> chromeDir;
00732           NS_GetSpecialDirectory(NS_APP_USER_CHROME_DIR,
00733                                  getter_AddRefs(chromeDir));
00734           if (chromeDir)
00735             rv = tridentFile->CopyToNative(chromeDir,
00736                               nsDependentCString("userContent.css"));
00737         }
00738       }
00739     }
00740   }
00741   ::RegCloseKey(regKey);
00742   return rv;
00743 }
00744 
00745 void
00746 nsTridentPreferencesWin::GetUserStyleSheetFile(nsIFile **aUserFile) {
00747 
00748   nsCOMPtr<nsIFile> userChrome;
00749 
00750   *aUserFile = 0;
00751 
00752   // establish the chrome directory
00753   NS_GetSpecialDirectory(NS_APP_USER_CHROME_DIR, getter_AddRefs(userChrome));
00754 
00755   if (userChrome) {
00756     PRBool exists;
00757     userChrome->Exists(&exists);
00758     if (!exists &&
00759         NS_FAILED(userChrome->Create(nsIFile::DIRECTORY_TYPE, 0755)))
00760       return;
00761 
00762     // establish the user content stylesheet file
00763     userChrome->AppendNative(NS_LITERAL_CSTRING("userContent.css"));
00764     *aUserFile = userChrome;
00765     NS_ADDREF(*aUserFile);
00766   }
00767 }
00768