Back to index

lightning-sunbird  0.9+nobinonly
nsChromeRegistry.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; 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) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Original Author: David W. Hyatt (hyatt@netscape.com)
00024  *   Gagan Saksena <gagan@netscape.com>
00025  *   Benjamin Smedberg <bsmedberg@covad.net>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 #include <string.h>
00042 #include "nsArrayEnumerator.h"
00043 #include "nsCOMPtr.h"
00044 #include "nsIChromeRegistry.h"
00045 #include "nsChromeRegistry.h"
00046 #include "nsChromeUIDataSource.h"
00047 #include "nsIRDFDataSource.h"
00048 #include "nsIRDFObserver.h"
00049 #include "nsIRDFRemoteDataSource.h"
00050 #include "nsIRDFXMLSink.h"
00051 #include "rdf.h"
00052 #include "nsIServiceManager.h"
00053 #include "nsIRDFService.h"
00054 #include "nsRDFCID.h"
00055 #include "nsIRDFResource.h"
00056 #include "nsIRDFDataSource.h"
00057 #include "nsIRDFContainer.h"
00058 #include "nsIRDFContainerUtils.h"
00059 #include "nsHashtable.h"
00060 #include "nsString.h"
00061 #include "nsReadableUtils.h"
00062 #include "nsXPIDLString.h"
00063 #include "nsISimpleEnumerator.h"
00064 #include "nsNetUtil.h"
00065 #include "nsIFileChannel.h"
00066 #include "nsIXBLService.h"
00067 #include "nsIDOMWindowInternal.h"
00068 #include "nsIDOMWindowCollection.h"
00069 #include "nsIDOMLocation.h"
00070 #include "nsIWindowMediator.h"
00071 #include "nsIDocument.h"
00072 #include "nsIDOMDocument.h"
00073 #include "nsIStyleSheet.h"
00074 #include "nsICSSLoader.h"
00075 #include "nsICSSStyleSheet.h"
00076 #include "nsIPresShell.h"
00077 #include "nsIDocShell.h"
00078 #include "nsISupportsArray.h"
00079 #include "nsIDocumentObserver.h"
00080 #include "nsIIOService.h"
00081 #include "nsLayoutCID.h"
00082 #include "nsIBindingManager.h"
00083 #include "prio.h"
00084 #include "nsInt64.h"
00085 #include "nsEscape.h"
00086 #include "nsIDirectoryService.h"
00087 #include "nsILocalFile.h"
00088 #include "nsAppDirectoryServiceDefs.h"
00089 #include "nsIPrefBranch.h"
00090 #include "nsIPrefService.h"
00091 #include "nsIObserverService.h"
00092 #include "nsIDOMElement.h"
00093 #include "nsIDOMWindowCollection.h"
00094 #include "nsIAtom.h"
00095 #include "nsStaticAtom.h"
00096 #include "nsNetCID.h"
00097 #include "nsIJARURI.h"
00098 #include "nsIFileURL.h"
00099 #include "nsIXPConnect.h"
00100 
00101 static char kChromePrefix[] = "chrome://";
00102 nsIAtom* nsChromeRegistry::sCPrefix; // atom for "c"
00103 
00104 #define kChromeFileName           NS_LITERAL_CSTRING("chrome.rdf")
00105 #define kInstalledChromeFileName  NS_LITERAL_CSTRING("installed-chrome.txt")
00106 
00107 static NS_DEFINE_CID(kWindowMediatorCID, NS_WINDOWMEDIATOR_CID);
00108 static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
00109 static NS_DEFINE_CID(kRDFXMLDataSourceCID, NS_RDFXMLDATASOURCE_CID);
00110 static NS_DEFINE_CID(kRDFContainerUtilsCID,      NS_RDFCONTAINERUTILS_CID);
00111 static NS_DEFINE_CID(kCSSLoaderCID, NS_CSS_LOADER_CID);
00112 
00113 class nsChromeRegistry;
00114 
00115 nsIChromeRegistry* gChromeRegistry = nsnull;
00116 
00117 #define CHROME_URI "http://www.mozilla.org/rdf/chrome#"
00118 
00119 DEFINE_RDF_VOCAB(CHROME_URI, CHROME, selectedSkin);
00120 DEFINE_RDF_VOCAB(CHROME_URI, CHROME, selectedLocale);
00121 DEFINE_RDF_VOCAB(CHROME_URI, CHROME, baseURL);
00122 DEFINE_RDF_VOCAB(CHROME_URI, CHROME, packages);
00123 DEFINE_RDF_VOCAB(CHROME_URI, CHROME, package);
00124 DEFINE_RDF_VOCAB(CHROME_URI, CHROME, name);
00125 DEFINE_RDF_VOCAB(CHROME_URI, CHROME, image);
00126 DEFINE_RDF_VOCAB(CHROME_URI, CHROME, locType);
00127 DEFINE_RDF_VOCAB(CHROME_URI, CHROME, allowScripts);
00128 DEFINE_RDF_VOCAB(CHROME_URI, CHROME, hasOverlays);
00129 DEFINE_RDF_VOCAB(CHROME_URI, CHROME, hasStylesheets);
00130 DEFINE_RDF_VOCAB(CHROME_URI, CHROME, skinVersion);
00131 DEFINE_RDF_VOCAB(CHROME_URI, CHROME, localeVersion);
00132 DEFINE_RDF_VOCAB(CHROME_URI, CHROME, packageVersion);
00133 DEFINE_RDF_VOCAB(CHROME_URI, CHROME, disabled);
00134 DEFINE_RDF_VOCAB(CHROME_URI, CHROME, xpcNativeWrappers);
00135 
00137 
00138 nsChromeRegistry::nsChromeRegistry() : mRDFService(nsnull),
00139                                        mRDFContainerUtils(nsnull),
00140                                        mInstallInitialized(PR_FALSE),
00141                                        mProfileInitialized(PR_FALSE),
00142                                        mRuntimeProvider(PR_FALSE),
00143                                        mBatchInstallFlushes(PR_FALSE),
00144                                        mSearchedForOverride(PR_FALSE),
00145                                        mLegacyOverlayinfo(PR_FALSE)
00146 {
00147   mDataSourceTable = nsnull;
00148 }
00149 
00150 
00151 static PRBool PR_CALLBACK
00152 DatasourceEnumerator(nsHashKey *aKey, void *aData, void* closure)
00153 {
00154   if (!closure || !aData)
00155     return PR_FALSE;
00156 
00157   nsIRDFCompositeDataSource* compositeDS = (nsIRDFCompositeDataSource*) closure;
00158 
00159   nsCOMPtr<nsISupports> supports = (nsISupports*)aData;
00160 
00161   nsCOMPtr<nsIRDFDataSource> dataSource = do_QueryInterface(supports);
00162   if (!dataSource)
00163     return PR_FALSE;
00164 
00165 #ifdef DEBUG
00166   nsresult rv =
00167 #endif
00168   compositeDS->RemoveDataSource(dataSource);
00169   NS_ASSERTION(NS_SUCCEEDED(rv), "failed to RemoveDataSource");
00170   return PR_TRUE;
00171 }
00172 
00173 
00174 nsChromeRegistry::~nsChromeRegistry()
00175 {
00176   gChromeRegistry = nsnull;
00177   
00178   if (mDataSourceTable) {
00179       mDataSourceTable->Enumerate(DatasourceEnumerator, mChromeDataSource);
00180       delete mDataSourceTable;
00181   }
00182 
00183   NS_IF_RELEASE(mRDFService);
00184   NS_IF_RELEASE(mRDFContainerUtils);
00185 
00186 }
00187 
00188 NS_IMPL_THREADSAFE_ISUPPORTS6(nsChromeRegistry,
00189                               nsIChromeRegistry,
00190                               nsIXULChromeRegistry,
00191                               nsIChromeRegistrySea,
00192                               nsIXULOverlayProvider,
00193                               nsIObserver,
00194                               nsISupportsWeakReference)
00195 
00196 
00197 // nsIChromeRegistry methods:
00198 
00199 nsresult
00200 nsChromeRegistry::Init()
00201 {
00202   // these atoms appear in almost every chrome registry manifest.rdf
00203   // in some form or another. making static atoms prevents the atoms
00204   // from constantly being created/destroyed during parsing
00205   
00206   static const nsStaticAtom atoms[] = {
00207     { "c",             &sCPrefix },
00208     { "chrome",        nsnull },
00209     { "NC",            nsnull },
00210     { "baseURL",       nsnull},
00211     { "allowScripts",  nsnull },
00212     { "skinVersion",   nsnull },
00213     { "package",       nsnull },
00214     { "packages",      nsnull },
00215     { "locType",       nsnull },
00216     { "displayName",   nsnull },
00217     { "author",        nsnull },
00218     { "localeVersion", nsnull },
00219     { "localeType",    nsnull },
00220     { "selectedLocale", nsnull },
00221     { "selectedSkin",  nsnull },
00222     { "hasOverlays",   nsnull },
00223     { "xpcNativeWrappers", nsnull },
00224     { "previewURL", nsnull },
00225   };
00226 
00227   NS_RegisterStaticAtoms(atoms, NS_ARRAY_LENGTH(atoms));
00228   
00229   gChromeRegistry = this;
00230   
00231   nsresult rv;
00232   rv = CallGetService(kRDFServiceCID, &mRDFService);
00233   NS_ENSURE_SUCCESS(rv, rv);
00234 
00235   rv = CallGetService(kRDFContainerUtilsCID, &mRDFContainerUtils);
00236   NS_ENSURE_SUCCESS(rv, rv);
00237 
00238   rv = mRDFService->GetResource(nsDependentCString(kURICHROME_selectedSkin),
00239                                 getter_AddRefs(mSelectedSkin));
00240   NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF resource");
00241 
00242   rv = mRDFService->GetResource(nsDependentCString(kURICHROME_selectedLocale),
00243                                 getter_AddRefs(mSelectedLocale));
00244   NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF resource");
00245 
00246   rv = mRDFService->GetResource(nsDependentCString(kURICHROME_baseURL),
00247                                 getter_AddRefs(mBaseURL));
00248   NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF resource");
00249 
00250   rv = mRDFService->GetResource(nsDependentCString(kURICHROME_packages),
00251                                 getter_AddRefs(mPackages));
00252   NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF resource");
00253 
00254   rv = mRDFService->GetResource(nsDependentCString(kURICHROME_package),
00255                                 getter_AddRefs(mPackage));
00256   NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF resource");
00257 
00258   rv = mRDFService->GetResource(nsDependentCString(kURICHROME_name),
00259                                 getter_AddRefs(mName));
00260   NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF resource");
00261 
00262   rv = mRDFService->GetResource(nsDependentCString(kURICHROME_image),
00263                                 getter_AddRefs(mImage));
00264   NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF resource");
00265 
00266   rv = mRDFService->GetResource(nsDependentCString(kURICHROME_locType),
00267                                 getter_AddRefs(mLocType));
00268   NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF resource");
00269 
00270   rv = mRDFService->GetResource(nsDependentCString(kURICHROME_allowScripts),
00271                                 getter_AddRefs(mAllowScripts));
00272   NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF resource");
00273 
00274   rv = mRDFService->GetResource(nsDependentCString(kURICHROME_hasOverlays),
00275                                 getter_AddRefs(mHasOverlays));
00276   NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF resource");
00277 
00278   rv = mRDFService->GetResource(nsDependentCString(kURICHROME_hasStylesheets),
00279                                 getter_AddRefs(mHasStylesheets));
00280   NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF resource");
00281 
00282   rv = mRDFService->GetResource(nsDependentCString(kURICHROME_skinVersion),
00283                                 getter_AddRefs(mSkinVersion));
00284   NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF resource");
00285 
00286   rv = mRDFService->GetResource(nsDependentCString(kURICHROME_localeVersion),
00287                                 getter_AddRefs(mLocaleVersion));
00288   NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF resource");
00289 
00290   rv = mRDFService->GetResource(nsDependentCString(kURICHROME_packageVersion),
00291                                 getter_AddRefs(mPackageVersion));
00292   NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF resource");
00293 
00294   rv = mRDFService->GetResource(nsDependentCString(kURICHROME_disabled),
00295                                 getter_AddRefs(mDisabled));
00296   NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF resource");
00297 
00298   rv = mRDFService->GetResource(nsDependentCString(kURICHROME_xpcNativeWrappers),
00299                                 getter_AddRefs(mXPCNativeWrappers));
00300   NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF resource");
00301 
00302   nsCOMPtr<nsIObserverService> observerService =
00303            do_GetService("@mozilla.org/observer-service;1", &rv);
00304   if (observerService) {
00305     observerService->AddObserver(this, "profile-before-change", PR_TRUE);
00306     observerService->AddObserver(this, "profile-after-change", PR_TRUE);
00307   }
00308 
00309   CheckForNewChrome();
00310   // CheckForNewChrome suppresses these during chrome registration
00311   FlagXPCNativeWrappers();
00312 
00313   return NS_OK;
00314 }
00315 
00316 
00317 static nsresult
00318 SplitURL(nsIURI *aChromeURI, nsCString& aPackage, nsCString& aProvider, nsCString& aFile,
00319          PRBool *aModified = nsnull)
00320 {
00321   // Splits a "chrome:" URL into its package, provider, and file parts.
00322   // Here are the current portions of a
00323   // chrome: url that make up the chrome-
00324   //
00325   //     chrome://global/skin/foo?bar
00326   //     \------/ \----/\---/ \-----/
00327   //         |       |     |     |
00328   //         |       |     |     `-- RemainingPortion
00329   //         |       |     |
00330   //         |       |     `-- Provider
00331   //         |       |
00332   //         |       `-- Package
00333   //         |
00334   //         `-- Always "chrome://"
00335   //
00336   //
00337 
00338   nsresult rv;
00339 
00340   nsCAutoString str;
00341   rv = aChromeURI->GetSpec(str);
00342   if (NS_FAILED(rv)) return rv;
00343 
00344   // We only want to deal with "chrome:" URLs here. We could return
00345   // an error code if the URL isn't properly prefixed here...
00346   if (PL_strncmp(str.get(), kChromePrefix, sizeof(kChromePrefix) - 1) != 0)
00347     return NS_ERROR_INVALID_ARG;
00348 
00349   // Cull out the "package" string; e.g., "navigator"
00350   aPackage = str.get() + sizeof(kChromePrefix) - 1;
00351 
00352   PRInt32 idx;
00353   idx = aPackage.FindChar('/');
00354   if (idx < 0)
00355     return NS_OK;
00356 
00357   // Cull out the "provider" string; e.g., "content"
00358   aPackage.Right(aProvider, aPackage.Length() - (idx + 1));
00359   aPackage.Truncate(idx);
00360 
00361   idx = aProvider.FindChar('/');
00362   if (idx < 0) {
00363     // Force the provider to end with a '/'
00364     idx = aProvider.Length();
00365     aProvider.Append('/');
00366   }
00367 
00368   // Cull out the "file"; e.g., "navigator.xul"
00369   aProvider.Right(aFile, aProvider.Length() - (idx + 1));
00370   aProvider.Truncate(idx);
00371 
00372   PRBool nofile = aFile.IsEmpty();
00373   if (nofile) {
00374     // If there is no file, then construct the default file
00375     aFile = aPackage;
00376 
00377     if (aProvider.Equals("content")) {
00378       aFile += ".xul";
00379     }
00380     else if (aProvider.Equals("skin")) {
00381       aFile += ".css";
00382     }
00383     else if (aProvider.Equals("locale")) {
00384       aFile += ".dtd";
00385     }
00386     else {
00387       NS_ERROR("unknown provider");
00388       return NS_ERROR_FAILURE;
00389     }
00390   } else {
00391     // Protect against URIs containing .. that reach up out of the
00392     // chrome directory to grant chrome privileges to non-chrome files.
00393     // XXX: If we find %-escaped dot or % in a chrome URI we assume
00394     // someone is trying to trick us.
00395     const char* pos = aFile.BeginReading();
00396     const char* end = aFile.EndReading();
00397     while (pos < end) {
00398       switch (*pos) {
00399         case ':':
00400           return NS_ERROR_FAILURE;
00401         case '.':
00402           if (pos[1] == '.')
00403             return NS_ERROR_FAILURE;
00404           break;
00405         case '%':
00406           // chrome: URIs with escaped dots are trying to trick us.
00407           // Double-escapes (%25) doubly so
00408           if (pos[1] == '2' &&
00409                ( pos[2] == 'e' || pos[2] == 'E' ||
00410                  pos[2] == '5' ))
00411             return NS_ERROR_FAILURE;
00412           break;
00413         case '?':
00414         case '#':
00415           // leave any query or ref section alone
00416           pos = end;
00417           continue;
00418       }
00419       ++pos;
00420     }
00421   }
00422   if (aModified)
00423     *aModified = nofile;
00424   return NS_OK;
00425 }
00426 
00427 static nsresult
00428 GetBaseURLFile(const nsACString& aBaseURL, nsIFile** aFile)
00429 {
00430   NS_ENSURE_ARG_POINTER(aFile);
00431   *aFile = nsnull;
00432 
00433   nsresult rv;
00434   nsCOMPtr<nsIIOService> ioServ(do_GetService(NS_IOSERVICE_CONTRACTID, &rv));
00435   if (NS_FAILED(rv)) return rv;
00436 
00437   nsCOMPtr<nsIURI> uri;
00438   rv = ioServ->NewURI(aBaseURL, nsnull, nsnull, getter_AddRefs(uri));
00439   if (NS_FAILED(rv)) return rv;
00440 
00441   // Loop, jar: URIs can nest (e.g. jar:jar:A.jar!B.jar!C.xml).
00442   // Often, however, we have jar:resource:/chrome/A.jar!C.xml.
00443   nsCOMPtr<nsIJARURI> jarURI;
00444   while ((jarURI = do_QueryInterface(uri)) != nsnull)
00445     jarURI->GetJARFile(getter_AddRefs(uri));
00446 
00447   // Here we must have a URL of the form resource:/chrome/A.jar
00448   // or file:/some/path/to/A.jar.
00449   nsCOMPtr<nsIFileURL> fileURL(do_QueryInterface(uri));
00450   if (fileURL) {
00451     nsCOMPtr<nsIFile> file;
00452     fileURL->GetFile(getter_AddRefs(file));
00453     if (file) {
00454       NS_ADDREF(*aFile = file);
00455       return NS_OK;
00456     }
00457   }
00458   NS_ERROR("GetBaseURLFile() failed. Remote chrome?");
00459   return NS_ERROR_FAILURE;
00460 }
00461 
00462 nsresult
00463 nsChromeRegistry::Canonify(nsIURI* aChromeURI)
00464 {
00465   // Canonicalize 'chrome:' URLs. We'll take any 'chrome:' URL
00466   // without a filename, and change it to a URL -with- a filename;
00467   // e.g., "chrome://navigator/content" to
00468   // "chrome://navigator/content/navigator.xul".
00469   if (! aChromeURI)
00470       return NS_ERROR_NULL_POINTER;
00471 
00472   PRBool modified = PR_TRUE; // default is we do canonification
00473   nsCAutoString package, provider, file;
00474   nsresult rv;
00475   rv = SplitURL(aChromeURI, package, provider, file, &modified);
00476   if (NS_FAILED(rv))
00477     return rv;
00478 
00479   if (!modified)
00480     return NS_OK;
00481 
00482   nsCAutoString canonical( kChromePrefix );
00483   canonical += package;
00484   canonical += "/";
00485   canonical += provider;
00486   canonical += "/";
00487   canonical += file;
00488 
00489   return aChromeURI->SetSpec(canonical);
00490 }
00491 
00492 NS_IMETHODIMP
00493 nsChromeRegistry::ConvertChromeURL(nsIURI* aChromeURL, nsIURI* *aResult)
00494 {
00495   nsresult rv = NS_OK;
00496   NS_ENSURE_ARG_POINTER(aChromeURL);
00497 
00498   // No need to canonify as the SplitURL() that we
00499   // do is the equivalent of canonification without modifying
00500   // aChromeURL
00501 
00502   // Obtain the package, provider and remaining from the URL
00503   nsCAutoString package, provider, remaining;
00504 
00505   rv = SplitURL(aChromeURL, package, provider, remaining);
00506   if (NS_FAILED(rv)) return rv;
00507 
00508   // Try for the profile data source first because it
00509   // will load the install data source as well.
00510   if (!mProfileInitialized) {
00511     rv = LoadProfileDataSource();
00512     if (NS_FAILED(rv)) return rv;
00513   }
00514   if (!mInstallInitialized) {
00515     rv = LoadInstallDataSource();
00516     if (NS_FAILED(rv)) return rv;
00517   }
00518 
00519   nsCAutoString finalURL;
00520 
00521   rv = GetOverrideURL(package, provider, remaining, finalURL);
00522   if (NS_SUCCEEDED(rv))
00523     return NS_OK;
00524   
00525   rv = GetBaseURL(package, provider, finalURL);
00526 #ifdef DEBUG
00527   if (NS_FAILED(rv)) {
00528     nsCAutoString msg("chrome: failed to get base url");
00529     nsCAutoString url;
00530     rv = aChromeURL->GetSpec(url);
00531     if (NS_SUCCEEDED(rv)) {
00532       msg += " for ";
00533       msg += url.get();
00534     }
00535     msg += " -- using wacky default";
00536     NS_WARNING(msg.get());
00537   }
00538 #endif
00539   if (finalURL.IsEmpty()) {
00540     // hard-coded fallback
00541     if (provider.Equals("skin")) {
00542       finalURL = "resource:/chrome/skins/classic/";
00543     }
00544     else if (provider.Equals("locale")) {
00545       finalURL = "resource:/chrome/locales/en-US/";
00546     }
00547     else if (package.Equals("aim")) {
00548       finalURL = "resource:/chrome/packages/aim/";
00549     }
00550     else if (package.Equals("messenger")) {
00551       finalURL = "resource:/chrome/packages/messenger/";
00552     }
00553     else if (package.Equals("global")) {
00554       finalURL = "resource:/chrome/packages/widget-toolkit/";
00555     }
00556     else {
00557       finalURL = "resource:/chrome/packages/core/";
00558     }
00559   }
00560 
00561   finalURL.Append(remaining);
00562 
00563   return NS_NewURI(aResult, finalURL);
00564 }
00565 
00566 nsresult
00567 nsChromeRegistry::GetBaseURL(const nsACString& aPackage,
00568                              const nsACString& aProvider,
00569                              nsACString& aBaseURL)
00570 {
00571   nsCOMPtr<nsIRDFResource> resource;
00572 
00573   nsCAutoString resourceStr("urn:mozilla:package:");
00574   resourceStr += aPackage;
00575 
00576   // Obtain the resource.
00577   nsresult rv = NS_OK;
00578   nsCOMPtr<nsIRDFResource> packageResource;
00579   rv = GetResource(resourceStr, getter_AddRefs(packageResource));
00580   if (NS_FAILED(rv)) {
00581     NS_ERROR("Unable to obtain the package resource.");
00582     return rv;
00583   }
00584 
00585   // Follow the "selectedSkin" or "selectedLocale" arc.
00586   nsCOMPtr<nsIRDFResource> arc;
00587   if (aProvider.EqualsLiteral("skin")) {
00588     arc = mSelectedSkin;
00589   }
00590   else if (aProvider.EqualsLiteral("locale")) {
00591     arc = mSelectedLocale;
00592   }
00593   else
00594     // We're a package.
00595     resource = packageResource;
00596 
00597   if (arc) {
00598 
00599     nsCOMPtr<nsIRDFNode> selectedProvider;
00600     if (NS_FAILED(rv = mChromeDataSource->GetTarget(packageResource, arc, PR_TRUE, getter_AddRefs(selectedProvider)))) {
00601       NS_ERROR("Unable to obtain the provider.");
00602       return rv;
00603     }
00604 
00605     resource = do_QueryInterface(selectedProvider);
00606 
00607     if (resource) {
00608       PRBool providerOK;
00609       rv = VerifyCompatibleProvider(packageResource, resource, arc, &providerOK);
00610       if (NS_FAILED(rv)) return rv;
00611       if (!providerOK) {
00612         // We had a selection but it was incompatible or not present.
00613         // That selection may have come from the profile, so check only
00614         // the part of the datasource in the install.  (If this succeeds,
00615         // we won't remember the choice, either, in case the user
00616         // switches back to a build where this theme does work.)
00617         if (NS_FAILED(rv = mInstallDirChromeDataSource->GetTarget(packageResource, arc, PR_TRUE, getter_AddRefs(selectedProvider)))) {
00618           NS_ERROR("Unable to obtain the provider.");
00619           return rv;
00620         }
00621         resource = do_QueryInterface(selectedProvider);
00622         if (resource) {
00623           rv = VerifyCompatibleProvider(packageResource, resource, arc, &providerOK);
00624           if (NS_FAILED(rv)) return rv;
00625           if (!providerOK) 
00626             selectedProvider = nsnull;
00627         }
00628       }
00629     }
00630 
00631     if (!selectedProvider) {
00632       // FindProvider will attempt to auto-select a version-compatible provider (skin).  If none
00633       // exist it will return nsnull in the selectedProvider variable.
00634       FindProvider(aPackage, aProvider, arc, getter_AddRefs(selectedProvider));
00635       resource = do_QueryInterface(selectedProvider);
00636     }
00637 
00638     if (!selectedProvider)
00639       return rv;
00640 
00641     if (!resource)
00642       return NS_ERROR_FAILURE;
00643   }
00644 
00645   // From this resource, follow the "baseURL" arc.
00646   return FollowArc(mChromeDataSource, aBaseURL, resource, mBaseURL);
00647 }
00648 
00649 nsresult
00650 nsChromeRegistry::GetOverrideURL(const nsACString& aPackage,
00651                                  const nsACString& aProvider,
00652                                  const nsACString& aPath,
00653                                  nsACString& aResult)
00654 {
00655   nsresult rv = InitOverrideJAR();
00656   if (NS_FAILED(rv)) return rv;
00657 
00658   // ok, if we get here, we have an override JAR
00659 
00660   aResult.SetCapacity(mOverrideJARURL.Length() +
00661                       aPackage.Length() +
00662                       aProvider.Length() +
00663                       aPath.Length() + 2);
00664   
00665   aResult = mOverrideJARURL;
00666   aResult += aPackage;
00667   aResult += '/';
00668   aResult += aProvider;
00669   aResult += '/';
00670 
00671   // skins and locales get their name tacked on, like
00672   // skin/modern/foo.css or
00673   // locale/en-US/navigator.properties
00674   if (aProvider.EqualsLiteral("skin") ||
00675       aProvider.EqualsLiteral("locale")) {
00676 
00677     // little hack here to get the right arc
00678     nsIRDFResource* providerArc;
00679     if (aProvider.Equals("skin"))
00680       providerArc = mSelectedSkin;
00681     else
00682       providerArc = mSelectedLocale;
00683     
00684     nsCAutoString selectedProvider;
00685     rv = GetSelectedProvider(aPackage, aProvider, providerArc, selectedProvider);
00686 
00687     if (NS_SUCCEEDED(rv)) {
00688       aResult += selectedProvider;
00689       aResult += '/';
00690     }
00691   }
00692   
00693   aResult += aPath;
00694 
00695   nsCOMPtr<nsIZipEntry> zipEntry;
00696   rv = mOverrideJAR->GetEntry(PromiseFlatCString(aResult).get(),
00697                               getter_AddRefs(zipEntry));
00698   if (NS_FAILED(rv)) {
00699     aResult.Truncate();
00700     return rv;
00701   }
00702 
00703   return NS_OK;
00704 }
00705 
00706 nsresult
00707 nsChromeRegistry::InitOverrideJAR()
00708 {
00709   // generic failure if we know there's no override
00710   if (mSearchedForOverride && !mOverrideJAR)
00711     return NS_ERROR_FAILURE;
00712 
00713   mSearchedForOverride = PR_TRUE;
00714 
00715   nsresult rv;
00716   //
00717   // look for custom.jar
00718   //
00719   nsCOMPtr<nsIFile> overrideFile;
00720   rv = GetInstallRoot(getter_AddRefs(overrideFile));
00721   if (NS_FAILED(rv)) return rv;
00722 
00723   rv = overrideFile->AppendNative(NS_LITERAL_CSTRING("custom.jar"));
00724   if (NS_FAILED(rv)) return rv;
00725 
00726   PRBool exists;
00727   rv = overrideFile->Exists(&exists);
00728   if (NS_FAILED(rv)) return rv;
00729 
00730   // ok, if the file doesn't exist, its just a generic failure
00731   if (!exists)
00732     return NS_ERROR_FAILURE;
00733 
00734   //
00735   // cache the url so we can later append
00736   //
00737   mOverrideJARURL.Assign("jar:");
00738   nsCAutoString jarURL;
00739   rv = NS_GetURLSpecFromFile(overrideFile, jarURL);
00740   if (NS_FAILED(rv)) return rv;
00741 
00742   mOverrideJARURL.Append(jarURL);
00743   mOverrideJARURL.Append("!/");
00744   if (NS_FAILED(rv)) return rv;
00745 
00746   //
00747   // also cache the zip file itself
00748   //
00749   nsCOMPtr<nsIZipReaderCache> readerCache =
00750     do_CreateInstance("@mozilla.org/libjar/zip-reader-cache;1", &rv);
00751   if (NS_FAILED(rv)) return rv;
00752 
00753   rv = readerCache->Init(32);
00754   
00755   rv = readerCache->GetZip(overrideFile, getter_AddRefs(mOverrideJAR));
00756   if (NS_FAILED(rv)) {
00757     mOverrideJARURL.Truncate();
00758     return rv;
00759   }
00760   
00761   return NS_OK;
00762 }
00763 
00764 nsresult
00765 nsChromeRegistry::VerifyCompatibleProvider(nsIRDFResource* aPackageResource,
00766                                            nsIRDFResource* aProviderResource,
00767                                            nsIRDFResource* aArc,
00768                                            PRBool *aAcceptable)
00769 {
00770   // We found a selected provider, but now we need to verify that the version
00771   // specified by the package and the version specified by the provider are
00772   // one and the same.  If they aren't, then we cannot use this provider.
00773   nsCOMPtr<nsIRDFResource> versionArc;
00774   if (aArc == mSelectedSkin)
00775     versionArc = mSkinVersion;
00776   else // Locale arc
00777     versionArc = mLocaleVersion;
00778 
00779   nsCOMPtr<nsIRDFNode> packageVersionNode;
00780   mChromeDataSource->GetTarget(aPackageResource, versionArc, PR_TRUE,
00781                                getter_AddRefs(packageVersionNode));
00782   if (packageVersionNode) {
00783     // The package only wants providers (skins) that say they can work
00784     // with it.  Let's find out if our provider (skin) can work with it.
00785     mChromeDataSource->HasAssertion(aProviderResource, versionArc,
00786                                     packageVersionNode, PR_TRUE, aAcceptable);
00787     if (!*aAcceptable)
00788       return NS_OK;
00789   }
00790   
00791   // Ensure that the provider actually exists.
00792   // XXX This will have to change if we handle remote chrome.
00793   nsCAutoString providerBaseURL;
00794   nsresult rv = FollowArc(mChromeDataSource, providerBaseURL,
00795                           aProviderResource, mBaseURL);
00796   if (NS_FAILED(rv))
00797     return rv;
00798   nsCOMPtr<nsIFile> baseURLFile;
00799   rv = GetBaseURLFile(providerBaseURL, getter_AddRefs(baseURLFile));
00800   if (NS_FAILED(rv))
00801     return rv;
00802   rv = baseURLFile->Exists(aAcceptable);
00803 #if DEBUG
00804   if (NS_FAILED(rv) || !*aAcceptable)
00805     printf("BaseURL %s cannot be found.\n",
00806            PromiseFlatCString(providerBaseURL).get());
00807 #endif
00808   return rv;
00809 }
00810 
00811 // locate
00812 nsresult
00813 nsChromeRegistry::FindProvider(const nsACString& aPackage,
00814                                const nsACString& aProvider,
00815                                nsIRDFResource *aArc,
00816                                nsIRDFNode **aSelectedProvider)
00817 {
00818   *aSelectedProvider = nsnull;
00819 
00820   nsCAutoString rootStr("urn:mozilla:");
00821   nsresult rv = NS_OK;
00822 
00823   rootStr += aProvider;
00824   rootStr += ":root";
00825 
00826   // obtain the provider root resource
00827   nsCOMPtr<nsIRDFResource> resource;
00828   rv = GetResource(rootStr, getter_AddRefs(resource));
00829   if (NS_FAILED(rv)) {
00830     NS_ERROR("Unable to obtain the provider root resource.");
00831     return rv;
00832   }
00833 
00834   // wrap it in a container
00835   nsCOMPtr<nsIRDFContainer> container =
00836       do_CreateInstance("@mozilla.org/rdf/container;1", &rv);
00837   if (NS_FAILED(rv)) return rv;
00838 
00839   rv = container->Init(mChromeDataSource, resource);
00840   if (NS_FAILED(rv)) return rv;
00841 
00842   // step through its (seq) arcs
00843   nsCOMPtr<nsISimpleEnumerator> arcs;
00844   rv = container->GetElements(getter_AddRefs(arcs));
00845   if (NS_FAILED(rv)) return rv;
00846 
00847   // XXX This needs to be something other than random.  See bug 191957.
00848   PRBool moreElements;
00849   rv = arcs->HasMoreElements(&moreElements);
00850   if (NS_FAILED(rv)) return rv;
00851   for ( ; moreElements; arcs->HasMoreElements(&moreElements)) {
00852 
00853     // get next arc resource
00854     nsCOMPtr<nsISupports> supports;
00855     rv = arcs->GetNext(getter_AddRefs(supports));
00856     if (NS_FAILED(rv)) return rv;
00857     nsCOMPtr<nsIRDFResource> kid = do_QueryInterface(supports);
00858 
00859     if (kid) {
00860       // get its name
00861       nsCAutoString providerName;
00862       rv = FollowArc(mChromeDataSource, providerName, kid, mName);
00863       if (NS_FAILED(rv)) return rv;
00864 
00865       // get its package list
00866       nsCOMPtr<nsIRDFNode> packageNode;
00867       nsCOMPtr<nsIRDFResource> packageList;
00868       rv = mChromeDataSource->GetTarget(kid, mPackages, PR_TRUE, getter_AddRefs(packageNode));
00869       if (NS_SUCCEEDED(rv))
00870         packageList = do_QueryInterface(packageNode);
00871       if (!packageList)
00872         continue;
00873 
00874       // if aPackage is named in kid's package list, select it and we're done
00875       rv = SelectPackageInProvider(packageList, aPackage, aProvider, providerName,
00876                                    aArc, aSelectedProvider);
00877       if (NS_FAILED(rv))
00878         continue; // Don't let this be disastrous.  We may find another acceptable match.
00879 
00880       if (*aSelectedProvider)
00881         return NS_OK;
00882     }
00883   }
00884   return NS_ERROR_FAILURE;
00885 }
00886 
00887 nsresult
00888 nsChromeRegistry::SelectPackageInProvider(nsIRDFResource *aPackageList,
00889                                           const nsACString& aPackage,
00890                                           const nsACString& aProvider,
00891                                           const nsACString& aProviderName,
00892                                           nsIRDFResource *aArc,
00893                                           nsIRDFNode **aSelectedProvider)
00894 {
00895   *aSelectedProvider = nsnull;
00896 
00897   nsresult rv = NS_OK;
00898 
00899   // wrap aPackageList in a container
00900   nsCOMPtr<nsIRDFContainer> container =
00901       do_CreateInstance("@mozilla.org/rdf/container;1", &rv);
00902   if (NS_SUCCEEDED(rv))
00903     rv = container->Init(mChromeDataSource, aPackageList);
00904   if (NS_FAILED(rv))
00905     return rv;
00906 
00907   // step through its (seq) arcs
00908   nsCOMPtr<nsISimpleEnumerator> arcs;
00909   rv = container->GetElements(getter_AddRefs(arcs));
00910   if (NS_FAILED(rv)) return rv;
00911 
00912   PRBool moreElements;
00913   rv = arcs->HasMoreElements(&moreElements);
00914   if (NS_FAILED(rv)) return rv;
00915   for ( ; moreElements; arcs->HasMoreElements(&moreElements)) {
00916 
00917     // get next arc resource
00918     nsCOMPtr<nsISupports> supports;
00919     rv = arcs->GetNext(getter_AddRefs(supports));
00920     if (NS_FAILED(rv)) return rv;
00921     nsCOMPtr<nsIRDFResource> kid = do_QueryInterface(supports);
00922 
00923     if (kid) {
00924       // get its package resource
00925       nsCOMPtr<nsIRDFNode> packageNode;
00926       nsCOMPtr<nsIRDFResource> package;
00927       rv = mChromeDataSource->GetTarget(kid, mPackage, PR_TRUE, getter_AddRefs(packageNode));
00928       if (NS_SUCCEEDED(rv))
00929         package = do_QueryInterface(packageNode);
00930       if (!package)
00931         continue;
00932 
00933       // get its name
00934       nsCAutoString packageName;
00935       rv = FollowArc(mChromeDataSource, packageName, package, mName);
00936       if (NS_FAILED(rv))
00937         continue;       // don't fail if package has not yet been installed
00938 
00939       if (packageName.Equals(aPackage)) {
00940         PRBool useProfile = !mProfileRoot.IsEmpty();
00941         // XXXldb Do we really want to do this?  We risk crossing skins.
00942         if (packageName.Equals("global") || packageName.Equals("communicator"))
00943           useProfile = PR_FALSE; // Always force the auto-selection to be in the
00944                                  // install dir for the packages required to bring up the profile UI.
00945         rv = SelectProviderForPackage(aProvider,
00946                                       aProviderName,
00947                                       NS_ConvertASCIItoUCS2(packageName).get(),
00948                                       aArc, useProfile, PR_TRUE);
00949         if (NS_FAILED(rv))
00950           return NS_ERROR_FAILURE;
00951 
00952         *aSelectedProvider = kid;
00953         NS_ADDREF(*aSelectedProvider);
00954         return NS_OK;
00955       }
00956     }
00957   }
00958   return NS_OK;
00959 }
00960 
00961 nsresult
00962 nsChromeRegistry::GetDynamicDataSource(nsIURI *aChromeURL,
00963                                        PRBool aIsOverlay, PRBool aUseProfile,
00964                                        PRBool aCreateDS,
00965                                        nsIRDFDataSource **aResult)
00966 {
00967   *aResult = nsnull;
00968 
00969   nsresult rv;
00970 
00971   if (!mDataSourceTable)
00972     return NS_OK;
00973 
00974   // Obtain the package, provider and remaining from the URL
00975   nsCAutoString package, provider, remaining;
00976 
00977   rv = SplitURL(aChromeURL, package, provider, remaining);
00978   NS_ENSURE_SUCCESS(rv, rv);
00979 
00980   if (!aCreateDS) {
00981     // We are not supposed to create the data source, which means
00982     // we should first check our chrome.rdf file to see if this
00983     // package even has dynamic data.  Only if it claims to have
00984     // dynamic data are we willing to hand back a datasource.
00985     nsDependentCString dataSourceStr(kChromeFileName);
00986     nsCOMPtr<nsIRDFDataSource> mainDataSource;
00987     rv = LoadDataSource(dataSourceStr, getter_AddRefs(mainDataSource), aUseProfile, nsnull);
00988     NS_ENSURE_SUCCESS(rv, rv);
00989     
00990     // Now that we have the appropriate chrome.rdf file, we
00991     // must check the package resource for stylesheets or overlays.
00992     nsCOMPtr<nsIRDFResource> hasDynamicDataArc;
00993     if (aIsOverlay)
00994       hasDynamicDataArc = mHasOverlays;
00995     else
00996       hasDynamicDataArc = mHasStylesheets;
00997     
00998     // Obtain the resource for the package.
00999     nsCAutoString packageResourceStr("urn:mozilla:package:");
01000     packageResourceStr += package;
01001     nsCOMPtr<nsIRDFResource> packageResource;
01002     GetResource(packageResourceStr, getter_AddRefs(packageResource));
01003     
01004     // Follow the dynamic data arc to see if we should continue.
01005     // Only if it claims to have dynamic data do we even bother.
01006     nsCOMPtr<nsIRDFNode> hasDynamicDSNode;
01007     mainDataSource->GetTarget(packageResource, hasDynamicDataArc, PR_TRUE,
01008                               getter_AddRefs(hasDynamicDSNode));
01009     if (!hasDynamicDSNode)
01010       return NS_OK; // No data source exists.
01011   }
01012 
01013   // Retrieve the mInner data source.
01014   nsCAutoString overlayFile; 
01015   if (aUseProfile && mLegacyOverlayinfo)
01016   {
01017     overlayFile.AppendLiteral("overlayinfo/");
01018     overlayFile += package;
01019     if (aIsOverlay)
01020       overlayFile.AppendLiteral("/content/");
01021     else
01022       overlayFile.AppendLiteral("/skin/");
01023   }
01024   if (aIsOverlay)
01025     overlayFile.AppendLiteral("overlays.rdf");
01026   else
01027     overlayFile.AppendLiteral("stylesheets.rdf");
01028 
01029   return LoadDataSource(overlayFile, aResult, aUseProfile, nsnull);
01030 }
01031 
01032 NS_IMETHODIMP
01033 nsChromeRegistry::GetStyleOverlays(nsIURI *aChromeURL,
01034                                    nsISimpleEnumerator **aResult)
01035 {
01036   return GetDynamicInfo(aChromeURL, PR_FALSE, aResult);
01037 }
01038 
01039 NS_IMETHODIMP
01040 nsChromeRegistry::GetXULOverlays(nsIURI *aChromeURL, nsISimpleEnumerator **aResult)
01041 {
01042   return GetDynamicInfo(aChromeURL, PR_TRUE, aResult);
01043 }
01044 
01045 nsresult
01046 nsChromeRegistry::GetURIList(nsIRDFDataSource *aSource,
01047                              nsIRDFResource *aResource,
01048                              nsCOMArray<nsIURI>& aArray)
01049 {
01050   nsresult rv;
01051   nsCOMPtr<nsISimpleEnumerator> arcs;
01052   nsCOMPtr<nsIRDFContainer> container =
01053     do_CreateInstance("@mozilla.org/rdf/container;1", &rv);
01054   if (NS_FAILED(rv)) goto end_GetURIList;
01055 
01056   rv = container->Init(aSource, aResource);
01057   if (NS_FAILED(rv)) {
01058     rv = NS_OK;
01059     goto end_GetURIList;
01060   }
01061 
01062   rv = container->GetElements(getter_AddRefs(arcs));
01063   if (NS_FAILED(rv)) goto end_GetURIList;
01064 
01065   {
01066     nsCOMPtr<nsISupports> supports;
01067     nsCOMPtr<nsIRDFLiteral> value;
01068     nsCOMPtr<nsIURI> uri;
01069     PRBool hasMore;
01070 
01071     while (NS_SUCCEEDED(rv = arcs->HasMoreElements(&hasMore)) && hasMore) {
01072       rv = arcs->GetNext(getter_AddRefs(supports));
01073       if (NS_FAILED(rv)) break;
01074 
01075       value = do_QueryInterface(supports, &rv);
01076       if (NS_FAILED(rv)) continue;
01077 
01078       const PRUnichar* valueStr;
01079       rv = value->GetValueConst(&valueStr);
01080       if (NS_FAILED(rv)) continue;
01081 
01082       rv = NS_NewURI(getter_AddRefs(uri), NS_ConvertUTF16toUTF8(valueStr));
01083       if (NS_FAILED(rv)) continue;
01084 
01085       if (IsOverlayAllowed(uri)) {
01086         if (!aArray.AppendObject(uri)) {
01087           rv = NS_ERROR_OUT_OF_MEMORY;
01088           break;
01089         }
01090       }
01091     }
01092   }
01093 
01094 end_GetURIList:
01095   return rv;
01096 }
01097 
01098 nsresult
01099 nsChromeRegistry::GetDynamicInfo(nsIURI *aChromeURL, PRBool aIsOverlay,
01100                                  nsISimpleEnumerator **aResult)
01101 {
01102   *aResult = nsnull;
01103 
01104   nsresult rv;
01105 
01106   if (!mDataSourceTable)
01107     return NS_OK;
01108 
01109   nsCOMPtr<nsIRDFDataSource> installSource;
01110   rv = GetDynamicDataSource(aChromeURL, aIsOverlay, PR_FALSE, PR_FALSE,
01111                             getter_AddRefs(installSource));
01112   NS_ENSURE_SUCCESS(rv, rv);
01113 
01114   nsCOMPtr<nsIRDFDataSource> profileSource;
01115   if (mProfileInitialized) {
01116     rv = GetDynamicDataSource(aChromeURL, aIsOverlay, PR_TRUE, PR_FALSE,
01117                               getter_AddRefs(profileSource));
01118     NS_ENSURE_SUCCESS(rv, rv);
01119   }
01120 
01121   nsCAutoString lookup;
01122   rv = aChromeURL->GetSpec(lookup);
01123   NS_ENSURE_SUCCESS(rv, rv);
01124    
01125   // Get the chromeResource from this lookup string
01126   nsCOMPtr<nsIRDFResource> chromeResource;
01127   rv = GetResource(lookup, getter_AddRefs(chromeResource));
01128   if (NS_FAILED(rv)) {
01129       NS_ERROR("Unable to retrieve the resource corresponding to the chrome skin or content.");
01130       return rv;
01131   }
01132 
01133   nsCOMArray<nsIURI> overlayURIs;
01134 
01135   if (installSource) {
01136     GetURIList(installSource, chromeResource, overlayURIs);
01137   }
01138   if (profileSource) {
01139     GetURIList(profileSource, chromeResource, overlayURIs);
01140   }
01141 
01142   return NS_NewArrayEnumerator(aResult, overlayURIs);
01143 }
01144 
01145 nsresult
01146 nsChromeRegistry::LoadDataSource(const nsACString &aFileName,
01147                                  nsIRDFDataSource **aResult,
01148                                  PRBool aUseProfileDir,
01149                                  const char *aProfilePath)
01150 {
01151   // Init the data source to null.
01152   *aResult = nsnull;
01153 
01154   nsCAutoString key;
01155 
01156   // Try the profile root first.
01157   if (aUseProfileDir) {
01158     // use given profile path if non-null
01159     if (aProfilePath) {
01160       key = aProfilePath;
01161       key += "chrome/";
01162     }
01163     else
01164       key = mProfileRoot;
01165 
01166     key += aFileName;
01167   }
01168   else {
01169     key = mInstallRoot;
01170     key += aFileName;
01171   }
01172 
01173   if (mDataSourceTable)
01174   {
01175     nsCStringKey skey(key);
01176     nsCOMPtr<nsISupports> supports =
01177       getter_AddRefs(NS_STATIC_CAST(nsISupports*, mDataSourceTable->Get(&skey)));
01178 
01179     if (supports)
01180     {
01181       nsCOMPtr<nsIRDFDataSource> dataSource = do_QueryInterface(supports);
01182       if (dataSource)
01183       {
01184         *aResult = dataSource;
01185         NS_ADDREF(*aResult);
01186         return NS_OK;
01187       }
01188       return NS_ERROR_FAILURE;
01189     }
01190   }
01191 
01192   nsresult rv = CallCreateInstance(kRDFXMLDataSourceCID, aResult);
01193   if (NS_FAILED(rv)) return rv;
01194 
01195   // Seed the datasource with the ``chrome'' namespace
01196   nsCOMPtr<nsIRDFXMLSink> sink = do_QueryInterface(*aResult);
01197   if (sink)
01198     sink->AddNameSpace(sCPrefix, NS_ConvertASCIItoUCS2(CHROME_URI));
01199 
01200   nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(*aResult);
01201   if (! remote)
01202       return NS_ERROR_UNEXPECTED;
01203 
01204   if (!mDataSourceTable)
01205     mDataSourceTable = new nsSupportsHashtable;
01206 
01207   // We need to read this synchronously.
01208   rv = remote->Init(key.get());
01209   if (NS_SUCCEEDED(rv))
01210     rv = remote->Refresh(PR_TRUE);
01211 
01212   nsCOMPtr<nsISupports> supports = do_QueryInterface(remote);
01213   nsCStringKey skey(key);
01214   mDataSourceTable->Put(&skey, supports.get());
01215 
01216   return NS_OK;
01217 }
01218 
01220 
01221 nsresult
01222 nsChromeRegistry::GetResource(const nsACString& aURL,
01223                               nsIRDFResource** aResult)
01224 {
01225   nsresult rv = NS_OK;
01226   if (NS_FAILED(rv = mRDFService->GetResource(aURL, aResult))) {
01227     NS_ERROR("Unable to retrieve a resource for this URL.");
01228     *aResult = nsnull;
01229     return rv;
01230   }
01231   return NS_OK;
01232 }
01233 
01234 nsresult
01235 nsChromeRegistry::FollowArc(nsIRDFDataSource *aDataSource,
01236                             nsACString& aResult,
01237                             nsIRDFResource* aChromeResource,
01238                             nsIRDFResource* aProperty)
01239 {
01240   if (!aDataSource)
01241     return NS_ERROR_FAILURE;
01242 
01243   nsresult rv;
01244 
01245   nsCOMPtr<nsIRDFNode> chromeBase;
01246   rv = aDataSource->GetTarget(aChromeResource, aProperty, PR_TRUE, getter_AddRefs(chromeBase));
01247   if (NS_FAILED(rv)) {
01248     NS_ERROR("Unable to obtain a base resource.");
01249     return rv;
01250   }
01251 
01252   if (chromeBase == nsnull)
01253     return NS_ERROR_FAILURE;
01254 
01255   nsCOMPtr<nsIRDFResource> resource(do_QueryInterface(chromeBase));
01256 
01257   if (resource) {
01258     nsXPIDLCString uri;
01259     rv = resource->GetValue(getter_Copies(uri));
01260     if (NS_FAILED(rv)) return rv;
01261     aResult.Assign(uri);
01262     return NS_OK;
01263   }
01264 
01265   nsCOMPtr<nsIRDFLiteral> literal(do_QueryInterface(chromeBase));
01266   if (literal) {
01267     const PRUnichar *s;
01268     rv = literal->GetValueConst(&s);
01269     if (NS_FAILED(rv)) return rv;
01270     CopyUTF16toUTF8(s, aResult);
01271   }
01272   else {
01273     // This should _never_ happen.
01274     NS_ERROR("uh, this isn't a resource or a literal!");
01275     return NS_ERROR_UNEXPECTED;
01276   }
01277 
01278   return NS_OK;
01279 }
01280 
01281 nsresult
01282 nsChromeRegistry::UpdateArc(nsIRDFDataSource *aDataSource, nsIRDFResource* aSource,
01283                             nsIRDFResource* aProperty,
01284                             nsIRDFNode *aTarget, PRBool aRemove)
01285 {
01286   nsresult rv;
01287   // Get the old targets
01288   nsCOMPtr<nsIRDFNode> retVal;
01289   rv = aDataSource->GetTarget(aSource, aProperty, PR_TRUE, getter_AddRefs(retVal));
01290   if (NS_FAILED(rv)) return rv;
01291 
01292   if (retVal) {
01293     if (!aRemove)
01294       aDataSource->Change(aSource, aProperty, retVal, aTarget);
01295     else
01296       aDataSource->Unassert(aSource, aProperty, aTarget);
01297   }
01298   else if (!aRemove)
01299     aDataSource->Assert(aSource, aProperty, aTarget, PR_TRUE);
01300 
01301   return NS_OK;
01302 }
01303 
01305 
01306 // theme stuff
01307 
01308 
01309 static void FlushSkinBindingsForWindow(nsIDOMWindowInternal* aWindow)
01310 {
01311   // Get the DOM document.
01312   nsCOMPtr<nsIDOMDocument> domDocument;
01313   aWindow->GetDocument(getter_AddRefs(domDocument));
01314   if (!domDocument)
01315     return;
01316 
01317   nsCOMPtr<nsIDocument> document = do_QueryInterface(domDocument);
01318   if (!document)
01319     return;
01320 
01321   // Annihilate all XBL bindings.
01322   document->BindingManager()->FlushSkinBindings();
01323 }
01324 
01325 // XXXbsmedberg: move this to nsIWindowMediator
01326 NS_IMETHODIMP nsChromeRegistry::RefreshSkins()
01327 {
01328   nsCOMPtr<nsIWindowMediator> windowMediator(do_GetService(kWindowMediatorCID));
01329   if (!windowMediator)
01330     return NS_OK;
01331 
01332   nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
01333   windowMediator->GetEnumerator(nsnull, getter_AddRefs(windowEnumerator));
01334   PRBool more;
01335   windowEnumerator->HasMoreElements(&more);
01336   while (more) {
01337     nsCOMPtr<nsISupports> protoWindow;
01338     windowEnumerator->GetNext(getter_AddRefs(protoWindow));
01339     if (protoWindow) {
01340       nsCOMPtr<nsIDOMWindowInternal> domWindow = do_QueryInterface(protoWindow);
01341       if (domWindow)
01342         FlushSkinBindingsForWindow(domWindow);
01343     }
01344     windowEnumerator->HasMoreElements(&more);
01345   }
01346 
01347   FlushSkinCaches();
01348   
01349   windowMediator->GetEnumerator(nsnull, getter_AddRefs(windowEnumerator));
01350   windowEnumerator->HasMoreElements(&more);
01351   while (more) {
01352     nsCOMPtr<nsISupports> protoWindow;
01353     windowEnumerator->GetNext(getter_AddRefs(protoWindow));
01354     if (protoWindow) {
01355       nsCOMPtr<nsIDOMWindowInternal> domWindow = do_QueryInterface(protoWindow);
01356       if (domWindow)
01357         RefreshWindow(domWindow);
01358     }
01359     windowEnumerator->HasMoreElements(&more);
01360   }
01361    
01362   return NS_OK;
01363 }
01364 
01365 
01366 void
01367 nsChromeRegistry::FlushSkinCaches()
01368 {
01369   nsCOMPtr<nsIObserverService> obsSvc =
01370     do_GetService("@mozilla.org/observer-service;1");
01371   NS_ASSERTION(obsSvc, "Couldn't get observer service.");
01372 
01373   obsSvc->NotifyObservers((nsIChromeRegistry*) this,
01374                           NS_CHROME_FLUSH_SKINS_TOPIC, nsnull);
01375 }
01376 
01377 static PRBool IsChromeURI(nsIURI* aURI)
01378 {
01379     PRBool isChrome=PR_FALSE;
01380     if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome)
01381         return PR_TRUE;
01382     return PR_FALSE;
01383 }
01384 
01385 // XXXbsmedberg: move this to windowmediator
01386 nsresult nsChromeRegistry::RefreshWindow(nsIDOMWindowInternal* aWindow)
01387 {
01388   // Deal with our subframes first.
01389   nsCOMPtr<nsIDOMWindowCollection> frames;
01390   aWindow->GetFrames(getter_AddRefs(frames));
01391   PRUint32 length;
01392   frames->GetLength(&length);
01393   PRUint32 j;
01394   for (j = 0; j < length; j++) {
01395     nsCOMPtr<nsIDOMWindow> childWin;
01396     frames->Item(j, getter_AddRefs(childWin));
01397     nsCOMPtr<nsIDOMWindowInternal> childInt(do_QueryInterface(childWin));
01398     RefreshWindow(childInt);
01399   }
01400 
01401   nsresult rv;
01402   // Get the DOM document.
01403   nsCOMPtr<nsIDOMDocument> domDocument;
01404   aWindow->GetDocument(getter_AddRefs(domDocument));
01405   if (!domDocument)
01406     return NS_OK;
01407 
01408   nsCOMPtr<nsIDocument> document = do_QueryInterface(domDocument);
01409   if (!document)
01410     return NS_OK;
01411 
01412   // Deal with the agent sheets first.  Have to do all the style sets by hand.
01413   PRUint32 shellCount = document->GetNumberOfShells();
01414   for (PRUint32 k = 0; k < shellCount; k++) {
01415     nsIPresShell *shell = document->GetShellAt(k);
01416 
01417     // Reload only the chrome URL agent style sheets.
01418     nsCOMArray<nsIStyleSheet> agentSheets;
01419     rv = shell->GetAgentStyleSheets(agentSheets);
01420     NS_ENSURE_SUCCESS(rv, rv);
01421 
01422     nsCOMArray<nsIStyleSheet> newAgentSheets;
01423     for (PRInt32 l = 0; l < agentSheets.Count(); ++l) {
01424       nsIStyleSheet *sheet = agentSheets[l];
01425 
01426       nsCOMPtr<nsIURI> uri;
01427       rv = sheet->GetSheetURI(getter_AddRefs(uri));
01428       if (NS_FAILED(rv)) return rv;
01429 
01430       if (IsChromeURI(uri)) {
01431         // Reload the sheet.
01432         nsCOMPtr<nsICSSStyleSheet> newSheet;
01433         rv = LoadStyleSheetWithURL(uri, PR_TRUE, getter_AddRefs(newSheet));
01434         if (NS_FAILED(rv)) return rv;
01435         if (newSheet) {
01436           rv = newAgentSheets.AppendObject(newSheet) ? NS_OK : NS_ERROR_FAILURE;
01437           if (NS_FAILED(rv)) return rv;
01438         }
01439       }
01440       else {  // Just use the same sheet.
01441         rv = newAgentSheets.AppendObject(sheet) ? NS_OK : NS_ERROR_FAILURE;
01442         if (NS_FAILED(rv)) return rv;
01443       }
01444     }
01445 
01446     rv = shell->SetAgentStyleSheets(newAgentSheets);
01447     NS_ENSURE_SUCCESS(rv, rv);
01448   }
01449 
01450   // Build an array of nsIURIs of style sheets we need to load.
01451   nsCOMArray<nsIStyleSheet> oldSheets;
01452   nsCOMArray<nsIStyleSheet> newSheets;
01453 
01454   PRInt32 count = document->GetNumberOfStyleSheets();
01455 
01456   // Iterate over the style sheets.
01457   PRInt32 i;
01458   for (i = 0; i < count; i++) {
01459     // Get the style sheet
01460     nsIStyleSheet *styleSheet = document->GetStyleSheetAt(i);
01461     
01462     if (!oldSheets.AppendObject(styleSheet)) {
01463       return NS_ERROR_OUT_OF_MEMORY;
01464     }
01465   }
01466 
01467   // Iterate over our old sheets and kick off a sync load of the new 
01468   // sheet if and only if it's a chrome URL.
01469   for (i = 0; i < count; i++) {
01470     nsCOMPtr<nsIStyleSheet> sheet = oldSheets[i];
01471     nsCOMPtr<nsIURI> uri;
01472     rv = sheet->GetSheetURI(getter_AddRefs(uri));
01473     if (NS_FAILED(rv)) return rv;
01474 
01475     if (IsChromeURI(uri)) {
01476       // Reload the sheet.
01477 #ifdef DEBUG
01478       nsCOMPtr<nsICSSStyleSheet> oldCSSSheet = do_QueryInterface(sheet);
01479       NS_ASSERTION(oldCSSSheet, "Don't know how to reload a non-CSS sheet");
01480 #endif
01481       nsCOMPtr<nsICSSStyleSheet> newSheet;
01482       // XXX what about chrome sheets that have a title or are disabled?  This
01483       // only works by sheer dumb luck.
01484       // XXXbz this should really use the document's CSSLoader!
01485       LoadStyleSheetWithURL(uri, PR_FALSE, getter_AddRefs(newSheet));
01486       // Even if it's null, we put in in there.
01487       newSheets.AppendObject(newSheet);
01488     }
01489     else {
01490       // Just use the same sheet.
01491       newSheets.AppendObject(sheet);
01492     }
01493   }
01494 
01495   // Now notify the document that multiple sheets have been added and removed.
01496   document->UpdateStyleSheets(oldSheets, newSheets);
01497   return NS_OK;
01498 }
01499 
01500 nsresult
01501 nsChromeRegistry::WriteInfoToDataSource(const char *aDocURI,
01502                                         const PRUnichar *aOverlayURI,
01503                                         PRBool aIsOverlay,
01504                                         PRBool aUseProfile,
01505                                         PRBool aRemove)
01506 {
01507   nsresult rv;
01508   nsCOMPtr<nsIURI> uri;
01509   nsCAutoString str(aDocURI);
01510   rv = NS_NewURI(getter_AddRefs(uri), str);
01511   if (NS_FAILED(rv)) return rv;
01512 
01513   if (!aRemove) {
01514     // We are installing a dynamic overlay or package.  
01515     // We must split the doc URI and obtain our package or skin.
01516     // We then annotate the chrome.rdf datasource in the appropriate
01517     // install/profile dir (based off aUseProfile) with the knowledge
01518     // that we have overlays or stylesheets.
01519     nsCAutoString package, provider, file;
01520     rv = SplitURL(uri, package, provider, file);
01521     if (NS_FAILED(rv)) return NS_OK;
01522     
01523     // Obtain our chrome data source.
01524     nsDependentCString dataSourceStr(kChromeFileName);
01525     nsCOMPtr<nsIRDFDataSource> mainDataSource;
01526     rv = LoadDataSource(dataSourceStr, getter_AddRefs(mainDataSource), aUseProfile, nsnull);
01527     if (NS_FAILED(rv)) return rv;
01528     
01529     // Now that we have the appropriate chrome.rdf file, we 
01530     // must annotate the package resource with the knowledge of
01531     // whether or not we have stylesheets or overlays.
01532     nsCOMPtr<nsIRDFResource> hasDynamicDataArc;
01533     if (aIsOverlay)
01534       hasDynamicDataArc = mHasOverlays;
01535     else
01536       hasDynamicDataArc = mHasStylesheets;
01537     
01538     // Obtain the resource for the package.
01539     nsCAutoString packageResourceStr("urn:mozilla:package:");
01540     packageResourceStr += package;
01541     nsCOMPtr<nsIRDFResource> packageResource;
01542     GetResource(packageResourceStr, getter_AddRefs(packageResource));
01543     
01544     // Now add the arc to the package.
01545     nsCOMPtr<nsIRDFLiteral> trueLiteral;
01546     mRDFService->GetLiteral(NS_LITERAL_STRING("true").get(), getter_AddRefs(trueLiteral));
01547     nsChromeRegistry::UpdateArc(mainDataSource, packageResource, 
01548                                 hasDynamicDataArc, 
01549                                 trueLiteral, PR_FALSE);
01550   }
01551 
01552   nsCOMPtr<nsIRDFDataSource> dataSource;
01553   rv = GetDynamicDataSource(uri, aIsOverlay, aUseProfile, PR_TRUE, getter_AddRefs(dataSource));
01554   if (NS_FAILED(rv)) return rv;
01555 
01556   if (!dataSource)
01557     return NS_OK;
01558 
01559   nsCOMPtr<nsIRDFResource> resource;
01560   rv = GetResource(str, getter_AddRefs(resource));
01561 
01562   if (NS_FAILED(rv))
01563     return NS_OK;
01564 
01565   nsCOMPtr<nsIRDFContainer> container;
01566   rv = mRDFContainerUtils->MakeSeq(dataSource, resource, getter_AddRefs(container));
01567   if (NS_FAILED(rv)) return rv;
01568   if (!container) {
01569     // Already exists. Create a container instead.
01570     container = do_CreateInstance("@mozilla.org/rdf/container;1", &rv);
01571     if (NS_FAILED(rv)) return rv;
01572     rv = container->Init(dataSource, resource);
01573     if (NS_FAILED(rv)) return rv;
01574   }
01575 
01576   nsAutoString unistr(aOverlayURI);
01577   nsCOMPtr<nsIRDFLiteral> literal;
01578   rv = mRDFService->GetLiteral(unistr.get(), getter_AddRefs(literal));
01579   if (NS_FAILED(rv)) return rv;
01580 
01581   if (aRemove) {
01582     rv = container->RemoveElement(literal, PR_TRUE);
01583     if (NS_FAILED(rv)) return rv;
01584   }
01585   else {
01586     PRInt32 index;
01587     rv = container->IndexOf(literal, &index);
01588     if (NS_FAILED(rv)) return rv;
01589     if (index == -1) {
01590       rv = container->AppendElement(literal);
01591       if (NS_FAILED(rv)) return rv;
01592     }
01593   }
01594 
01595   nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(dataSource, &rv);
01596   if (NS_SUCCEEDED(rv)) {
01597     rv = remote->Flush();
01598     // Explicitly ignore permissions failure since we sometimes try to write to
01599     // global chrome when we shouldn't.
01600     if (rv == NS_ERROR_FILE_ACCESS_DENIED ||
01601         rv == NS_ERROR_FILE_READ_ONLY ||
01602         rv == NS_ERROR_FILE_TOO_BIG)
01603       rv = NS_OK;
01604   }
01605 
01606   return rv;
01607 }
01608 
01609 nsresult
01610 nsChromeRegistry::UpdateDynamicDataSource(nsIRDFDataSource *aDataSource,
01611                                           nsIRDFResource *aResource,
01612                                           PRBool aIsOverlay,
01613                                           PRBool aUseProfile, PRBool aRemove)
01614 {
01615   nsresult rv;
01616 
01617   nsCOMPtr<nsIRDFContainer> container =
01618       do_CreateInstance("@mozilla.org/rdf/container;1", &rv);
01619   if (NS_FAILED(rv)) return rv;
01620 
01621   rv = container->Init(aDataSource, aResource);
01622   if (NS_FAILED(rv)) return rv;
01623 
01624   nsCOMPtr<nsISimpleEnumerator> arcs;
01625   rv = container->GetElements(getter_AddRefs(arcs));
01626   if (NS_FAILED(rv)) return rv;
01627 
01628   PRBool moreElements;
01629   rv = arcs->HasMoreElements(&moreElements);
01630   if (NS_FAILED(rv)) return rv;
01631 
01632   const char *value;
01633   rv = aResource->GetValueConst(&value);
01634   if (NS_FAILED(rv)) return rv;
01635 
01636   while (moreElements)
01637   {
01638     nsCOMPtr<nsISupports> supports;
01639     rv = arcs->GetNext(getter_AddRefs(supports));
01640     if (NS_FAILED(rv)) return rv;
01641 
01642     nsCOMPtr<nsIRDFLiteral> literal = do_QueryInterface(supports, &rv);
01643 
01644     if (NS_SUCCEEDED(rv))
01645     {
01646       const PRUnichar* valueStr;
01647       rv = literal->GetValueConst(&valueStr);
01648       if (NS_FAILED(rv)) return rv;
01649 
01650       rv = WriteInfoToDataSource(value, valueStr, aIsOverlay, aUseProfile, aRemove);
01651       if (NS_FAILED(rv)) return rv;
01652     }
01653     rv = arcs->HasMoreElements(&moreElements);
01654     if (NS_FAILED(rv)) return rv;
01655   }
01656 
01657   return NS_OK;
01658 }
01659 
01660 
01661 nsresult
01662 nsChromeRegistry::UpdateDynamicDataSources(nsIRDFDataSource *aDataSource,
01663                                            PRBool aIsOverlay,
01664                                            PRBool aUseProfile, PRBool aRemove)
01665 {
01666   nsresult rv;
01667   nsCOMPtr<nsIRDFResource> resource;
01668   nsCAutoString root;
01669   if (aIsOverlay)
01670     root.Assign("urn:mozilla:overlays");
01671   else root.Assign("urn:mozilla:stylesheets");
01672 
01673   rv = GetResource(root, getter_AddRefs(resource));
01674 
01675   if (!resource)
01676     return NS_OK;
01677 
01678   nsCOMPtr<nsIRDFContainer> container(do_CreateInstance("@mozilla.org/rdf/container;1"));
01679   if (!container)
01680     return NS_OK;
01681 
01682   if (NS_FAILED(container->Init(aDataSource, resource)))
01683     return NS_OK;
01684 
01685   nsCOMPtr<nsISimpleEnumerator> arcs;
01686   if (NS_FAILED(container->GetElements(getter_AddRefs(arcs))))
01687     return NS_OK;
01688 
01689   PRBool moreElements;
01690   rv = arcs->HasMoreElements(&moreElements);
01691   if (NS_FAILED(rv)) return rv;
01692 
01693   while (moreElements)
01694   {
01695     nsCOMPtr<nsISupports> supports;
01696     rv = arcs->GetNext(getter_AddRefs(supports));
01697     if (NS_FAILED(rv)) return rv;
01698 
01699     nsCOMPtr<nsIRDFResource> resource2 = do_QueryInterface(supports, &rv);
01700 
01701     if (NS_SUCCEEDED(rv))
01702     {
01703       rv = UpdateDynamicDataSource(aDataSource, resource2, aIsOverlay, aUseProfile, aRemove);
01704       if (NS_FAILED(rv)) return rv;
01705     }
01706 
01707     rv = arcs->HasMoreElements(&moreElements);
01708     if (NS_FAILED(rv)) return rv;
01709   }
01710 
01711   return NS_OK;
01712 }
01713 
01714 NS_IMETHODIMP nsChromeRegistry::SelectSkin(const nsACString& aSkin,
01715                                         PRBool aUseProfile)
01716 {
01717   nsresult rv = SetProvider(NS_LITERAL_CSTRING("skin"), mSelectedSkin, aSkin, aUseProfile, nsnull, PR_TRUE);
01718   FlushSkinCaches();
01719   return rv;
01720 }
01721 
01722 NS_IMETHODIMP nsChromeRegistry::SelectLocale(const nsACString& aLocale,
01723                                           PRBool aUseProfile)
01724 {
01725   return SetProvider(NS_LITERAL_CSTRING("locale"), mSelectedLocale, aLocale, aUseProfile, nsnull, PR_TRUE);
01726 }
01727 
01728 NS_IMETHODIMP nsChromeRegistry::SelectLocaleForProfile(const nsACString& aLocale,
01729                                                        const PRUnichar *aProfilePath)
01730 {
01731   // to be changed to use given path
01732   return SetProvider(NS_LITERAL_CSTRING("locale"), mSelectedLocale, aLocale, PR_TRUE, NS_ConvertUCS2toUTF8(aProfilePath).get(), PR_TRUE);
01733 }
01734 
01735 NS_IMETHODIMP nsChromeRegistry::SelectSkinForProfile(const nsACString& aSkin,
01736                                                      const PRUnichar *aProfilePath)
01737 {
01738   return SetProvider(NS_LITERAL_CSTRING("skin"), mSelectedSkin, aSkin, PR_TRUE, NS_ConvertUCS2toUTF8(aProfilePath).get(), PR_TRUE);
01739 }
01740 
01741 /* void setRuntimeProvider (in boolean runtimeProvider); */
01742 // should we inline this one?
01743 NS_IMETHODIMP nsChromeRegistry::SetRuntimeProvider(PRBool runtimeProvider)
01744 {
01745   mRuntimeProvider = runtimeProvider;
01746   return NS_OK;
01747 }
01748 
01749 
01750 /* ACString getSelectedLocale (ACString packageName); */
01751 NS_IMETHODIMP
01752 nsChromeRegistry::GetSelectedLocale(const nsACString& aPackageName,
01753                                     nsACString& aResult)
01754 {
01755   return GetSelectedProvider(aPackageName,
01756                              NS_LITERAL_CSTRING("locale"), mSelectedLocale,
01757                              aResult);
01758 }
01759 
01760 NS_IMETHODIMP
01761 nsChromeRegistry::GetSelectedSkin(const nsACString& aPackageName,
01762                                   nsACString& aResult)
01763 {
01764   return GetSelectedProvider(aPackageName,
01765                              NS_LITERAL_CSTRING("skin"), mSelectedSkin,
01766                              aResult);
01767 }
01768 
01769 nsresult
01770 nsChromeRegistry::GetSelectedProvider(const nsACString& aPackageName,
01771                                       const nsACString& aProvider,
01772                                       nsIRDFResource* aSelectionArc,
01773                                       nsACString& _retval)
01774 {
01775   // check if mChromeDataSource is null; do we need to apply this to every instance?
01776   // is there a better way to test if the data source is ready?
01777   if (!mChromeDataSource) {
01778     return NS_ERROR_FAILURE;
01779   }
01780 
01781   nsCAutoString resourceStr("urn:mozilla:package:");
01782   resourceStr += aPackageName;
01783 
01784   // Obtain the resource.
01785   nsresult rv = NS_OK;
01786   nsCOMPtr<nsIRDFResource> resource;
01787   rv = GetResource(resourceStr, getter_AddRefs(resource));
01788   if (NS_FAILED(rv)) {
01789     NS_ERROR("Unable to obtain the package resource.");
01790     return rv;
01791   }
01792 
01793   if (mChromeDataSource == nsnull)
01794     return NS_ERROR_NULL_POINTER;
01795 
01796   // Follow the "selectedLocale" arc.
01797   nsCOMPtr<nsIRDFNode> selectedProvider;
01798   if (NS_FAILED(rv = mChromeDataSource->GetTarget(resource, aSelectionArc, PR_TRUE, getter_AddRefs(selectedProvider)))) {
01799     NS_ERROR("Unable to obtain the provider.");
01800     return rv;
01801   }
01802 
01803   if (!selectedProvider) {
01804     rv = FindProvider(aPackageName, aProvider, aSelectionArc, getter_AddRefs(selectedProvider));
01805     if (!selectedProvider)
01806       return rv;
01807   }
01808 
01809   resource = do_QueryInterface(selectedProvider);
01810   if (!resource)
01811     return NS_ERROR_FAILURE;
01812 
01813   // selectedProvider.mURI now looks like "urn:mozilla:locale:ja-JP:navigator"
01814   const char *uri;
01815   if (NS_FAILED(rv = resource->GetValueConst(&uri)))
01816     return rv;
01817 
01818   // trim down to "urn:mozilla:locale:ja-JP"
01819   nsCAutoString packageStr(":");
01820   packageStr += aPackageName;
01821 
01822   nsCAutoString ustr(uri);
01823   PRInt32 pos = ustr.RFind(packageStr);
01824   nsCAutoString urn;
01825   ustr.Left(urn, pos);
01826 
01827   rv = GetResource(urn, getter_AddRefs(resource));
01828   if (NS_FAILED(rv)) {
01829     NS_ERROR("Unable to obtain the provider resource.");
01830     return rv;
01831   }
01832 
01833   // From this resource, follow the "name" arc.
01834   return FollowArc(mChromeDataSource, _retval, resource, mName);
01835 }
01836 
01837 NS_IMETHODIMP nsChromeRegistry::DeselectSkin(const nsACString& aSkin,
01838                                         PRBool aUseProfile)
01839 {
01840   nsresult rv = SetProvider(NS_LITERAL_CSTRING("skin"), mSelectedSkin, aSkin, aUseProfile, nsnull, PR_FALSE);
01841   FlushSkinCaches();
01842   return rv;
01843 }
01844 
01845 NS_IMETHODIMP nsChromeRegistry::DeselectLocale(const nsACString& aLocale,
01846                                           PRBool aUseProfile)
01847 {
01848   return SetProvider(NS_LITERAL_CSTRING("locale"), mSelectedLocale, aLocale, aUseProfile, nsnull, PR_FALSE);
01849 }
01850 
01851 nsresult
01852 nsChromeRegistry::SetProvider(const nsACString& aProvider,
01853                               nsIRDFResource* aSelectionArc,
01854                               const nsACString& aProviderName,
01855                               PRBool aUseProfile, const char *aProfilePath,
01856                               PRBool aIsAdding)
01857 {
01858   // Build the provider resource str.
01859   // e.g., urn:mozilla:skin:aqua/1.0
01860   nsCAutoString resourceStr( "urn:mozilla:" );
01861   resourceStr += aProvider;
01862   resourceStr += ":";
01863   resourceStr += aProviderName;
01864 
01865   // Obtain the provider resource.
01866   nsresult rv = NS_OK;
01867   nsCOMPtr<nsIRDFResource> resource;
01868   rv = GetResource(resourceStr, getter_AddRefs(resource));
01869   if (NS_FAILED(rv)) {
01870     NS_ERROR("Unable to obtain the package resource.");
01871     return rv;
01872   }
01873   NS_ASSERTION(resource, "failed to GetResource");
01874 
01875   // Follow the packages arc to the package resources.
01876   nsCOMPtr<nsIRDFNode> packageList;
01877   rv = mChromeDataSource->GetTarget(resource, mPackages, PR_TRUE, getter_AddRefs(packageList));
01878   if (NS_FAILED(rv)) {
01879     NS_ERROR("Unable to obtain the SEQ for the package list.");
01880     return rv;
01881   }
01882   // ok for packageList to be null here -- it just means that we haven't encountered that package yet
01883 
01884   nsCOMPtr<nsIRDFResource> packageSeq(do_QueryInterface(packageList, &rv));
01885   if (NS_FAILED(rv)) return rv;
01886 
01887   // Build an RDF container to wrap the SEQ
01888   nsCOMPtr<nsIRDFContainer> container =
01889       do_CreateInstance("@mozilla.org/rdf/container;1", &rv);
01890   if (NS_FAILED(rv))
01891     return NS_OK;
01892 
01893   if (NS_FAILED(container->Init(mChromeDataSource, packageSeq)))
01894     return NS_OK;
01895 
01896   nsCOMPtr<nsISimpleEnumerator> arcs;
01897   if (NS_FAILED(container->GetElements(getter_AddRefs(arcs))))
01898     return NS_OK;
01899 
01900   // For each skin/package entry, follow the arcs to the real package
01901   // resource.
01902   PRBool more;
01903   rv = arcs->HasMoreElements(&more);
01904   if (NS_FAILED(rv)) return rv;
01905   while (more) {
01906     nsCOMPtr<nsISupports> packageSkinEntry;
01907     rv = arcs->GetNext(getter_AddRefs(packageSkinEntry));
01908     if (NS_SUCCEEDED(rv) && packageSkinEntry) {
01909       nsCOMPtr<nsIRDFResource> entry = do_QueryInterface(packageSkinEntry);
01910       if (entry) {
01911          // Obtain the real package resource.
01912          nsCOMPtr<nsIRDFNode> packageNode;
01913          rv = mChromeDataSource->GetTarget(entry, mPackage, PR_TRUE, getter_AddRefs(packageNode));
01914          if (NS_FAILED(rv)) {
01915            NS_ERROR("Unable to obtain the package resource.");
01916            return rv;
01917          }
01918 
01919          // Select the skin for this package resource.
01920          nsCOMPtr<nsIRDFResource> packageResource(do_QueryInterface(packageNode));
01921          if (packageResource) {
01922            rv = SetProviderForPackage(aProvider, packageResource, entry, aSelectionArc, aUseProfile, aProfilePath, aIsAdding);
01923            if (NS_FAILED(rv))
01924              continue; // Well, let's set as many sub-packages as we can...
01925          }
01926       }
01927     }
01928     rv = arcs->HasMoreElements(&more);
01929     if (NS_FAILED(rv)) return rv;
01930   }
01931 
01932   // always reset the flag
01933   mRuntimeProvider = PR_FALSE;
01934 
01935   return NS_OK;
01936 }
01937 
01938 nsresult
01939 nsChromeRegistry::SetProviderForPackage(const nsACString& aProvider,
01940                                         nsIRDFResource* aPackageResource,
01941                                         nsIRDFResource* aProviderPackageResource,
01942                                         nsIRDFResource* aSelectionArc,
01943                                         PRBool aUseProfile, const char *aProfilePath,
01944                                         PRBool aIsAdding)
01945 {
01946   nsresult rv;
01947   
01948   if (aUseProfile && !mProfileInitialized) {
01949     rv = LoadProfileDataSource();
01950     NS_ENSURE_TRUE(rv, rv);
01951   }
01952 
01953   // Figure out which file we're needing to modify, e.g., is it the install
01954   // dir or the profile dir, and get the right datasource.
01955   nsCOMPtr<nsIRDFDataSource> dataSource;
01956   rv = LoadDataSource(kChromeFileName, getter_AddRefs(dataSource), aUseProfile, aProfilePath);
01957   if (NS_FAILED(rv)) return rv;
01958 
01959   rv = nsChromeRegistry::UpdateArc(dataSource, aPackageResource, aSelectionArc, aProviderPackageResource, !aIsAdding);
01960   if (NS_FAILED(rv)) return rv;
01961 
01962   nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(dataSource, &rv);
01963   if (NS_FAILED(rv)) return rv;
01964 
01965   // add one more check: 
01966   //   assert the data source only when we are not setting runtime-only provider
01967   if (!mBatchInstallFlushes && !mRuntimeProvider)
01968     rv = remote->Flush();
01969   // Explicitly ignore permissions failure since we sometimes try to write to
01970   // global chrome when we shouldn't.
01971   if (rv == NS_ERROR_FILE_ACCESS_DENIED ||
01972       rv == NS_ERROR_FILE_READ_ONLY ||
01973       rv == NS_ERROR_FILE_TOO_BIG)
01974     rv = NS_OK;
01975 
01976   return rv;
01977 }
01978 
01979 NS_IMETHODIMP nsChromeRegistry::SelectSkinForPackage(const nsACString& aSkin,
01980                                                      const PRUnichar *aPackageName,
01981                                                   PRBool aUseProfile)
01982 {
01983   return SelectProviderForPackage(NS_LITERAL_CSTRING("skin"), aSkin, aPackageName, mSelectedSkin, aUseProfile, PR_TRUE);
01984 }
01985 
01986 NS_IMETHODIMP nsChromeRegistry::SelectLocaleForPackage(const nsACString& aLocale,
01987                                                        const PRUnichar *aPackageName,
01988                                                     PRBool aUseProfile)
01989 {
01990   return SelectProviderForPackage(NS_LITERAL_CSTRING("locale"), aLocale, aPackageName, mSelectedLocale, aUseProfile, PR_TRUE);
01991 }
01992 
01993 NS_IMETHODIMP nsChromeRegistry::DeselectSkinForPackage(const nsACString& aSkin,
01994                                                   const PRUnichar *aPackageName,
01995                                                   PRBool aUseProfile)
01996 {
01997   return SelectProviderForPackage(NS_LITERAL_CSTRING("skin"), aSkin, aPackageName, mSelectedSkin, aUseProfile, PR_FALSE);
01998 }
01999 
02000 NS_IMETHODIMP nsChromeRegistry::DeselectLocaleForPackage(const nsACString& aLocale,
02001                                                     const PRUnichar *aPackageName,
02002                                                     PRBool aUseProfile)
02003 {
02004   return SelectProviderForPackage(NS_LITERAL_CSTRING("locale"), aLocale, aPackageName, mSelectedLocale, aUseProfile, PR_FALSE);
02005 }
02006 
02007 NS_IMETHODIMP nsChromeRegistry::IsSkinSelectedForPackage(const nsACString& aSkin,
02008                                                   const PRUnichar *aPackageName,
02009                                                   PRBool aUseProfile, PRBool* aResult)
02010 {
02011   return IsProviderSelectedForPackage(NS_LITERAL_CSTRING("skin"), aSkin, aPackageName, mSelectedSkin, aUseProfile, aResult);
02012 }
02013 
02014 NS_IMETHODIMP nsChromeRegistry::IsLocaleSelectedForPackage(const nsACString& aLocale,
02015                                                     const PRUnichar *aPackageName,
02016                                                     PRBool aUseProfile, PRBool* aResult)
02017 {
02018   return IsProviderSelectedForPackage(NS_LITERAL_CSTRING("locale"), aLocale, aPackageName, mSelectedLocale, aUseProfile, aResult);
02019 }
02020 
02021 nsresult
02022 nsChromeRegistry::SelectProviderForPackage(const nsACString& aProviderType,
02023                                            const nsACString& aProviderName,
02024                                            const PRUnichar *aPackageName,
02025                                            nsIRDFResource* aSelectionArc,
02026                                            PRBool aUseProfile, PRBool aIsAdding)
02027 {
02028   nsCAutoString package( "urn:mozilla:package:" );
02029   AppendUTF16toUTF8(aPackageName, package);
02030 
02031   nsCAutoString provider( "urn:mozilla:" );
02032   provider += aProviderType;
02033   provider += ":";
02034   provider += aProviderName;
02035   provider += ":";
02036   AppendUTF16toUTF8(aPackageName, provider);
02037 
02038   // Obtain the package resource.
02039   nsresult rv = NS_OK;
02040   nsCOMPtr<nsIRDFResource> packageResource;
02041   rv = GetResource(package, getter_AddRefs(packageResource));
02042   if (NS_FAILED(rv)) {
02043     NS_ERROR("Unable to obtain the package resource.");
02044     return rv;
02045   }
02046   NS_ASSERTION(packageResource, "failed to get packageResource");
02047 
02048   // Obtain the provider resource.
02049   nsCOMPtr<nsIRDFResource> providerResource;
02050   rv = GetResource(provider, getter_AddRefs(providerResource));
02051   if (NS_FAILED(rv)) {
02052     NS_ERROR("Unable to obtain the provider resource.");
02053     return rv;
02054   }
02055   NS_ASSERTION(providerResource, "failed to get providerResource");
02056 
02057   // Version-check before selecting.  If this skin isn't a compatible version, then
02058   // don't allow the selection.
02059   PRBool acceptable;
02060   rv = VerifyCompatibleProvider(packageResource, providerResource,
02061                                 aSelectionArc, &acceptable);
02062   if (NS_FAILED(rv))
02063     return rv;
02064   if (!acceptable)
02065     return NS_ERROR_FAILURE;
02066 
02067   rv = SetProviderForPackage(aProviderType, packageResource, providerResource, aSelectionArc,
02068                              aUseProfile, nsnull, aIsAdding);
02069   // always reset the flag
02070   mRuntimeProvider = PR_FALSE;
02071 
02072   return rv;
02073 }
02074 
02075 NS_IMETHODIMP nsChromeRegistry::IsSkinSelected(const nsACString& aSkin,
02076                                                PRBool aUseProfile, PRInt32* aResult)
02077 {
02078   return IsProviderSelected(NS_LITERAL_CSTRING("skin"), aSkin, mSelectedSkin, aUseProfile, aResult);
02079 }
02080 
02081 NS_IMETHODIMP nsChromeRegistry::IsLocaleSelected(const nsACString& aLocale,
02082                                                  PRBool aUseProfile, PRInt32* aResult)
02083 {
02084   return IsProviderSelected(NS_LITERAL_CSTRING("locale"), aLocale, mSelectedLocale, aUseProfile, aResult);
02085 }
02086 
02087 nsresult
02088 nsChromeRegistry::IsProviderSelected(const nsACString& aProvider,
02089                                      const nsACString& aProviderName,
02090                                      nsIRDFResource* aSelectionArc,
02091                                      PRBool aUseProfile, PRInt32* aResult)
02092 {
02093   // Build the provider resource str.
02094   // e.g., urn:mozilla:skin:aqua/1.0
02095   *aResult = NONE;
02096   nsCAutoString resourceStr( "urn:mozilla:" );
02097   resourceStr += aProvider;
02098   resourceStr += ":";
02099   resourceStr += aProviderName;
02100   // Obtain the provider resource.
02101   nsresult rv = NS_OK;
02102   nsCOMPtr<nsIRDFResource> resource;
02103   rv = GetResource(resourceStr, getter_AddRefs(resource));
02104   if (NS_FAILED(rv)) {
02105     NS_ERROR("Unable to obtain the package resource.");
02106     return rv;
02107   }
02108   NS_ASSERTION(resource, "failed to GetResource");
02109 
02110   // Follow the packages arc to the package resources.
02111   nsCOMPtr<nsIRDFNode> packageList;
02112   rv = mChromeDataSource->GetTarget(resource, mPackages, PR_TRUE, getter_AddRefs(packageList));
02113   if (NS_FAILED(rv)) {
02114     NS_ERROR("Unable to obtain the SEQ for the package list.");
02115     return rv;
02116   }
02117   // ok for packageList to be null here -- it just means that we haven't encountered that package yet
02118 
02119   nsCOMPtr<nsIRDFResource> packageSeq(do_QueryInterface(packageList, &rv));
02120   if (NS_FAILED(rv)) return rv;
02121 
02122   // Build an RDF container to wrap the SEQ
02123   nsCOMPtr<nsIRDFContainer> container(do_CreateInstance("@mozilla.org/rdf/container;1"));
02124   if (NS_FAILED(container->Init(mChromeDataSource, packageSeq)))
02125     return NS_OK;
02126 
02127   nsCOMPtr<nsISimpleEnumerator> arcs;
02128   container->GetElements(getter_AddRefs(arcs));
02129 
02130   // For each skin/package entry, follow the arcs to the real package
02131   // resource.
02132   PRBool more;
02133   PRInt32 numSet = 0;
02134   PRInt32 numPackages = 0;
02135   rv = arcs->HasMoreElements(&more);
02136   if (NS_FAILED(rv)) return rv;
02137   while (more) {
02138     nsCOMPtr<nsISupports> packageSkinEntry;
02139     rv = arcs->GetNext(getter_AddRefs(packageSkinEntry));
02140     if (NS_SUCCEEDED(rv) && packageSkinEntry) {
02141       nsCOMPtr<nsIRDFResource> entry = do_QueryInterface(packageSkinEntry);
02142       if (entry) {
02143          // Obtain the real package resource.
02144          nsCOMPtr<nsIRDFNode> packageNode;
02145          rv = mChromeDataSource->GetTarget(entry, mPackage, PR_TRUE, getter_AddRefs(packageNode));
02146          if (NS_FAILED(rv)) {
02147            NS_ERROR("Unable to obtain the package resource.");
02148            return rv;
02149          }
02150 
02151          // Select the skin for this package resource.
02152          nsCOMPtr<nsIRDFResource> packageResource(do_QueryInterface(packageNode));
02153          if (packageResource) {
02154            PRBool isSet = PR_FALSE;
02155            rv = IsProviderSetForPackage(aProvider, packageResource, entry, aSelectionArc, aUseProfile, &isSet);
02156            if (NS_FAILED(rv)) {
02157              NS_ERROR("Unable to set provider for package resource.");
02158              return rv;
02159            }
02160            ++numPackages;
02161            if (isSet)
02162              ++numSet;
02163          }
02164       }
02165     }
02166     rv = arcs->HasMoreElements(&more);
02167     if (NS_FAILED(rv)) return rv;
02168   }
02169   if (numPackages == numSet)
02170     *aResult = FULL;
02171   else if (numSet)
02172     *aResult = PARTIAL;
02173   return NS_OK;
02174 }
02175 
02176 nsresult
02177 nsChromeRegistry::IsProviderSelectedForPackage(const nsACString& aProviderType,
02178                                                const nsACString& aProviderName,
02179                                                const PRUnichar *aPackageName,
02180                                                nsIRDFResource* aSelectionArc,
02181                                                PRBool aUseProfile, PRBool* aResult)
02182 {
02183   *aResult = PR_FALSE;
02184   nsCAutoString package( "urn:mozilla:package:" );
02185   AppendUTF16toUTF8(aPackageName, package);
02186 
02187   nsCAutoString provider( "urn:mozilla:" );
02188   provider += aProviderType;
02189   provider += ":";
02190   provider += aProviderName;
02191   provider += ":";
02192   AppendUTF16toUTF8(aPackageName, provider);
02193 
02194   // Obtain the package resource.
02195   nsresult rv = NS_OK;
02196   nsCOMPtr<nsIRDFResource> packageResource;
02197   rv = GetResource(package, getter_AddRefs(packageResource));
02198   if (NS_FAILED(rv)) {
02199     NS_ERROR("Unable to obtain the package resource.");
02200     return rv;
02201   }
02202   NS_ASSERTION(packageResource, "failed to get packageResource");
02203 
02204   // Obtain the provider resource.
02205   nsCOMPtr<nsIRDFResource> providerResource;
02206   rv = GetResource(provider, getter_AddRefs(providerResource));
02207   if (NS_FAILED(rv)) {
02208     NS_ERROR("Unable to obtain the provider resource.");
02209     return rv;
02210   }
02211   NS_ASSERTION(providerResource, "failed to get providerResource");
02212 
02213   return IsProviderSetForPackage(aProviderType, packageResource, providerResource, aSelectionArc,
02214                                  aUseProfile, aResult);
02215 }
02216 
02217 nsresult
02218 nsChromeRegistry::IsProviderSetForPackage(const nsACString& aProvider,
02219                                           nsIRDFResource* aPackageResource,
02220                                           nsIRDFResource* aProviderPackageResource,
02221                                           nsIRDFResource* aSelectionArc,
02222                                           PRBool aUseProfile, PRBool* aResult)
02223 {
02224   nsresult rv;
02225   // Figure out which file we're needing to modify, e.g., is it the install
02226   // dir or the profile dir, and get the right datasource.
02227   
02228   nsCOMPtr<nsIRDFDataSource> dataSource;
02229   rv = LoadDataSource(kChromeFileName, getter_AddRefs(dataSource), aUseProfile, nsnull);
02230   if (NS_FAILED(rv)) return rv;
02231 
02232   nsCOMPtr<nsIRDFNode> retVal;
02233   dataSource->GetTarget(aPackageResource, aSelectionArc, PR_TRUE, getter_AddRefs(retVal));
02234   if (retVal) {
02235     nsCOMPtr<nsIRDFNode> node(do_QueryInterface(aProviderPackageResource));
02236     if (node == retVal)
02237       *aResult = PR_TRUE;
02238   }
02239 
02240   return NS_OK;
02241 }
02242 
02243 nsresult
02244 nsChromeRegistry::InstallProvider(const nsACString& aProviderType,
02245                                   const nsACString& aBaseURL,
02246                                   PRBool aUseProfile, PRBool aAllowScripts,
02247                                   PRBool aRemove)
02248 {
02249   // XXX don't allow local chrome overrides of install chrome!
02250 #ifdef DEBUG
02251   printf("*** Chrome Registration of %-7s: Checking for contents.rdf at %s\n", PromiseFlatCString(aProviderType).get(), PromiseFlatCString(aBaseURL).get());
02252 #endif
02253 
02254   // Load the data source found at the base URL.
02255   nsresult rv;
02256   nsCOMPtr<nsIRDFDataSource> dataSource =
02257       do_CreateInstance(kRDFXMLDataSourceCID, &rv);
02258   if (NS_FAILED(rv)) return rv;
02259 
02260   nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(dataSource, &rv);
02261   if (NS_FAILED(rv)) return rv;
02262 
02263   // We need to read this synchronously.
02264   nsCAutoString key(aBaseURL);
02265   key += "contents.rdf";
02266   remote->Init(key.get());
02267   remote->Refresh(PR_TRUE);
02268 
02269   PRBool skinCount = GetProviderCount(NS_LITERAL_CSTRING("skin"), dataSource);
02270   PRBool localeCount = GetProviderCount(NS_LITERAL_CSTRING("locale"), dataSource);
02271   PRBool packageCount = GetProviderCount(NS_LITERAL_CSTRING("package"), dataSource);
02272 
02273   PRBool appendPackage = PR_FALSE;
02274   PRBool appendProvider = PR_FALSE;
02275   PRBool appendProviderName = PR_FALSE;
02276 
02277   if (skinCount == 0 && localeCount == 0 && packageCount == 0) {
02278     // Try the old-style manifest.rdf instead
02279     key = aBaseURL;
02280     key += "manifest.rdf";
02281     (void)remote->Init(key.get());      // ignore failure here
02282     rv = remote->Refresh(PR_TRUE);
02283     if (NS_FAILED(rv)) return rv;
02284     appendPackage = PR_TRUE;
02285     appendProvider = PR_TRUE;
02286     NS_WARNING("Trying old-style manifest.rdf. Please update to contents.rdf.");
02287   }
02288   else {
02289     if ((skinCount > 1 && aProviderType.Equals("skin")) ||
02290         (localeCount > 1 && aProviderType.Equals("locale")))
02291       appendProviderName = PR_TRUE;
02292 
02293     if (!appendProviderName && packageCount > 1) {
02294       appendPackage = PR_TRUE;
02295     }
02296 
02297     if (aProviderType.Equals("skin")) {
02298       if (!appendProviderName && (localeCount == 1 || packageCount != 0))
02299         appendProvider = PR_TRUE;
02300     }
02301     else if (aProviderType.Equals("locale")) {
02302       if (!appendProviderName && (skinCount == 1 || packageCount != 0))
02303         appendProvider = PR_TRUE;
02304     }
02305     else {
02306       // Package install.
02307       if (localeCount == 1 || skinCount == 1)
02308         appendProvider = PR_TRUE;
02309     }
02310   }
02311 
02312   // Load the install data source that we wish to manipulate.
02313   nsCOMPtr<nsIRDFDataSource> installSource;
02314   rv = LoadDataSource(kChromeFileName, getter_AddRefs(installSource), aUseProfile, nsnull);
02315   if (NS_FAILED(rv)) return rv;
02316   NS_ASSERTION(installSource, "failed to get installSource");
02317 
02318   // install our dynamic overlays
02319   if (aProviderType.Equals("package"))
02320     rv = UpdateDynamicDataSources(dataSource, PR_TRUE, aUseProfile, aRemove);
02321   else if (aProviderType.Equals("skin"))
02322     rv = UpdateDynamicDataSources(dataSource, PR_FALSE, aUseProfile, aRemove);
02323   if (NS_FAILED(rv)) return rv;
02324 
02325   // Get the literal for our loc type.
02326   nsAutoString locstr;
02327   if (aUseProfile)
02328     locstr.AssignLiteral("profile");
02329   else locstr.AssignLiteral("install");
02330   nsCOMPtr<nsIRDFLiteral> locLiteral;
02331   rv = mRDFService->GetLiteral(locstr.get(), getter_AddRefs(locLiteral));
02332   if (NS_FAILED(rv)) return rv;
02333 
02334   // Get the literal for our script access.
02335   nsCOMPtr<nsIRDFLiteral> scriptLiteral;
02336   rv = mRDFService->GetLiteral(NS_LITERAL_STRING("false").get(),
02337                                getter_AddRefs(scriptLiteral));
02338   if (NS_FAILED(rv)) return rv;
02339 
02340   // Build the prefix string. Only resources with this prefix string will have their
02341   // assertions copied.
02342   nsCAutoString prefix( "urn:mozilla:" );
02343   prefix += aProviderType;
02344   prefix += ":";
02345 
02346   // Get all the resources
02347   nsCOMPtr<nsISimpleEnumerator> resources;
02348   rv = dataSource->GetAllResources(getter_AddRefs(resources));
02349   if (NS_FAILED(rv)) return rv;
02350 
02351   // For each resource
02352   PRBool moreElements;
02353   rv = resources->HasMoreElements(&moreElements);
02354   if (NS_FAILED(rv)) return rv;
02355 
02356   while (moreElements) {
02357     nsCOMPtr<nsISupports> supports;
02358     rv = resources->GetNext(getter_AddRefs(supports));
02359     if (NS_FAILED(rv)) return rv;
02360 
02361     nsCOMPtr<nsIRDFResource> resource = do_QueryInterface(supports);
02362 
02363     // Check against the prefix string
02364     const char* value;
02365     rv = resource->GetValueConst(&value);
02366     if (NS_FAILED(rv)) return rv;
02367     nsCAutoString val(value);
02368     if (val.Find(prefix) == 0) {
02369       // It's valid.
02370 
02371       if (aProviderType.Equals("package") && !val.Equals("urn:mozilla:package:root")) {
02372         // Add arcs for the base url and loctype
02373         // Get the value of the base literal.
02374         nsCAutoString baseURL(aBaseURL);
02375 
02376         // Peel off the package.
02377         const char* val2;
02378         rv = resource->GetValueConst(&val2);
02379         if (NS_FAILED(rv)) return rv;
02380         nsCAutoString value2(val2);
02381         PRInt32 index = value2.RFind(":");
02382         nsCAutoString packageName;
02383         value2.Right(packageName, value2.Length() - index - 1);
02384 
02385         if (appendPackage) {
02386           baseURL += packageName;
02387           baseURL += "/";
02388         }
02389         if (appendProvider) {
02390           baseURL += "content/";
02391         }
02392 
02393         nsCOMPtr<nsIRDFLiteral> baseLiteral;
02394         mRDFService->GetLiteral(NS_ConvertASCIItoUCS2(baseURL).get(), getter_AddRefs(baseLiteral));
02395 
02396         rv = nsChromeRegistry::UpdateArc(installSource, resource, mBaseURL, baseLiteral, aRemove);
02397         if (NS_FAILED(rv)) return rv;
02398         rv = nsChromeRegistry::UpdateArc(installSource, resource, mLocType, locLiteral, aRemove);
02399         if (NS_FAILED(rv)) return rv;
02400       }
02401 
02402       nsCOMPtr<nsIRDFContainer> container =
02403           do_CreateInstance("@mozilla.org/rdf/container;1", &rv);
02404       if (NS_FAILED(rv)) return rv;
02405       rv = container->Init(dataSource, resource);
02406       if (NS_SUCCEEDED(rv)) {
02407         // XXX Deal with BAGS and ALTs? Aww, to hell with it. Who cares? I certainly don't.
02408         // We're a SEQ. Different rules apply. Do an AppendElement instead.
02409         // First do the decoration in the install data source.
02410         nsCOMPtr<nsIRDFContainer> installContainer;
02411         rv = mRDFContainerUtils->MakeSeq(installSource, resource, getter_AddRefs(installContainer));
02412         if (NS_FAILED(rv)) return rv;
02413         if (!installContainer) {
02414           // Already exists. Create a container instead.
02415           installContainer = do_CreateInstance("@mozilla.org/rdf/container;1", &rv);
02416           if (NS_FAILED(rv)) return rv;
02417           rv = installContainer->Init(installSource, resource);
02418           if (NS_FAILED(rv)) return rv;
02419         }
02420 
02421         // Put all our elements into the install container.
02422         nsCOMPtr<nsISimpleEnumerator> seqKids;
02423         rv = container->GetElements(getter_AddRefs(seqKids));
02424         if (NS_FAILED(rv)) return rv;
02425         PRBool moreKids;
02426         rv = seqKids->HasMoreElements(&moreKids);
02427         if (NS_FAILED(rv)) return rv;
02428         while (moreKids) {
02429           nsCOMPtr<nsISupports> supp;
02430           rv = seqKids->GetNext(getter_AddRefs(supp));
02431           if (NS_FAILED(rv)) return rv;
02432           nsCOMPtr<nsIRDFNode> kid = do_QueryInterface(supp);
02433           if (aRemove) {
02434             rv = installContainer->RemoveElement(kid, PR_TRUE);
02435             if (NS_FAILED(rv)) return rv;
02436           }
02437           else {
02438             PRInt32 index;
02439             rv = installContainer->IndexOf(kid, &index);
02440             if (NS_FAILED(rv)) return rv;
02441             if (index == -1) {
02442               rv = installContainer->AppendElement(kid);
02443               if (NS_FAILED(rv)) return rv;
02444             }
02445             rv = seqKids->HasMoreElements(&moreKids);
02446             if (NS_FAILED(rv)) return rv;
02447           }
02448         }
02449 
02450         // See if we're a packages seq in a skin/locale.  If so, we need to set up the baseURL, allowScripts
02451         // and package arcs.
02452         if (val.Find(":packages") != -1 && !aProviderType.EqualsLiteral("package")) {
02453           PRBool doAppendPackage = appendPackage;
02454           PRInt32 perProviderPackageCount;
02455           container->GetCount(&perProviderPackageCount);
02456           if (perProviderPackageCount > 1)
02457             doAppendPackage = PR_TRUE;
02458 
02459           // Iterate over our kids a second time.
02460           nsCOMPtr<nsISimpleEnumerator> seqKids2;
02461           rv = container->GetElements(getter_AddRefs(seqKids2));
02462           if (NS_FAILED(rv)) return rv;
02463           PRBool moreKids2;
02464           rv = seqKids2->HasMoreElements(&moreKids2);
02465           if (NS_FAILED(rv)) return rv;
02466           while (moreKids2) {
02467             nsCOMPtr<nsISupports> supp;
02468             rv = seqKids2->GetNext(getter_AddRefs(supp));
02469             if (NS_FAILED(rv)) return rv;
02470             nsCOMPtr<nsIRDFResource> entry(do_QueryInterface(supp));
02471             if (entry) {
02472               // Get the value of the base literal.
02473               nsCAutoString baseURL(aBaseURL);
02474 
02475               // Peel off the package and the provider.
02476               const char* val2;
02477               rv = entry->GetValueConst(&val2);
02478               if (NS_FAILED(rv)) return rv;
02479               nsCAutoString value2(val2);
02480               PRInt32 index = value2.RFind(":");
02481               nsCAutoString packageName;
02482               value2.Right(packageName, value2.Length() - index - 1);
02483               nsCAutoString remainder;
02484               value2.Left(remainder, index);
02485 
02486               nsCAutoString providerName;
02487               index = remainder.RFind(":");
02488               remainder.Right(providerName, remainder.Length() - index - 1);
02489 
02490               // Append them to the base literal and tack on a final slash.
02491               if (appendProviderName) {
02492                 baseURL += providerName;
02493                 baseURL += "/";
02494               }
02495               if (doAppendPackage) {
02496                 baseURL += packageName;
02497                 baseURL += "/";
02498               }
02499               if (appendProvider) {
02500                 baseURL += aProviderType;
02501                 baseURL += "/";
02502               }
02503 
02504               nsCOMPtr<nsIRDFLiteral> baseLiteral;
02505               mRDFService->GetLiteral(NS_ConvertASCIItoUCS2(baseURL).get(), getter_AddRefs(baseLiteral));
02506 
02507               rv = nsChromeRegistry::UpdateArc(installSource, entry, mBaseURL, baseLiteral, aRemove);
02508               if (NS_FAILED(rv)) return rv;
02509               if (aProviderType.EqualsLiteral("skin") && !aAllowScripts) {
02510                 rv = nsChromeRegistry::UpdateArc(installSource, entry, mAllowScripts, scriptLiteral, aRemove);
02511                 if (NS_FAILED(rv)) return rv;
02512               }
02513 
02514               // Now set up the package arc.
02515               if (index != -1) {
02516                 // Peel off the package name.
02517 
02518                 nsCAutoString resourceName("urn:mozilla:package:");
02519                 resourceName += packageName;
02520                 nsCOMPtr<nsIRDFResource> packageResource;
02521                 rv = GetResource(resourceName, getter_AddRefs(packageResource));
02522                 if (NS_FAILED(rv)) return rv;
02523                 if (packageResource) {
02524                   rv = nsChromeRegistry::UpdateArc(installSource, entry, mPackage, packageResource, aRemove);
02525                   if (NS_FAILED(rv)) return rv;
02526                 }
02527               }
02528             }
02529 
02530             rv = seqKids2->HasMoreElements(&moreKids2);
02531             if (NS_FAILED(rv)) return rv;
02532           }
02533         }
02534       }
02535       else {
02536         // We're not a seq. Get all of the arcs that go out.
02537         nsCOMPtr<nsISimpleEnumerator> arcs;
02538         rv = dataSource->ArcLabelsOut(resource, getter_AddRefs(arcs));
02539         if (NS_FAILED(rv)) return rv;
02540 
02541         PRBool moreArcs;
02542         rv = arcs->HasMoreElements(&moreArcs);
02543         if (NS_FAILED(rv)) return rv;
02544         while (moreArcs) {
02545           nsCOMPtr<nsISupports> supp;
02546           rv = arcs->GetNext(getter_AddRefs(supp));
02547           if (NS_FAILED(rv)) return rv;
02548           nsCOMPtr<nsIRDFResource> arc = do_QueryInterface(supp);
02549 
02550           if (arc == mPackages) {
02551             // We are the main entry for a skin/locale.
02552             // Set up our loctype and our script access
02553             rv = nsChromeRegistry::UpdateArc(installSource, resource, mLocType, locLiteral, aRemove);
02554             if (NS_FAILED(rv)) return rv;
02555           }
02556 
02557           nsCOMPtr<nsISimpleEnumerator> targets;
02558           rv = installSource->GetTargets(resource, arc, PR_TRUE, getter_AddRefs(targets));
02559           if (NS_FAILED(rv)) return rv;
02560 
02561           PRBool moreTargets;
02562           rv = targets->HasMoreElements(&moreTargets);
02563           if (NS_FAILED(rv)) return rv;
02564 
02565           while (moreTargets) {
02566             targets->GetNext(getter_AddRefs(supp));
02567             nsCOMPtr<nsIRDFNode> node(do_QueryInterface(supp));
02568             installSource->Unassert(resource, arc, node);
02569 
02570             rv = targets->HasMoreElements(&moreTargets);
02571             if (NS_FAILED(rv)) return rv;
02572           }
02573 
02574           if (!aRemove) {
02575             rv = dataSource->GetTargets(resource, arc, PR_TRUE, getter_AddRefs(targets));
02576             if (NS_FAILED(rv)) return rv;
02577 
02578             rv = targets->HasMoreElements(&moreTargets);
02579             if (NS_FAILED(rv)) return rv;
02580 
02581             while (moreTargets) {
02582               nsresult rv = targets->GetNext(getter_AddRefs(supp));
02583               if (NS_FAILED(rv)) return rv;
02584               nsCOMPtr<nsIRDFNode> newTarget(do_QueryInterface(supp));
02585 
02586               if (arc == mImage) {
02587                 // We are an image URL.  Check to see if we're a relative URL.
02588                 nsCOMPtr<nsIRDFLiteral> literal(do_QueryInterface(newTarget));
02589                 if (literal) {
02590                   const PRUnichar* valueStr;
02591                   literal->GetValueConst(&valueStr);
02592                   nsAutoString imageURL(valueStr);
02593                   if (imageURL.FindChar(':') == -1) {
02594                     // We're relative. Prepend the base URL of the
02595                     // package.
02596                     NS_ConvertUTF8toUCS2 fullURL(aBaseURL);
02597                     fullURL += imageURL;
02598                     mRDFService->GetLiteral(fullURL.get(), getter_AddRefs(literal));
02599                     newTarget = do_QueryInterface(literal);
02600                   }
02601                 }
02602               }
02603 
02604               rv = installSource->Assert(resource, arc, newTarget, PR_TRUE);
02605               if (NS_FAILED(rv)) return rv;
02606 
02607               rv = targets->HasMoreElements(&moreTargets);
02608               if (NS_FAILED(rv)) return rv;
02609             }
02610           }
02611 
02612           rv = arcs->HasMoreElements(&moreArcs);
02613           if (NS_FAILED(rv)) return rv;
02614         }
02615       }
02616     }
02617     rv = resources->HasMoreElements(&moreElements);
02618     if (NS_FAILED(rv)) return rv;
02619   }
02620 
02621   // Flush the install source
02622   nsCOMPtr<nsIRDFRemoteDataSource> remoteInstall = do_QueryInterface(installSource, &rv);
02623   if (NS_FAILED(rv))
02624     return NS_OK;
02625 
02626   if (!mBatchInstallFlushes) {
02627     rv = remoteInstall->Flush();
02628     // Explicitly ignore permissions failure since we sometimes try to write to
02629     // global chrome when we shouldn't.
02630     if (rv == NS_ERROR_FILE_ACCESS_DENIED ||
02631         rv == NS_ERROR_FILE_READ_ONLY ||
02632         rv == NS_ERROR_FILE_TOO_BIG)
02633       rv = NS_OK;
02634     if (NS_SUCCEEDED(rv) && aProviderType.Equals("package"))
02635       rv = FlagXPCNativeWrappers();
02636   }
02637 
02638   // XXX Handle the installation of overlays.
02639 
02640   return rv;
02641 }
02642 
02643 NS_IMETHODIMP nsChromeRegistry::SetAllowOverlaysForPackage(const PRUnichar *aPackageName, PRBool allowOverlays)
02644 {
02645   nsCAutoString package("urn:mozilla:package:");
02646   AppendUTF16toUTF8(aPackageName, package);
02647 
02648   // Obtain the package resource.
02649   nsCOMPtr<nsIRDFResource> packageResource;
02650   nsresult rv = GetResource(package, getter_AddRefs(packageResource));
02651   if (NS_FAILED(rv)) {
02652     NS_ERROR("Unable to obtain the package resource.");
02653     return rv;
02654   }
02655   NS_ASSERTION(packageResource, "failed to get packageResource");
02656 
02657   nsCOMPtr<nsIRDFDataSource> dataSource;
02658   rv = LoadDataSource(kChromeFileName, getter_AddRefs(dataSource), PR_TRUE, nsnull);
02659   if (NS_FAILED(rv)) return rv;
02660 
02661   nsCOMPtr<nsIRDFLiteral> trueLiteral;
02662   mRDFService->GetLiteral(NS_LITERAL_STRING("true").get(), getter_AddRefs(trueLiteral));
02663   nsChromeRegistry::UpdateArc(dataSource, packageResource, 
02664                               mDisabled, 
02665                               trueLiteral, allowOverlays);
02666 
02667   nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(dataSource, &rv);
02668   if (NS_FAILED(rv)) return rv;
02669 
02670   rv = remote->Flush();
02671   // Explicitly ignore permissions failure since we sometimes try to write to
02672   // global chrome when we shouldn't.
02673   if (rv == NS_ERROR_FILE_ACCESS_DENIED ||
02674       rv == NS_ERROR_FILE_READ_ONLY ||
02675       rv == NS_ERROR_FILE_TOO_BIG)
02676     rv = NS_OK;
02677 
02678   return rv;
02679 }
02680 
02681 PRBool nsChromeRegistry::IsOverlayAllowed(nsIURI *aChromeURL)
02682 {
02683   nsCAutoString package, provider, file;
02684   nsresult rv = SplitURL(aChromeURL, package, provider, file);
02685   if (NS_FAILED(rv)) return PR_FALSE;
02686 
02687   // Get the chrome resource for the package.
02688   nsCAutoString rdfpackage( "urn:mozilla:package:" );
02689   rdfpackage.Append(package);
02690 
02691   // Obtain the package resource.
02692   nsCOMPtr<nsIRDFResource> packageResource;
02693   rv = GetResource(rdfpackage, getter_AddRefs(packageResource));
02694   if (NS_FAILED(rv) || !packageResource) {
02695     NS_ERROR("Unable to obtain the package resource.");
02696     return PR_FALSE;
02697   }
02698 
02699   // See if the disabled arc is set for the package.
02700   nsCOMPtr<nsIRDFNode> disabledNode;
02701   mChromeDataSource->GetTarget(packageResource, mDisabled, PR_TRUE,
02702                                getter_AddRefs(disabledNode));
02703   return !disabledNode;
02704 }
02705 
02706 NS_IMETHODIMP nsChromeRegistry::InstallSkin(const char* aBaseURL, PRBool aUseProfile, PRBool aAllowScripts)
02707 {
02708   return InstallProvider(NS_LITERAL_CSTRING("skin"),
02709                          nsDependentCString(aBaseURL),
02710                          aUseProfile, aAllowScripts, PR_FALSE);
02711 }
02712 
02713 NS_IMETHODIMP nsChromeRegistry::InstallLocale(const char* aBaseURL, PRBool aUseProfile)
02714 {
02715   return InstallProvider(NS_LITERAL_CSTRING("locale"),
02716                          nsDependentCString(aBaseURL),
02717                          aUseProfile, PR_TRUE, PR_FALSE);
02718 }
02719 
02720 NS_IMETHODIMP nsChromeRegistry::InstallPackage(const char* aBaseURL, PRBool aUseProfile)
02721 {
02722   return InstallProvider(NS_LITERAL_CSTRING("package"),
02723                          nsDependentCString(aBaseURL),
02724                          aUseProfile, PR_TRUE, PR_FALSE);
02725 }
02726 
02727 NS_IMETHODIMP nsChromeRegistry::UninstallSkin(const nsACString& aSkinName, PRBool aUseProfile)
02728 {
02729   // The skin must first be deselected.
02730   DeselectSkin(aSkinName, aUseProfile);
02731 
02732   // Now uninstall it.
02733   return UninstallProvider(NS_LITERAL_CSTRING("skin"), aSkinName, aUseProfile);
02734 }
02735 
02736 NS_IMETHODIMP nsChromeRegistry::UninstallLocale(const nsACString& aLocaleName, PRBool aUseProfile)
02737 {
02738   // The locale must first be deselected.
02739   DeselectLocale(aLocaleName, aUseProfile);
02740 
02741   return UninstallProvider(NS_LITERAL_CSTRING("locale"), aLocaleName, aUseProfile);
02742 }
02743 
02744 NS_IMETHODIMP nsChromeRegistry::UninstallPackage(const nsACString& aPackageName, PRBool aUseProfile)
02745 {
02746   NS_ERROR("XXX Write me!\n");
02747   return NS_ERROR_FAILURE;
02748 }
02749 
02750 nsresult
02751 nsChromeRegistry::UninstallProvider(const nsACString& aProviderType,
02752                                     const nsACString& aProviderName,
02753                                     PRBool aUseProfile)
02754 {
02755   // XXX We are going to simply do a snip of the arc from the seq ROOT to
02756   // the associated package.  waterson is going to provide the ability to name
02757   // roots in a datasource, and only resources that are reachable from the
02758   // root will be saved.
02759   nsresult rv = NS_OK;
02760   nsCAutoString prefix( "urn:mozilla:" );
02761   prefix += aProviderType;
02762   prefix += ":";
02763 
02764   // Obtain the root.
02765   nsCAutoString providerRoot(prefix);
02766   providerRoot += "root";
02767 
02768   // Obtain the child we wish to remove.
02769   nsCAutoString specificChild(prefix);
02770   specificChild += aProviderName;
02771 
02772   // Instantiate the data source we wish to modify.
02773   nsCOMPtr<nsIRDFDataSource> installSource;
02774   rv = LoadDataSource(kChromeFileName, getter_AddRefs(installSource), aUseProfile, nsnull);
02775   if (NS_FAILED(rv)) return rv;
02776   NS_ASSERTION(installSource, "failed to get installSource");
02777 
02778   // Now make a container out of the root seq.
02779   nsCOMPtr<nsIRDFContainer> container(do_CreateInstance("@mozilla.org/rdf/container;1"));
02780 
02781   // Get the resource for the root.
02782   nsCOMPtr<nsIRDFResource> chromeResource;
02783   if (NS_FAILED(rv = GetResource(providerRoot, getter_AddRefs(chromeResource)))) {
02784     NS_ERROR("Unable to retrieve the resource corresponding to the skin/locale root.");
02785     return rv;
02786   }
02787 
02788   if (NS_FAILED(container->Init(installSource, chromeResource)))
02789     return NS_ERROR_FAILURE;
02790 
02791   // Get the resource for the child.
02792   nsCOMPtr<nsIRDFResource> childResource;
02793   if (NS_FAILED(rv = GetResource(specificChild, getter_AddRefs(childResource)))) {
02794     NS_ERROR("Unable to retrieve the resource corresponding to the skin/locale child being removed.");
02795     return rv;
02796   }
02797 
02798   // Remove the child from the container.
02799   container->RemoveElement(childResource, PR_TRUE);
02800 
02801   // Now flush the datasource.
02802   nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(installSource);
02803   remote->Flush();
02804 
02805   return NS_OK;
02806 }
02807 
02808 nsresult
02809 nsChromeRegistry::GetProfileRoot(nsACString& aFileURL)
02810 {
02811    nsresult rv;
02812    nsCOMPtr<nsIFile> userChromeDir;
02813 
02814    // Build a fileSpec that points to the destination
02815    // (profile dir + chrome)
02816    rv = NS_GetSpecialDirectory(NS_APP_USER_CHROME_DIR, getter_AddRefs(userChromeDir));
02817    if (NS_FAILED(rv) || !userChromeDir)
02818      return NS_ERROR_FAILURE;
02819 
02820    PRBool exists;
02821    rv = userChromeDir->Exists(&exists);
02822    if (NS_SUCCEEDED(rv) && !exists) {
02823      rv = userChromeDir->Create(nsIFile::DIRECTORY_TYPE, 0755);
02824      if (NS_SUCCEEDED(rv)) {
02825        // now we need to put the userContent.css and userChrome.css
02826        // stubs into place
02827 
02828        // first get the locations of the defaults
02829        nsCOMPtr<nsIFile> defaultUserContentFile;
02830        nsCOMPtr<nsIFile> defaultUserChromeFile;
02831        rv = NS_GetSpecialDirectory(NS_APP_PROFILE_DEFAULTS_50_DIR,
02832                                    getter_AddRefs(defaultUserContentFile));
02833        if (NS_FAILED(rv))
02834          rv = NS_GetSpecialDirectory(NS_APP_PROFILE_DEFAULTS_NLOC_50_DIR,
02835                                      getter_AddRefs(defaultUserContentFile));
02836        if (NS_FAILED(rv))
02837          return(rv);
02838        rv = NS_GetSpecialDirectory(NS_APP_PROFILE_DEFAULTS_50_DIR,
02839                                    getter_AddRefs(defaultUserChromeFile));
02840        if (NS_FAILED(rv))
02841          rv = NS_GetSpecialDirectory(NS_APP_PROFILE_DEFAULTS_NLOC_50_DIR,
02842                                      getter_AddRefs(defaultUserChromeFile));
02843        if (NS_FAILED(rv))
02844          return(rv);
02845        defaultUserContentFile->AppendNative(NS_LITERAL_CSTRING("chrome"));
02846        defaultUserContentFile->AppendNative(NS_LITERAL_CSTRING("userContent-example.css"));
02847        defaultUserChromeFile->AppendNative(NS_LITERAL_CSTRING("chrome"));
02848        defaultUserChromeFile->AppendNative(NS_LITERAL_CSTRING("userChrome-example.css"));
02849 
02850        const nsAFlatCString& empty = EmptyCString();
02851 
02852        // copy along
02853        // It aint an error if these files dont exist
02854        defaultUserContentFile->CopyToNative(userChromeDir, empty);
02855        defaultUserChromeFile->CopyToNative(userChromeDir, empty);
02856      }
02857    }
02858    if (NS_FAILED(rv))
02859      return rv;
02860 
02861    return NS_GetURLSpecFromFile(userChromeDir, aFileURL);
02862 }
02863 
02864 nsresult
02865 nsChromeRegistry::GetInstallRoot(nsIFile** aFileURL)
02866 {
02867   return NS_GetSpecialDirectory(NS_APP_CHROME_DIR, aFileURL);
02868 }
02869 
02870 void
02871 nsChromeRegistry::FlushAllCaches()
02872 {
02873   nsCOMPtr<nsIObserverService> obsSvc =
02874     do_GetService("@mozilla.org/observer-service;1");
02875   NS_ASSERTION(obsSvc, "Couldn't get observer service.");
02876 
02877   obsSvc->NotifyObservers((nsIChromeRegistry*) this,
02878                           NS_CHROME_FLUSH_TOPIC, nsnull);
02879 
02880 }  
02881 
02882 // xxxbsmedberg Move me to nsIWindowMediator
02883 NS_IMETHODIMP
02884 nsChromeRegistry::ReloadChrome()
02885 {
02886   FlushAllCaches();
02887   // Do a reload of all top level windows.
02888   nsresult rv = NS_OK;
02889 
02890   // Get the window mediator
02891   nsCOMPtr<nsIWindowMediator> windowMediator = do_GetService(kWindowMediatorCID, &rv);
02892   if (NS_SUCCEEDED(rv)) {
02893     nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
02894 
02895     rv = windowMediator->GetEnumerator(nsnull, getter_AddRefs(windowEnumerator));
02896     if (NS_SUCCEEDED(rv)) {
02897       // Get each dom window
02898       PRBool more;
02899       rv = windowEnumerator->HasMoreElements(&more);
02900       if (NS_FAILED(rv)) return rv;
02901       while (more) {
02902         nsCOMPtr<nsISupports> protoWindow;
02903         rv = windowEnumerator->GetNext(getter_AddRefs(protoWindow));
02904         if (NS_SUCCEEDED(rv)) {
02905           nsCOMPtr<nsIDOMWindowInternal> domWindow =
02906             do_QueryInterface(protoWindow);
02907           if (domWindow) {
02908             nsCOMPtr<nsIDOMLocation> location;
02909             domWindow->GetLocation(getter_AddRefs(location));
02910             if (location) {
02911               rv = location->Reload(PR_FALSE);
02912               if (NS_FAILED(rv)) return rv;
02913             }
02914           }
02915         }
02916         rv = windowEnumerator->HasMoreElements(&more);
02917         if (NS_FAILED(rv)) return rv;
02918       }
02919     }
02920   }
02921   return rv;
02922 }
02923 
02924 nsresult
02925 nsChromeRegistry::GetArcs(nsIRDFDataSource* aDataSource,
02926                           const nsACString& aType,
02927                           nsISimpleEnumerator** aResult)
02928 {
02929   nsresult rv;
02930 
02931   nsCOMPtr<nsIRDFContainer> container =
02932       do_CreateInstance("@mozilla.org/rdf/container;1", &rv);
02933   if (NS_FAILED(rv))
02934     return NS_OK;
02935 
02936   nsCAutoString lookup("chrome:");
02937   lookup += aType;
02938 
02939   // Get the chromeResource from this lookup string
02940   nsCOMPtr<nsIRDFResource> chromeResource;
02941   if (NS_FAILED(rv = GetResource(lookup, getter_AddRefs(chromeResource)))) {
02942     NS_ERROR("Unable to retrieve the resource corresponding to the chrome skin or content.");
02943     return rv;
02944   }
02945 
02946   if (NS_FAILED(container->Init(aDataSource, chromeResource)))
02947     return NS_OK;
02948 
02949   nsCOMPtr<nsISimpleEnumerator> arcs;
02950   if (NS_FAILED(container->GetElements(getter_AddRefs(arcs))))
02951     return NS_OK;
02952 
02953   *aResult = arcs;
02954   NS_IF_ADDREF(*aResult);
02955   return NS_OK;
02956 }
02957 
02958 nsresult
02959 nsChromeRegistry::AddToCompositeDataSource(PRBool aUseProfile)
02960 {
02961   nsresult rv = NS_OK;
02962   if (!mChromeDataSource) {
02963     mChromeDataSource = do_CreateInstance(
02964         "@mozilla.org/rdf/datasource;1?name=composite-datasource", &rv);
02965     if (NS_FAILED(rv))
02966       return rv;
02967 
02968     // Also create and hold on to our UI data source.
02969     rv = NS_NewChromeUIDataSource(mChromeDataSource, getter_AddRefs(mUIDataSource));
02970     if (NS_FAILED(rv)) return rv;
02971   }
02972 
02973   if (aUseProfile) {
02974     // Profiles take precedence.  Load them first.
02975     nsCOMPtr<nsIRDFDataSource> dataSource;
02976     LoadDataSource(kChromeFileName, getter_AddRefs(dataSource), PR_TRUE, nsnull);
02977     mChromeDataSource->AddDataSource(dataSource);
02978   }
02979 
02980   // Always load the install dir datasources
02981   LoadDataSource(kChromeFileName, getter_AddRefs(mInstallDirChromeDataSource), PR_FALSE, nsnull);
02982   mChromeDataSource->AddDataSource(mInstallDirChromeDataSource);
02983 
02984   return rv;
02985 }
02986 
02987 nsresult
02988 nsChromeRegistry::FlagXPCNativeWrappers()
02989 {
02990   nsresult rv;
02991   // List all packages that want XPC native wrappers
02992   nsCOMPtr<nsIXPConnect> xpc(do_GetService("@mozilla.org/js/xpc/XPConnect;1", &rv));
02993   NS_ENSURE_SUCCESS(rv, rv);
02994   nsCOMPtr<nsISimpleEnumerator> arcs;
02995   nsCOMPtr<nsIRDFLiteral> trueLiteral;
02996   mRDFService->GetLiteral(NS_LITERAL_STRING("true").get(), getter_AddRefs(trueLiteral));
02997   rv = mChromeDataSource->GetSources(mXPCNativeWrappers, trueLiteral, PR_TRUE,
02998                                      getter_AddRefs(arcs));
02999   if (NS_FAILED(rv)) return rv;
03000 
03001   nsCAutoString uri;
03002   PRBool more;
03003   rv = arcs->HasMoreElements(&more);
03004   if (NS_FAILED(rv)) return rv;
03005   while (more) {
03006     nsCOMPtr<nsISupports> supp;
03007     rv = arcs->GetNext(getter_AddRefs(supp));
03008     if (NS_FAILED(rv)) return rv;
03009     nsCOMPtr<nsIRDFResource> package(do_QueryInterface(supp));
03010     if (package) {
03011       const char urn[] = "urn:mozilla:package:";
03012       const char* source;
03013       package->GetValueConst(&source);
03014       if (!memcmp(source, urn, sizeof urn - 1)) {
03015         uri.AssignLiteral("chrome://");
03016         uri.Append(source + sizeof urn - 1);
03017         uri.Append('/');
03018         rv = xpc->FlagSystemFilenamePrefix(uri.get());
03019         NS_ENSURE_SUCCESS(rv, rv);
03020       }
03021     }
03022     rv = arcs->HasMoreElements(&more);
03023     if (NS_FAILED(rv)) return rv;
03024   }
03025 
03026   return NS_OK;
03027 }
03028 
03029 nsresult nsChromeRegistry::LoadStyleSheetWithURL(nsIURI* aURL,
03030                                                  PRBool aAllowUnsafeRules,
03031                                                  nsICSSStyleSheet** aSheet)
03032 {
03033   *aSheet = nsnull;
03034 
03035   nsCOMPtr<nsICSSLoader_MOZILLA_1_8_BRANCH> cssLoader = do_GetService(kCSSLoaderCID);
03036   if (!cssLoader) return NS_ERROR_FAILURE;
03037 
03038   return cssLoader->LoadSheetSync(aURL, aAllowUnsafeRules, aSheet);
03039 }
03040 
03041 nsresult nsChromeRegistry::LoadInstallDataSource()
03042 {
03043   nsCOMPtr<nsIFile> installRootFile;
03044   
03045   nsresult rv = GetInstallRoot(getter_AddRefs(installRootFile));
03046   NS_ENSURE_SUCCESS(rv, rv);
03047   
03048   rv = NS_GetURLSpecFromFile(installRootFile, mInstallRoot);
03049   NS_ENSURE_SUCCESS(rv, rv);
03050   
03051   mInstallInitialized = PR_TRUE;
03052   return AddToCompositeDataSource(PR_FALSE);
03053 }
03054 
03055 nsresult nsChromeRegistry::LoadProfileDataSource()
03056 {
03057   mLegacyOverlayinfo = PR_FALSE;
03058   nsresult rv = GetProfileRoot(mProfileRoot);
03059   if (NS_SUCCEEDED(rv)) {
03060     // Load the profile search path for skins, content, and locales
03061     // Prepend them to our list of substitutions.
03062     mProfileInitialized = mInstallInitialized = PR_TRUE;
03063     mChromeDataSource = nsnull;
03064     rv = AddToCompositeDataSource(PR_TRUE);
03065     if (NS_FAILED(rv)) return rv;
03066     rv = FlagXPCNativeWrappers();
03067     if (NS_FAILED(rv)) return rv;
03068 
03069     // XXX this sucks ASS. This is a temporary hack until we get
03070     // around to fixing the skin switching bugs.
03071     // Select and Remove skins based on a pref set in a previous session.
03072     nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
03073     if (prefBranch) {
03074       nsXPIDLCString skinToSelect;
03075       rv = prefBranch->GetCharPref("general.skins.selectedSkin", getter_Copies(skinToSelect));
03076       if (NS_SUCCEEDED(rv)) {
03077         rv = SelectSkin(skinToSelect, PR_TRUE);
03078         if (NS_SUCCEEDED(rv))
03079           prefBranch->DeleteBranch("general.skins.selectedSkin");
03080       }
03081     }
03082 
03083     // We have to flush the chrome skin cache...
03084     FlushSkinCaches();
03085     
03086     // make sure we don't lose any old profile overlayinfo
03087     // by checking the existence of the respective overlayinfo/ directory
03088     nsCOMPtr<nsIFile> overlayinfoDir;
03089     rv = NS_GetSpecialDirectory(NS_APP_USER_CHROME_DIR, getter_AddRefs(overlayinfoDir));
03090     if (NS_SUCCEEDED(rv))
03091     {
03092       rv = overlayinfoDir->AppendNative(NS_LITERAL_CSTRING("overlayinfo"));
03093       if (NS_SUCCEEDED(rv))
03094       {
03095         PRBool isLegacyOverlayinfo;
03096         rv = overlayinfoDir->IsDirectory(&isLegacyOverlayinfo);
03097         mLegacyOverlayinfo = NS_SUCCEEDED(rv) && isLegacyOverlayinfo;
03098       }
03099     }
03100 
03101   }
03102   return NS_OK;
03103 }
03104 
03105 NS_IMETHODIMP
03106 nsChromeRegistry::AllowScriptsForPackage(nsIURI* aChromeURI, PRBool *aResult)
03107 {
03108   *aResult = PR_TRUE;
03109 
03110   // split the url
03111   nsCAutoString package, provider, file;
03112   nsresult rv;
03113   rv = SplitURL(aChromeURI, package, provider, file);
03114   if (NS_FAILED(rv)) return NS_OK;
03115 
03116   // verify it's a skin url
03117   if (!provider.Equals("skin"))
03118     return NS_OK;
03119 
03120   // XXX could factor this with selectproviderforpackage
03121   // get the selected skin resource for the package
03122   nsCOMPtr<nsIRDFNode> selectedProvider;
03123 
03124   nsCAutoString resourceStr("urn:mozilla:package:");
03125   resourceStr += package;
03126 
03127   // Obtain the resource.
03128   nsCOMPtr<nsIRDFResource> resource;
03129   rv = GetResource(resourceStr, getter_AddRefs(resource));
03130   if (NS_FAILED(rv)) {
03131     NS_ERROR("Unable to obtain the package resource.");
03132     return rv;
03133   }
03134 
03135   if (NS_FAILED(rv = mChromeDataSource->GetTarget(resource, mSelectedSkin, PR_TRUE, getter_AddRefs(selectedProvider))))
03136     return NS_OK;
03137 
03138   if (!selectedProvider) {
03139     rv = FindProvider(package, provider, mSelectedSkin, getter_AddRefs(selectedProvider));
03140     if (NS_FAILED(rv)) return rv;
03141   }
03142   if (!selectedProvider)
03143     return NS_OK;
03144 
03145   resource = do_QueryInterface(selectedProvider, &rv);
03146   if (NS_SUCCEEDED(rv)) {
03147     // get its script access
03148     nsCOMPtr<nsIRDFNode> scriptAccessNode;
03149     mChromeDataSource->GetTarget(resource, mAllowScripts, PR_TRUE,
03150                                  getter_AddRefs(scriptAccessNode));
03151     if (scriptAccessNode)
03152       *aResult = PR_FALSE;
03153   }
03154   return NS_OK;
03155 }
03156 
03157 NS_IMETHODIMP
03158 nsChromeRegistry::CheckForNewChrome()
03159 {
03160   nsresult rv;
03161 
03162   rv = LoadInstallDataSource();
03163   if (NS_FAILED(rv)) return rv;
03164 
03165   // open the installed-chrome file
03166   nsCOMPtr<nsILocalFile> listFile;
03167   nsCOMPtr<nsIProperties> directoryService =
03168            do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
03169   if (NS_FAILED(rv))
03170     return rv;
03171   rv = directoryService->Get(NS_APP_CHROME_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(listFile));
03172   if (NS_FAILED(rv))
03173     return rv;
03174 
03175   nsCOMPtr<nsIFile> chromeFile;
03176   rv = listFile->Clone(getter_AddRefs(chromeFile));
03177   if (NS_FAILED(rv)) return rv;
03178   rv = chromeFile->AppendNative(kChromeFileName);
03179   if (NS_FAILED(rv)) return rv;
03180   // XXXldb For the case where the file is nonexistent, we're depending
03181   // on the fact that the nsInt64 constructor initializes to 0 and
03182   // |GetLastModifiedTime| doesn't touch the out parameter.
03183   nsInt64 chromeDate;
03184   (void)chromeFile->GetLastModifiedTime(&chromeDate.mValue);
03185 
03186   rv = listFile->AppendRelativeNativePath(kInstalledChromeFileName);
03187   if (NS_FAILED(rv)) return rv;
03188   nsInt64 listFileDate;
03189   (void)listFile->GetLastModifiedTime(&listFileDate.mValue);
03190 
03191   if (listFileDate < chromeDate)
03192     return NS_OK;
03193 
03194   PRFileDesc *file;
03195   rv = listFile->OpenNSPRFileDesc(PR_RDONLY, 0, &file);
03196   if (NS_FAILED(rv)) return rv;
03197 
03198   // file is open.
03199 
03200   PRFileInfo finfo;
03201 
03202   if (PR_GetOpenFileInfo(file, &finfo) == PR_SUCCESS) {
03203     char *dataBuffer = new char[finfo.size+1];
03204     if (dataBuffer) {
03205       PRInt32 bufferSize = PR_Read(file, dataBuffer, finfo.size);
03206       if (bufferSize > 0) {
03207         mBatchInstallFlushes = PR_TRUE;
03208         rv = ProcessNewChromeBuffer(dataBuffer, bufferSize);
03209         mBatchInstallFlushes = PR_FALSE;
03210       }
03211       delete [] dataBuffer;
03212     }
03213   }
03214   PR_Close(file);
03215   // listFile->Remove(PR_FALSE);
03216 
03217   return rv;
03218 }
03219 
03220 // flaming unthreadsafe function
03221 nsresult
03222 nsChromeRegistry::ProcessNewChromeBuffer(char *aBuffer, PRInt32 aLength)
03223 {
03224   nsresult rv = NS_OK;
03225   char   *bufferEnd = aBuffer + aLength;
03226   char   *chromeType,      // "content", "locale" or "skin"
03227          *chromeProfile,   // "install" or "profile"
03228          *chromeLocType,   // type of location (local path or URL)
03229          *chromeLocation;  // base location of chrome (jar file)
03230   PRBool isProfile;
03231   PRBool isSelection;
03232 
03233   NS_NAMED_LITERAL_CSTRING(content, "content");
03234   NS_NAMED_LITERAL_CSTRING(locale, "locale");
03235   NS_NAMED_LITERAL_CSTRING(skin, "skin");
03236   NS_NAMED_LITERAL_CSTRING(profile, "profile");
03237   NS_NAMED_LITERAL_CSTRING(select, "select");
03238   NS_NAMED_LITERAL_CSTRING(path, "path");
03239   nsCAutoString fileURL;
03240   nsCAutoString chromeURL;
03241 
03242   // process chromeType, chromeProfile, chromeLocType, chromeLocation
03243   while (aBuffer < bufferEnd) {
03244     // parse one line of installed-chrome.txt
03245     chromeType = aBuffer;
03246     while (aBuffer < bufferEnd && *aBuffer != ',')
03247       ++aBuffer;
03248     *aBuffer = '\0';
03249 
03250     chromeProfile = ++aBuffer;
03251     if (aBuffer >= bufferEnd)
03252       break;
03253 
03254     while (aBuffer < bufferEnd && *aBuffer != ',')
03255       ++aBuffer;
03256     *aBuffer = '\0';
03257 
03258     chromeLocType = ++aBuffer;
03259     if (aBuffer >= bufferEnd)
03260       break;
03261 
03262     while (aBuffer < bufferEnd && *aBuffer != ',')
03263       ++aBuffer;
03264     *aBuffer = '\0';
03265 
03266     chromeLocation = ++aBuffer;
03267     if (aBuffer >= bufferEnd)
03268       break;
03269 
03270     while (aBuffer < bufferEnd &&
03271            (*aBuffer != '\r' && *aBuffer != '\n' && *aBuffer != ' '))
03272       ++aBuffer;
03273     *aBuffer = '\0';
03274 
03275     // process the parsed line
03276     isSelection = select.Equals(chromeLocType);
03277     isProfile = profile.Equals(chromeProfile);
03278     if (isProfile && !mProfileInitialized) 
03279     { // load profile chrome.rdf only if needed
03280       rv = LoadProfileDataSource();
03281       if (NS_FAILED(rv)) 
03282         return rv;
03283     }
03284 
03285     if (path.Equals(chromeLocType)) {
03286       // location is a (full) path. convert it to an URL.
03287 
03288       /* this is some convoluted shit... this creates a file, inits it with
03289        * the path parsed above (chromeLocation), makes a url, and inits it
03290        * with the file created. the purpose of this is just to have the
03291        * canonical url of the stupid thing.
03292        */
03293       nsCOMPtr<nsILocalFile> chromeFile(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv));
03294       if (NS_FAILED(rv))
03295         return rv;
03296       // assuming chromeLocation is given in the charset of the current locale
03297       rv = chromeFile->InitWithNativePath(nsDependentCString(chromeLocation));
03298       if (NS_FAILED(rv))
03299         return rv;
03300 
03301       /* 
03302        * all we want here is the canonical url
03303        */
03304       rv = NS_GetURLSpecFromFile(chromeFile, chromeURL);
03305       if (NS_FAILED(rv)) return rv;
03306 
03307       /* if we're a file, we must be a jar file. do appropriate string munging.
03308        * otherwise, the string we got from GetSpec is fine.
03309        */
03310       PRBool isFile;
03311       rv = chromeFile->IsFile(&isFile);
03312       if (NS_FAILED(rv))
03313         return rv;
03314 
03315       if (isFile) {
03316         fileURL = "jar:";
03317         fileURL += chromeURL;
03318         fileURL += "!/";
03319         chromeURL = fileURL;
03320       }
03321     }
03322     else {
03323       // not "path". assume "url".
03324       chromeURL = chromeLocation;
03325     }
03326 
03327     // process the line
03328     if (skin.Equals(chromeType)) {
03329       if (isSelection) {
03330 
03331         rv = SelectSkin(nsDependentCString(chromeLocation), isProfile);
03332 #ifdef DEBUG
03333         printf("***** Chrome Registration: Selecting skin %s as default\n", (const char*)chromeLocation);
03334 #endif
03335       }
03336       else
03337         rv = InstallSkin(chromeURL.get(), isProfile, PR_FALSE);
03338     }
03339     else if (content.Equals(chromeType))
03340       rv = InstallPackage(chromeURL.get(), isProfile);
03341     else if (locale.Equals(chromeType)) {
03342       if (isSelection) {
03343 
03344         rv = SelectLocale(nsDependentCString(chromeLocation), isProfile);
03345 #ifdef DEBUG
03346         printf("***** Chrome Registration: Selecting locale %s as default\n", (const char*)chromeLocation);
03347 #endif
03348       }
03349       else
03350         rv = InstallLocale(chromeURL.get(), isProfile);
03351     }
03352     
03353     while (aBuffer < bufferEnd && (*aBuffer == '\0' || *aBuffer == ' ' || *aBuffer == '\r' || *aBuffer == '\n'))
03354       ++aBuffer;
03355   }
03356 
03357   nsCOMPtr<nsIRDFDataSource> dataSource;
03358   LoadDataSource(kChromeFileName, getter_AddRefs(dataSource), PR_FALSE, nsnull);
03359   nsCOMPtr<nsIRDFRemoteDataSource> remote(do_QueryInterface(dataSource));
03360   remote->Flush();
03361   return NS_OK;
03362 }
03363 
03364 PRBool
03365 nsChromeRegistry::GetProviderCount(const nsACString& aProviderType, nsIRDFDataSource* aDataSource)
03366 {
03367   nsresult rv;
03368 
03369   nsCAutoString rootStr("urn:mozilla:");
03370   rootStr += aProviderType;
03371   rootStr += ":root";
03372 
03373   // obtain the provider root resource
03374   nsCOMPtr<nsIRDFResource> resource;
03375   rv = GetResource(rootStr, getter_AddRefs(resource));
03376   if (NS_FAILED(rv))
03377     return 0;
03378 
03379   // wrap it in a container
03380   nsCOMPtr<nsIRDFContainer> container =
03381       do_CreateInstance("@mozilla.org/rdf/container;1", &rv);
03382   if (NS_FAILED(rv)) return 0;
03383 
03384   rv = container->Init(aDataSource, resource);
03385   if (NS_FAILED(rv)) return 0;
03386 
03387   PRInt32 count;
03388   container->GetCount(&count);
03389   return count;
03390 }
03391 
03392 
03393 NS_IMETHODIMP nsChromeRegistry::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData)
03394 {
03395   nsresult rv = NS_OK;
03396 
03397   if (!strcmp("profile-before-change", aTopic)) {
03398 
03399     mChromeDataSource = nsnull;
03400     mInstallInitialized = mProfileInitialized = PR_FALSE;
03401 
03402     if (!strcmp("shutdown-cleanse", NS_ConvertUCS2toUTF8(someData).get())) {
03403       nsCOMPtr<nsIFile> userChromeDir;
03404       rv = NS_GetSpecialDirectory(NS_APP_USER_CHROME_DIR, getter_AddRefs(userChromeDir));
03405       if (NS_SUCCEEDED(rv) && userChromeDir)
03406         rv = userChromeDir->Remove(PR_TRUE);
03407     }
03408     FlushAllCaches();
03409   }
03410   else if (!strcmp("profile-after-change", aTopic)) {
03411     rv = LoadProfileDataSource();
03412   }
03413 
03414   return rv;
03415 }
03416 
03417 NS_IMETHODIMP nsChromeRegistry::CheckThemeVersion(const nsACString& aSkin,
03418                                                   PRBool* aResult)
03419 {
03420   return CheckProviderVersion(NS_LITERAL_CSTRING("skin"), aSkin, mSkinVersion, aResult);
03421 }
03422 
03423 
03424 NS_IMETHODIMP nsChromeRegistry::CheckLocaleVersion(const nsACString& aLocale,
03425                                                    PRBool* aResult)
03426 {
03427   nsCAutoString provider("locale");
03428   return CheckProviderVersion(NS_LITERAL_CSTRING("skin"), aLocale, mLocaleVersion, aResult);
03429 }
03430 
03431 
03432 nsresult
03433 nsChromeRegistry::CheckProviderVersion (const nsACString& aProviderType,
03434                                         const nsACString& aProviderName,
03435                                         nsIRDFResource* aSelectionArc,
03436                                         PRBool *aCompatible)
03437 {
03438   *aCompatible = PR_TRUE;
03439 
03440   // Build the provider resource str.
03441   // e.g., urn:mozilla:skin:aqua/1.0
03442   nsCAutoString resourceStr( "urn:mozilla:" );
03443   resourceStr += aProviderType;
03444   resourceStr += ":";
03445   resourceStr += aProviderName;
03446 
03447   // Obtain the provider resource.
03448   nsresult rv = NS_OK;
03449   nsCOMPtr<nsIRDFResource> resource;
03450   rv = GetResource(resourceStr, getter_AddRefs(resource));
03451   if (NS_FAILED(rv)) {
03452     NS_ERROR("Unable to obtain the package resource.");
03453     return rv;
03454   }
03455 
03456   // Follow the packages arc to the package resources.
03457   nsCOMPtr<nsIRDFNode> packageList;
03458   rv = mChromeDataSource->GetTarget(resource, mPackages, PR_TRUE, getter_AddRefs(packageList));
03459   if (NS_FAILED(rv)) {
03460     NS_ERROR("Unable to obtain the SEQ for the package list.");
03461     return rv;
03462   }
03463   // ok for packageList to be null here -- it just means that we haven't encountered that package yet
03464 
03465   nsCOMPtr<nsIRDFResource> packageSeq(do_QueryInterface(packageList, &rv));
03466   if (NS_FAILED(rv)) return rv;
03467 
03468   // Build an RDF container to wrap the SEQ
03469   nsCOMPtr<nsIRDFContainer> container =
03470       do_CreateInstance("@mozilla.org/rdf/container;1", &rv);
03471   if (NS_FAILED(rv))
03472     return rv;
03473 
03474   rv = container->Init(mChromeDataSource, packageSeq);
03475   if (NS_FAILED(rv))
03476     return rv;
03477 
03478   nsCOMPtr<nsISimpleEnumerator> arcs;
03479 
03480   rv = container->GetElements(getter_AddRefs(arcs));
03481   if (NS_FAILED(rv))
03482     return NS_OK;
03483 
03484   // For each skin-package entry, follow the arcs to the real package
03485   // resource.
03486   PRBool more;
03487   rv = arcs->HasMoreElements(&more);
03488   if (NS_FAILED(rv)) return rv;
03489   while (more) {
03490     nsCOMPtr<nsISupports> packageSkinEntry;
03491     rv = arcs->GetNext(getter_AddRefs(packageSkinEntry));
03492     if (NS_SUCCEEDED(rv) && packageSkinEntry) {
03493       nsCOMPtr<nsIRDFResource> entry = do_QueryInterface(packageSkinEntry);
03494       if (entry) {
03495         // Obtain the real package resource.
03496         nsCOMPtr<nsIRDFNode> packageNode;
03497         rv = mChromeDataSource->GetTarget(entry, mPackage, PR_TRUE, getter_AddRefs(packageNode));
03498         if (NS_FAILED(rv)) {
03499           NS_ERROR("Unable to obtain the package resource.");
03500           return rv;
03501         }
03502 
03503         nsCOMPtr<nsIRDFResource> packageResource(do_QueryInterface(packageNode));
03504         if (packageResource) {
03505           nsCOMPtr<nsIRDFNode> packageNameNode;
03506           mChromeDataSource->GetTarget(packageResource, mName, PR_TRUE,
03507                                        getter_AddRefs(packageNameNode));
03508 
03509           if (packageNameNode) {
03510             nsCOMPtr<nsIRDFNode> packageVersionNode;
03511             mChromeDataSource->GetTarget(packageResource, aSelectionArc, PR_TRUE,
03512                                          getter_AddRefs(packageVersionNode));
03513 
03514             if (packageVersionNode) {
03515               mChromeDataSource->HasAssertion(entry, aSelectionArc,
03516                                               packageVersionNode, PR_TRUE,
03517                                               aCompatible);
03518               // if just one theme package is NOT compatible, the theme will be disabled
03519               if (!*aCompatible)
03520                 return NS_OK;
03521             }
03522           }
03523         }
03524       }
03525     }
03526     rv = arcs->HasMoreElements(&more);
03527     if (NS_FAILED(rv))
03528       return rv;
03529   }
03530 
03531   return NS_OK;
03532 }
03533