Back to index

lightning-sunbird  0.9+nobinonly
nsAppRunner.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client 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  *   Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
00024  *   Benjamin Smedberg <benjamin@smedbergs.us>
00025  *   Ben Goodger <ben@mozilla.org>
00026  *   Fredrik Holmqvist <thesuckiestemail@yahoo.se>
00027  *   Ben Turner <mozilla@songbirdnest.com>
00028  *
00029  * Alternatively, the contents of this file may be used under the terms of
00030  * either the GNU General Public License Version 2 or later (the "GPL"), or
00031  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00032  * in which case the provisions of the GPL or the LGPL are applicable instead
00033  * of those above. If you wish to allow use of your version of this file only
00034  * under the terms of either the GPL or the LGPL, and not to allow others to
00035  * use your version of this file under the terms of the MPL, indicate your
00036  * decision by deleting the provisions above and replace them with the notice
00037  * and other provisions required by the GPL or the LGPL. If you do not delete
00038  * the provisions above, a recipient may use your version of this file under
00039  * the terms of any one of the MPL, the GPL or the LGPL.
00040  *
00041  * ***** END LICENSE BLOCK ***** */
00042 
00043 #if defined(XP_OS2) && defined(MOZ_OS2_HIGH_MEMORY)
00044 // os2safe.h has to be included before os2.h, needed for high mem
00045 #include <os2safe.h>
00046 #endif
00047 
00048 #define XPCOM_TRANSLATE_NSGM_ENTRY_POINT 1
00049 
00050 #include "nsAppRunner.h"
00051 #include "nsUpdateDriver.h"
00052 #include "nsBuildID.h"
00053 
00054 #ifdef XP_MACOSX
00055 #include "MacLaunchHelper.h"
00056 #endif
00057 
00058 #ifdef XP_OS2
00059 #include "private/pprthred.h"
00060 #endif
00061 #include "plevent.h"
00062 #include "prmem.h"
00063 #include "prnetdb.h"
00064 #include "prprf.h"
00065 #include "prproces.h"
00066 #include "prenv.h"
00067 
00068 #include "nsIAppShellService.h"
00069 #include "nsIAppStartup.h"
00070 #include "nsIAppStartupNotifier.h"
00071 #include "nsIArray.h"
00072 #include "nsICategoryManager.h"
00073 #include "nsIChromeRegistry.h"
00074 #include "nsICommandLineRunner.h"
00075 #include "nsIComponentManager.h"
00076 #include "nsIComponentRegistrar.h"
00077 #include "nsIContentHandler.h"
00078 #include "nsIDialogParamBlock.h"
00079 #include "nsIDOMWindow.h"
00080 #include "nsIEventQueueService.h"
00081 #include "nsIExtensionManager.h"
00082 #include "nsIFastLoadService.h" // for PLATFORM_FASL_SUFFIX
00083 #include "nsIGenericFactory.h"
00084 #include "nsIIOService.h"
00085 #include "nsIObserverService.h"
00086 #include "nsINativeAppSupport.h"
00087 #include "nsIProcess.h"
00088 #include "nsIProfileUnlocker.h"
00089 #include "nsIPromptService.h"
00090 #include "nsIServiceManager.h"
00091 #include "nsIStringBundle.h"
00092 #include "nsISupportsPrimitives.h"
00093 #include "nsITimelineService.h"
00094 #include "nsIToolkitChromeRegistry.h"
00095 #include "nsIToolkitProfile.h"
00096 #include "nsIToolkitProfileService.h"
00097 #include "nsIURI.h"
00098 #include "nsIWindowCreator.h"
00099 #include "nsIWindowMediator.h"
00100 #include "nsIWindowWatcher.h"
00101 #include "nsIXULAppInfo.h"
00102 #include "nsIXULRuntime.h"
00103 #ifdef XP_WIN
00104 #include "nsIWinAppHelper.h"
00105 #endif
00106 
00107 #include "nsCRT.h"
00108 #include "nsCOMPtr.h"
00109 #include "nsDirectoryServiceDefs.h"
00110 #include "nsDirectoryServiceUtils.h"
00111 #include "nsEmbedCID.h"
00112 #include "nsNetUtil.h"
00113 #include "nsStaticComponents.h"
00114 #include "nsXPCOM.h"
00115 #include "nsXPIDLString.h"
00116 #include "nsXPFEComponentsCID.h"
00117 
00118 #include "nsAppDirectoryServiceDefs.h"
00119 #include "nsXULAppAPI.h"
00120 #include "nsXREDirProvider.h"
00121 #include "nsToolkitCompsCID.h"
00122 
00123 #include "nsINIParser.h"
00124 
00125 #include "InstallCleanupDefines.h"
00126 
00127 #include <stdlib.h>
00128 
00129 #ifdef XP_UNIX
00130 #include <sys/stat.h>
00131 #include <unistd.h>
00132 #endif
00133 
00134 #ifdef XP_BEOS
00135 // execv() behaves bit differently in R5 and Zeta, looks unreliable in such situation
00136 //#include <unistd.h>
00137 #include <AppKit.h>
00138 #include <AppFileInfo.h>
00139 #endif //XP_BEOS
00140 
00141 #ifdef XP_WIN
00142 #include <process.h>
00143 #include <shlobj.h>
00144 #ifndef CSIDL_PROGRAM_FILES
00145 #define CSIDL_PROGRAM_FILES   0x0026
00146 #endif
00147 #endif
00148 
00149 #ifdef XP_OS2
00150 #include <process.h>
00151 #endif
00152 
00153 #ifdef XP_MACOSX
00154 #include "nsILocalFileMac.h"
00155 #include "nsCommandLineServiceMac.h"
00156 #endif
00157 
00158 // for X remote support
00159 #ifdef MOZ_ENABLE_XREMOTE
00160 #ifdef MOZ_WIDGET_PHOTON
00161 #include "PhRemoteClient.h"
00162 #else
00163 #include "XRemoteClient.h"
00164 #endif
00165 #include "nsIRemoteService.h"
00166 #endif
00167 
00168 #ifdef NS_TRACE_MALLOC
00169 #include "nsTraceMalloc.h"
00170 #endif
00171 
00172 #if defined(DEBUG) && defined(XP_WIN32)
00173 #include <malloc.h>
00174 #endif
00175 
00176 #if defined (XP_MACOSX)
00177 #include <Processes.h>
00178 #include <Events.h>
00179 #endif
00180 
00181 extern "C" void ShowOSAlert(const char* aMessage);
00182 
00183 #define HELP_SPACER_1   "\t"
00184 #define HELP_SPACER_2   "\t\t"
00185 #define HELP_SPACER_4   "\t\t\t\t"
00186 
00187 #ifdef DEBUG
00188 #include "prlog.h"
00189 #endif
00190 
00191 #ifdef MOZ_JPROF
00192 #include "jprof.h"
00193 #endif
00194 
00195 // on x86 linux, the current builds of some popular plugins (notably
00196 // flashplayer and real) expect a few builtin symbols from libgcc
00197 // which were available in some older versions of gcc.  However,
00198 // they're _NOT_ available in newer versions of gcc (eg 3.1), so if
00199 // we want those plugin to work with a gcc-3.1 built binary, we need
00200 // to provide these symbols.  MOZ_ENABLE_OLD_ABI_COMPAT_WRAPPERS defaults
00201 // to true on x86 linux, and false everywhere else.
00202 //
00203 // The fact that the new and free operators are mismatched 
00204 // mirrors the way the original functions in egcs 1.1.2 worked.
00205 
00206 #ifdef MOZ_ENABLE_OLD_ABI_COMPAT_WRAPPERS
00207 
00208 extern "C" {
00209 
00210 # ifndef HAVE___BUILTIN_VEC_NEW
00211   void *__builtin_vec_new(size_t aSize, const std::nothrow_t &aNoThrow) throw()
00212   {
00213     return ::operator new(aSize, aNoThrow);
00214   }
00215 # endif
00216 
00217 # ifndef HAVE___BUILTIN_VEC_DELETE
00218   void __builtin_vec_delete(void *aPtr, const std::nothrow_t &) throw ()
00219   {
00220     if (aPtr) {
00221       free(aPtr);
00222     }
00223   }
00224 # endif
00225 
00226 # ifndef HAVE___BUILTIN_NEW
00227        void *__builtin_new(int aSize)
00228   {
00229     return malloc(aSize);
00230   }
00231 # endif
00232 
00233 # ifndef HAVE___BUILTIN_DELETE
00234        void __builtin_delete(void *aPtr)
00235   {
00236     free(aPtr);
00237   }
00238 # endif
00239 
00240 # ifndef HAVE___PURE_VIRTUAL
00241   void __pure_virtual(void) {
00242 #ifdef WRAP_SYSTEM_INCLUDES
00243 #pragma GCC visibility push(default)
00244 #endif
00245     extern void __cxa_pure_virtual(void);
00246 #ifdef WRAP_SYSTEM_INCLUDES
00247 #pragma GCC visibility pop
00248 #endif
00249 
00250     __cxa_pure_virtual();
00251   }
00252 # endif
00253 }
00254 #endif
00255 
00256 #if defined(XP_UNIX) || defined(XP_BEOS)
00257   extern void InstallUnixSignalHandlers(const char *ProgramName);
00258 #endif
00259 
00260 int    gArgc;
00261 char **gArgv;
00262 
00263 static int    gRestartArgc;
00264 static char **gRestartArgv;
00265 
00266 #if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_GTK2)
00267 #include <gtk/gtk.h>
00268 #endif //MOZ_WIDGET_GTK || MOZ_WIDGET_GTK2
00269 
00270 #if defined(MOZ_WIDGET_QT)
00271 #include <qapplication.h>
00272 #endif
00273 
00274 // Save the path of the given file to the specified environment variable.
00275 static void
00276 SaveFileToEnv(const char *name, nsIFile *file)
00277 {
00278   nsCAutoString path;
00279   file->GetNativePath(path);
00280 
00281   char *expr = PR_smprintf("%s=%s", name, path.get());
00282   if (expr)
00283     PR_SetEnv(expr);
00284   // We intentionally leak |expr| here since it is required by PR_SetEnv.
00285 }
00286 
00287 // Save the path of the given file to the specified environment variable
00288 // provided the environment variable does not have a value.
00289 static void
00290 SaveFileToEnvIfUnset(const char *name, nsIFile *file)
00291 {
00292   const char *val = PR_GetEnv(name);
00293   if (!(val && *val))
00294     SaveFileToEnv(name, file);
00295 }
00296 
00297 static PRBool
00298 strimatch(const char* lowerstr, const char* mixedstr)
00299 {
00300   while(*lowerstr) {
00301     if (!*mixedstr) return PR_FALSE; // mixedstr is shorter
00302     if (tolower(*mixedstr) != *lowerstr) return PR_FALSE; // no match
00303 
00304     ++lowerstr;
00305     ++mixedstr;
00306   }
00307 
00308   if (*mixedstr) return PR_FALSE; // lowerstr is shorter
00309 
00310   return PR_TRUE;
00311 }
00312 
00313 enum RemoteResult {
00314   REMOTE_NOT_FOUND  = 0,
00315   REMOTE_FOUND      = 1,
00316   REMOTE_ARG_BAD    = 2
00317 };
00318 
00319 enum ArgResult {
00320   ARG_NONE  = 0,
00321   ARG_FOUND = 1,
00322   ARG_BAD   = 2 // you wanted a param, but there isn't one
00323 };
00324 
00325 static void RemoveArg(char **argv)
00326 {
00327   do {
00328     *argv = *(argv + 1);
00329     ++argv;
00330   } while (*argv);
00331 
00332   --gArgc;
00333 }
00334 
00346 static ArgResult
00347 CheckArg(const char* aArg, PRBool aCheckOSInt = PR_FALSE, const char **aParam = nsnull)
00348 {
00349   char **curarg = gArgv + 1; // skip argv[0]
00350   ArgResult ar = ARG_NONE;
00351 
00352   while (*curarg) {
00353     char *arg = curarg[0];
00354 
00355     if (arg[0] == '-'
00356 #if defined(XP_WIN) || defined(XP_OS2)
00357         || *arg == '/'
00358 #endif
00359         ) {
00360       ++arg;
00361       if (*arg == '-')
00362         ++arg;
00363 
00364       if (strimatch(aArg, arg)) {
00365         RemoveArg(curarg);
00366         if (!aParam) {
00367           ar = ARG_FOUND;
00368           break;
00369         }
00370 
00371         if (*curarg) {
00372           if (**curarg == '-'
00373 #if defined(XP_WIN) || defined(XP_OS2)
00374               || **curarg == '/'
00375 #endif
00376               )
00377             return ARG_BAD;
00378 
00379           *aParam = *curarg;
00380           RemoveArg(curarg);
00381           ar = ARG_FOUND;
00382           break;
00383         }
00384         return ARG_BAD;
00385       }
00386     }
00387 
00388     ++curarg;
00389   }
00390 
00391   if (aCheckOSInt && ar == ARG_FOUND) {
00392     ArgResult arOSInt = CheckArg("osint");
00393     if (arOSInt == ARG_FOUND) {
00394       ar = ARG_BAD;
00395       PR_fprintf(PR_STDERR, "Error: argument -osint is invalid\n");
00396     }
00397   }
00398 
00399   return ar;
00400 }
00401 
00402 #if defined(XP_WIN)
00403 
00409 static ArgResult
00410 CheckArgShell(const char* aArg)
00411 {
00412   char **curarg = gRestartArgv + 1; // skip argv[0]
00413 
00414   while (*curarg) {
00415     char *arg = curarg[0];
00416 
00417     if (arg[0] == '-') {
00418       ++arg;
00419 
00420       if (strimatch(aArg, arg)) {
00421         do {
00422           *curarg = *(curarg + 1);
00423           ++curarg;
00424         } while (*curarg);
00425 
00426         --gRestartArgc;
00427 
00428         return ARG_FOUND;
00429       }
00430     }
00431 
00432     ++curarg;
00433   }
00434 
00435   return ARG_NONE;
00436 }
00437 
00444 static void
00445 ProcessDDE(nsINativeAppSupport* aNative)
00446 {
00447   // When the app is launched by the windows shell the windows shell
00448   // expects the app to be available for DDE messages and if it isn't
00449   // windows displays an error dialog. To prevent the error the DDE server
00450   // is enabled and pending events are processed when the app needs to
00451   // restart after it was launched by the shell with the requestpending
00452   // argument. The requestpending pending argument is removed to
00453   // differentiate it from being launched when an app restart is not
00454   // required.
00455   ArgResult ar;
00456   ar = CheckArgShell("requestpending");
00457   if (ar == ARG_FOUND) {
00458     aNative->Enable(); // enable win32 DDE responses
00459 
00460     nsresult rv;
00461     nsCOMPtr<nsIEventQueueService> eventQService(do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv));
00462     if (NS_SUCCEEDED(rv) && eventQService) {
00463       nsCOMPtr<nsIEventQueue> queue;
00464       rv = eventQService->GetThreadEventQueue(NS_CURRENT_THREAD,
00465                                               getter_AddRefs(queue));
00466       if (NS_SUCCEEDED(rv) && queue) {
00467         // This is just a guesstimate based on testing different values.
00468         // If count is 8 or less windows will display an error dialog.
00469         PRInt32 count = 20;
00470         while(--count >= 0) {
00471           queue->ProcessPendingEvents();
00472           PR_Sleep(PR_MillisecondsToInterval(1));
00473         }
00474       }
00475     }
00476   }
00477 }
00478 #endif
00479 
00480 PRBool gSafeMode = PR_FALSE;
00481 
00486 class nsXULAppInfo : public nsIXULAppInfo,
00487 #ifdef XP_WIN
00488                      public nsIWinAppHelper,
00489 #endif
00490                      public nsIXULRuntime
00491                      
00492 {
00493 public:
00494   NS_DECL_ISUPPORTS_INHERITED
00495   NS_DECL_NSIXULAPPINFO
00496   NS_DECL_NSIXULRUNTIME
00497 #ifdef XP_WIN
00498   NS_DECL_NSIWINAPPHELPER
00499 private:
00500   nsresult LaunchAppHelperWithArgs(int aArgc, char **aArgv);
00501 #endif
00502 };
00503 
00504 NS_INTERFACE_MAP_BEGIN(nsXULAppInfo)
00505   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULRuntime)
00506   NS_INTERFACE_MAP_ENTRY(nsIXULRuntime)
00507 #ifdef XP_WIN
00508   NS_INTERFACE_MAP_ENTRY(nsIWinAppHelper)
00509 #endif
00510   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIXULAppInfo, gAppData)
00511 NS_INTERFACE_MAP_END
00512 
00513 NS_IMETHODIMP_(nsrefcnt)
00514 nsXULAppInfo::AddRef()
00515 {
00516   return 1;
00517 }
00518 
00519 NS_IMETHODIMP_(nsrefcnt)
00520 nsXULAppInfo::Release()
00521 {
00522   return 1;
00523 }
00524 
00525 NS_IMETHODIMP
00526 nsXULAppInfo::GetVendor(nsACString& aResult)
00527 {
00528   aResult.Assign(gAppData->vendor);
00529 
00530   return NS_OK;
00531 }
00532 
00533 NS_IMETHODIMP
00534 nsXULAppInfo::GetName(nsACString& aResult)
00535 {
00536   aResult.Assign(gAppData->name);
00537 
00538   return NS_OK;
00539 }
00540 
00541 NS_IMETHODIMP
00542 nsXULAppInfo::GetID(nsACString& aResult)
00543 {
00544   aResult.Assign(gAppData->ID);
00545 
00546   return NS_OK;
00547 }
00548 
00549 NS_IMETHODIMP
00550 nsXULAppInfo::GetVersion(nsACString& aResult)
00551 {
00552   aResult.Assign(gAppData->version);
00553 
00554   return NS_OK;
00555 }
00556 
00557 NS_IMETHODIMP
00558 nsXULAppInfo::GetPlatformVersion(nsACString& aResult)
00559 {
00560   aResult.AssignLiteral(TOOLKIT_EM_VERSION);
00561 
00562   return NS_OK;
00563 }
00564 
00565 NS_IMETHODIMP
00566 nsXULAppInfo::GetAppBuildID(nsACString& aResult)
00567 {
00568   aResult.Assign(gAppData->buildID);
00569 
00570   return NS_OK;
00571 }
00572 
00573 NS_IMETHODIMP
00574 nsXULAppInfo::GetPlatformBuildID(nsACString& aResult)
00575 {
00576   aResult.Assign(NS_STRINGIFY(BUILD_ID));
00577 
00578   return NS_OK;
00579 }
00580 
00581 NS_IMETHODIMP
00582 nsXULAppInfo::GetLogConsoleErrors(PRBool *aResult)
00583 {
00584   *aResult = gLogConsoleErrors;
00585   return NS_OK;
00586 }
00587 
00588 NS_IMETHODIMP
00589 nsXULAppInfo::SetLogConsoleErrors(PRBool aValue)
00590 {
00591   gLogConsoleErrors = aValue;
00592   return NS_OK;
00593 }
00594 
00595 NS_IMETHODIMP
00596 nsXULAppInfo::GetInSafeMode(PRBool *aResult)
00597 {
00598   *aResult = gSafeMode;
00599   return NS_OK;
00600 }
00601 
00602 NS_IMETHODIMP
00603 nsXULAppInfo::GetOS(nsACString& aResult)
00604 {
00605   aResult.AssignLiteral(OS_TARGET);
00606   return NS_OK;
00607 }
00608 
00609 NS_IMETHODIMP
00610 nsXULAppInfo::GetXPCOMABI(nsACString& aResult)
00611 {
00612 #ifdef TARGET_XPCOM_ABI
00613   aResult.AssignLiteral(TARGET_XPCOM_ABI);
00614   return NS_OK;
00615 #else
00616   return NS_ERROR_NOT_AVAILABLE;
00617 #endif
00618 }
00619 
00620 #ifdef XP_WIN
00621 nsresult 
00622 nsXULAppInfo::LaunchAppHelperWithArgs(int aArgc, char **aArgv)
00623 {
00624   nsresult rv;
00625   nsCOMPtr<nsIProperties> directoryService = 
00626     do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
00627   NS_ENSURE_SUCCESS(rv, rv);
00628 
00629   nsCOMPtr<nsILocalFile> appHelper;
00630   rv = directoryService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(appHelper));
00631   NS_ENSURE_SUCCESS(rv, rv);
00632 
00633   rv = appHelper->AppendNative(NS_LITERAL_CSTRING("uninstall"));
00634   NS_ENSURE_SUCCESS(rv, rv);
00635 
00636   rv = appHelper->AppendNative(NS_LITERAL_CSTRING("helper.exe"));
00637   NS_ENSURE_SUCCESS(rv, rv);
00638 
00639   nsCAutoString appHelperPath;
00640   rv = appHelper->GetNativePath(appHelperPath);
00641   NS_ENSURE_SUCCESS(rv, rv);
00642 
00643   if (!WinLaunchChild(appHelperPath.get(), aArgc, aArgv, 1))
00644     return NS_ERROR_FAILURE;
00645   else
00646     return NS_OK;
00647 }
00648 
00649 NS_IMETHODIMP
00650 nsXULAppInfo::FixReg()
00651 {
00652   int resetRegArgc = 2;
00653   char **resetRegArgv = (char**) malloc(sizeof(char*) * (resetRegArgc + 1));
00654   if (!resetRegArgv)
00655     return NS_ERROR_OUT_OF_MEMORY;
00656 
00657   resetRegArgv[0] = "argv0ignoredbywinlaunchchild";
00658   resetRegArgv[1] = "/fixreg";
00659   resetRegArgv[2] = nsnull;
00660   nsresult rv = LaunchAppHelperWithArgs(resetRegArgc, resetRegArgv);
00661   free(resetRegArgv);
00662   return rv;
00663 }
00664 
00665 NS_IMETHODIMP
00666 nsXULAppInfo::PostUpdate(nsILocalFile *aLogFile)
00667 {
00668   nsresult rv;
00669   int upgradeArgc = aLogFile ? 3 : 2;
00670   char **upgradeArgv = (char**) malloc(sizeof(char*) * (upgradeArgc + 1));
00671 
00672   if (!upgradeArgv)
00673     return NS_ERROR_OUT_OF_MEMORY;
00674 
00675   upgradeArgv[0] = "argv0ignoredbywinlaunchchild";
00676   upgradeArgv[1] = "/postupdate";
00677 
00678   char *pathArg = nsnull;
00679 
00680   if (aLogFile) {
00681     nsCAutoString logFilePath;
00682     rv = aLogFile->GetNativePath(logFilePath);
00683     NS_ENSURE_SUCCESS(rv, rv);
00684 
00685     pathArg = PR_smprintf("/uninstalllog=%s", logFilePath.get());
00686     if (!pathArg)
00687       return NS_ERROR_OUT_OF_MEMORY;
00688 
00689     upgradeArgv[2] = pathArg;
00690     upgradeArgv[3] = nsnull;
00691   }
00692   else {
00693     upgradeArgv[2] = nsnull;
00694   }
00695 
00696   rv = LaunchAppHelperWithArgs(upgradeArgc, upgradeArgv);
00697   
00698   if (pathArg)
00699     PR_smprintf_free(pathArg);
00700 
00701   free(upgradeArgv);
00702   return rv;
00703 }
00704 #endif
00705 
00706 static const nsXULAppInfo kAppInfo;
00707 static NS_METHOD AppInfoConstructor(nsISupports* aOuter,
00708                                     REFNSIID aIID, void **aResult)
00709 {
00710   NS_ENSURE_NO_AGGREGATION(aOuter);
00711 
00712   return NS_CONST_CAST(nsXULAppInfo*, &kAppInfo)->
00713     QueryInterface(aIID, aResult);
00714 }
00715 
00716 PRBool gLogConsoleErrors
00717 #ifdef DEBUG
00718          = PR_TRUE;
00719 #else
00720          = PR_FALSE;
00721 #endif
00722 
00723 #define NS_ENSURE_TRUE_LOG(x, ret)               \
00724   PR_BEGIN_MACRO                                 \
00725   if (NS_UNLIKELY(!(x))) {                       \
00726     NS_WARNING("NS_ENSURE_TRUE(" #x ") failed"); \
00727     gLogConsoleErrors = PR_TRUE;                 \
00728     return ret;                                  \
00729   }                                              \
00730   PR_END_MACRO
00731 
00732 #define NS_ENSURE_SUCCESS_LOG(res, ret)          \
00733   NS_ENSURE_TRUE_LOG(NS_SUCCEEDED(res), ret)
00734 
00741 class ScopedXPCOMStartup
00742 {
00743 public:
00744   ScopedXPCOMStartup() :
00745     mServiceManager(nsnull) { }
00746   ~ScopedXPCOMStartup();
00747 
00748   nsresult Initialize();
00749   nsresult DoAutoreg();
00750   nsresult RegisterProfileService(nsIToolkitProfileService* aProfileService);
00751   nsresult InitEventQueue();
00752   nsresult SetWindowCreator(nsINativeAppSupport* native);
00753 
00754 private:
00755   nsIServiceManager* mServiceManager;
00756 };
00757 
00758 ScopedXPCOMStartup::~ScopedXPCOMStartup()
00759 {
00760   if (mServiceManager) {
00761     gDirServiceProvider->DoShutdown();
00762 
00763     WriteConsoleLog();
00764 
00765     NS_ShutdownXPCOM(mServiceManager);
00766     mServiceManager = nsnull;
00767   }
00768 }
00769 
00770 // {95d89e3e-a169-41a3-8e56-719978e15b12}
00771 #define APPINFO_CID \
00772   { 0x95d89e3e, 0xa169, 0x41a3, { 0x8e, 0x56, 0x71, 0x99, 0x78, 0xe1, 0x5b, 0x12 } }
00773 
00774 static nsModuleComponentInfo kComponents[] =
00775 {
00776   {
00777     "nsXULAppInfo",
00778     APPINFO_CID,
00779     XULAPPINFO_SERVICE_CONTRACTID,
00780     AppInfoConstructor
00781   }
00782 };
00783 
00784 NS_IMPL_NSGETMODULE(Apprunner, kComponents)
00785 
00786 #if !defined(_BUILD_STATIC_BIN) && !defined(MOZ_ENABLE_LIBXUL)
00787 static nsStaticModuleInfo const kXREStaticModules[] =
00788 {
00789   {
00790     "Apprunner",
00791     Apprunner_NSGetModule
00792   }
00793 };
00794 
00795 nsStaticModuleInfo const *const kPStaticModules = kXREStaticModules;
00796 PRUint32 const kStaticModuleCount = NS_ARRAY_LENGTH(kXREStaticModules);
00797 #endif
00798 
00799 nsresult
00800 ScopedXPCOMStartup::Initialize()
00801 {
00802   NS_ASSERTION(gDirServiceProvider, "Should not get here!");
00803 
00804   nsresult rv;
00805   rv = NS_InitXPCOM3(&mServiceManager, gDirServiceProvider->GetAppDir(),
00806                      gDirServiceProvider,
00807                      kPStaticModules, kStaticModuleCount);
00808   if (NS_FAILED(rv)) {
00809     NS_ERROR("Couldn't start xpcom!");
00810     mServiceManager = nsnull;
00811   }
00812   else {
00813     nsCOMPtr<nsIComponentRegistrar> reg =
00814       do_QueryInterface(mServiceManager);
00815     NS_ASSERTION(reg, "Service Manager doesn't QI to Registrar.");
00816   }
00817 
00818   return rv;
00819 }
00820 
00821 // {0C4A446C-EE82-41f2-8D04-D366D2C7A7D4}
00822 static const nsCID kNativeAppSupportCID =
00823   { 0xc4a446c, 0xee82, 0x41f2, { 0x8d, 0x4, 0xd3, 0x66, 0xd2, 0xc7, 0xa7, 0xd4 } };
00824 
00825 // {5F5E59CE-27BC-47eb-9D1F-B09CA9049836}
00826 static const nsCID kProfileServiceCID =
00827   { 0x5f5e59ce, 0x27bc, 0x47eb, { 0x9d, 0x1f, 0xb0, 0x9c, 0xa9, 0x4, 0x98, 0x36 } };
00828 
00829 nsresult
00830 ScopedXPCOMStartup::RegisterProfileService(nsIToolkitProfileService* aProfileService)
00831 {
00832   NS_ASSERTION(mServiceManager, "Not initialized!");
00833 
00834   nsCOMPtr<nsIFactory> factory = do_QueryInterface(aProfileService);
00835   NS_ASSERTION(factory, "Supposed to be an nsIFactory!");
00836 
00837   nsCOMPtr<nsIComponentRegistrar> reg (do_QueryInterface(mServiceManager));
00838   if (!reg) return NS_ERROR_NO_INTERFACE;
00839 
00840   return reg->RegisterFactory(kProfileServiceCID,
00841                               "Toolkit Profile Service",
00842                               NS_PROFILESERVICE_CONTRACTID,
00843                               factory);
00844 }
00845 
00846 nsresult
00847 ScopedXPCOMStartup::InitEventQueue()
00848 {
00849   NS_TIMELINE_ENTER("init event service");
00850   nsresult rv;
00851 
00852   nsCOMPtr<nsIEventQueueService> eventQService(do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv));
00853   NS_ENSURE_SUCCESS(rv, rv);
00854 
00855   rv = eventQService->CreateThreadEventQueue();
00856   NS_TIMELINE_LEAVE("init event service");
00857 
00858   return rv;
00859 }
00860 
00861 nsresult
00862 ScopedXPCOMStartup::DoAutoreg()
00863 {
00864 #ifdef DEBUG
00865   // _Always_ autoreg if we're in a debug build, under the assumption
00866   // that people are busily modifying components and will be angry if
00867   // their changes aren't noticed.
00868   nsCOMPtr<nsIComponentRegistrar> registrar
00869     (do_QueryInterface(mServiceManager));
00870   NS_ASSERTION(registrar, "Where's the component registrar?");
00871 
00872   registrar->AutoRegister(nsnull);
00873 #endif
00874 
00875   return NS_OK;
00876 }
00877 
00882 class nsSingletonFactory : public nsIFactory
00883 {
00884 public:
00885   NS_DECL_ISUPPORTS
00886   NS_DECL_NSIFACTORY
00887 
00888   nsSingletonFactory(nsISupports* aSingleton);
00889   ~nsSingletonFactory() { }
00890 
00891 private:
00892   nsCOMPtr<nsISupports> mSingleton;
00893 };
00894 
00895 nsSingletonFactory::nsSingletonFactory(nsISupports* aSingleton)
00896   : mSingleton(aSingleton)
00897 {
00898   NS_ASSERTION(mSingleton, "Singleton was null!");
00899 }
00900 
00901 NS_IMPL_ISUPPORTS1(nsSingletonFactory, nsIFactory)
00902 
00903 NS_IMETHODIMP
00904 nsSingletonFactory::CreateInstance(nsISupports* aOuter,
00905                                    const nsIID& aIID,
00906                                    void* *aResult)
00907 {
00908   NS_ENSURE_NO_AGGREGATION(aOuter);
00909 
00910   return mSingleton->QueryInterface(aIID, aResult);
00911 }
00912 
00913 NS_IMETHODIMP
00914 nsSingletonFactory::LockFactory(PRBool)
00915 {
00916   return NS_OK;
00917 }
00918 
00922 nsresult
00923 ScopedXPCOMStartup::SetWindowCreator(nsINativeAppSupport* native)
00924 {
00925   nsresult rv;
00926 
00927   nsCOMPtr<nsIComponentRegistrar> registrar
00928     (do_QueryInterface(mServiceManager));
00929   NS_ASSERTION(registrar, "Where's the component registrar?");
00930 
00931   nsCOMPtr<nsIFactory> nativeFactory = new nsSingletonFactory(native);
00932   NS_ENSURE_TRUE(nativeFactory, NS_ERROR_OUT_OF_MEMORY);
00933 
00934   rv = registrar->RegisterFactory(kNativeAppSupportCID,
00935                                   "Native App Support",
00936                                   NS_NATIVEAPPSUPPORT_CONTRACTID,
00937                                   nativeFactory);
00938   NS_ENSURE_SUCCESS(rv, rv);
00939 
00940   // Inform the chrome registry about OS accessibility
00941   nsCOMPtr<nsIToolkitChromeRegistry> cr (do_GetService(NS_CHROMEREGISTRY_CONTRACTID));
00942   if (cr)
00943     cr->CheckForOSAccessibility();
00944 
00945   nsCOMPtr<nsIWindowCreator> creator (do_GetService(NS_APPSTARTUP_CONTRACTID));
00946   if (!creator) return NS_ERROR_UNEXPECTED;
00947 
00948   nsCOMPtr<nsIWindowWatcher> wwatch
00949     (do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
00950   NS_ENSURE_SUCCESS(rv, rv);
00951 
00952   return wwatch->SetWindowCreator(creator);
00953 }
00954 
00955 static void DumpArbitraryHelp()
00956 {
00957   nsresult rv;
00958 
00959   nsXREDirProvider dirProvider;
00960   dirProvider.Initialize(nsnull);
00961 
00962   ScopedXPCOMStartup xpcom;
00963   xpcom.Initialize();
00964   xpcom.DoAutoreg();
00965 
00966   nsCOMPtr<nsICommandLineRunner> cmdline
00967     (do_CreateInstance("@mozilla.org/toolkit/command-line;1"));
00968   if (!cmdline)
00969     return;
00970 
00971   nsCString text;
00972   rv = cmdline->GetHelpText(text);
00973   if (NS_SUCCEEDED(rv))
00974     printf("%s", text.get());
00975 }
00976 
00977 // English text needs to go into a dtd file.
00978 // But when this is called we have no components etc. These strings must either be
00979 // here, or in a native resource file.
00980 static void
00981 DumpHelp()
00982 {
00983   printf("Usage: %s [ options ... ] [URL]\n", gArgv[0]);
00984   printf("       where options include:\n");
00985   printf("\n");
00986 
00987 #ifdef MOZ_WIDGET_GTK
00988   /* insert gtk options above moz options, like any other gtk app
00989    *
00990    * note: this isn't a very cool way to do things -- i'd rather get
00991    * these straight from a user's gtk version -- but it seems to be
00992    * what most gtk apps do. -dr
00993    */
00994 
00995   printf("GTK options\n");
00996   printf("%s--gdk-debug=FLAGS%sGdk debugging flags to set\n", HELP_SPACER_1, HELP_SPACER_2);
00997   printf("%s--gdk-no-debug=FLAGS%sGdk debugging flags to unset\n", HELP_SPACER_1, HELP_SPACER_2);
00998   printf("%s--gtk-debug=FLAGS%sGtk+ debugging flags to set\n", HELP_SPACER_1, HELP_SPACER_2);
00999   printf("%s--gtk-no-debug=FLAGS%sGtk+ debugging flags to unset\n", HELP_SPACER_1, HELP_SPACER_2);
01000   printf("%s--gtk-module=MODULE%sLoad an additional Gtk module\n", HELP_SPACER_1, HELP_SPACER_2);
01001   printf("%s-install%sInstall a private colormap\n", HELP_SPACER_1, HELP_SPACER_2);
01002 
01003   /* end gtk toolkit options */
01004 #endif /* MOZ_WIDGET_GTK */
01005 #if MOZ_WIDGET_XLIB
01006   printf("Xlib options\n");
01007   printf("%s-display=DISPLAY%sX display to use\n", HELP_SPACER_1, HELP_SPACER_2);
01008   printf("%s-visual=VISUALID%sX visual to use\n", HELP_SPACER_1, HELP_SPACER_2);
01009   printf("%s-install_colormap%sInstall own colormap\n", HELP_SPACER_1, HELP_SPACER_2);
01010   printf("%s-sync%sMake X calls synchronous\n", HELP_SPACER_1, HELP_SPACER_2);
01011   printf("%s-no-xshm%sDon't use X shared memory extension\n", HELP_SPACER_1, HELP_SPACER_2);
01012 
01013   /* end xlib toolkit options */
01014 #endif /* MOZ_WIDGET_XLIB */
01015 #ifdef MOZ_X11
01016   printf("X11 options\n");
01017   printf("%s--display=DISPLAY%sX display to use\n", HELP_SPACER_1, HELP_SPACER_2);
01018   printf("%s--sync%sMake X calls synchronous\n", HELP_SPACER_1, HELP_SPACER_2);
01019   printf("%s--no-xshm%sDon't use X shared memory extension\n", HELP_SPACER_1, HELP_SPACER_2);
01020   printf("%s--xim-preedit=STYLE\n", HELP_SPACER_1);
01021   printf("%s--xim-status=STYLE\n", HELP_SPACER_1);
01022 #endif
01023 #ifdef XP_UNIX
01024   printf("%s--g-fatal-warnings%sMake all warnings fatal\n", HELP_SPACER_1, HELP_SPACER_2);
01025 
01026   printf("\nMozilla options\n");
01027 #endif
01028 
01029   printf("%s-height <value>%sSet height of startup window to <value>.\n",HELP_SPACER_1,HELP_SPACER_2);
01030   printf("%s-h or -help%sPrint this message.\n",HELP_SPACER_1,HELP_SPACER_2);
01031   printf("%s-width <value>%sSet width of startup window to <value>.\n",HELP_SPACER_1,HELP_SPACER_2);
01032   printf("%s-v or -version%sPrint %s version.\n",HELP_SPACER_1,HELP_SPACER_2, gAppData->name);
01033   printf("%s-P <profile>%sStart with <profile>.\n",HELP_SPACER_1,HELP_SPACER_2);
01034   printf("%s-ProfileManager%sStart with Profile Manager.\n",HELP_SPACER_1,HELP_SPACER_2);
01035   printf("%s-UILocale <locale>%sStart with <locale> resources as UI Locale.\n",HELP_SPACER_1,HELP_SPACER_2);
01036   printf("%s-contentLocale <locale>%sStart with <locale> resources as content Locale.\n",HELP_SPACER_1,HELP_SPACER_2);
01037   printf("%s-safe-mode%sDisables extensions and themes for this session.\n",HELP_SPACER_1,HELP_SPACER_2);
01038 #if defined(XP_WIN) || defined(XP_OS2)
01039   printf("%s-console%sStart %s with a debugging console.\n",HELP_SPACER_1,HELP_SPACER_2,gAppData->name);
01040 #endif
01041 
01042   // this works, but only after the components have registered.  so if you drop in a new command line handler, -help
01043   // won't not until the second run.
01044   // out of the bug, because we ship a component.reg file, it works correctly.
01045   DumpArbitraryHelp();
01046 }
01047 
01048 // don't modify aAppDir directly... clone it first
01049 static int
01050 VerifyInstallation(nsIFile* aAppDir)
01051 {
01052   static const char lastResortMessage[] =
01053     "A previous install did not complete correctly.  Finishing install.";
01054 
01055   // Maximum allowed / used length of alert message is 255 chars, due to restrictions on Mac.
01056   // Please make sure that file contents and fallback_alert_text are at most 255 chars.
01057 
01058   char message[256];
01059   PRInt32 numRead = 0;
01060   const char *messageToShow = lastResortMessage;
01061 
01062   nsresult rv;
01063   nsCOMPtr<nsIFile> messageFile;
01064   rv = aAppDir->Clone(getter_AddRefs(messageFile));
01065   if (NS_SUCCEEDED(rv)) {
01066     messageFile->AppendNative(NS_LITERAL_CSTRING("res"));
01067     messageFile->AppendNative(CLEANUP_MESSAGE_FILENAME);
01068     PRFileDesc* fd = 0;
01069 
01070     nsCOMPtr<nsILocalFile> lf (do_QueryInterface(messageFile));
01071     if (lf) {
01072       rv = lf->OpenNSPRFileDesc(PR_RDONLY, 0664, &fd);
01073       if (NS_SUCCEEDED(rv)) {
01074         numRead = PR_Read(fd, message, sizeof(message)-1);
01075         if (numRead > 0) {
01076           message[numRead] = 0;
01077           messageToShow = message;
01078         }
01079       }
01080     }
01081   }
01082 
01083   ShowOSAlert(messageToShow);
01084 
01085   nsCOMPtr<nsIFile> cleanupUtility;
01086   aAppDir->Clone(getter_AddRefs(cleanupUtility));
01087   if (!cleanupUtility) return 1;
01088 
01089   cleanupUtility->AppendNative(CLEANUP_UTIL);
01090 
01091   ScopedXPCOMStartup xpcom;
01092   rv = xpcom.Initialize();
01093   if (NS_FAILED(rv)) return 1;
01094 
01095   { // extra scoping needed to release things before xpcom shutdown
01096     //Create the process framework to run the cleanup utility
01097     nsCOMPtr<nsIProcess> cleanupProcess
01098       (do_CreateInstance(NS_PROCESS_CONTRACTID));
01099     rv = cleanupProcess->Init(cleanupUtility);
01100     if (NS_FAILED(rv)) return 1;
01101 
01102     rv = cleanupProcess->Run(PR_FALSE,nsnull, 0, nsnull);
01103     if (NS_FAILED(rv)) return 1;
01104   }
01105 
01106   return 0;
01107 }
01108 
01109 #ifdef DEBUG_warren
01110 #ifdef XP_WIN
01111 #define _CRTDBG_MAP_ALLOC
01112 #include <crtdbg.h>
01113 #endif
01114 #endif
01115 
01116 #if defined(FREEBSD)
01117 // pick up fpsetmask prototype.
01118 #include <ieeefp.h>
01119 #endif
01120 
01121 static void
01122 DumpVersion()
01123 {
01124   printf("%s %s %s, %s\n", gAppData->vendor ? gAppData->vendor : "", gAppData->name, gAppData->version, gAppData->copyright);
01125 }
01126 
01127 #ifdef MOZ_ENABLE_XREMOTE
01128 // use int here instead of a PR type since it will be returned
01129 // from main - just to keep types consistent
01130 static int
01131 HandleRemoteArgument(const char* remote)
01132 {
01133   nsresult rv;
01134   ArgResult ar;
01135 
01136   const char *profile = 0;
01137   nsCAutoString program(gAppData->name);
01138   ToLowerCase(program);
01139   const char *username = getenv("LOGNAME");
01140 
01141   ar = CheckArg("p", PR_FALSE, &profile);
01142   if (ar == ARG_BAD) {
01143     PR_fprintf(PR_STDERR, "Error: argument -p requires a profile name\n");
01144     return 1;
01145   }
01146 
01147   const char *temp = nsnull;
01148   ar = CheckArg("a", PR_FALSE, &temp);
01149   if (ar == ARG_BAD) {
01150     PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n");
01151     return 1;
01152   } else if (ar == ARG_FOUND) {
01153     program.Assign(temp);
01154   }
01155 
01156   ar = CheckArg("u", PR_FALSE, &username);
01157   if (ar == ARG_BAD) {
01158     PR_fprintf(PR_STDERR, "Error: argument -u requires a username\n");
01159     return 1;
01160   }
01161 
01162   XRemoteClient client;
01163   rv = client.Init();
01164   if (NS_FAILED(rv)) {
01165     PR_fprintf(PR_STDERR, "Error: Failed to connect to X server.\n");
01166     return 1;
01167   }
01168 
01169   nsXPIDLCString response;
01170   PRBool success = PR_FALSE;
01171   rv = client.SendCommand(program.get(), username, profile, remote,
01172                            getter_Copies(response), &success);
01173   // did the command fail?
01174   if (NS_FAILED(rv)) {
01175     PR_fprintf(PR_STDERR, "Error: Failed to send command: %s\n",
01176                response ? response.get() : "No response included");
01177     return 1;
01178   }
01179 
01180   if (!success) {
01181     PR_fprintf(PR_STDERR, "Error: No running window found\n");
01182     return 2;
01183   }
01184 
01185   return 0;
01186 }
01187 
01188 static RemoteResult
01189 RemoteCommandLine()
01190 {
01191   nsresult rv;
01192   ArgResult ar;
01193 
01194   nsCAutoString program(gAppData->name);
01195   ToLowerCase(program);
01196   const char *username = getenv("LOGNAME");
01197 
01198   const char *temp = nsnull;
01199   ar = CheckArg("a", PR_TRUE, &temp);
01200   if (ar == ARG_BAD) {
01201     PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n");
01202     return REMOTE_ARG_BAD;
01203   } else if (ar == ARG_FOUND) {
01204     program.Assign(temp);
01205   }
01206 
01207   ar = CheckArg("u", PR_TRUE, &username);
01208   if (ar == ARG_BAD) {
01209     PR_fprintf(PR_STDERR, "Error: argument -u requires a username\n");
01210     return REMOTE_ARG_BAD;
01211   }
01212 
01213   XRemoteClient client;
01214   rv = client.Init();
01215   if (NS_FAILED(rv))
01216     return REMOTE_NOT_FOUND;
01217  
01218   nsXPIDLCString response;
01219   PRBool success = PR_FALSE;
01220   rv = client.SendCommandLine(program.get(), username, nsnull,
01221                               gArgc, gArgv,
01222                               getter_Copies(response), &success);
01223   // did the command fail?
01224   if (NS_FAILED(rv) || !success)
01225     return REMOTE_NOT_FOUND;
01226 
01227   return REMOTE_FOUND;
01228 }
01229 #endif // MOZ_ENABLE_XREMOTE
01230 
01231 #ifdef XP_MACOSX
01232 static char const *gBinaryPath;
01233 #endif
01234 
01235 nsresult
01236 XRE_GetBinaryPath(const char* argv0, nsILocalFile* *aResult)
01237 {
01238   nsresult rv;
01239   nsCOMPtr<nsILocalFile> lf;
01240 
01241   // We need to use platform-specific hackery to find the
01242   // path of this executable. This is copied, with some modifications, from
01243   // nsGREDirServiceProvider.cpp
01244 
01245 #ifdef XP_WIN
01246   char exePath[MAXPATHLEN];
01247 
01248   if (!::GetModuleFileName(0, exePath, MAXPATHLEN))
01249     return NS_ERROR_FAILURE;
01250 
01251   rv = NS_NewNativeLocalFile(nsDependentCString(exePath), PR_TRUE,
01252                              getter_AddRefs(lf));
01253   if (NS_FAILED(rv))
01254     return rv;
01255 
01256 #elif defined(XP_MACOSX)
01257   if (gBinaryPath)
01258     return NS_NewNativeLocalFile(nsDependentCString(gBinaryPath), PR_FALSE,
01259                                  aResult);
01260 
01261   NS_NewNativeLocalFile(EmptyCString(), PR_TRUE, getter_AddRefs(lf));
01262   nsCOMPtr<nsILocalFileMac> lfm (do_QueryInterface(lf));
01263   if (!lfm)
01264     return NS_ERROR_FAILURE;
01265 
01266   // Works even if we're not bundled.
01267   CFBundleRef appBundle = CFBundleGetMainBundle();
01268   if (!appBundle)
01269     return NS_ERROR_FAILURE;
01270 
01271   CFURLRef bundleURL = CFBundleCopyExecutableURL(appBundle);
01272   if (!bundleURL)
01273     return NS_ERROR_FAILURE;
01274 
01275   FSRef fileRef;
01276   if (!CFURLGetFSRef(bundleURL, &fileRef)) {
01277     CFRelease(bundleURL);
01278     return NS_ERROR_FAILURE;
01279   }
01280 
01281   rv = lfm->InitWithFSRef(&fileRef);
01282   CFRelease(bundleURL);
01283 
01284   if (NS_FAILED(rv))
01285     return rv;
01286 
01287 #elif defined(XP_UNIX)
01288   struct stat fileStat;
01289   char exePath[MAXPATHLEN];
01290   char tmpPath[MAXPATHLEN];
01291 
01292   rv = NS_ERROR_FAILURE;
01293 
01294   // on unix, there is no official way to get the path of the current binary.
01295   // instead of using the MOZILLA_FIVE_HOME hack, which doesn't scale to
01296   // multiple applications, we will try a series of techniques:
01297   //
01298   // 1) look for /proc/<pid>/exe which is a symlink to the executable on newer
01299   //    Linux kernels
01300   // 2) use realpath() on argv[0], which works unless we're loaded from the
01301   //    PATH
01302   // 3) manually walk through the PATH and look for ourself
01303   // 4) give up
01304 
01305 // #ifdef __linux__
01306 #if 0
01307   int r = readlink("/proc/self/exe", exePath, MAXPATHLEN);
01308 
01309   // apparently, /proc/self/exe can sometimes return weird data... check it
01310   if (r > 0 && r < MAXPATHLEN && stat(exePath, &fileStat) == 0) {
01311     rv = NS_OK;
01312   }
01313 
01314 #endif
01315   if (NS_FAILED(rv) &&
01316       realpath(argv0, exePath) && stat(exePath, &fileStat) == 0) {
01317     rv = NS_OK;
01318   }
01319 
01320   if (NS_FAILED(rv)) {
01321     const char *path = getenv("PATH");
01322     if (!path)
01323       return NS_ERROR_FAILURE;
01324 
01325     char *pathdup = strdup(path);
01326     if (!pathdup)
01327       return NS_ERROR_OUT_OF_MEMORY;
01328 
01329     PRBool found = PR_FALSE;
01330     char *newStr = pathdup;
01331     char *token;
01332     while ( (token = nsCRT::strtok(newStr, ":", &newStr)) ) {
01333       sprintf(tmpPath, "%s/%s", token, argv0);
01334       if (realpath(tmpPath, exePath) && stat(exePath, &fileStat) == 0) {
01335         found = PR_TRUE;
01336         break;
01337       }
01338     }
01339     free(pathdup);
01340     if (!found)
01341       return NS_ERROR_FAILURE;
01342   }
01343 
01344   rv = NS_NewNativeLocalFile(nsDependentCString(exePath), PR_TRUE,
01345                              getter_AddRefs(lf));
01346   if (NS_FAILED(rv))
01347     return rv;
01348 
01349 #elif defined(XP_OS2)
01350   PPIB ppib;
01351   PTIB ptib;
01352   char exePath[MAXPATHLEN];
01353 
01354   DosGetInfoBlocks( &ptib, &ppib);
01355   DosQueryModuleName( ppib->pib_hmte, MAXPATHLEN, exePath);
01356   rv = NS_NewNativeLocalFile(nsDependentCString(exePath), PR_TRUE,
01357                              getter_AddRefs(lf));
01358   if (NS_FAILED(rv))
01359     return rv;
01360 
01361 #elif defined(XP_BEOS)
01362   int32 cookie = 0;
01363   image_info info;
01364 
01365   if(get_next_image_info(0, &cookie, &info) != B_OK)
01366     return NS_ERROR_FAILURE;
01367 
01368   rv = NS_NewNativeLocalFile(nsDependentCString(info.name), PR_TRUE,
01369                              getter_AddRefs(lf));
01370   if (NS_FAILED(rv))
01371     return rv;
01372 
01373 #elif
01374 #error Oops, you need platform-specific code here
01375 #endif
01376 
01377   NS_ADDREF(*aResult = lf);
01378   return NS_OK;
01379 }
01380 
01381 #define NS_ERROR_LAUNCHED_CHILD_PROCESS NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_PROFILE, 200)
01382 
01383 #ifdef XP_WIN
01384 #include "nsWindowsRestart.cpp"
01385 #endif
01386 
01387 #if defined(XP_OS2) && (__GNUC__ == 3 && __GNUC_MINOR__ == 3) // broken OS/2 GCC
01388 // Copy the environment maintained by the C library into an ASCIIZ array
01389 // that can be used to pass it on to the OS/2 Dos* APIs (which otherwise
01390 // don't know anything about the stuff set by PR_SetEnv() or setenv()).
01391 char *createEnv()
01392 {
01393   // just allocate the maximum amount (24 kB = 0x60000 bytes), to be able to
01394   // copy the existing environment
01395   char *env = (char *)calloc(0x6000, sizeof(char));
01396   if (!env) {
01397     return NULL;
01398   }
01399 
01400   // walk along the environ string array of the C library and copy
01401   // everything (that fits) into the output environment array, leaving
01402   // null bytes between the entries
01403   char *penv = env; // movable pointer to result environment ASCIIZ array
01404   int i = 0, space = 0x6000;
01405   while (environ[i] && environ[i][0]) {
01406     int len = strlen(environ[i]);
01407     if (space - len <= 0) {
01408       break;
01409     }
01410     strcpy(penv, environ[i]);
01411     i++; // next environment variable
01412     penv += len + 1; // jump to after next null byte
01413     space -= len - 1; // subtract consumed length from usable space
01414   }
01415 
01416   return env;
01417 }
01418 
01419 // OS2LaunchChild() is there to replace _execv() which is broken in the C
01420 // runtime library that comes with GCC 3.3.5 on OS/2. It uses createEnv()
01421 // to copy the process environment and add necessary variables
01422 //
01423 // returns -1 on failure and 0 on success
01424 int OS2LaunchChild(const char *aExePath, int aArgc, char **aArgv)
01425 {
01426   // find total length of aArgv
01427   int len = 0;
01428   for (int i = 0; i < aArgc; i++) {
01429     len += strlen(aArgv[i]) + 1; // plus space in between
01430   }
01431   len++; // leave space for null byte at end
01432   // allocate enough space for all strings and nulls,
01433   // calloc helpfully initializes to null
01434   char *args = (char *)calloc(len, sizeof(char));
01435   if (!args) {
01436     return -1;
01437   }
01438   char *pargs = args; // extra pointer to after the last argument
01439   // build argument list in the format the DosStartSession() wants,
01440   // adding spaces between the arguments
01441   for (int i = 0; i < aArgc; i++, *pargs++ = ' ') {
01442     strcpy(pargs, aArgv[i]);
01443     pargs += strlen(aArgv[i]);
01444   }
01445   if (aArgc > 1) {
01446     *(pargs-1) = '\0'; // replace last space
01447   }
01448   *pargs = '\0';
01449   // make sure that the program is separated by null byte
01450   pargs = strchr(args, ' ');
01451   if (pargs) {
01452     *pargs = '\0';
01453   }
01454 
01455   char *env = createEnv();
01456 
01457   char error[CCHMAXPATH] = { 0 };
01458   RESULTCODES crc = { 0 };
01459   ULONG rc = DosExecPgm(error, sizeof(error), EXEC_ASYNC, args, env,
01460                         &crc, (PSZ)aExePath);
01461   free(args); // done with the arguments
01462   if (env) {
01463     free(env);
01464   }
01465   if (rc != NO_ERROR) {
01466     return -1;
01467   }
01468 
01469   return 0;
01470 }
01471 #endif
01472 
01473 // If aBlankCommandLine is true, then the application will be launched with a
01474 // blank command line instead of being launched with the same command line that
01475 // it was initially started with.
01476 static nsresult LaunchChild(nsINativeAppSupport* aNative,
01477                             PRBool aBlankCommandLine = PR_FALSE,
01478                             int needElevation = 0)
01479 {
01480   aNative->Quit(); // release DDE mutex, if we're holding it
01481 
01482   // Restart this process by exec'ing it into the current process
01483   // if supported by the platform.  Otherwise, use NSPR.
01484  
01485   if (aBlankCommandLine) {
01486     gRestartArgc = 1;
01487     gRestartArgv[gRestartArgc] = nsnull;
01488   }
01489 
01490   PR_SetEnv("MOZ_LAUNCHED_CHILD=1");
01491 
01492 #if defined(XP_MACOSX)
01493   LaunchChildMac(gRestartArgc, gRestartArgv);
01494 #else
01495   nsCOMPtr<nsILocalFile> lf;
01496   nsresult rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
01497   if (NS_FAILED(rv))
01498     return rv;
01499 
01500   nsCAutoString exePath;
01501   rv = lf->GetNativePath(exePath);
01502   if (NS_FAILED(rv))
01503     return rv;
01504 
01505 #if defined(XP_WIN)
01506   if (!WinLaunchChild(exePath.get(), gRestartArgc, gRestartArgv, needElevation))
01507     return NS_ERROR_FAILURE;
01508 #elif defined(XP_OS2) && (__GNUC__ == 3 && __GNUC_MINOR__ == 3)
01509   // implementation of _execv() is broken with GCC 3.3.x on OS/2
01510   if (OS2LaunchChild(exePath.get(), gRestartArgc, gRestartArgv) == -1)
01511     return NS_ERROR_FAILURE;
01512 #elif defined(XP_OS2)
01513   if (_execv(exePath.get(), gRestartArgv) == -1)
01514     return NS_ERROR_FAILURE;
01515 #elif defined(XP_UNIX)
01516   if (execv(exePath.get(), gRestartArgv) == -1)
01517     return NS_ERROR_FAILURE;
01518 #elif defined(XP_BEOS)
01519   extern char **environ;
01520   status_t res;
01521   res = resume_thread(load_image(gRestartArgc,(const char **)gRestartArgv,(const char **)environ));
01522   if (res != B_OK)
01523     return NS_ERROR_FAILURE;
01524 #else
01525   PRProcess* process = PR_CreateProcess(exePath.get(), gRestartArgv,
01526                                         nsnull, nsnull);
01527   if (!process) return NS_ERROR_FAILURE;
01528 
01529   PRInt32 exitCode;
01530   PRStatus failed = PR_WaitProcess(process, &exitCode);
01531   if (failed || exitCode)
01532     return NS_ERROR_FAILURE;
01533 #endif
01534 #endif
01535 
01536   return NS_ERROR_LAUNCHED_CHILD_PROCESS;
01537 }
01538 
01539 static const char kProfileProperties[] =
01540   "chrome://mozapps/locale/profile/profileSelection.properties";
01541 
01542 static nsresult
01543 ProfileLockedDialog(nsILocalFile* aProfileDir, nsILocalFile* aProfileLocalDir,
01544                     nsIProfileUnlocker* aUnlocker,
01545                     nsINativeAppSupport* aNative, nsIProfileLock* *aResult)
01546 {
01547   nsresult rv;
01548 
01549   ScopedXPCOMStartup xpcom;
01550   rv = xpcom.Initialize();
01551   NS_ENSURE_SUCCESS(rv, rv);
01552 
01553   rv = xpcom.DoAutoreg();
01554   rv |= xpcom.InitEventQueue();
01555   rv |= xpcom.SetWindowCreator(aNative);
01556   NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
01557 
01558   { //extra scoping is needed so we release these components before xpcom shutdown
01559     nsCOMPtr<nsIStringBundleService> sbs
01560       (do_GetService(NS_STRINGBUNDLE_CONTRACTID));
01561     NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE);
01562 
01563     nsCOMPtr<nsIStringBundle> sb;
01564     sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
01565     NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
01566 
01567     NS_ConvertUTF8toUTF16 appName(gAppData->name);
01568     const PRUnichar* params[] = {appName.get(), appName.get()};
01569 
01570     nsXPIDLString killMessage;
01571 #ifndef XP_MACOSX
01572     static const PRUnichar kRestartNoUnlocker[] = {'r','e','s','t','a','r','t','M','e','s','s','a','g','e','N','o','U','n','l','o','c','k','e','r','\0'}; // "restartMessageNoUnlocker"
01573     static const PRUnichar kRestartUnlocker[] = {'r','e','s','t','a','r','t','M','e','s','s','a','g','e','U','n','l','o','c','k','e','r','\0'}; // "restartMessageUnlocker"
01574 #else
01575     static const PRUnichar kRestartNoUnlocker[] = {'r','e','s','t','a','r','t','M','e','s','s','a','g','e','N','o','U','n','l','o','c','k','e','r','M','a','c','\0'}; // "restartMessageNoUnlockerMac"
01576     static const PRUnichar kRestartUnlocker[] = {'r','e','s','t','a','r','t','M','e','s','s','a','g','e','U','n','l','o','c','k','e','r','M','a','c','\0'}; // "restartMessageUnlockerMac"
01577 #endif
01578 
01579     sb->FormatStringFromName(aUnlocker ? kRestartUnlocker : kRestartNoUnlocker,
01580                              params, 2, getter_Copies(killMessage));
01581 
01582     nsXPIDLString killTitle;
01583     sb->FormatStringFromName(NS_LITERAL_STRING("restartTitle").get(),
01584                              params, 1, getter_Copies(killTitle));
01585 
01586     if (!killMessage || !killTitle)
01587       return NS_ERROR_FAILURE;
01588 
01589     nsCOMPtr<nsIPromptService> ps
01590       (do_GetService(NS_PROMPTSERVICE_CONTRACTID));
01591     NS_ENSURE_TRUE(ps, NS_ERROR_FAILURE);
01592 
01593     PRUint32 flags = nsIPromptService::BUTTON_TITLE_OK * nsIPromptService::BUTTON_POS_0;
01594 
01595     if (aUnlocker) {
01596       flags =
01597         nsIPromptService::BUTTON_TITLE_CANCEL * nsIPromptService::BUTTON_POS_0 +
01598         nsIPromptService::BUTTON_TITLE_IS_STRING * nsIPromptService::BUTTON_POS_1 +
01599         nsIPromptService::BUTTON_POS_1_DEFAULT;
01600     }
01601 
01602     PRInt32 button;
01603     rv = ps->ConfirmEx(nsnull, killTitle, killMessage, flags,
01604                        killTitle, nsnull, nsnull, nsnull, nsnull, &button);
01605     NS_ENSURE_SUCCESS_LOG(rv, rv);
01606 
01607     if (button == 1 && aUnlocker) {
01608       rv = aUnlocker->Unlock(nsIProfileUnlocker::FORCE_QUIT);
01609       if (NS_FAILED(rv)) return rv;
01610 
01611       return NS_LockProfilePath(aProfileDir, aProfileLocalDir, nsnull, aResult);
01612     }
01613 
01614     return NS_ERROR_ABORT;
01615   }
01616 }
01617 
01618 static const char kProfileManagerURL[] =
01619   "chrome://mozapps/content/profile/profileSelection.xul";
01620 
01621 static nsresult
01622 ShowProfileManager(nsIToolkitProfileService* aProfileSvc,
01623                    nsINativeAppSupport* aNative)
01624 {
01625   nsresult rv;
01626 
01627   nsCOMPtr<nsILocalFile> profD, profLD;
01628 
01629   {
01630     ScopedXPCOMStartup xpcom;
01631     rv = xpcom.Initialize();
01632     NS_ENSURE_SUCCESS(rv, rv);
01633 
01634     rv = xpcom.RegisterProfileService(aProfileSvc);
01635     rv |= xpcom.DoAutoreg();
01636     rv |= xpcom.InitEventQueue();
01637     rv |= xpcom.SetWindowCreator(aNative);
01638     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
01639 
01640 #ifdef XP_MACOSX
01641     SetupMacCommandLine(gRestartArgc, gRestartArgv);
01642 #endif
01643 
01644 #ifdef XP_WIN
01645     ProcessDDE(aNative);
01646 #endif
01647 
01648     { //extra scoping is needed so we release these components before xpcom shutdown
01649       nsCOMPtr<nsIWindowWatcher> windowWatcher
01650         (do_GetService(NS_WINDOWWATCHER_CONTRACTID));
01651       nsCOMPtr<nsIDialogParamBlock> ioParamBlock
01652         (do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID));
01653       nsCOMPtr<nsIMutableArray> dlgArray (do_CreateInstance(NS_ARRAY_CONTRACTID));
01654       NS_ENSURE_TRUE(windowWatcher && ioParamBlock && dlgArray, NS_ERROR_FAILURE);
01655 
01656       ioParamBlock->SetObjects(dlgArray);
01657 
01658       nsCOMPtr<nsIAppStartup> appStartup
01659         (do_GetService(NS_APPSTARTUP_CONTRACTID));
01660       NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE);
01661 
01662       appStartup->EnterLastWindowClosingSurvivalArea();
01663 
01664       nsCOMPtr<nsIDOMWindow> newWindow;
01665       rv = windowWatcher->OpenWindow(nsnull,
01666                                      kProfileManagerURL,
01667                                      "_blank",
01668                                      "centerscreen,chrome,modal,titlebar",
01669                                      ioParamBlock,
01670                                      getter_AddRefs(newWindow));
01671 
01672       appStartup->ExitLastWindowClosingSurvivalArea();
01673 
01674       NS_ENSURE_SUCCESS_LOG(rv, rv);
01675 
01676       aProfileSvc->Flush();
01677 
01678       PRInt32 dialogConfirmed;
01679       rv = ioParamBlock->GetInt(0, &dialogConfirmed);
01680       if (NS_FAILED(rv) || dialogConfirmed == 0) return NS_ERROR_ABORT;
01681 
01682       nsCOMPtr<nsIProfileLock> lock;
01683       rv = dlgArray->QueryElementAt(0, NS_GET_IID(nsIProfileLock),
01684                                     getter_AddRefs(lock));
01685       NS_ENSURE_SUCCESS_LOG(rv, rv);
01686 
01687       rv = lock->GetDirectory(getter_AddRefs(profD));
01688       NS_ENSURE_SUCCESS(rv, rv);
01689 
01690       rv = lock->GetLocalDirectory(getter_AddRefs(profLD));
01691       NS_ENSURE_SUCCESS(rv, rv);
01692 
01693       lock->Unlock();
01694     }
01695   }
01696 
01697   SaveFileToEnv("XRE_PROFILE_PATH", profD);
01698   SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", profLD);
01699 
01700   PRBool offline = PR_FALSE;
01701   aProfileSvc->GetStartOffline(&offline);
01702   if (offline) {
01703     PR_SetEnv("XRE_START_OFFLINE=1");
01704   }
01705 
01706   return LaunchChild(aNative);
01707 }
01708 
01709 static nsresult
01710 ImportProfiles(nsIToolkitProfileService* aPService,
01711                nsINativeAppSupport* aNative)
01712 {
01713   nsresult rv;
01714 
01715   PR_SetEnv("XRE_IMPORT_PROFILES=1");
01716 
01717   // try to import old-style profiles
01718   { // scope XPCOM
01719     ScopedXPCOMStartup xpcom;
01720     rv = xpcom.Initialize();
01721     if (NS_SUCCEEDED(rv)) {
01722       xpcom.DoAutoreg();
01723       xpcom.RegisterProfileService(aPService);
01724 
01725 #ifdef XP_MACOSX
01726       SetupMacCommandLine(gRestartArgc, gRestartArgv);
01727 #endif
01728 
01729       nsCOMPtr<nsIProfileMigrator> migrator
01730         (do_GetService(NS_PROFILEMIGRATOR_CONTRACTID));
01731       if (migrator) {
01732         migrator->Import();
01733       }
01734     }
01735   }
01736 
01737   aPService->Flush();
01738   return LaunchChild(aNative);
01739 }
01740 
01741 // Pick a profile. We need to end up with a profile lock.
01742 //
01743 // 1) check for -profile <path>
01744 // 2) check for -P <name>
01745 // 3) check for -ProfileManager
01746 // 4) use the default profile, if there is one
01747 // 5) if there are *no* profiles, set up profile-migration
01748 // 6) display the profile-manager UI
01749 
01750 static PRBool gDoMigration = PR_FALSE;
01751 
01752 static nsresult
01753 SelectProfile(nsIProfileLock* *aResult, nsINativeAppSupport* aNative,
01754               PRBool* aStartOffline)
01755 {
01756   nsresult rv;
01757   ArgResult ar;
01758   const char* arg;
01759   *aResult = nsnull;
01760   *aStartOffline = PR_FALSE;
01761 
01762   ar = CheckArg("offline", PR_TRUE);
01763   if (ar == ARG_BAD) {
01764     PR_fprintf(PR_STDERR, "Error: argument -offline is invalid when argument -osint is specified\n");
01765     return NS_ERROR_FAILURE;
01766   }
01767 
01768   arg = PR_GetEnv("XRE_START_OFFLINE");
01769   if ((arg && *arg) || ar)
01770     *aStartOffline = PR_TRUE;
01771 
01772 
01773   arg = PR_GetEnv("XRE_PROFILE_PATH");
01774   if (arg && *arg) {
01775     nsCOMPtr<nsILocalFile> lf;
01776     rv = NS_NewNativeLocalFile(nsDependentCString(arg), PR_TRUE,
01777                                getter_AddRefs(lf));
01778     NS_ENSURE_SUCCESS(rv, rv);
01779 
01780     nsCOMPtr<nsILocalFile> localDir;
01781     arg = PR_GetEnv("XRE_PROFILE_LOCAL_PATH");
01782     if (arg && *arg) {
01783       rv = NS_NewNativeLocalFile(nsDependentCString(arg), PR_TRUE,
01784                                  getter_AddRefs(localDir));
01785       NS_ENSURE_SUCCESS(rv, rv);
01786     } else {
01787       localDir = lf;
01788     }
01789 
01790     // Clear out flags that we handled (or should have handled!) last startup.
01791     const char *dummy;
01792     CheckArg("p", PR_FALSE, &dummy);
01793     CheckArg("profile", PR_FALSE, &dummy);
01794     CheckArg("profilemanager");
01795 
01796     return NS_LockProfilePath(lf, localDir, nsnull, aResult);
01797   }
01798 
01799   ar = CheckArg("migration", PR_TRUE);
01800   if (ar == ARG_BAD) {
01801     PR_fprintf(PR_STDERR, "Error: argument -migration is invalid when argument -osint is specified\n");
01802     return NS_ERROR_FAILURE;
01803   } else if (ar == ARG_FOUND) {
01804     gDoMigration = PR_TRUE;
01805   }
01806 
01807   ar = CheckArg("profile", PR_TRUE, &arg);
01808   if (ar == ARG_BAD) {
01809     PR_fprintf(PR_STDERR, "Error: argument -profile requires a path\n");
01810     return NS_ERROR_FAILURE;
01811   }
01812   if (ar) {
01813     nsCOMPtr<nsILocalFile> lf;
01814     rv = XRE_GetFileFromPath(arg, getter_AddRefs(lf));
01815     NS_ENSURE_SUCCESS(rv, rv);
01816 
01817     nsCOMPtr<nsIProfileUnlocker> unlocker;
01818 
01819     // If a profile path is specified directory on the command line, then
01820     // assume that the temp directory is the same as the given directory.
01821     rv = NS_LockProfilePath(lf, lf, getter_AddRefs(unlocker), aResult);
01822     if (NS_SUCCEEDED(rv))
01823       return rv;
01824 
01825     return ProfileLockedDialog(lf, lf, unlocker, aNative, aResult);
01826   }
01827 
01828   nsCOMPtr<nsIToolkitProfileService> profileSvc;
01829   rv = NS_NewToolkitProfileService(getter_AddRefs(profileSvc));
01830   NS_ENSURE_SUCCESS(rv, rv);
01831 
01832   ar = CheckArg("createprofile", PR_TRUE, &arg);
01833   if (ar == ARG_BAD) {
01834     PR_fprintf(PR_STDERR, "Error: argument -createprofile requires a profile name\n");
01835     return NS_ERROR_FAILURE;
01836   }
01837   if (ar) {
01838     nsCOMPtr<nsIToolkitProfile> profile;
01839 
01840     const char* delim = strchr(arg, ' ');
01841     if (delim) {
01842       nsCOMPtr<nsILocalFile> lf;
01843       rv = NS_NewNativeLocalFile(nsDependentCString(delim + 1),
01844                                    PR_TRUE, getter_AddRefs(lf));
01845       if (NS_FAILED(rv)) {
01846         PR_fprintf(PR_STDERR, "Error: profile path not valid.");
01847         return rv;
01848       }
01849       
01850       // As with -profile, assume that the given path will be used for both the
01851       // main profile directory and the temp profile directory.
01852       rv = profileSvc->CreateProfile(lf, lf, nsDependentCSubstring(arg, delim),
01853                                      getter_AddRefs(profile));
01854     } else {
01855       rv = profileSvc->CreateProfile(nsnull, nsnull, nsDependentCString(arg),
01856                                      getter_AddRefs(profile));
01857     }
01858     if (NS_SUCCEEDED(rv)) {
01859       rv = NS_ERROR_ABORT;
01860       PR_fprintf(PR_STDERR, "Success: created profile '%s'\n", arg);
01861     }
01862     profileSvc->Flush();
01863 
01864     // XXXben need to ensure prefs.js exists here so the tinderboxes will
01865     //        not go orange.
01866     nsCOMPtr<nsILocalFile> prefsJSFile;
01867     profile->GetRootDir(getter_AddRefs(prefsJSFile));
01868     prefsJSFile->AppendNative(NS_LITERAL_CSTRING("prefs.js"));
01869     PRBool exists;
01870     prefsJSFile->Exists(&exists);
01871     if (!exists)
01872       prefsJSFile->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
01873     // XXXdarin perhaps 0600 would be better?
01874 
01875     return rv;
01876   }
01877 
01878   PRUint32 count;
01879   rv = profileSvc->GetProfileCount(&count);
01880   NS_ENSURE_SUCCESS(rv, rv);
01881 
01882   if (gAppData->flags & NS_XRE_ENABLE_PROFILE_MIGRATOR) {
01883     arg = PR_GetEnv("XRE_IMPORT_PROFILES");
01884     if (!count && (!arg || !*arg)) {
01885       return ImportProfiles(profileSvc, aNative);
01886     }
01887   }
01888 
01889   ar = CheckArg("p", PR_FALSE, &arg);
01890   if (ar == ARG_BAD) {
01891     ar = CheckArg("osint");
01892     if (ar == ARG_FOUND) {
01893       PR_fprintf(PR_STDERR, "Error: argument -p is invalid when argument -osint is specified\n");
01894       return NS_ERROR_FAILURE;
01895     }
01896     return ShowProfileManager(profileSvc, aNative);
01897   }
01898   if (ar) {
01899     ar = CheckArg("osint");
01900     if (ar == ARG_FOUND) {
01901       PR_fprintf(PR_STDERR, "Error: argument -p is invalid when argument -osint is specified\n");
01902       return NS_ERROR_FAILURE;
01903     }
01904     nsCOMPtr<nsIToolkitProfile> profile;
01905     rv = profileSvc->GetProfileByName(nsDependentCString(arg),
01906                                       getter_AddRefs(profile));
01907     if (NS_SUCCEEDED(rv)) {
01908       nsCOMPtr<nsIProfileUnlocker> unlocker;
01909       rv = profile->Lock(nsnull, aResult);
01910       if (NS_SUCCEEDED(rv))
01911         return NS_OK;
01912 
01913       nsCOMPtr<nsILocalFile> profileDir;
01914       rv = profile->GetRootDir(getter_AddRefs(profileDir));
01915       NS_ENSURE_SUCCESS(rv, rv);
01916 
01917       nsCOMPtr<nsILocalFile> profileLocalDir;
01918       rv = profile->GetLocalDir(getter_AddRefs(profileLocalDir));
01919       NS_ENSURE_SUCCESS(rv, rv);
01920 
01921       return ProfileLockedDialog(profileDir, profileLocalDir, unlocker,
01922                                  aNative, aResult);
01923     }
01924 
01925     return ShowProfileManager(profileSvc, aNative);
01926   }
01927 
01928   ar = CheckArg("profilemanager", PR_TRUE);
01929   if (ar == ARG_BAD) {
01930     PR_fprintf(PR_STDERR, "Error: argument -profilemanager is invalid when argument -osint is specified\n");
01931     return NS_ERROR_FAILURE;
01932   } else if (ar == ARG_FOUND) {
01933     return ShowProfileManager(profileSvc, aNative);
01934   }
01935 
01936   if (!count) {
01937     gDoMigration = PR_TRUE;
01938 
01939     // create a default profile
01940     nsCOMPtr<nsIToolkitProfile> profile;
01941     nsresult rv = profileSvc->CreateProfile(nsnull, // choose a default dir for us
01942                                             nsnull, // choose a default dir for us
01943                                             NS_LITERAL_CSTRING("default"),
01944                                             getter_AddRefs(profile));
01945     if (NS_SUCCEEDED(rv)) {
01946       profileSvc->Flush();
01947       rv = profile->Lock(nsnull, aResult);
01948       if (NS_SUCCEEDED(rv))
01949         return NS_OK;
01950     }
01951   }
01952 
01953   PRBool useDefault = PR_TRUE;
01954   if (count > 1)
01955     profileSvc->GetStartWithLastProfile(&useDefault);
01956 
01957   if (useDefault) {
01958     nsCOMPtr<nsIToolkitProfile> profile;
01959     // GetSelectedProfile will auto-select the only profile if there's just one
01960     profileSvc->GetSelectedProfile(getter_AddRefs(profile));
01961     if (profile) {
01962       nsCOMPtr<nsIProfileUnlocker> unlocker;
01963       rv = profile->Lock(getter_AddRefs(unlocker), aResult);
01964       if (NS_SUCCEEDED(rv))
01965         return NS_OK;
01966 
01967       nsCOMPtr<nsILocalFile> profileDir;
01968       rv = profile->GetRootDir(getter_AddRefs(profileDir));
01969       NS_ENSURE_SUCCESS(rv, rv);
01970 
01971       nsCOMPtr<nsILocalFile> profileLocalDir;
01972       rv = profile->GetRootDir(getter_AddRefs(profileLocalDir));
01973       NS_ENSURE_SUCCESS(rv, rv);
01974 
01975       return ProfileLockedDialog(profileDir, profileLocalDir, unlocker,
01976                                  aNative, aResult);
01977     }
01978   }
01979 
01980   return ShowProfileManager(profileSvc, aNative);
01981 }
01982 
01983 #define FILE_COMPATIBILITY_INFO NS_LITERAL_CSTRING("compatibility.ini")
01984 
01985 static PRBool
01986 CheckCompatibility(nsIFile* aProfileDir, const nsCString& aVersion,
01987                    const nsCString& aOSABI, nsIFile* aXULRunnerDir,
01988                    nsIFile* aAppDir)
01989 {
01990   nsCOMPtr<nsIFile> file;
01991   aProfileDir->Clone(getter_AddRefs(file));
01992   if (!file)
01993     return PR_FALSE;
01994   file->AppendNative(FILE_COMPATIBILITY_INFO);
01995 
01996   nsINIParser parser;
01997   nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(file));
01998   nsresult rv = parser.Init(localFile);
01999   if (NS_FAILED(rv))
02000     return PR_FALSE;
02001 
02002   nsCAutoString buf;
02003   rv = parser.GetString("Compatibility", "LastVersion", buf);
02004   if (NS_FAILED(rv))
02005     return PR_FALSE;
02006 
02007   if (!aVersion.Equals(buf))
02008     return PR_FALSE;
02009 
02010   rv = parser.GetString("Compatibility", "LastOSABI", buf);
02011   if (NS_FAILED(rv))
02012     return PR_FALSE;
02013 
02014   if (!aOSABI.Equals(buf))
02015     return PR_FALSE;
02016 
02017   rv = parser.GetString("Compatibility", "LastPlatformDir", buf);
02018   if (NS_FAILED(rv))
02019     return PR_FALSE;
02020 
02021   nsCOMPtr<nsILocalFile> lf;
02022   rv = NS_NewNativeLocalFile(buf, PR_FALSE,
02023                              getter_AddRefs(lf));
02024   if (NS_FAILED(rv))
02025     return PR_FALSE;
02026 
02027   PRBool eq;
02028   rv = lf->Equals(aXULRunnerDir, &eq);
02029   if (NS_FAILED(rv) || !eq)
02030     return PR_FALSE;
02031 
02032   if (aAppDir) {
02033     rv = parser.GetString("Compatibility", "LastAppDir", buf);
02034     if (NS_FAILED(rv))
02035       return PR_FALSE;
02036 
02037     rv = NS_NewNativeLocalFile(buf, PR_FALSE,
02038                                getter_AddRefs(lf));
02039     if (NS_FAILED(rv))
02040       return PR_FALSE;
02041 
02042     rv = lf->Equals(aAppDir, &eq);
02043     if (NS_FAILED(rv) || !eq)
02044       return PR_FALSE;
02045   }
02046 
02047   return PR_TRUE;
02048 }
02049 
02050 static void BuildVersion(nsCString &aBuf)
02051 {
02052   aBuf.Assign(gAppData->version);
02053   aBuf.Append('_');
02054   aBuf.Append(gAppData->buildID);
02055   aBuf.Append('/');
02056   aBuf.AppendLiteral(GRE_BUILD_ID);
02057 }
02058 
02059 static void
02060 WriteVersion(nsIFile* aProfileDir, const nsCString& aVersion,
02061              const nsCString& aOSABI, nsIFile* aXULRunnerDir,
02062              nsIFile* aAppDir)
02063 {
02064   nsCOMPtr<nsIFile> file;
02065   aProfileDir->Clone(getter_AddRefs(file));
02066   if (!file)
02067     return;
02068   file->AppendNative(FILE_COMPATIBILITY_INFO);
02069 
02070   nsCOMPtr<nsILocalFile> lf = do_QueryInterface(file);
02071 
02072   nsCAutoString platformDir;
02073   aXULRunnerDir->GetNativePath(platformDir);
02074 
02075   nsCAutoString appDir;
02076   if (aAppDir)
02077     aAppDir->GetNativePath(appDir);
02078 
02079   PRFileDesc *fd = nsnull;
02080   lf->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0600, &fd);
02081   if (!fd) {
02082     NS_ERROR("could not create output stream");
02083     return;
02084   }
02085 
02086   static const char kHeader[] = "[Compatibility]" NS_LINEBREAK
02087                                 "LastVersion=";
02088 
02089   PR_Write(fd, kHeader, sizeof(kHeader) - 1);
02090   PR_Write(fd, aVersion.get(), aVersion.Length());
02091 
02092   static const char kOSABIHeader[] = NS_LINEBREAK "LastOSABI=";
02093   PR_Write(fd, kOSABIHeader, sizeof(kOSABIHeader) - 1);
02094   PR_Write(fd, aOSABI.get(), aOSABI.Length());
02095 
02096   static const char kPlatformDirHeader[] = NS_LINEBREAK "LastPlatformDir=";
02097 
02098   PR_Write(fd, kPlatformDirHeader, sizeof(kPlatformDirHeader) - 1);
02099   PR_Write(fd, platformDir.get(), platformDir.Length());
02100 
02101   static const char kAppDirHeader[] = NS_LINEBREAK "LastAppDir=";
02102   if (aAppDir) {
02103     PR_Write(fd, kAppDirHeader, sizeof(kAppDirHeader) - 1);
02104     PR_Write(fd, appDir.get(), appDir.Length());
02105   }
02106 
02107   static const char kNL[] = NS_LINEBREAK;
02108   PR_Write(fd, kNL, sizeof(kNL) - 1);
02109 
02110   PR_Close(fd);
02111 }
02112 
02113 static PRBool ComponentsListChanged(nsIFile* aProfileDir)
02114 {
02115   nsCOMPtr<nsIFile> file;
02116   aProfileDir->Clone(getter_AddRefs(file));
02117   if (!file)
02118     return PR_TRUE;
02119   file->AppendNative(NS_LITERAL_CSTRING(".autoreg"));
02120 
02121   PRBool exists = PR_FALSE;
02122   file->Exists(&exists);
02123   return exists;
02124 }
02125 
02126 static void RemoveComponentRegistries(nsIFile* aProfileDir, nsIFile* aLocalProfileDir,
02127                                       PRBool aRemoveEMFiles)
02128 {
02129   nsCOMPtr<nsIFile> file;
02130   aProfileDir->Clone(getter_AddRefs(file));
02131   if (!file)
02132     return;
02133 
02134   file->AppendNative(NS_LITERAL_CSTRING("compreg.dat"));
02135   file->Remove(PR_FALSE);
02136 
02137   file->SetNativeLeafName(NS_LITERAL_CSTRING("xpti.dat"));
02138   file->Remove(PR_FALSE);
02139 
02140   file->SetNativeLeafName(NS_LITERAL_CSTRING(".autoreg"));
02141   file->Remove(PR_FALSE);
02142 
02143   if (aRemoveEMFiles) {
02144     file->SetNativeLeafName(NS_LITERAL_CSTRING("extensions.ini"));
02145     file->Remove(PR_FALSE);
02146   }
02147 
02148   aLocalProfileDir->Clone(getter_AddRefs(file));
02149   if (!file)
02150     return;
02151 
02152   file->AppendNative(NS_LITERAL_CSTRING("XUL" PLATFORM_FASL_SUFFIX));
02153   file->Remove(PR_FALSE);
02154 }
02155 
02156 // To support application initiated restart via nsIAppStartup.quit, we
02157 // need to save various environment variables, and then restore them
02158 // before re-launching the application.
02159 
02160 static struct {
02161   const char *name;
02162   char *value;
02163 } gSavedVars[] = {
02164   {"XUL_APP_FILE", nsnull}
02165 };
02166 
02167 static void SaveStateForAppInitiatedRestart()
02168 {
02169   for (size_t i = 0; i < NS_ARRAY_LENGTH(gSavedVars); ++i) {
02170     const char *s = PR_GetEnv(gSavedVars[i].name);
02171     if (s)
02172       gSavedVars[i].value = PR_smprintf("%s=%s", gSavedVars[i].name, s);
02173   }
02174 }
02175 
02176 static void RestoreStateForAppInitiatedRestart()
02177 {
02178   for (size_t i = 0; i < NS_ARRAY_LENGTH(gSavedVars); ++i) {
02179     if (gSavedVars[i].value)
02180       PR_SetEnv(gSavedVars[i].value);
02181   }
02182 }
02183 
02184 const nsXREAppData* gAppData = nsnull;
02185 
02186 #if defined(XP_OS2)
02187 // because we use early returns, we use a stack-based helper to un-set the OS2 FP handler
02188 class ScopedFPHandler {
02189 private:
02190   EXCEPTIONREGISTRATIONRECORD excpreg;
02191 
02192 public:
02193   ScopedFPHandler() { PR_OS2_SetFloatExcpHandler(&excpreg); }
02194   ~ScopedFPHandler() { PR_OS2_UnsetFloatExcpHandler(&excpreg); }
02195 };
02196 #endif
02197 
02198 #ifdef MOZ_WIDGET_GTK2
02199 #include "prlink.h"
02200 typedef void (*_g_set_application_name_fn)(const gchar *application_name);
02201 #endif
02202 
02203 int
02204 XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
02205 {
02206   nsresult rv;
02207   ArgResult ar;
02208   NS_TIMELINE_MARK("enter main");
02209 
02210 #ifdef DEBUG
02211   if (PR_GetEnv("XRE_MAIN_BREAK"))
02212     NS_BREAK();
02213 #endif
02214 
02215 #ifdef XP_WIN32
02216   // Suppress the "DLL Foo could not be found" dialog, such that if dependent
02217   // libraries (such as GDI+) are not preset, we gracefully fail to load those
02218   // XPCOM components, instead of being ungraceful.
02219   SetErrorMode(SEM_FAILCRITICALERRORS);
02220 
02221 #ifdef DEBUG
02222   // Disable small heap allocator to get heapwalk() giving us
02223   // accurate heap numbers. Win2k non-debug does not use small heap allocator.
02224   // Win2k debug seems to be still using it.
02225   // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt__set_sbh_threshold.asp
02226   _set_sbh_threshold(0);
02227 #endif
02228 #endif
02229 
02230 #if defined(XP_UNIX) || defined(XP_BEOS)
02231   InstallUnixSignalHandlers(argv[0]);
02232 #endif
02233 
02234 #ifdef MOZ_ACCESSIBILITY_ATK
02235   // Reset GTK_MODULES, strip atk-bridge if exists
02236   // Mozilla will load libatk-bridge.so later if necessary
02237   const char* gtkModules = PR_GetEnv("GTK_MODULES");
02238   if (gtkModules && *gtkModules) {
02239     nsCString gtkModulesStr(gtkModules);
02240     gtkModulesStr.ReplaceSubstring("atk-bridge", "");
02241     char* expr = PR_smprintf("GTK_MODULES=%s", gtkModulesStr.get());
02242     if (expr)
02243       PR_SetEnv(expr);
02244     // We intentionally leak |expr| here since it is required by PR_SetEnv.
02245   }
02246 #endif
02247 
02248   // Unbuffer stdout, needed for tinderbox tests.
02249   setbuf(stdout, 0);
02250 
02251 #if defined(FREEBSD)
02252   // Disable all SIGFPE's on FreeBSD, as it has non-IEEE-conformant fp
02253   // trap behavior that trips up on floating-point tests performed by
02254   // the JS engine.  See bugzilla bug 9967 details.
02255   fpsetmask(0);
02256 #endif
02257 
02258   gArgc = argc;
02259   gArgv = argv;
02260 
02261   NS_ASSERTION(aAppData, "must specify XUL app data");
02262 
02263   // In the future when nsXREAppData is extended, this check will need to
02264   // have more finesse.
02265   if (aAppData->size < sizeof(nsXREAppData)) {
02266     NS_ERROR("aAppdata.size isn't set properly!");
02267     return 1;
02268   }
02269 
02270 #ifdef XP_MACOSX
02271   // The xulrunner stub executable tricks CFBundleGetMainBundle on
02272   // purpose into lying about the main bundle path. It will set
02273   // XRE_BINARY_PATH to inform us of our real location.
02274   gBinaryPath = getenv("XRE_BINARY_PATH");
02275 
02276   if (gBinaryPath && !*gBinaryPath)
02277     gBinaryPath = nsnull;
02278 
02279   if (PR_GetEnv("MOZ_LAUNCHED_CHILD")) {
02280     // When the app relaunches, the original process exits.  This causes
02281     // the dock tile to stop bouncing, lose the "running" triangle, and
02282     // if the tile does not permanently reside in the Dock, even disappear.
02283     // This can be confusing to the user, who is expecting the app to launch.
02284     // Calling ReceiveNextEvent without requesting any event is enough to
02285     // cause a dock tile for the child process to appear.
02286     const EventTypeSpec kFakeEventList[] = { { INT_MAX, INT_MAX } };
02287     EventRef event;
02288     ::ReceiveNextEvent(GetEventTypeCount(kFakeEventList), kFakeEventList,
02289                        kEventDurationNoWait, PR_FALSE, &event);
02290   }
02291 
02292   if (CheckArg("foreground")) {
02293     // The original process communicates that it was in the foreground by
02294     // adding this argument.  This new process, which is taking over for
02295     // the old one, should make itself the active application.
02296     ProcessSerialNumber psn;
02297     if (::GetCurrentProcess(&psn) == noErr)
02298       ::SetFrontProcess(&psn);
02299   }
02300 #endif
02301 
02302   PR_SetEnv("MOZ_LAUNCHED_CHILD=");
02303 
02304   gAppData = aAppData;
02305 
02306   gRestartArgc = gArgc;
02307   gRestartArgv = (char**) malloc(sizeof(char*) * (gArgc + 1));
02308   if (!gRestartArgv) return 1;
02309 
02310   int i;
02311   for (i = 0; i < gArgc; ++i) {
02312     gRestartArgv[i] = gArgv[i];
02313   }
02314   gRestartArgv[gArgc] = nsnull;
02315 
02316 #if defined(XP_OS2)
02317   PRBool StartOS2App(int aArgc, char **aArgv);
02318   if (!StartOS2App(gArgc, gArgv))
02319     return 1;
02320   ScopedFPHandler handler;
02321 #endif /* XP_OS2 */
02322 
02323   ar = CheckArg("safe-mode", PR_TRUE);
02324   if (ar == ARG_BAD) {
02325     PR_fprintf(PR_STDERR, "Error: argument -safe-mode is invalid when argument -osint is specified\n");
02326     return 1;
02327   } else if (ar == ARG_FOUND) {
02328     gSafeMode = PR_TRUE;
02329   }
02330 
02331   // Handle -no-remote command line argument. Setup the environment to
02332   // better accommodate other components and various restart scenarios.
02333   ar = CheckArg("no-remote", PR_TRUE);
02334   if (ar == ARG_BAD) {
02335     PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n");
02336     return 1;
02337   } else if (ar == ARG_FOUND) {
02338     PR_SetEnv("MOZ_NO_REMOTE=1");
02339   }
02340 
02341   // Handle -help and -version command line arguments.
02342   // They should return quickly, so we deal with them here.
02343   if (CheckArg("h") || CheckArg("help") || CheckArg("?")) {
02344     DumpHelp();
02345     return 0;
02346   }
02347 
02348   if (CheckArg("v") || CheckArg("version")) {
02349     DumpVersion();
02350     return 0;
02351   }
02352     
02353 #ifdef NS_TRACE_MALLOC
02354   gArgc = argc = NS_TraceMallocStartupArgs(argc, argv);
02355 #endif
02356 
02357   nsXREDirProvider dirProvider;
02358   {
02359     rv = dirProvider.Initialize(gAppData->directory);
02360     if (NS_FAILED(rv))
02361       return 1;
02362   }
02363 
02364   // Check for -register, which registers chrome and then exits immediately.
02365 
02366   ar = CheckArg("register", PR_TRUE);
02367   if (ar == ARG_BAD) {
02368     PR_fprintf(PR_STDERR, "Error: argument -register is invalid when argument -osint is specified\n");
02369     return 1;
02370   } else if (ar == ARG_FOUND) {
02371     ScopedXPCOMStartup xpcom;
02372     rv = xpcom.Initialize();
02373     NS_ENSURE_SUCCESS(rv, 1);
02374 
02375     {
02376       nsCOMPtr<nsIChromeRegistry> chromeReg
02377         (do_GetService("@mozilla.org/chrome/chrome-registry;1"));
02378       NS_ENSURE_TRUE(chromeReg, 1);
02379 
02380       chromeReg->CheckForNewChrome();
02381     }
02382     return 0;
02383   }
02384 
02385 #if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_GTK2)
02386   // setup for private colormap.  Ideally we'd like to do this
02387   // in nsAppShell::Create, but we need to get in before gtk
02388   // has been initialized to make sure everything is running
02389   // consistently.
02390 #if defined(MOZ_WIDGET_GTK2)
02391   g_thread_init(NULL);
02392 #endif
02393   if (CheckArg("install"))
02394     gdk_rgb_set_install(TRUE);
02395 
02396   // Initialize GTK+1/2 here for splash
02397 #if defined(MOZ_WIDGET_GTK)
02398   gtk_set_locale();
02399 #endif
02400   gtk_init(&gArgc, &gArgv);
02401 
02402 #if defined(MOZ_WIDGET_GTK2)
02403   // g_set_application_name () is only defined in glib2.2 and higher.
02404   PRLibrary *glib2 = nsnull;
02405   _g_set_application_name_fn _g_set_application_name =
02406       (_g_set_application_name_fn)PR_FindFunctionSymbolAndLibrary("g_set_application_name", &glib2);
02407   if (_g_set_application_name) {
02408     _g_set_application_name(gAppData->name);
02409   }
02410   if (glib2) {
02411     PR_UnloadLibrary(glib2);
02412   }
02413 #endif
02414 
02415   gtk_widget_set_default_visual(gdk_rgb_get_visual());
02416   gtk_widget_set_default_colormap(gdk_rgb_get_cmap());
02417 #endif /* MOZ_WIDGET_GTK || MOZ_WIDGET_GTK2 */
02418 
02419 #if defined(MOZ_WIDGET_QT)
02420   QApplication qapp(argc, argv);
02421 #endif
02422 
02423 // #if defined(MOZ_WIDGET_XLIB)
02424 // XXXtimeless fix me! How do we get a Display from here to nsAppShell.cpp ?
02425 // #endif
02426     
02427   // Call the code to install our handler
02428 #ifdef MOZ_JPROF
02429   setupProfilingStuff();
02430 #endif
02431 
02432   // Try to allocate "native app support."
02433   nsCOMPtr<nsINativeAppSupport> nativeApp;
02434   rv = NS_CreateNativeAppSupport(getter_AddRefs(nativeApp));
02435   if (NS_FAILED(rv))
02436     return 1;
02437 
02438   PRBool canRun = PR_FALSE;
02439   rv = nativeApp->Start(&canRun);
02440   if (NS_FAILED(rv) || !canRun) {
02441     return 1;
02442   }
02443 
02444   //----------------------------------------------------------------
02445   // We need to check if a previous installation occured and
02446   // if so, make sure it finished and cleaned up correctly.
02447   //
02448   // If there is an xpicleanup.dat file left around, that means the
02449   // previous installation did not finish correctly. We must cleanup
02450   // before a valid mozilla can run.
02451   //
02452   // Show the user a platform-specific Alert message, then spawn the
02453   // xpicleanup utility, then exit.
02454   //----------------------------------------------------------------
02455   nsCOMPtr<nsIFile> registryFile;
02456   rv = dirProvider.GetAppDir()->Clone(getter_AddRefs(registryFile));
02457   if (NS_SUCCEEDED(rv)) {
02458     registryFile->AppendNative(CLEANUP_REGISTRY);
02459 
02460     PRBool exists;
02461     rv = registryFile->Exists(&exists);
02462     if (NS_SUCCEEDED(rv) && exists) {
02463       return VerifyInstallation(dirProvider.GetAppDir());
02464     }
02465   }
02466 
02467 #ifdef MOZ_ENABLE_XREMOTE
02468   // handle -remote now that xpcom is fired up
02469 
02470   const char* xremotearg;
02471   ar = CheckArg("remote", PR_TRUE, &xremotearg);
02472   if (ar == ARG_BAD) {
02473     PR_fprintf(PR_STDERR, "Error: -remote requires an argument\n");
02474     return 1;
02475   }
02476   if (ar) {
02477     return HandleRemoteArgument(xremotearg);
02478   }
02479 
02480   if (!PR_GetEnv("MOZ_NO_REMOTE")) {
02481     // Try to remote the entire command line. If this fails, start up normally.
02482     RemoteResult rr = RemoteCommandLine();
02483     if (rr == REMOTE_FOUND)
02484       return 0;
02485     else if (rr == REMOTE_ARG_BAD)
02486       return 1;
02487   }
02488 #endif
02489 
02490 #if defined(MOZ_UPDATER)
02491   // If this is a XULRunner app then the updater needs to know the base
02492   // directory that contains the application.ini file. This should be the
02493   // parent of the xulrunner directory on Windows/Linux and it should be the
02494   // Contents directory on MacOSX. Just in case someone packaged their app
02495   // incorrectly we'll pass the directory here.
02496   nsCOMPtr<nsIFile> greDir = dirProvider.GetAppDir();
02497   NS_ENSURE_TRUE(greDir, 1);
02498 
02499   nsCOMPtr<nsIFile> appDir;
02500   PRBool dummy;
02501   rv = dirProvider.GetFile("resource:app",
02502                            &dummy,
02503                            getter_AddRefs(appDir));
02504   if (NS_FAILED(rv)) {
02505     // This must not be a XULRunner app
02506     appDir = greDir;
02507   }
02508 
02509   // Check for and process any available updates
02510   nsCOMPtr<nsIFile> updRoot;
02511   PRBool persistent;
02512   rv = dirProvider.GetFile(XRE_UPDATE_ROOT_DIR, &persistent,
02513                            getter_AddRefs(updRoot));
02514   // XRE_UPDATE_ROOT_DIR may fail. Fallback to appDir if failed
02515   if (NS_FAILED(rv))
02516     updRoot = dirProvider.GetAppDir();
02517 
02518   // Check for and process any available updates
02519   ProcessUpdates(greDir,
02520                  appDir,
02521                  updRoot,
02522                  gRestartArgc,
02523                  gRestartArgv);
02524 #endif
02525 
02526   nsCOMPtr<nsIProfileLock> profileLock;
02527   PRBool startOffline = PR_FALSE;
02528 
02529   rv = SelectProfile(getter_AddRefs(profileLock), nativeApp, &startOffline);
02530   if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS ||
02531       rv == NS_ERROR_ABORT) return 0;
02532   if (NS_FAILED(rv)) return 1;
02533 
02534   nsCOMPtr<nsILocalFile> profD;
02535   rv = profileLock->GetDirectory(getter_AddRefs(profD));
02536   NS_ENSURE_SUCCESS(rv, 1);
02537 
02538   nsCOMPtr<nsILocalFile> profLD;
02539   rv = profileLock->GetLocalDirectory(getter_AddRefs(profLD));
02540   NS_ENSURE_SUCCESS(rv, 1);
02541 
02542   rv = dirProvider.SetProfile(profD, profLD);
02543   NS_ENSURE_SUCCESS(rv, 1);
02544 
02546 
02547   PRBool upgraded = PR_FALSE;
02548 
02549   nsCAutoString version;
02550   BuildVersion(version);
02551 
02552 #ifdef TARGET_OS_ABI
02553     NS_NAMED_LITERAL_CSTRING(osABI, TARGET_OS_ABI);
02554 #else
02555     // No TARGET_XPCOM_ABI, but at least the OS is known
02556     NS_NAMED_LITERAL_CSTRING(osABI, OS_TARGET "_UNKNOWN");
02557 #endif
02558 
02559   // Check for version compatibility with the last version of the app this 
02560   // profile was started with.  The format of the version stamp is defined
02561   // by the BuildVersion function.
02562   PRBool versionOK = CheckCompatibility(profD, version, osABI,
02563                                         dirProvider.GetAppDir(),
02564                                         gAppData->directory);
02565 
02566   // Every time a profile is loaded by a build with a different version,
02567   // it updates the compatibility.ini file saying what version last wrote
02568   // the compreg.dat.  On subsequent launches if the version matches, 
02569   // there is no need for re-registration.  If the user loads the same
02570   // profile in different builds the component registry must be
02571   // re-generated to prevent mysterious component loading failures.
02572   //
02573   if (gSafeMode) {
02574     RemoveComponentRegistries(profD, profLD, PR_FALSE);
02575     WriteVersion(profD, NS_LITERAL_CSTRING("Safe Mode"), osABI,
02576                  dirProvider.GetAppDir(), gAppData->directory);
02577   }
02578   else if (versionOK) {
02579     if (ComponentsListChanged(profD)) {
02580       // Remove compreg.dat and xpti.dat, forcing component re-registration,
02581       // with the new list of additional components directories specified
02582       // in "components.ini" which we have just discovered changed since the
02583       // last time the application was run. 
02584       RemoveComponentRegistries(profD, profLD, PR_FALSE);
02585     }
02586     // Nothing need be done for the normal startup case.
02587   }
02588   else {
02589     // Remove compreg.dat and xpti.dat, forcing component re-registration
02590     // with the default set of components (this disables any potentially
02591     // troublesome incompatible XPCOM components). 
02592     RemoveComponentRegistries(profD, profLD, PR_TRUE);
02593 
02594     // Tell the Extension Manager it should check for incompatible 
02595     // Extensions and re-write the Components manifest ("components.ini")
02596     // with a list of XPCOM components for compatible extensions
02597     upgraded = PR_TRUE;
02598 
02599     // Write out version
02600     WriteVersion(profD, version, osABI,
02601                  dirProvider.GetAppDir(), gAppData->directory);
02602   }
02603 
02604   PRBool needsRestart = PR_FALSE;
02605   PRBool appInitiatedRestart = PR_FALSE;
02606 
02607   // Allows the user to forcefully bypass the restart process at their
02608   // own risk. Useful for debugging or for tinderboxes where child 
02609   // processes can be problematic.
02610   {
02611     // Start the real application
02612     ScopedXPCOMStartup xpcom;
02613     rv = xpcom.Initialize();
02614     NS_ENSURE_SUCCESS(rv, 1); 
02615     rv = xpcom.DoAutoreg();
02616     rv |= xpcom.InitEventQueue();
02617     rv |= xpcom.SetWindowCreator(nativeApp);
02618     NS_ENSURE_SUCCESS(rv, 1);
02619 
02620     {
02621       if (startOffline) {
02622         nsCOMPtr<nsIIOService> io (do_GetService("@mozilla.org/network/io-service;1"));
02623         NS_ENSURE_TRUE(io, 1);
02624         io->SetOffline(PR_TRUE);
02625       }
02626 
02627       {
02628         NS_TIMELINE_ENTER("startupNotifier");
02629         nsCOMPtr<nsIObserver> startupNotifier
02630           (do_CreateInstance(NS_APPSTARTUPNOTIFIER_CONTRACTID, &rv));
02631         NS_ENSURE_SUCCESS(rv, 1);
02632 
02633         startupNotifier->Observe(nsnull, APPSTARTUP_TOPIC, nsnull);
02634         NS_TIMELINE_LEAVE("startupNotifier");
02635       }
02636 
02637       nsCOMPtr<nsIAppStartup> appStartup
02638         (do_GetService(NS_APPSTARTUP_CONTRACTID));
02639       NS_ENSURE_TRUE(appStartup, 1);
02640 
02641       // So we can open and close windows during startup
02642       appStartup->EnterLastWindowClosingSurvivalArea();
02643 
02644       if (gDoMigration) {
02645         nsCOMPtr<nsIFile> file;
02646         dirProvider.GetAppDir()->Clone(getter_AddRefs(file));
02647         file->AppendNative(NS_LITERAL_CSTRING("override.ini"));
02648         nsINIParser parser;
02649         nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(file));
02650         nsresult rv = parser.Init(localFile);
02651         if (NS_SUCCEEDED(rv)) {
02652           nsCAutoString buf;
02653           rv = parser.GetString("XRE", "EnableProfileMigrator", buf);
02654           if (NS_SUCCEEDED(rv)) {
02655             if (buf[0] == '0' || buf[0] == 'f' || buf[0] == 'F') {
02656               gDoMigration = PR_FALSE;
02657             }
02658           }
02659         }
02660       }
02661 
02662       // Profile Migration
02663       if (gAppData->flags & NS_XRE_ENABLE_PROFILE_MIGRATOR && gDoMigration) {
02664         gDoMigration = PR_FALSE;
02665         nsCOMPtr<nsIProfileMigrator> pm
02666           (do_CreateInstance(NS_PROFILEMIGRATOR_CONTRACTID));
02667         if (pm)
02668           pm->Migrate(&dirProvider);
02669       }
02670       dirProvider.DoStartup();
02671 
02672       nsCOMPtr<nsICommandLineRunner> cmdLine
02673         (do_CreateInstance("@mozilla.org/toolkit/command-line;1"));
02674       NS_ENSURE_TRUE(cmdLine, 1);
02675 
02676       nsCOMPtr<nsIFile> workingDir;
02677       rv = NS_GetSpecialDirectory(NS_OS_CURRENT_WORKING_DIR, getter_AddRefs(workingDir));
02678       NS_ENSURE_SUCCESS(rv, 1);
02679 
02680       rv = cmdLine->Init(gArgc, gArgv,
02681                          workingDir, nsICommandLine::STATE_INITIAL_LAUNCH);
02682       NS_ENSURE_SUCCESS(rv, 1);
02683 
02684       /* Special-case services that need early access to the command
02685          line. */
02686       nsCOMPtr<nsIObserver> chromeObserver
02687         (do_GetService("@mozilla.org/chrome/chrome-registry;1"));
02688       if (chromeObserver) {
02689         chromeObserver->Observe(cmdLine, "command-line-startup", nsnull);
02690       }
02691 
02692       NS_TIMELINE_ENTER("appStartup->CreateHiddenWindow");
02693       rv = appStartup->CreateHiddenWindow();
02694       NS_TIMELINE_LEAVE("appStartup->CreateHiddenWindow");
02695       NS_ENSURE_SUCCESS(rv, 1);
02696 
02697       // Extension Compatibility Checking and Startup
02698       if (gAppData->flags & NS_XRE_ENABLE_EXTENSION_MANAGER) {
02699         nsCOMPtr<nsIExtensionManager> em(do_GetService("@mozilla.org/extensions/manager;1"));
02700         NS_ENSURE_TRUE(em, 1);
02701 
02702         ar = CheckArg("install-global-extension", PR_TRUE);
02703         if (ar == ARG_BAD) {
02704           PR_fprintf(PR_STDERR, "Error: argument -install-global-extension is invalid when argument -osint is specified\n");
02705           return 1;
02706         } else if (ar == ARG_FOUND) {
02707           // Do the required processing and then shut down.
02708           em->HandleCommandLineArgs(cmdLine);
02709           return 0;
02710         }
02711 
02712         ar = CheckArg("install-global-theme", PR_TRUE);
02713         if (ar == ARG_BAD) {
02714           PR_fprintf(PR_STDERR, "Error: argument -install-global-theme is invalid when argument -osint is specified\n");
02715           return 1;
02716         } else if (ar == ARG_FOUND) {
02717           // Do the required processing and then shut down.
02718           em->HandleCommandLineArgs(cmdLine);
02719           return 0;
02720         }
02721 
02722         if (upgraded) {
02723           rv = em->CheckForMismatches(&needsRestart);
02724           if (NS_FAILED(rv)) {
02725             needsRestart = PR_FALSE;
02726             upgraded = PR_FALSE;
02727           }
02728         }
02729 
02730         if (!upgraded || !needsRestart)
02731           em->Start(cmdLine, &needsRestart);
02732       }
02733 
02734       // We want to restart no more than 2 times. The first restart,
02735       // NO_EM_RESTART == "0" , and the second time, "1".
02736       char* noEMRestart = PR_GetEnv("NO_EM_RESTART");
02737       if (noEMRestart && *noEMRestart && *noEMRestart == '1') {
02738         if (upgraded || needsRestart) {
02739           NS_WARNING("EM tried to force us to restart twice! Forcefully preventing that.");
02740         }
02741         needsRestart = upgraded = PR_FALSE;
02742       }
02743 
02744       if (!upgraded && !needsRestart) {
02745         SaveStateForAppInitiatedRestart();
02746 
02747         // clear out any environment variables which may have been set 
02748         // during the relaunch process now that we know we won't be relaunching.
02749         PR_SetEnv("XRE_PROFILE_PATH=");
02750         PR_SetEnv("XRE_PROFILE_LOCAL_PATH=");
02751         PR_SetEnv("XRE_START_OFFLINE=");
02752         PR_SetEnv("XRE_IMPORT_PROFILES=");
02753         PR_SetEnv("NO_EM_RESTART=");
02754         PR_SetEnv("XUL_APP_FILE=");
02755         PR_SetEnv("XRE_BINARY_PATH=");
02756 
02757 #ifdef XP_MACOSX
02758         // we re-initialize the command-line service and do appleevents munging
02759         // after we are sure that we're not restarting
02760         cmdLine = do_CreateInstance("@mozilla.org/toolkit/command-line;1");
02761         NS_ENSURE_TRUE(cmdLine, 1);
02762 
02763         SetupMacCommandLine(gArgc, gArgv);
02764 
02765         rv = cmdLine->Init(gArgc, gArgv,
02766                            workingDir, nsICommandLine::STATE_INITIAL_LAUNCH);
02767         NS_ENSURE_SUCCESS(rv, 1);
02768 
02769         // Kick off the prebinding update now that we know we won't be
02770         // relaunching.
02771 
02772         UpdatePrebinding();
02773 #endif
02774         nsCOMPtr<nsIObserverService> obsService
02775           (do_GetService("@mozilla.org/observer-service;1"));
02776         if (obsService)
02777           obsService->NotifyObservers(nsnull, "final-ui-startup", nsnull);        
02778 
02779         rv = cmdLine->Run();
02780         NS_ENSURE_SUCCESS_LOG(rv, 1);
02781 
02782         nsCOMPtr<nsIWindowMediator> windowMediator
02783           (do_GetService(NS_WINDOWMEDIATOR_CONTRACTID, &rv));
02784         NS_ENSURE_SUCCESS(rv, 1);
02785 
02786         // Make sure there exists at least 1 window.
02787         nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
02788         rv = windowMediator->GetEnumerator(nsnull, getter_AddRefs(windowEnumerator));
02789         NS_ENSURE_SUCCESS(rv, 1);
02790 
02791         PRBool more;
02792         windowEnumerator->HasMoreElements(&more);
02793         if (!more) {
02794           // We didn't open any windows. This is normally not a good thing,
02795           // so we force console logging to file.
02796           gLogConsoleErrors = PR_TRUE;
02797         }
02798         else {
02799 #ifndef XP_MACOSX
02800           appStartup->ExitLastWindowClosingSurvivalArea();
02801 #endif
02802 
02803 #ifdef MOZ_ENABLE_XREMOTE
02804           // if we have X remote support and we have our one window up and
02805           // running start listening for requests on the proxy window.
02806           nsCOMPtr<nsIRemoteService> remoteService;
02807           remoteService = do_GetService("@mozilla.org/toolkit/remote-service;1");
02808           if (remoteService)
02809             remoteService->Startup(gAppData->name, nsnull);
02810 #endif /* MOZ_ENABLE_XREMOTE */
02811 
02812           // enable win32 DDE responses and Mac appleevents responses
02813           nativeApp->Enable();
02814 
02815           // Start main event loop
02816           NS_TIMELINE_ENTER("appStartup->Run");
02817           rv = appStartup->Run();
02818           NS_TIMELINE_LEAVE("appStartup->Run");
02819           if (NS_FAILED(rv)) {
02820             NS_ERROR("failed to run appstartup");
02821             gLogConsoleErrors = PR_TRUE;
02822           }
02823 
02824           // Check for an application initiated restart.  This is one that
02825           // corresponds to nsIAppStartup.quit(eRestart)
02826           if (rv == NS_SUCCESS_RESTART_APP) {
02827             needsRestart = PR_TRUE;
02828             appInitiatedRestart = PR_TRUE;
02829           }
02830 
02831 #ifdef MOZ_ENABLE_XREMOTE
02832           // shut down the x remote proxy window
02833           if (remoteService)
02834             remoteService->Shutdown();
02835 #endif /* MOZ_ENABLE_XREMOTE */
02836         }
02837 
02838 #ifdef MOZ_TIMELINE
02839         // Make sure we print this out even if timeline is runtime disabled
02840         if (NS_FAILED(NS_TIMELINE_LEAVE("main1")))
02841           NS_TimelineForceMark("...main1");
02842 #endif
02843       }
02844       else {
02845         // Upgrade condition (build id changes), but the restart hint was 
02846         // not set by the Extension Manager. This is because the compatibility
02847         // resolution for Extensions is different than for the component 
02848         // registry - major milestone vs. build id. 
02849         needsRestart = PR_TRUE;
02850 
02851 #ifdef XP_WIN
02852         ProcessDDE(nativeApp);
02853 #endif
02854 
02855 #ifdef XP_MACOSX
02856         SetupMacCommandLine(gRestartArgc, gRestartArgv);
02857 #endif
02858       }
02859     }
02860 
02861     profileLock->Unlock();
02862   }
02863 
02864   // Restart the app after XPCOM has been shut down cleanly. 
02865   if (needsRestart) {
02866     if (appInitiatedRestart) {
02867       RestoreStateForAppInitiatedRestart();
02868     }
02869     else {
02870       char* noEMRestart = PR_GetEnv("NO_EM_RESTART");
02871       if (noEMRestart && *noEMRestart) {
02872         PR_SetEnv("NO_EM_RESTART=1");
02873       }
02874       else {
02875         PR_SetEnv("NO_EM_RESTART=0");
02876       }
02877     }
02878 
02879     // Ensure that these environment variables are set:
02880     SaveFileToEnvIfUnset("XRE_PROFILE_PATH", profD);
02881     SaveFileToEnvIfUnset("XRE_PROFILE_LOCAL_PATH", profLD);
02882 
02883 #ifdef XP_MACOSX
02884     if (gBinaryPath) {
02885       static char kEnvVar[MAXPATHLEN];
02886       sprintf(kEnvVar, "XRE_BINARY_PATH=%s", gBinaryPath);
02887       PR_SetEnv(kEnvVar);
02888     }
02889 #endif
02890 
02891     rv = LaunchChild(nativeApp, appInitiatedRestart, upgraded ? -1 : 0);
02892     return rv == NS_ERROR_LAUNCHED_CHILD_PROCESS ? 0 : 1;
02893   }
02894 
02895   return NS_FAILED(rv) ? 1 : 0;
02896 }