Back to index

lightning-sunbird  0.9+nobinonly
nsRegisterItem.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 Communicator client code, released
00016  * March 31, 1998.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 2000
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Daniel Veditz <dveditz@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "prprf.h"
00041 #include "nsRegisterItem.h"
00042 #include "nsInstallResources.h"
00043 #include "nsNetUtil.h"
00044 #include "nsXPIDLString.h"
00045 #include "nsReadableUtils.h"
00046 #include "nsInstallTrigger.h"
00047 #include "nsIChromeRegistry.h"
00048 #include "nsIDirectoryService.h"
00049 #include "nsDirectoryServiceDefs.h"
00050 #include "nsAppDirectoryServiceDefs.h"
00051 #include "nsNativeCharsetUtils.h"
00052 
00053 MOZ_DECL_CTOR_COUNTER(nsRegisterItem)
00054 
00055 nsRegisterItem:: nsRegisterItem(  nsInstall* inInstall,
00056                                   nsIFile* chrome,
00057                                   PRUint32 chromeType,
00058                                   const char* path )
00059 : nsInstallObject(inInstall), mChrome(chrome), mChromeType(chromeType), mPath(path)
00060 {
00061     MOZ_COUNT_CTOR(nsRegisterItem);
00062 }
00063 
00064 
00065 nsRegisterItem::~nsRegisterItem()
00066 {
00067     MOZ_COUNT_DTOR(nsRegisterItem);
00068 }
00069 
00070 #if defined (XP_MAC)
00071 static void SwapSlashColon(char * s)
00072 {
00073        while (*s)
00074        {
00075               if (*s == '/')
00076                      *s++ = ':';
00077               else if (*s == ':')
00078                      *s++ = '/';
00079               else
00080                      *s++;
00081        }
00082 } 
00083 #endif
00084 
00085 #if defined(XP_WIN)
00086 #include <windows.h>
00087 #endif
00088 
00089 static nsresult 
00090 hack_nsIFile2URL(nsIFile* file, char * *aURL)
00091 {
00092     nsresult rv;
00093     nsCAutoString ePath;
00094     rv = file->GetNativePath(ePath);
00095     if (NS_FAILED(rv)) return rv;
00096 #if defined(XP_WIN) || defined(XP_OS2)
00097     // Replace \ with / to convert to an url
00098     char* s;
00099     ePath.BeginWriting(s);
00100     while (*s) {
00101 #ifndef XP_OS2
00102         // We need to call IsDBCSLeadByte because
00103         // Japanese windows can have 0x5C in the sencond byte 
00104         // of a Japanese character, for example 0x8F 0x5C is
00105         // one Japanese character
00106         if(::IsDBCSLeadByte(*s) && *(s+1) != nsnull) {
00107             s++;
00108         } else 
00109 #endif
00110             if (*s == '\\')
00111                 *s = '/';
00112         s++;
00113     }
00114 #endif
00115 #if defined( XP_MAC )
00116     // Swap the / and colons to convert to an url
00117     SwapSlashColon(ePath.BeginWriting());
00118 #endif
00119     // Escape the path with the directory mask
00120     nsCAutoString tmp(ePath);
00121     tmp.ReplaceChar(":", '|');
00122 #ifdef XP_MAC
00123     nsCAutoString escPath("file:///");
00124 #else
00125     nsCAutoString escPath("file://");
00126 #endif
00127        escPath += tmp;
00128 //    rv = nsURLEscape(ePath,nsIIOService::url_Directory + nsIIOService::url_Forced, escPath);
00129 //    if (NS_SUCCEEDED(rv)) {
00130         PRBool dir;
00131         rv = file->IsDirectory(&dir);
00132         if (NS_SUCCEEDED(rv) && dir && escPath[escPath.Length() - 1] != '/') {
00133             // make sure we have a trailing slash
00134             escPath += "/";
00135         }
00136         *aURL = ToNewCString(escPath);
00137         if (*aURL == nsnull) {
00138             return NS_ERROR_OUT_OF_MEMORY;
00139         }
00140 //    }
00141     return rv;
00142 }
00143 
00144 void nsRegisterItem::LogErrorWithFilename(const nsAString& aMessage, nsresult code, nsILocalFile* localFile)
00145 {
00146     nsCAutoString path;
00147     nsAutoString unipath;
00148 
00149     LogError(aMessage, code);
00150     localFile->GetNativePath(path);
00151     if(NS_SUCCEEDED(NS_CopyNativeToUnicode(path, unipath)))
00152         mInstall->LogComment(unipath);
00153 }
00154 
00155 void nsRegisterItem::LogError(const nsAString& aMessage, nsresult code)
00156 {
00157     char resultString[12];
00158 
00159     PR_snprintf(resultString, 12, "0x%lx", code);
00160     mInstall->LogComment(aMessage + NS_LITERAL_STRING(" - nsresult code: ") +
00161                          NS_ConvertASCIItoUTF16(resultString));
00162 }
00163 
00164 PRInt32 nsRegisterItem::Prepare()
00165 {
00166     // The chrome must exist
00167     PRBool exists;
00168     nsresult rv = mChrome->Exists(&exists);
00169     if (NS_FAILED(rv))
00170         return nsInstall::UNEXPECTED_ERROR;
00171     if (!exists)
00172         return nsInstall::DOES_NOT_EXIST;
00173 
00174 
00175     // Are we dealing with a directory (flat chrome) or an archive?
00176     PRBool isDir;
00177     rv = mChrome->IsDirectory(&isDir);
00178     if (NS_FAILED(rv))
00179         return nsInstall::UNEXPECTED_ERROR;
00180 
00181 
00182     // Can we construct a resource: URL or do we need a file: URL instead?
00183     // find the xpcom directory and see if mChrome is a child
00184     PRBool isChild = PR_FALSE;
00185     mProgDir = nsSoftwareUpdate::GetProgramDirectory();
00186     if (!mProgDir)
00187     {
00188         // not in the wizard, so ask the directory service where it is
00189         nsCOMPtr<nsIProperties> dirService(
00190                 do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
00191         if(NS_SUCCEEDED(rv))
00192         {
00193             NS_ASSERTION(dirService,"directory service lied to us");
00194             rv = dirService->Get(NS_XPCOM_CURRENT_PROCESS_DIR,
00195                         NS_GET_IID(nsIFile), getter_AddRefs(mProgDir));
00196         }
00197     }
00198     if (NS_SUCCEEDED(rv))
00199     {
00200         NS_ASSERTION(mProgDir,"NS_SUCCESS but no mProgDir");
00201         rv = mProgDir->Contains(mChrome, PR_TRUE, &isChild);
00202         if (NS_FAILED(rv)) 
00203             return nsInstall::UNEXPECTED_ERROR;
00204     }
00205     else
00206         return nsInstall::UNEXPECTED_ERROR;
00207 
00208 
00209     // Either way we need the file: URL to the chrome
00210     nsXPIDLCString localURL;
00211     rv = GetURLFromIFile( mChrome, getter_Copies(localURL) );
00212     if (NS_FAILED(rv))
00213         return nsInstall::UNEXPECTED_ERROR;
00214 
00215     // see what kind of URL we have to construct
00216     if (!isChild)
00217     {
00218         // Not relative so use the file:// URL we got above
00219         PRInt32 urlLen = strlen(localURL) + mPath.Length();
00220 
00221         if (isDir)
00222         {
00223             // "flat" chrome, urlLen is suffient
00224             mURL.SetCapacity( urlLen );
00225         }
00226         else
00227         {
00228             // archive, add room for jar: syntax (over by one, but harmless)
00229             mURL.SetCapacity( urlLen + sizeof("jar:") + sizeof('!') );
00230             mURL = "jar:";
00231         }
00232         mURL.Append(localURL);
00233     }
00234     else
00235     {
00236         // we can construct a resource: URL to chrome in a subdir
00237         nsXPIDLCString binURL;
00238         rv = GetURLFromIFile( mProgDir, getter_Copies(binURL) );
00239         if (NS_FAILED(rv))
00240             return nsInstall::UNEXPECTED_ERROR;
00241 
00242         PRInt32 binLen = strlen(binURL);
00243         const char *subURL = localURL + binLen;
00244         PRInt32 padding = sizeof("resource:/") + sizeof("jar:!/");
00245 
00246         mURL.SetCapacity( strlen(subURL) + mPath.Length() + padding );
00247 
00248         if (!isDir)
00249             mURL = "jar:";
00250 
00251         mURL.Append("resource:/");
00252         mURL.Append(subURL);
00253     }
00254 
00255         
00256     if (!isDir)
00257     {
00258         // need jar: URL closing bang-slash
00259         mURL.Append("!/");
00260     }
00261     else
00262     {
00263         // Necko should already slash-terminate directory file:// URLs
00264         NS_ASSERTION(mURL[mURL.Length()-1] == '/', "Necko changed the rules");
00265     }
00266 
00267     // add on "extra" subpath to new content.rdf
00268     mURL.Append(mPath);
00269 
00270     return nsInstall::SUCCESS;
00271 }
00272 
00273 PRInt32 nsRegisterItem::Complete()
00274 {
00275     nsresult rv = NS_OK;
00276     PRInt32 result = nsInstall::SUCCESS;
00277     CHROMEREG_IFACE* reg = mInstall->GetChromeRegistry();
00278 #ifndef MOZ_XUL_APP
00279     PRBool  isProfile = mChromeType & CHROME_PROFILE;
00280 #endif
00281 
00282     if ( reg && !(mChromeType & CHROME_DELAYED) )
00283     {
00284 #ifdef MOZ_XUL_APP
00285         nsCOMPtr<nsIURI> baseuri;
00286         rv = NS_NewURI(getter_AddRefs(baseuri), mURL);
00287         if (NS_FAILED(rv)) {
00288             LogError(NS_LITERAL_STRING("NS_NewURI failed."), rv);
00289         }
00290         else {
00291             nsCOMPtr<nsIURI> manifesturi;
00292             rv = NS_NewURI(getter_AddRefs(manifesturi),
00293                            NS_LITERAL_CSTRING("resource:///chrome/xpinstall.manifest"));
00294             if (NS_FAILED(rv)) {
00295                 LogError(NS_LITERAL_STRING("NS_NewURI failed."), rv);
00296             }
00297             else {
00298                 PRBool skinOnly = (mChromeType & CHROME_ALL) == CHROME_SKIN;
00299                 rv = reg->ProcessContentsManifest(baseuri, manifesturi,
00300                                                   baseuri, PR_TRUE,
00301                                                   skinOnly);
00302                 if (NS_FAILED(rv)) {
00303                     LogError(NS_LITERAL_STRING("ProcessContentsManifest failed."), rv);
00304                 }
00305                 reg->CheckForNewChrome();
00306             }
00307         }
00308 #else
00309         // We can register right away
00310         if (mChromeType & CHROME_SKIN)
00311             rv = reg->InstallSkin(mURL.get(), isProfile, PR_TRUE);
00312         if (NS_FAILED(rv)) {
00313             LogError(NS_LITERAL_STRING("InstallSkin() failed."), rv);
00314         }
00315 
00316         if (NS_SUCCEEDED(rv) && (mChromeType & CHROME_LOCALE))
00317             rv = reg->InstallLocale(mURL.get(), isProfile);
00318         if (NS_FAILED(rv)) {
00319             LogError(NS_LITERAL_STRING("InstallLocale() failed."), rv);
00320         }
00321 
00322         if (NS_SUCCEEDED(rv) && (mChromeType & CHROME_CONTENT))
00323             rv = reg->InstallPackage(mURL.get(), isProfile);
00324         if (NS_FAILED(rv)) {
00325             LogError(NS_LITERAL_STRING("InstallPackage() failed."), rv);
00326         }
00327 #endif
00328     }
00329     else
00330     {
00331         // Either script asked for delayed chrome or we can't find
00332         // the chrome registry to do it now.
00333 
00334         // construct a reference to the magic file
00335         PRFileDesc* fd = nsnull;
00336         nsCOMPtr<nsIFile> tmp;
00337         PRBool bExists = PR_FALSE;
00338         if (!nsSoftwareUpdate::GetProgramDirectory())  // not in the stub installer
00339         { 
00340             nsCOMPtr<nsIProperties> directoryService = 
00341                      do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
00342             if (NS_FAILED(rv)) {
00343                 LogError(NS_LITERAL_STRING("failed to get directory service."), rv);
00344             }
00345             if (NS_SUCCEEDED(rv) && directoryService) 
00346             {
00347                 rv = directoryService->Get(NS_APP_CHROME_DIR, 
00348                                        NS_GET_IID(nsIFile), 
00349                                        getter_AddRefs(tmp));
00350                 if(NS_FAILED(rv))
00351                 {
00352                     LogError(NS_LITERAL_STRING("failed get application chrome directory."), rv);
00353                     result = nsInstall::CHROME_REGISTRY_ERROR;
00354                     return result;
00355                 }
00356             }
00357         }
00358         else
00359         {
00360             rv = nsSoftwareUpdate::GetProgramDirectory()->Clone(getter_AddRefs(tmp));
00361 
00362             if (NS_SUCCEEDED(rv))
00363             {
00364                 tmp->AppendNative(INSTALL_CHROME_DIR);
00365             } else {
00366                 LogError(NS_LITERAL_STRING("failed to clone program directory. (not critical)"), rv);
00367             }
00368         }
00369         nsCOMPtr<nsILocalFile> startupFile( do_QueryInterface(tmp, &rv) );
00370 
00371         if (NS_SUCCEEDED(rv))
00372         {
00373             rv = startupFile->Exists(&bExists);
00374             if(NS_FAILED(rv))
00375             {
00376                 LogErrorWithFilename(NS_LITERAL_STRING("directory existance check failed."), rv, startupFile);
00377             }
00378             if (NS_SUCCEEDED(rv) && !bExists)
00379                 rv = startupFile->Create(nsIFile::DIRECTORY_TYPE, 0755);
00380             if (NS_SUCCEEDED(rv))
00381             {
00382                 rv = startupFile->AppendNative(NS_LITERAL_CSTRING("installed-chrome.txt"));
00383                 if (NS_SUCCEEDED(rv))
00384                 {
00385                     rv = startupFile->OpenNSPRFileDesc(
00386                                     PR_CREATE_FILE | PR_WRONLY,
00387                                     0744,
00388                                     &fd);
00389                     if(NS_FAILED(rv))
00390                     {
00391                         LogErrorWithFilename(NS_LITERAL_STRING("opening of installed-chrome.txt failed."), rv, startupFile);
00392                     }
00393                 } else {
00394                     LogError(NS_LITERAL_STRING("String append failed."), rv);
00395                 }
00396             } else {
00397                 LogErrorWithFilename(NS_LITERAL_STRING("startup directory creation failed."), rv, startupFile);
00398             }
00399         }
00400 
00401         if ( NS_SUCCEEDED(rv) && fd )
00402         {
00403             PR_Seek(fd, 0, PR_SEEK_END);
00404             const char* location = (mChromeType & CHROME_PROFILE) ? "profile" : "install";
00405 
00406             if (NS_SUCCEEDED(rv)/* && path*/)
00407             {
00408                 PRInt32 written, actual;
00409                 char* installStr = nsnull;
00410        
00411                 // this looks redundant, but a single registerChrome()
00412                 // call can register all three types.
00413                 if (mChromeType & CHROME_SKIN)
00414                 {
00415                     installStr = PR_smprintf("skin,%s,url,%s\n",
00416                                              location, mURL.get());
00417                     if (installStr)
00418                     {
00419                         actual = strlen(installStr);
00420                         written = PR_Write(fd, installStr, actual);
00421                         if ( written != actual ) 
00422                         {
00423                             LogErrorWithFilename(NS_LITERAL_STRING("writing to installed-chrome.txt failed."), rv, startupFile);
00424                             result = nsInstall::CHROME_REGISTRY_ERROR;
00425                         }
00426                         PR_smprintf_free(installStr);
00427                     }
00428                     else 
00429                         result = nsInstall::OUT_OF_MEMORY;
00430                 }
00431 
00432                 if (mChromeType & CHROME_LOCALE)
00433                 {
00434                     installStr = PR_smprintf("locale,%s,url,%s\n",
00435                                              location, mURL.get());
00436                     if (installStr)
00437                     {
00438                         actual = strlen(installStr);
00439                         written = PR_Write(fd, installStr, actual);
00440                         if ( written != actual ) 
00441                         {
00442                             LogErrorWithFilename(NS_LITERAL_STRING("writing to installed-chrome.txt failed."), rv, startupFile);
00443                             result = nsInstall::CHROME_REGISTRY_ERROR;
00444                         }
00445                         PR_smprintf_free(installStr);
00446                     }
00447                     else
00448                         result = nsInstall::OUT_OF_MEMORY;
00449                 }
00450 
00451                 if (mChromeType & CHROME_CONTENT)
00452                 {
00453                     installStr = PR_smprintf("content,%s,url,%s\n",
00454                                              location, mURL.get());
00455                     if (installStr)
00456                     {
00457                         actual = strlen(installStr);
00458                         written = PR_Write(fd, installStr, actual);
00459                         if ( written != actual ) 
00460                         {
00461                             LogErrorWithFilename(NS_LITERAL_STRING("writing to installed-chrome.txt failed."), rv, startupFile);
00462                             result = nsInstall::CHROME_REGISTRY_ERROR;
00463                         }
00464                         PR_smprintf_free(installStr);
00465                     }
00466                     else
00467                         result = nsInstall::OUT_OF_MEMORY;
00468                 }
00469             }
00470             PR_Close(fd);
00471 
00472 #ifdef MOZ_XUL_APP
00473             // app-chrome.manifest is not regenerated if it exists
00474             rv = startupFile->SetNativeLeafName(NS_LITERAL_CSTRING("app-chrome.manifest"));
00475             if (NS_SUCCEEDED(rv))
00476                 startupFile->Remove(PR_FALSE);
00477 #endif
00478         }
00479         else
00480         {
00481             LogError(NS_LITERAL_STRING("opening of installed-chrome.txt failed."), rv);
00482             result = nsInstall::CHROME_REGISTRY_ERROR;
00483         }
00484     }
00485 
00486     if (NS_FAILED(rv))
00487     {
00488         LogError(NS_LITERAL_STRING("Failed to register chrome."), rv);
00489         result = nsInstall::CHROME_REGISTRY_ERROR;
00490     }
00491 
00492     return result;
00493 }
00494 
00495 void nsRegisterItem::Abort()
00496 {
00497     // nothing to undo
00498 }
00499 
00500 char* nsRegisterItem::toString()
00501 {
00502     char* buffer = new char[1024];
00503     char* rsrcVal = nsnull;
00504 
00505     if (buffer == nsnull || !mInstall)
00506         return nsnull;
00507 
00508     buffer[0] = '\0';
00509     switch (mChromeType & CHROME_ALL)
00510     {
00511     case CHROME_SKIN:
00512         rsrcVal = mInstall->GetResourcedString(
00513                     NS_LITERAL_STRING("RegSkin"));
00514         break;
00515     case CHROME_LOCALE:
00516         rsrcVal = mInstall->GetResourcedString(
00517                     NS_LITERAL_STRING("RegLocale"));
00518         break;
00519     case CHROME_CONTENT:
00520         rsrcVal = mInstall->GetResourcedString(
00521                     NS_LITERAL_STRING("RegContent"));
00522         break;
00523     default:
00524         rsrcVal = mInstall->GetResourcedString(
00525                     NS_LITERAL_STRING("RegPackage"));
00526         break;
00527     }
00528 
00529     if (rsrcVal)
00530     {
00531         PR_snprintf(buffer, 1024, rsrcVal, mURL.get());
00532         nsCRT::free(rsrcVal);
00533     }
00534 
00535     return buffer;
00536 }
00537 
00538 
00539 PRBool
00540 nsRegisterItem::CanUninstall()
00541 {
00542     return PR_FALSE;
00543 }
00544 
00545 PRBool
00546 nsRegisterItem::RegisterPackageNode()
00547 {
00548     return PR_FALSE;
00549 }
00550 
00551 nsresult
00552 nsRegisterItem::GetURLFromIFile(nsIFile* aFile, char** aOutURL)
00553 {
00554     if (!aFile || !aOutURL)
00555     {
00556         NS_WARNING("bogus arg passed to nsRegisterItem::GetURLFromIFile()");
00557         return NS_ERROR_NULL_POINTER;
00558     }
00559     *aOutURL = nsnull;
00560 
00561     // try to use Necko to create the URL; if that fails (as
00562     // it will for the install wizards which don't have Necko)
00563     // then use warren's local hack.
00564 
00565     nsCAutoString spec;
00566     nsresult rv = NS_GetURLSpecFromFile(aFile, spec);
00567     if (NS_FAILED(rv))
00568         rv = hack_nsIFile2URL(aFile, aOutURL);
00569     else {
00570         *aOutURL = ToNewCString(spec);
00571         if (!*aOutURL)
00572             rv = NS_ERROR_OUT_OF_MEMORY;
00573     }
00574 
00575     return rv;
00576 }
00577