home *** CD-ROM | disk | FTP | other *** search
/ Australian Personal Computer 2004 September / APC0409D1.iso / f_looks / files / adblock-0.5-dev.xpi / chrome / adblock.jar / content / uninstall.js < prev    next >
Encoding:
JavaScript  |  2004-01-03  |  19.4 KB  |  470 lines

  1. /*
  2. ** authored by rue and Wladimir, with code adapted from the optimoz project
  3. */
  4.  
  5. /* global vars for uninstall-status */
  6. var removalCheckArray = new Array(); // the array of our deinstall "checks"
  7. var reportN; // the total value of our deinstall "checks"
  8. var syncComplete = false; // if true, all synchronous operations have completed
  9. var quitTimer; // repeatedly checks if asynchronous disk-operations have completed
  10. var quitTimerMonitor; // monitors the quitTimer -- stops it after 120 seconds
  11. var isProfileInstalled = false; // if true, component-removal will be unnecessary -- set by deleteJar()
  12.  
  13.  
  14. // confirm and begin the uninstall
  15. function uninstallAdblock() {
  16.     
  17.   var confirmUninstall = confirm("Do you really want to deinstall Adblock?-\n..the proceedure may take up to two-minutes, and the browser will have to quit immediately afterwards." );
  18.   
  19.     // user choose to cancel
  20.     if (!confirmUninstall) 
  21.         return; // do nothing further
  22.     
  23.     document.getElementById("deinstall-menuitem").setAttribute("disabled", true); // disable the "DeInstall" menuitem
  24.  
  25.     // initialize our removal-check array    
  26.     removalCheckArray[0] = 0; // removeRDFOverlayEntries
  27.     removalCheckArray[1] = 0; // removeInstalledChrome
  28.     removalCheckArray[2] = 0; // deleteJar                :UNAGGREGATED
  29.     removalCheckArray[3] = 0; // deleteXULCache            :UNAGGREGATED
  30.     removalCheckArray[4] = 0; // deleteComponent        :UNAGGREGATED
  31.     removalCheckArray[5] = 0; // removeCompregDat
  32.     
  33.     setShutdownTimers(); // sets the shutdown timers, which wait a while so asynchronous disk-operations can complete
  34.  
  35.     removeChromeAndOverlayEntries(); // remove all entries from the rdf-overlays
  36.     removeInstalledChrome(); // remove all entries from installed-chrome.txt
  37.     //disableFurtherAdblocking(); // disable adblock services / menuitems
  38.     deleteJar(); // delete the jar-file
  39.     deleteXULCache(); // delete the xul cache-file
  40.     deleteComponent(); // delete the adblock-component
  41.     removeCompregDat(); // remove all entries from compreg.dat
  42.     
  43.     syncComplete = true;
  44.     
  45.     
  46. }
  47.  
  48. // sets the shutdown timers -- ensures asynchronous disk-operations have completed
  49. function setShutdownTimers() {
  50.     // if all checks completed, or just the unaggregated-checks failed, close out -!
  51.     quitTimer = setInterval('\
  52.         if (syncComplete) {\
  53.             reportN = 0;\
  54.             for (var r = 0 ; r < removalCheckArray.length ; r++)\
  55.                 reportN += removalCheckArray[r];\
  56. \
  57.             if (reportN == 6) {\
  58.                 clearInterval(quitTimer);\
  59.                 clearInterval(quitTimerMonitor);\
  60.                 shutdownMonitor(); }\
  61.             else if (reportN >= 3 && (removalCheckArray[2] + removalCheckArray[3] + removalCheckArray[4] == reportN-3)) {\
  62.                 clearInterval(quitTimer);\
  63.                 clearInterval(quitTimerMonitor); shutdownMonitor(); }\
  64. \
  65.         }',500);
  66.         
  67.     quitTimerMonitor = setInterval('clearInterval(quitTimer); clearInterval(quitTimerMonitor); failureNotify();', 120000);
  68. }
  69.  
  70.  
  71. // activates and monitors the shutdown proceedure
  72. function shutdownMonitor() {
  73.     if (!shutdownAppNow())
  74.         alert("Adblock was unable to shutdown the browser. \n\nYou are strongly advised to close all windows and shutdown the app.");
  75. }
  76.  
  77. // alerts the user to "deinstall-failure" -- the timer doesn't like string-literals
  78. function failureNotify() {
  79.     alert("DeInstallation failed. \n\n\ " + removalCheckArray[0] + removalCheckArray[1] + removalCheckArray[2] + removalCheckArray[3] + removalCheckArray[4] + removalCheckArray[5] + "\n\nPlease post this error-code, along with the browser-name, build date, and any other information you think might be relevant, to:\n\n    adblock.mozdev.org/forum.html/no_wrap\n\n  Thank You. \n--The Adblock Team");
  80. }
  81.  
  82. // removes entries from the rdf-overlays in user-chrome and app-chrome and corresponding entries in chrome.rdf
  83. function removeChromeAndOverlayEntries() {
  84.     const DIRSERVICE_CONTRACTID     = '@mozilla.org/file/directory_service;1';
  85.     const IOSERVICE_CONTRACTID      = '@mozilla.org/network/io-service;1';
  86.     const RDFSERVICE_CONTRACTID     = '@mozilla.org/rdf/rdf-service;1';
  87.     const CONTAINERUTILS_CONTRACTID = '@mozilla.org/rdf/container-utils;1';
  88.     
  89.     var dirService = Components.classes[DIRSERVICE_CONTRACTID].getService(Components.interfaces.nsIProperties);
  90.     var ioService = Components.classes[IOSERVICE_CONTRACTID].getService(Components.interfaces.nsIIOService);
  91.     var fileHandler = ioService.getProtocolHandler('file').QueryInterface(Components.interfaces.nsIFileProtocolHandler);
  92.     var rdf  = Components.classes[RDFSERVICE_CONTRACTID].getService(Components.interfaces.nsIRDFService);
  93.     var utils = Components.classes[CONTAINERUTILS_CONTRACTID].getService(Components.interfaces.nsIRDFContainerUtils);
  94.  
  95.     const overlayURL = 'chrome://adblock/content/adblock.xul'
  96.     
  97.     var dirArray = new Array();
  98.     var nameArray = new Array();
  99.     var overlayArray = new Array();
  100.     var parents = new Array();
  101.     var chromeDir, chromefile, overlay, datasource, sequence;
  102.  
  103.     dirArray[0] = "UChrm"; // profile-chrome magic-key
  104.     dirArray[1] = "AChrom"; // application-chrome magic-key
  105.     nameArray[0] = "browser";
  106.     nameArray[1] = "navigator";
  107.     //nameArray[2] = "communicator";
  108.     //nameArray[3] = "messenger";
  109.     const rootSequence = "urn:mozilla:package:root";
  110.     const adblockSequence = "urn:mozilla:package:adblock";
  111.     parents[0] = rootSequence;
  112.     parents[1] = adblockSequence;
  113.     parents[2] = "chrome://communicator/content/communicatorOverlay.xul";
  114.     parents[3] = "chrome://browser/content/browser.xul";
  115.     parents[4] = "chrome://navigator/content/navigator.xul";
  116.     //parents[5] = "chrome://communicator/content/tasksOverlay.xul";
  117.     //parents[6] = "chrome://messenger/content/mailWindowOverlay.xul";
  118.  
  119.     // for each chrome-dir, get all overlay files
  120.     for (var i = 0; i < dirArray.length; i++) {
  121.         chromeDir = dirService.get(dirArray[i], Components.interfaces.nsIFile);
  122.         chromefile = chromeDir.clone();
  123.         chromefile.append("chrome.rdf");
  124.         if (chromefile.exists() && chromefile.isReadable() && chromefile.isWritable())
  125.             overlayArray.push(chromefile); // chrome-registry
  126.         for (var j = 0; j < nameArray.length; j++) {
  127.             overlay = chromeDir.clone();
  128.             overlay.append("overlayinfo");
  129.             overlay.append(nameArray[j]);
  130.             overlay.append("content");
  131.             overlay.append("overlays.rdf");
  132.             if (overlay.exists() && overlay.isReadable() && overlay.isWritable())
  133.                 overlayArray.push(overlay); // only keep if we have permissions
  134.         }
  135.     }
  136.  
  137.     for (i = 0; i < overlayArray.length; i++) {
  138.         overlay = fileHandler.newFileURI(overlayArray[i]).spec;
  139.         datasource = rdf.GetDataSourceBlocking(overlay);
  140.         
  141.         if (datasource) {
  142.             for (var k = 0; k < parents.length; k++) {
  143.                 sequence = utils.MakeSeq(datasource, rdf.GetResource(parents[k]));
  144.                 if (sequence) {
  145.                     var element = (parents[k] == rootSequence && overlayArray[i].leafName == "chrome.rdf") ?
  146.                         rdf.GetResource(adblockSequence).QueryInterface(Components.interfaces.nsIRDFNode)
  147.                         :
  148.                         rdf.GetLiteral(overlayURL);
  149.                     sequence.RemoveElement(element, true);
  150.  
  151.                     // Remove parent container -- if node is left empty, or we're eliminating *our* chrome.rdf-sequence
  152.                     if (sequence.GetCount() == 0 || 
  153.                             (overlayArray[i].leafName == "chrome.rdf" && parents[k] == adblockSequence)) {
  154.                         var it = datasource.ArcLabelsOut(rdf.GetResource(parents[k]));
  155.                         while (it.hasMoreElements()) {
  156.                             var property = it.getNext();
  157.                             var target = datasource.GetTarget(rdf.GetResource(parents[k]), property, true);
  158.                             if (property && target)
  159.                                 datasource.Unassert(rdf.GetResource(parents[k]), property, target);
  160.                         }
  161.                     }
  162.                 }
  163.             }
  164.  
  165.             datasource.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource).Flush();
  166.         }
  167.     }
  168.     removalCheckArray[0]++;
  169. }
  170.  
  171.  
  172. // removes the installed-chrome.txt entries
  173. function removeInstalledChrome() {
  174.     var dirService = Components.classes['@mozilla.org/file/directory_service;1'].getService(Components.interfaces.nsIProperties);
  175.  
  176.     var installedChromeArray = new Array();
  177.     installedChromeArray[0] = dirService.get("UChrm", Components.interfaces.nsIFile); // app-chrome file
  178.     installedChromeArray[1] = dirService.get("AChrom", Components.interfaces.nsIFile); // profile-chrome file
  179.     
  180.     installedChromeArray[0].append("installed-chrome.txt");
  181.     installedChromeArray[1].append("installed-chrome.txt");
  182.     
  183.     var streamIn = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);
  184.     var streamOut = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
  185.     var wrappedIn = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream);
  186.     var input;
  187.     
  188.     var chromeRe = /.*\/chrome\/adblock\.jar\!\/content\/.*[\r\n]+/gi; // catch abberrant newlines also
  189.     
  190.     for (var n = 0 ; n < installedChromeArray.length ; n++) {
  191.         if (installedChromeArray[n].exists()) {
  192.             streamIn.init(installedChromeArray[n], 0x01, 0444, null);
  193.             wrappedIn.init(streamIn);
  194.             input = wrappedIn.read(streamIn.available());
  195.             wrappedIn.close();
  196.             streamIn.close();
  197.             
  198.             //alert(input);
  199.     
  200.             while (chromeRe.test(input))
  201.                 input = input.replace(chromeRe, '');
  202.             
  203.             installedChromeArray[n].remove(true); // remove the file so we can replace it
  204.             installedChromeArray[n].create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0666); // create a new, blank file -- there's no way to empty an existing one
  205.     
  206.             streamOut.init(installedChromeArray[n], 0x02, 0x200, null);
  207.             streamOut.flush();
  208.             streamOut.write(input, input.length);
  209.             streamOut.close();
  210.             
  211.             removalCheckArray[1]++;
  212.         }
  213.     }
  214. }
  215.  
  216.  
  217. // UNUSED: never got this working -- disables adblock's services and menuitems
  218. function disableFurtherAdblocking() {
  219.  
  220.     var windowMediator = Components.classes['@mozilla.org/appshell/window-mediator;1'].getService(Components.interfaces.nsIWindowMediator);
  221.     var enumerator = windowMediator.getEnumerator("navigator:browser"); // the iterator returns domWindows (using getNext() )
  222.     var win; // enumerator reference object
  223.     var windowObject; // the converted DOM-window object
  224.     var browsers;
  225.     
  226.     while(enumerator.hasMoreElements()) {
  227.         win = enumerator.getNext();
  228.         browsers = win.getBrowser().browsers;
  229.  
  230.         for (var i = 0; i < browsers.length; i++) {
  231.             try {
  232.                 browsers[i].contentDocument.removeEventListener("keypress", checkEvent, true); // remove binding listener
  233.                 browsers[i].contentDocument.removeEventListener("contextmenu", checkContextMenu, true); // remove context-click listener
  234.                 // ^^^___ contentWindow would access the local "window" object
  235.             } catch(e) {alert("Access to browser[" + i + "].webNavigation failed: " + e);}
  236.         }
  237.         
  238.     }
  239.  
  240.     
  241.     /*
  242.     var browsers = win.getBrowser().browsers;
  243.     for (var i = 0; i < browsers.length; i++) {
  244.         try {
  245.             nextLocation = browsers[i].currentURI.hostPort;
  246.         }
  247.         catch(ex) { 
  248.         //blank window
  249.         }
  250.         
  251.         if (nextLocation) {
  252.     */
  253.  
  254. }
  255.  
  256.  
  257. // deletes or renames the jar-file
  258. function deleteJar() {
  259.     var dirService = Components.classes['@mozilla.org/file/directory_service;1'].getService(Components.interfaces.nsIProperties);
  260.     var tempDir = dirService.get("UChrm", Components.interfaces.nsIFile);
  261.     var dirArray = new Array();
  262.     var chromeDir, adblockJar;
  263.     var moveSuccess = false;
  264.     tempDir.append("adblock-temp");
  265.     
  266.     dirArray[0] = "AChrom"; // application-chrome magic-key
  267.     dirArray[1] = "UChrm"; // profile-chrome magic-key
  268.     
  269.     // remove any existing temp-dir and re-create ( --install cleanup)
  270.     try {
  271.         if (tempDir.exists()) tempDir.remove(true); 
  272.         tempDir.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0666); // create a new temp-dir
  273.     } catch(e) {}
  274.  
  275.     for ( var i = 0 ; i < dirArray.length ; i++) {
  276.         chromeDir = dirService.get(dirArray[i], Components.interfaces.nsIFile);
  277.         adblockJar = chromeDir.clone();
  278.         adblockJar.append("adblock.jar"); // "appends" the file-string to our dir file-obj
  279.                 
  280.         // move jar-file to temp-dir
  281.         try {
  282.             if (adblockJar.exists()) {
  283.                 if (dirArray[i] == "UChrm") isProfileInstalled = true; // component-removal will be unnecessary
  284.                 adblockJar.moveTo(tempDir, "adblock-jar-"+dirArray[i]+"-uninstalled"); // move the jar to the temp-dir, renaming
  285.                 if (!removalCheckArray[2]) removalCheckArray[2]++; // don't increment twice (..if adblock was double-installed)
  286.             }
  287.         } catch(ei) {
  288.         
  289.             // rename jar-file -- if move fails
  290.             try {
  291.                 if (adblockJar.exists()) {
  292.                     var newNameMain = "adblock-uninstalled";
  293.                     var newName = newNameMain;
  294.                     var adblockJarRenamed = chromeDir.clone();
  295.                     var n = 1;
  296.                     
  297.                     adblockJarRenamed.append(newName);
  298.                     if (adblockJarRenamed.exists())
  299.                         while(adblockJarRenamed.exists()) {
  300.                             newName = new String(newNameMain + n); // + nameEnd); // find a unique-name for our "move-to" destination
  301.                             adblockJarRenamed = chromeDir.clone();
  302.                             adblockJarRenamed.append(newName);
  303.                             n++;
  304.                         }
  305.  
  306.                     adblockJar.moveTo(null, newName); // rename the jar to the "unique name"
  307.                     if (!removalCheckArray[2]) removalCheckArray[2]++; // don't increment twice (..if adblock was double-installed)
  308.                 }
  309.             } catch(eii) { /*alert("Unable to remove adblock.jar from:\n\n"+adblockJar.path+"\n\n..you'll have to quit the browser and remove it by hand.");*/ }
  310.         }
  311.     }
  312. }
  313.  
  314.  
  315. // deletes the xul cache-file
  316. function deleteXULCache() {
  317.     var dirService = Components.classes['@mozilla.org/file/directory_service;1'].getService(Components.interfaces.nsIProperties);
  318.     var profileDir = dirService.get("ProfD", Components.interfaces.nsIFile);
  319.     var profileChromeDir = dirService.get("UChrm", Components.interfaces.nsIFile);
  320.     var tempDir = profileChromeDir.clone();
  321.     var cacheArray = [];
  322.     var found = false, xulCacheFile;
  323.     
  324.     tempDir.append("adblock-temp");
  325.     cacheArray[0] = "XUL FastLoad File"; // -- mac classic
  326.     cacheArray[1] = "XUL.mfast"; // -- mac osX
  327.     cacheArray[2] = "XUL.mfasl"; // -- linux
  328.     cacheArray[3] = "XUL.mfl"; // -- windows + other
  329.     
  330.     for (var n = 0 ; n < cacheArray.length &! found ; n++) {
  331.         xulCacheFile = profileDir.clone();
  332.         xulCacheFile.append(cacheArray[n]);
  333.         found = xulCacheFile.exists(); }
  334.     
  335.     if (!found) {
  336.         removalCheckArray[3]++; // if there's no cache-file, we're done
  337.         return; }
  338.     
  339.     // if the temp-dir doesn't exist yet, create it
  340.     try {
  341.         if (!tempDir.exists()) tempDir.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0666);
  342.     } catch(e) {}
  343.     
  344.     try {
  345.         xulCacheFile.moveTo(tempDir, xulCacheFile.leafName + "-uninstalled"); // move the jar to the temp-dir, renaming
  346.         removalCheckArray[3]++;
  347.     } catch(e) { alert("Unable to remove the XUL Cache File:  " + xulCacheFile.leafName + " \n..you'll have to quit the browser and remove it by hand.");}
  348.  
  349. }
  350.  
  351.  
  352. // deletes the adblock-component
  353. function deleteComponent() {
  354.     /*
  355.     if (isProfileInstalled) {
  356.         removalCheckArray[4]++;
  357.         return; } // component-removal was unnecessary
  358.     */
  359.     var dirService = Components.classes['@mozilla.org/file/directory_service;1'].getService(Components.interfaces.nsIProperties);
  360.     var profileChromeDir = dirService.get("UChrm", Components.interfaces.nsIFile);
  361.     var tempDir = profileChromeDir.clone();
  362.     var component = dirService.get("ComsD", Components.interfaces.nsIFile); // http://lxr.mozilla.org/seamonkey/source/xpcom/io/nsDirectoryServiceDefs.h
  363.     tempDir.append("adblock-temp");
  364.     component.append("nsAdblock.js");
  365.     
  366.     // remove component, if it exists
  367.     try {
  368.         if (component.exists()) component.moveTo(tempDir, component.leafName + "-uninstalled"); // move the jar to the temp-dir, renaming
  369.         removalCheckArray[4]++;
  370.     } catch(e) {alert("Unable to remove Adblock's Component File:\n\n" + component.path + "\n\n..you'll have to quit the browser and remove it by hand.");}
  371. }
  372.  
  373.  
  374. // removes all entries from compreg.dat
  375. function removeCompregDat() {
  376.     /*
  377.     if (isProfileInstalled) {
  378.         removalCheckArray[5]++;
  379.         return; } // component-removal was unnecessary
  380.     */
  381.     var dirService = Components.classes['@mozilla.org/file/directory_service;1'].getService(Components.interfaces.nsIProperties);
  382.     var compRegistry = dirService.get("ComRegF", Components.interfaces.nsIFile); // http://lxr.mozilla.org/seamonkey/source/xpcom/io/nsDirectoryServiceDefs.h
  383.     var streamIn = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);
  384.     var streamOut = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
  385.     var wrappedIn = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream);
  386.     var input;
  387.     var restored = false;
  388.     
  389.     // test if magic-key is working
  390.     if (!compRegistry.exists()) {
  391.         // if not, manually define the registry name
  392.         compRegistry = dirService.get("ComsD", Components.interfaces.nsIFile);
  393.         compRegistry.append("compreg.dat");
  394.         // test again
  395.         if (!compRegistry.exists() && isProfileInstalled) {
  396.             alert("Your browser's Component Registry could not be ascertained.\n\nStandby. Further instructions will follow in a minute...");
  397.             return; // still not found -- don't continue
  398.         }
  399.     }
  400.     
  401.     // if the registry-file is readable    
  402.     if (compRegistry.isReadable()) {
  403.         streamIn.init(compRegistry, 0x01, 0444, null);
  404.         wrappedIn.init(streamIn);
  405.         input = wrappedIn.read(streamIn.available());
  406.         wrappedIn.close();
  407.         streamIn.close();
  408.         
  409.         // remove all lines concerning adblock
  410.         var entryRemoveRe = /.*[\W\d](ns)?adblock[\W\d].*/i; // lines concerning adblock's component-loader + category
  411.         while (entryRemoveRe.test(input)) { // [Note: the global-flag doesn't work across lines]
  412.             input = input.replace(entryRemoveRe, ""); // purge -!
  413.             if (!restored) restored = true; }
  414.         
  415.         // if no entries were found
  416.         if (!restored) {
  417.             removalCheckArray[5]++;
  418.             return; // we're finished
  419.         }
  420.         
  421.         // otherwise, write the restored registry
  422.         if (compRegistry.isWritable()) {
  423.             streamOut.init(compRegistry, 0x02, 0x200, null);
  424.             streamOut.flush();
  425.             streamOut.write(input, input.length);
  426.             streamOut.close();
  427.             
  428.             removalCheckArray[5]++;
  429.         }
  430.         else alert("Your browser's Component Registry was not restored.\n\nThe registry file could not be written: \n\n" + compRegistry.path + "\n\nPlease verify that \'"+compRegistry.leafName+"\' has the necessary permissions and restart your browser.");
  431.     
  432.     }
  433.     else alert("Your browser's Component Registry was not restored.\n\nThe registry file could not be read: \n\n" + compRegistry.path + "\n\nPlease verify that \'"+compRegistry.leafName+"\' has the necessary permissions and restart your browser.");
  434.  
  435.  
  436. // shuts down the app
  437. //  -- copied straight from: lxr.mozilla.org/seamonkey/source/xpfe/global/resources/content/globalOverlay.js
  438. function shutdownAppNow()  {
  439.     var ObserverService = Components.classes["@mozilla.org/observer-service;1"].getService();
  440.     ObserverService = ObserverService.QueryInterface(Components.interfaces.nsIObserverService);
  441.     
  442.     if (ObserverService) {
  443.         try {
  444.             // XXX FIX! we should have a way to cancel a requested quit; see
  445.             // bugzilla bug 149764
  446.             ObserverService.notifyObservers(null, "quit-application-requested", null);
  447.         } catch (ex) { /* dump("no observer found \n"); */ }
  448.     }
  449.     
  450.     var windowManager = Components.classes['@mozilla.org/appshell/window-mediator;1'].getService();
  451.     var windowManagerInterface = windowManager.QueryInterface( Components.interfaces.nsIWindowMediator);
  452.     var enumerator = windowManagerInterface.getEnumerator(null);
  453.     var appShell = Components.classes['@mozilla.org/appshell/appShellService;1'].getService();
  454.     appShell = appShell.QueryInterface( Components.interfaces.nsIAppShellService );
  455.     var nativeAppSupport = null;
  456.     
  457.     try { nativeAppSupport = appShell.nativeAppSupport; } catch (ex) {}
  458.     
  459.     while (enumerator.hasMoreElements()) {
  460.         var domWindow = enumerator.getNext();
  461.         if (("tryToClose" in domWindow) && !domWindow.tryToClose())
  462.             return false;
  463.         domWindow.close(); }
  464.         
  465.     if (!nativeAppSupport || !nativeAppSupport.isServerMode)
  466.         appShell.quit(Components.interfaces.nsIAppShellService.eAttemptQuit); // final quit
  467.         
  468.     return true;
  469. }