home *** CD-ROM | disk | FTP | other *** search
/ PC World 2006 December / PCWorld_2006-12_cd.bin / komunikace / netscape / nsb-install-8-1-2.exe / chrome / browser.jar / content / browser / contentAreaUtils.js < prev    next >
Text File  |  2006-09-01  |  33KB  |  1,001 lines

  1. /**
  2.  * Determine whether or not a given focused DOMWindow is in the content
  3.  * area.
  4.  **/
  5.  
  6. function openNewTabWith(href, linkNode, event, securityCheck, postData)
  7. {
  8.   if (securityCheck)
  9.     urlSecurityCheck(href, document);
  10.  
  11.   var prefSvc = Components.classes["@mozilla.org/preferences-service;1"]
  12.                           .getService(Components.interfaces.nsIPrefService);
  13.   prefSvc = prefSvc.getBranch(null);
  14.  
  15.   // should we open it in a new tab?
  16.   var loadInBackground = true;
  17.   try {
  18.     loadInBackground = prefSvc.getBoolPref("browser.tabs.loadInBackground");
  19.   }
  20.   catch(ex) {
  21.   }
  22.  
  23.   if (event && event.shiftKey)
  24.     loadInBackground = !loadInBackground;
  25.  
  26.   // As in openNewWindowWith(), we want to pass the charset of the
  27.   // current document over to a new tab.
  28.   var wintype = document.firstChild.getAttribute('windowtype');
  29.   var originCharset;
  30.   if (wintype == "navigator:browser") {
  31.     originCharset = window._content.document.characterSet;
  32.   }
  33.  
  34.   // open link in new tab
  35.   var browser = top.document.getElementById("content");
  36.   var theTab = browser.addTabAt(href, undefined, getReferrer(document), originCharset, postData);  // MERC (DP): changed to addTabAt
  37.   if (!loadInBackground)
  38.     browser.selectedTab = theTab;
  39.   else{
  40.       
  41.       //CCOTE bug # 119809
  42.       //When loading tab in the background, this add the close button
  43.       // on the current selected tab (if needed).
  44.       //(Note this middle-click and ctrl-right-click
  45.       browser.updateChromeWhenLastTab();
  46.       
  47.   }
  48.  
  49.   if (linkNode)
  50.     markLinkVisited(href, linkNode);
  51. }
  52.  
  53. // Stevo
  54. function askUserAboutJar(href)
  55. {
  56.     var xpinstallObj = {};
  57.     var args = new Object( );
  58.     args.handled = 2;
  59.     args.jarUrl = href;
  60.  
  61.   var uri = Components.classes["@mozilla.org/network/standard-url;1"]
  62.                       .createInstance(Components.interfaces.nsIURI);
  63.   uri.spec = href;
  64.   var url = uri.QueryInterface(Components.interfaces.nsIURL);
  65.   if (url.fileExtension == "xpi") {
  66.     xpinstallObj[url.fileName] = uri.spec;
  67.       InstallTrigger.install(xpinstallObj);
  68.       args.handled = 0;
  69.   }
  70.   else if (url.fileExtension == "jar") {
  71.          window.openDialog("chrome://browser/content/askUserAboutJar.xul",
  72.             "Descision", "modal,centerscreen,chrome,resizable=no",args);
  73. //    InstallTrigger.installChrome(InstallTrigger.SKIN, href, url.fileName);
  74. //        args.handled = 0;
  75.   }
  76.  
  77.     return args.handled;
  78. }
  79.  
  80. //JA
  81. function openPopupInTab(href,bUserInitiated)
  82. {
  83.   // As in openNewWindowWith(), we want to pass the charset of the
  84.   // current document over to a new tab.
  85.   dump("\n\n****openPopupInTab("+href+", "+bUserInitiated+")\n\n");
  86.   var wintype = document.firstChild.getAttribute('windowtype');
  87.   var originCharset;
  88.   if (wintype == "navigator:browser")
  89.   {
  90.     //sliu, it crash when close tab cause a unload event,
  91.     //    , the event is open a new window and pref set to open popup in tab
  92.     //originCharset = window._content.document.characterSet;
  93.     originCharset = gCurrentDocCharset;
  94.   }
  95.  
  96.   // open link in new tab
  97.   var browser = top.document.getElementById("content");
  98.  
  99.   var theTab = browser.addTabAt(href, undefined, getReferrer(document), originCharset, null);
  100.  
  101.   var b = browser.getBrowserForTab(theTab);
  102.  
  103.   if(b)
  104.   {
  105.       // whether or not to set focus to the new popup tab
  106.       var bgLoad = browser.mPrefs.getBoolPref("browser.tabs.loadInBackground");
  107.       if(bUserInitiated && !bgLoad)
  108.           browser.selectedTab = theTab;
  109.       return b.contentWindow;
  110.   }
  111.   else
  112.      return null;//error
  113.  
  114. }
  115.  
  116. function openNewWindowWith(href, linkNode, securityCheck, postData)
  117. {
  118.   if (securityCheck)
  119.     urlSecurityCheck(href, document);
  120.  
  121.   // if and only if the current window is a browser window and it has a document with a character
  122.   // set, then extract the current charset menu setting from the current document and use it to
  123.   // initialize the new browser window...
  124.   var charsetArg = null;
  125.   var wintype = document.firstChild.getAttribute('windowtype');
  126.   if (wintype == "navigator:browser")
  127.     charsetArg = "charset=" + window._content.document.characterSet;
  128.  
  129.   var referrer = getReferrer(document);
  130.   window.openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no", href, charsetArg, referrer, postData);
  131.  
  132.   if (linkNode)
  133.     markLinkVisited(href, linkNode);
  134. }
  135.  
  136. function markLinkVisited(href, linkNode)
  137. {
  138.   var globalHistory = Components.classes["@mozilla.org/browser/global-history;2"]
  139.                                 .getService(Components.interfaces.nsIGlobalHistory2);
  140.  
  141.   var uri = makeURL(href);
  142.   if (!globalHistory.isVisited(uri)) {
  143.     globalHistory.addURI(uri, false, true);
  144.     var oldHref = linkNode.getAttribute("href");
  145.     if (typeof oldHref == "string") {
  146.       // Use setAttribute instead of direct assignment.
  147.       // (bug 217195, bug 187195)
  148.       linkNode.setAttribute("href", "");
  149.       linkNode.setAttribute("href", oldHref);
  150.     }
  151.     else {
  152.       // Converting to string implicitly would be a
  153.       // minor security hole (similar to bug 202994).
  154.     }
  155.   }
  156. }
  157.  
  158. function urlSecurityCheck(url, doc)
  159. {
  160.   // URL Loading Security Check
  161.   var focusedWindow = doc.commandDispatcher.focusedWindow;
  162.   var sourceURL = getContentFrameURI(focusedWindow);
  163.  
  164.   const nsIScriptSecurityManager = Components.interfaces.nsIScriptSecurityManager;
  165.   var secMan = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
  166.                          .getService(nsIScriptSecurityManager);
  167.   try {
  168.     secMan.checkLoadURIStr(sourceURL, url, nsIScriptSecurityManager.STANDARD);
  169.   } catch (e) {
  170.     throw "Load of " + url + " denied.";
  171.   }
  172. }
  173.  
  174. function webPanelSecurityCheck(aSourceURL, aDestURL) {
  175.   var sourceURI = makeURL(aSourceURL);
  176.   var destURI = makeURL(aDestURL);
  177.  
  178.   const nsIScriptSecurityManager = Components.interfaces.nsIScriptSecurityManager;
  179.   var secMan = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
  180.                          .getService(nsIScriptSecurityManager);
  181.   try {
  182.     secMan.checkLoadURI(sourceURI, destURI, nsIScriptSecurityManager.STANDARD);
  183.   } catch (e) {
  184.     return false;
  185.   }
  186.   return true;
  187. }
  188.  
  189. function isContentFrame(aFocusedWindow)
  190. {
  191.   if (!aFocusedWindow)
  192.     return false;
  193.  
  194.   var focusedTop = Components.lookupMethod(aFocusedWindow, 'top')
  195.                              .call(aFocusedWindow);
  196.  
  197.   return (focusedTop == window.content);
  198. }
  199.  
  200. function getContentFrameURI(aFocusedWindow)
  201. {
  202.   var contentFrame = isContentFrame(aFocusedWindow) ? aFocusedWindow : window.content;
  203.   if (contentFrame)
  204.     return Components.lookupMethod(contentFrame, 'location').call(contentFrame).href;
  205.   else
  206.     return null;
  207. }
  208.  
  209. function getReferrer(doc)
  210. {
  211.   var focusedWindow = doc.commandDispatcher.focusedWindow;
  212.   var sourceURL = getContentFrameURI(focusedWindow);
  213.  
  214.   if (sourceURL) {
  215.     try {
  216.       return makeURL(sourceURL);
  217.     }
  218.     catch (e) { }
  219.   }
  220.   return null;
  221. }
  222.  
  223. const kSaveAsType_Complete = 0;   // Save document with attached objects
  224. const kSaveAsType_URL = 1;        // Save document or URL by itself
  225. const kSaveAsType_Text = 2;       // Save document, converting to plain text.
  226.  
  227. // Clientelle: (Make sure you don't break any of these)
  228. //  - File    ->  Save Page/Frame As...
  229. //  - Context ->  Save Page/Frame As...
  230. //  - Context ->  Save Link As...
  231. //  - Context ->  Save Image As...
  232. //  - Alt-Click links in web pages
  233. //  - Alt-Click links in the UI
  234. //
  235. // Try saving each of these types:
  236. // - A complete webpage using File->Save Page As, and Context->Save Page As
  237. // - A webpage as HTML only using the above methods
  238. // - A webpage as Text only using the above methods
  239. // - An image with an extension (e.g. .jpg) in its file name, using
  240. //   Context->Save Image As...
  241. // - An image without an extension (e.g. a banner ad on cnn.com) using
  242. //   the above method.
  243. // - A linked document using Save Link As...
  244. // - A linked document using Alt-click Save Link As...
  245. //
  246. function saveURL(aURL, aFileName, aFilePickerTitleKey, aShouldBypassCache, aSkipPrompt, aReferrer)
  247. {
  248.   saveInternal(aURL, null, aFileName, aFilePickerTitleKey, aShouldBypassCache, aSkipPrompt, aReferrer);
  249. }
  250.  
  251. function saveDocument(aDocument, aSkipPrompt)
  252. {
  253.   // In both cases here, we want to use cached data because the
  254.   // document is currently visible.
  255.   //Mercurial start
  256.    var hpDoc;
  257.    try
  258.    {
  259.        hpDoc=gBrowser.contentDocument.QueryInterface(Components.interfaces.nsIHTMLPluginDocument);
  260.    }
  261.    catch(ex){}
  262.  
  263.    try
  264.    {
  265.       if(hpDoc)
  266.       {
  267.          hpDoc.doOLECmd(3);
  268.       }
  269.       else
  270.       {
  271.          if (aDocument)
  272.             saveInternal(aDocument.location.href, aDocument, false, aSkipPrompt);
  273.          else
  274.             saveInternal(_content.location.href, null, false, aSkipPrompt);
  275.       }
  276.    }
  277.    catch(e)
  278.    {}
  279. }
  280.  
  281. function saveInternal(aURL, aDocument,
  282.                       aFileName, aFilePickerTitleKey,
  283.                       aShouldBypassCache, aSkipPrompt,
  284.                       aReferrer)
  285. {
  286.   if (aSkipPrompt == undefined)
  287.     aSkipPrompt = false;
  288.  
  289.   var data = {
  290.     url: aURL,
  291.     fileName: aFileName,
  292.     filePickerTitle: aFilePickerTitleKey,
  293.     document: aDocument,
  294.     bypassCache: aShouldBypassCache,
  295.     window: window,
  296.     referrer: aReferrer
  297.   };
  298.   var sniffer = new nsHeaderSniffer(aURL, foundHeaderInfo, data, aSkipPrompt);
  299. }
  300.  
  301. function foundHeaderInfo(aSniffer, aData, aSkipPrompt)
  302. {
  303.   var contentType = aSniffer.contentType;
  304.   var contentEncodingType = aSniffer.contentEncodingType;
  305.  
  306.   var shouldDecode = false;
  307.   // Are we allowed to decode?
  308.   try {
  309.     const helperAppService =
  310.       Components.classes["@mozilla.org/uriloader/external-helper-app-service;1"].
  311.         getService(Components.interfaces.nsIExternalHelperAppService);
  312.     var url = aSniffer.uri.QueryInterface(Components.interfaces.nsIURL);
  313.     var urlExt = url.fileExtension;
  314.     if (helperAppService.applyDecodingForExtension(urlExt,
  315.                                                    contentEncodingType)) {
  316.       shouldDecode = true;
  317.     }
  318.   }
  319.   catch (e) {
  320.   }
  321.  
  322.   var isDocument = aData.document != null && isDocumentType(contentType);
  323.   if (!isDocument && !shouldDecode && contentEncodingType) {
  324.     // The data is encoded, we are not going to decode it, and this is not a
  325.     // document save so we won't be doing a "save as, complete" (which would
  326.     // break if we reset the type here).  So just set our content type to
  327.     // correspond to the outermost encoding so we get extensions and the like
  328.     // right.
  329.     contentType = contentEncodingType;
  330.   }
  331.  
  332.   var file = null;
  333.   var saveAsType = kSaveAsType_URL;
  334.   try {
  335.     file = aData.fileName.QueryInterface(Components.interfaces.nsILocalFile);
  336.   }
  337.   catch (e) {
  338.     var saveAsTypeResult = { rv: 0 };
  339.     file = getTargetFile(aData, aSniffer, contentType, isDocument, aSkipPrompt, saveAsTypeResult);
  340.     if (!file)
  341.       return;
  342.     saveAsType = saveAsTypeResult.rv;
  343.   }
  344.  
  345.   // If we're saving a document, and are saving either in complete mode or
  346.   // as converted text, pass the document to the web browser persist component.
  347.   // If we're just saving the HTML (second option in the list), send only the URI.
  348.   var source = (isDocument && saveAsType != kSaveAsType_URL) ? aData.document : aSniffer.uri;
  349.   var persistArgs = {
  350.     source      : source,
  351.     contentType : (isDocument && saveAsType == kSaveAsType_Text) ? "text/plain" : contentType,
  352.     target      : makeFileURL(file),
  353.     postData    : aData.document ? getPostData() : null,
  354.     bypassCache : aData.bypassCache
  355.   };
  356.  
  357.   var persist = makeWebBrowserPersist();
  358.  
  359.   // Calculate persist flags.
  360.   const nsIWBP = Components.interfaces.nsIWebBrowserPersist;
  361.   const flags = nsIWBP.PERSIST_FLAGS_NO_CONVERSION | nsIWBP.PERSIST_FLAGS_REPLACE_EXISTING_FILES;
  362.   if (aData.bypassCache)
  363.     persist.persistFlags = flags | nsIWBP.PERSIST_FLAGS_BYPASS_CACHE;
  364.   else
  365.     persist.persistFlags = flags | nsIWBP.PERSIST_FLAGS_FROM_CACHE;
  366.  
  367.   if (shouldDecode)
  368.     persist.persistFlags &= ~nsIWBP.PERSIST_FLAGS_NO_CONVERSION;
  369.  
  370.   // Create download and initiate it (below)
  371.   var dl = Components.classes["@mozilla.org/download;1"].createInstance(Components.interfaces.nsIDownload);
  372.  
  373.   if (isDocument && saveAsType != kSaveAsType_URL) {
  374.     // Saving a Document, not a URI:
  375.     var filesFolder = null;
  376.     if (persistArgs.contentType != "text/plain") {
  377.       // Create the local directory into which to save associated files.
  378.       filesFolder = file.clone();
  379.  
  380.       var nameWithoutExtension = filesFolder.leafName;
  381.       nameWithoutExtension = nameWithoutExtension.substring(0, nameWithoutExtension.lastIndexOf("."));
  382.       var filesFolderLeafName = getStringBundle().formatStringFromName("filesFolder",
  383.                                                                        [nameWithoutExtension],
  384.                                                                        1);
  385.  
  386.       filesFolder.leafName = filesFolderLeafName;
  387.     }
  388.  
  389.     var encodingFlags = 0;
  390.     if (persistArgs.contentType == "text/plain") {
  391.       encodingFlags |= nsIWBP.ENCODE_FLAGS_FORMATTED;
  392.       encodingFlags |= nsIWBP.ENCODE_FLAGS_ABSOLUTE_LINKS;
  393.       encodingFlags |= nsIWBP.ENCODE_FLAGS_NOFRAMES_CONTENT;
  394.     }
  395.     else {
  396.       encodingFlags |= nsIWBP.ENCODE_FLAGS_ENCODE_BASIC_ENTITIES;
  397.     }
  398.  
  399.     const kWrapColumn = 80;
  400.     dl.init(aSniffer.uri, persistArgs.target, null, null, null, persist);
  401.     persist.saveDocument(persistArgs.source, persistArgs.target, filesFolder,
  402.                          persistArgs.contentType, encodingFlags, kWrapColumn);
  403.   } else {
  404.     dl.init(source, persistArgs.target, null, null, null, persist);
  405.     var referrer = aData.referrer || getReferrer(document)
  406.     persist.saveURI(source, null, referrer, persistArgs.postData, null, persistArgs.target);
  407.   }
  408. }
  409.  
  410. function getTargetFile(aData, aSniffer, aContentType, aIsDocument, aSkipPrompt, aSaveAsTypeResult)
  411. {
  412.   aSaveAsTypeResult.rv = kSaveAsType_Complete;
  413.  
  414.   // Determine what the 'default' string to display in the File Picker dialog
  415.   // should be.
  416.   var defaultFileName = getDefaultFileName(aData.fileName,
  417.                                            aSniffer.suggestedFileName,
  418.                                            aSniffer.uri,
  419.                                            aData.document);
  420.  
  421.   var defaultExtension = getDefaultExtension(defaultFileName, aSniffer.uri, aContentType);
  422.   var defaultString = getNormalizedLeafName(defaultFileName, defaultExtension);
  423.  
  424.   const prefSvcContractID = "@mozilla.org/preferences-service;1";
  425.   const prefSvcIID = Components.interfaces.nsIPrefService;
  426.   var prefs = Components.classes[prefSvcContractID].getService(prefSvcIID).getBranch("browser.download.");
  427.  
  428.   const nsILocalFile = Components.interfaces.nsILocalFile;
  429.  
  430.   // ben 07/31/2003:
  431.   // |browser.download.defaultFolder| holds the default download folder for
  432.   // all files when the user has elected to have all files automatically
  433.   // download to a folder. The values of |defaultFolder| can be either their
  434.   // desktop, their downloads folder (My Documents\My Downloads) or some other
  435.   // location of their choosing (which is mapped to |browser.download.dir|
  436.   // This pref is _unset_ when the user has elected to be asked about where
  437.   // to place every download - this will force the prompt to ask the user
  438.   // where to put saved files.
  439.   var dir = null;
  440.   try {
  441.     dir = prefs.getComplexValue("defaultFolder", nsILocalFile);
  442.   }
  443.   catch (e) { }
  444.  
  445.   var file;
  446.   if (!aSkipPrompt || !dir) {
  447.     // If we're asking the user where to save the file, root the Save As...
  448.     // dialog on they place they last picked.
  449.     try {
  450.       dir = prefs.getComplexValue("lastDir", nsILocalFile);
  451.     }
  452.     catch (e) {
  453.       // No default download location. Default to desktop.
  454.       var fileLocator = Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties);
  455.  
  456.       function getDesktopKey()
  457.       {
  458.         return "DeskP";
  459.         return "Home";
  460.       }
  461.  
  462.       dir = fileLocator.get(getDesktopKey(), Components.interfaces.nsILocalFile);
  463.     }
  464.  
  465.  
  466.     var fp = makeFilePicker();
  467.     var titleKey = aData.filePickerTitle || "SaveLinkTitle";
  468.     var bundle = getStringBundle();
  469.     fp.init(window, bundle.GetStringFromName(titleKey),
  470.             Components.interfaces.nsIFilePicker.modeSave);
  471.  
  472.     appendFiltersForContentType(fp, aContentType, defaultExtension,
  473.                                 aIsDocument ? MODE_COMPLETE : MODE_FILEONLY);
  474.  
  475.     if (dir)
  476.       fp.displayDirectory = dir;
  477.  
  478.     if (aIsDocument) {
  479.       try {
  480.         fp.filterIndex = prefs.getIntPref("save_converter_index");
  481.       }
  482.       catch (e) {
  483.       }
  484.     }
  485.  
  486.     fp.defaultExtension = defaultExtension;
  487.     fp.defaultString = defaultString;
  488.  
  489.     if (fp.show() == Components.interfaces.nsIFilePicker.returnCancel || !fp.file)
  490.       return null;
  491.  
  492.     var useDownloadDir = false;
  493.     try {
  494.       useDownloadDir = prefs.getBoolPref("useDownloadDir");
  495.     }
  496.     catch(ex) {
  497.     }
  498.  
  499.     var directory = fp.file.parent.QueryInterface(nsILocalFile);
  500.     prefs.setComplexValue("lastDir", nsILocalFile, directory);
  501.  
  502.     fp.file.leafName = validateFileName(fp.file.leafName);
  503.     aSaveAsTypeResult.rv = fp.filterIndex;
  504.     file = fp.file;
  505.  
  506.     if (aIsDocument)
  507.       prefs.setIntPref("save_converter_index", aSaveAsTypeResult.rv);
  508.   }
  509.   else {
  510.     // ben 07/31/2003:
  511.     // We don't nullcheck dir here because dir should never be null if we get here
  512.     // unless something is badly wrong, and if it is, I want to know about it in
  513.     // bugs.
  514.     dir.append(defaultString);
  515.     file = dir;
  516.  
  517.     // Since we're automatically downloading, we don't get the file picker's
  518.     // logic to check for existing files, so we need to do that here.
  519.     //
  520.     // Note - this code is identical to that in
  521.     //   browser/components/downloads/content/nsHelperAppDlg.js.
  522.     // If you are updating this code, update that code too! We can't share code
  523.     // here since that code is called in a js component.
  524.     while (file.exists()) {
  525.       var parts = /.+-(\d+)(\..*)?$/.exec(file.leafName);
  526.       if (parts) {
  527.         file.leafName = file.leafName.replace(/((\d+)\.)|((\d+)$)/,
  528.                                               function (str, dot, dotNum, noDot, noDotNum, pos, s) {
  529.                                                 return (parseInt(str) + 1) + (dot ? "." : "");
  530.                                               });
  531.       }
  532.       else {
  533.         file.leafName = file.leafName.replace(/\.|$/, "-1$&");
  534.       }
  535.     }
  536.  
  537.   }
  538.  
  539.   return file;
  540. }
  541.  
  542. function nsHeaderSniffer(aURL, aCallback, aData, aSkipPrompt)
  543. {
  544.   this.mCallback = aCallback;
  545.   this.mData = aData;
  546.   this.mSkipPrompt = aSkipPrompt;
  547.  
  548.   this.uri = makeURL(aURL);
  549.  
  550.   this.linkChecker = Components.classes["@mozilla.org/network/urichecker;1"]
  551.     .createInstance(Components.interfaces.nsIURIChecker);
  552.   this.linkChecker.init(this.uri);
  553.  
  554.   var flags;
  555.   if (aData.bypassCache) {
  556.     flags = Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE;
  557.   } else {
  558.     flags = Components.interfaces.nsIRequest.LOAD_FROM_CACHE;
  559.   }
  560.   this.linkChecker.loadFlags = flags;
  561.  
  562.   this.linkChecker.asyncCheck(this, null);
  563. }
  564.  
  565. nsHeaderSniffer.prototype = {
  566.  
  567.   // ---------- nsISupports methods ----------
  568.   QueryInterface: function (iid) {
  569.     if (!iid.equals(Components.interfaces.nsIRequestObserver) &&
  570.         !iid.equals(Components.interfaces.nsISupports) &&
  571.         !iid.equals(Components.interfaces.nsIInterfaceRequestor)) {
  572.       throw Components.results.NS_ERROR_NO_INTERFACE;
  573.     }
  574.     return this;
  575.   },
  576.  
  577.   // ---------- nsIInterfaceRequestor methods ----------
  578.   getInterface : function(iid) {
  579.     if (iid.equals(Components.interfaces.nsIAuthPrompt)) {
  580.       // use the window watcher service to get a nsIAuthPrompt impl
  581.       var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
  582.                          .getService(Components.interfaces.nsIWindowWatcher);
  583.       return ww.getNewAuthPrompter(window);
  584.     }
  585.     Components.returnCode = Components.results.NS_ERROR_NO_INTERFACE;
  586.     return null;
  587.   },
  588.  
  589.   // ---------- nsIRequestObserver methods ----------
  590.   onStartRequest: function (aRequest, aContext) { },
  591.  
  592.   onStopRequest: function (aRequest, aContext, aStatus) {
  593.     try {
  594.       if (aStatus == 0) { // NS_BINDING_SUCCEEDED, so there's something there
  595.         var linkChecker = aRequest.QueryInterface(Components.interfaces.nsIURIChecker);
  596.         var channel = linkChecker.baseChannel;
  597.         this.contentType = channel.contentType;
  598.         try {
  599.           var httpChannel = channel.QueryInterface(Components.interfaces.nsIHttpChannel);
  600.           var encodedChannel = channel.QueryInterface(Components.interfaces.nsIEncodedChannel);
  601.           this.contentEncodingType = null;
  602.           // There may be content-encodings on the channel.  Multiple content
  603.           // encodings are allowed, eg "Content-Encoding: gzip, uuencode".  This
  604.           // header would mean that the content was first gzipped and then
  605.           // uuencoded.  The encoding enumerator returns MIME types
  606.           // corresponding to each encoding starting from the end, so the first
  607.           // thing it returns corresponds to the outermost encoding.
  608.           var encodingEnumerator = encodedChannel.contentEncodings;
  609.           if (encodingEnumerator && encodingEnumerator.hasMore()) {
  610.             try {
  611.               this.contentEncodingType = encodingEnumerator.getNext();
  612.             } catch (e) {
  613.             }
  614.           }
  615.           this.mContentDisposition = httpChannel.getResponseHeader("content-disposition");
  616.         }
  617.         catch (e) {
  618.         }
  619.         if (!this.contentType || this.contentType == "application/x-unknown-content-type") {
  620.           // We didn't get a type from the server.  Fall back on other type detection mechanisms
  621.           throw "Unknown Type";
  622.         }
  623.       }
  624.       else {
  625.         dump("Error saving link aStatus = 0x" + aStatus.toString(16) + "\n");
  626.         var bundle = getStringBundle();
  627.         var errorTitle = bundle.GetStringFromName("saveLinkErrorTitle");
  628.         var errorMsg = bundle.GetStringFromName("saveLinkErrorMsg");
  629.         const promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
  630.         promptService.alert(this.mData.window, errorTitle, errorMsg);
  631.         return;
  632.       }
  633.     }
  634.     catch (e) {
  635.       if (this.mData.document) {
  636.         this.contentType = this.mData.document.contentType;
  637.       } else {
  638.         var type = getMIMETypeForURI(this.uri);
  639.         if (type)
  640.           this.contentType = type;
  641.       }
  642.     }
  643.     this.mCallback(this, this.mData, this.mSkipPrompt);
  644.   },
  645.  
  646.   // ------------------------------------------------
  647.  
  648.   get promptService()
  649.   {
  650.     var promptSvc;
  651.     try {
  652.       promptSvc = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService();
  653.       promptSvc = promptSvc.QueryInterface(Components.interfaces.nsIPromptService);
  654.     }
  655.     catch (e) {}
  656.     return promptSvc;
  657.   },
  658.  
  659.   get suggestedFileName()
  660.   {
  661.     var fileName = "";
  662.  
  663.     if (this.mContentDisposition) {
  664.       const mhpContractID = "@mozilla.org/network/mime-hdrparam;1"
  665.       const mhpIID = Components.interfaces.nsIMIMEHeaderParam;
  666.       const mhp = Components.classes[mhpContractID].getService(mhpIID);
  667.       var dummy = { value: null }; // To make JS engine happy.
  668.       var charset = getCharsetforSave(null);
  669.  
  670.       try {
  671.         fileName = mhp.getParameter(this.mContentDisposition, "filename", charset, true, dummy);
  672.       }
  673.       catch (e) {
  674.         try {
  675.           fileName = mhp.getParameter(this.mContentDisposition, "name", charset, true, dummy);
  676.         }
  677.         catch (e) {
  678.         }
  679.       }
  680.     }
  681.     fileName = fileName.replace(/^"|"$/g, "");
  682.     return fileName;
  683.   }
  684. };
  685.  
  686. const MODE_COMPLETE = 0;
  687. const MODE_FILEONLY = 1;
  688.  
  689. function appendFiltersForContentType(aFilePicker, aContentType, aFileExtension, aSaveMode)
  690. {
  691.   var bundle = getStringBundle();
  692.  
  693.   switch (aContentType) {
  694.   case "text/html":
  695.     if (aSaveMode == MODE_COMPLETE)
  696.       aFilePicker.appendFilter(bundle.GetStringFromName("WebPageCompleteFilter"), "*.htm; *.html");
  697.     aFilePicker.appendFilter(bundle.GetStringFromName("WebPageHTMLOnlyFilter"), "*.htm; *.html");
  698.     if (aSaveMode == MODE_COMPLETE)
  699.       aFilePicker.appendFilters(Components.interfaces.nsIFilePicker.filterText);
  700.     break;
  701.   default:
  702.     var mimeInfo = getMIMEInfoForType(aContentType, aFileExtension);
  703.     if (mimeInfo) {
  704.  
  705.       var extEnumerator = mimeInfo.getFileExtensions();
  706.  
  707.       var extString = "";
  708.       var defaultDesc = "";
  709.       var plural = false;
  710.       while (extEnumerator.hasMore()) {
  711.         if (defaultDesc) {
  712.           defaultDesc += ", ";
  713.           plural = true;
  714.         }
  715.         var extension = extEnumerator.getNext();
  716.         if (extString)
  717.           extString += "; ";    // If adding more than one extension,
  718.                                 // separate by semi-colon
  719.         extString += "*." + extension;
  720.         defaultDesc += extension.toUpperCase();
  721.       }
  722.  
  723.       if (extString) {
  724.         var desc = mimeInfo.Description;
  725.         if (!desc) {
  726.           var key = plural ? "unknownDescriptionFilesPluralFilter" :
  727.                              "unknownDescriptionFilesFilter";
  728.           desc = getStringBundle().formatStringFromName(key, [defaultDesc], 1);
  729.         }
  730.         aFilePicker.appendFilter(desc, extString);
  731.       } else {
  732.         aFilePicker.appendFilters(Components.interfaces.nsIFilePicker.filterAll);
  733.       }
  734.     }
  735.     else
  736.       aFilePicker.appendFilters(Components.interfaces.nsIFilePicker.filterAll);
  737.     break;
  738.   }
  739. }
  740.  
  741. function getPostData()
  742. {
  743.   try {
  744.     var sessionHistory = getWebNavigation().sessionHistory;
  745.     entry = sessionHistory.getEntryAtIndex(sessionHistory.index, false);
  746.     entry = entry.QueryInterface(Components.interfaces.nsISHEntry);
  747.     return entry.postData;
  748.   }
  749.   catch (e) {
  750.   }
  751.   return null;
  752. }
  753.  
  754. //XXXPch: that that be removed.
  755. function getStringBundle()
  756. {
  757.   const bundleURL = "chrome://browser/locale/contentAreaCommands.properties";
  758.  
  759.   const sbsContractID = "@mozilla.org/intl/stringbundle;1";
  760.   const sbsIID = Components.interfaces.nsIStringBundleService;
  761.   const sbs = Components.classes[sbsContractID].getService(sbsIID);
  762.  
  763.   const lsContractID = "@mozilla.org/intl/nslocaleservice;1";
  764.   const lsIID = Components.interfaces.nsILocaleService;
  765.   const ls = Components.classes[lsContractID].getService(lsIID);
  766.   var appLocale = ls.getApplicationLocale();
  767.   return sbs.createBundle(bundleURL, appLocale);
  768. }
  769.  
  770. function makeWebBrowserPersist()
  771. {
  772.   const persistContractID = "@mozilla.org/embedding/browser/nsWebBrowserPersist;1";
  773.   const persistIID = Components.interfaces.nsIWebBrowserPersist;
  774.   return Components.classes[persistContractID].createInstance(persistIID);
  775. }
  776.  
  777. function makeURL(aURL)
  778. {
  779.   var ioService = Components.classes["@mozilla.org/network/io-service;1"]
  780.                             .getService(Components.interfaces.nsIIOService);
  781.   return ioService.newURI(aURL, null, null);
  782. }
  783.  
  784. function makeFileURL(aFile)
  785. {
  786.   var ioService = Components.classes["@mozilla.org/network/io-service;1"]
  787.                 .getService(Components.interfaces.nsIIOService);
  788.   return ioService.newFileURI(aFile);
  789. }
  790.  
  791. function makeFilePicker()
  792. {
  793.   const fpContractID = "@mozilla.org/filepicker;1";
  794.   const fpIID = Components.interfaces.nsIFilePicker;
  795.   return Components.classes[fpContractID].createInstance(fpIID);
  796. }
  797.  
  798. function getMIMEService()
  799. {
  800.   const mimeSvcContractID = "@mozilla.org/mime;1";
  801.   const mimeSvcIID = Components.interfaces.nsIMIMEService;
  802.   const mimeSvc = Components.classes[mimeSvcContractID].getService(mimeSvcIID);
  803.   return mimeSvc;
  804. }
  805.  
  806. function getMIMETypeForURI(aURI)
  807. {
  808.   try {
  809.     return getMIMEService().getTypeFromURI(aURI);
  810.   }
  811.   catch (e) {
  812.   }
  813.   return null;
  814. }
  815.  
  816. function getMIMEInfoForType(aMIMEType, aExtension)
  817. {
  818.   try {
  819.     return getMIMEService().getFromTypeAndExtension(aMIMEType, aExtension);
  820.   }
  821.   catch (e) {
  822.   }
  823.   return null;
  824. }
  825.  
  826. function getDefaultFileName(aDefaultFileName, aNameFromHeaders, aDocumentURI, aDocument)
  827. {
  828.   if (aNameFromHeaders)
  829.     // 1) Use the name suggested by the HTTP headers
  830.     return validateFileName(aNameFromHeaders);
  831.  
  832.   try {
  833.     var url = aDocumentURI.QueryInterface(Components.interfaces.nsIURL);
  834.     if (url.fileName != "") {
  835.       // 2) Use the actual file name, if present
  836.       return validateFileName(decodeURIComponent(url.fileName));
  837.     }
  838.   } catch (e) {
  839.     try {
  840.       // the file name might be non ASCII
  841.       // try unescape again with a characterSet
  842.       var textToSubURI = Components.classes["@mozilla.org/intl/texttosuburi;1"]
  843.                                    .getService(Components.interfaces.nsITextToSubURI);
  844.       var charset = getCharsetforSave(aDocument);
  845.       return validateFileName(textToSubURI.unEscapeURIForUI(charset, url.fileName));
  846.     } catch (e) {
  847.       // This is something like a wyciwyg:, data:, and so forth
  848.       // URI... no usable filename here.
  849.     }
  850.   }
  851.  
  852.   if (aDocument) {
  853.     var docTitle = validateFileName(aDocument.title).replace(/^\s+|\s+$/g, "");
  854.  
  855.     if (docTitle != "") {
  856.       // 3) Use the document title
  857.       return docTitle;
  858.     }
  859.   }
  860.  
  861.   if (aDefaultFileName)
  862.     // 4) Use the caller-provided name, if any
  863.     return validateFileName(aDefaultFileName);
  864.  
  865.   // 5) If this is a directory, use the last directory name
  866.   var re = /\/([^\/]+)\/$/;
  867.   var path = aDocumentURI.path.match(re);
  868.   if (path && path.length > 1) {
  869.       return validateFileName(path[1]);
  870.   }
  871.  
  872.   try {
  873.     if (aDocumentURI.host)
  874.       // 6) Use the host.
  875.       return aDocumentURI.host;
  876.   } catch (e) {
  877.     // Some files have no information at all, like Javascript generated pages
  878.   }
  879.   try {
  880.     // 7) Use the default file name
  881.     return getStringBundle().GetStringFromName("DefaultSaveFileName");
  882.   } catch (e) {
  883.     //in case localized string cannot be found
  884.   }
  885.   // 8) If all else fails, use "index"
  886.   return "index";
  887. }
  888.  
  889. function validateFileName(aFileName)
  890. {
  891.   var re = /[\/]+/g;
  892.   if (navigator.appVersion.indexOf("Windows") != -1) {
  893.     re = /[\\\/\|]+/g;
  894.     aFileName = aFileName.replace(/[\"]+/g, "'");
  895.     aFileName = aFileName.replace(/[\*\:\?]+/g, " ");
  896.     aFileName = aFileName.replace(/[\<]+/g, "(");
  897.     aFileName = aFileName.replace(/[\>]+/g, ")");
  898.   }
  899.   else if (navigator.appVersion.indexOf("Macintosh") != -1)
  900.     re = /[\:\/]+/g;
  901.  
  902.   return aFileName.replace(re, "_");
  903. }
  904.  
  905. function getNormalizedLeafName(aFile, aDefaultExtension)
  906. {
  907.   if (!aDefaultExtension)
  908.     return aFile;
  909.  
  910.   // Fix up the file name we're saving to to include the default extension
  911.   const stdURLContractID = "@mozilla.org/network/standard-url;1";
  912.   const stdURLIID = Components.interfaces.nsIURL;
  913.   var url = Components.classes[stdURLContractID].createInstance(stdURLIID);
  914.   url.filePath = aFile;
  915.  
  916.   if (url.fileExtension != aDefaultExtension) {
  917.     return aFile + "." + aDefaultExtension;
  918.   }
  919.  
  920.   return aFile;
  921. }
  922.  
  923. function getDefaultExtension(aFilename, aURI, aContentType)
  924. {
  925.   if (aContentType == "text/plain" || aContentType == "application/octet-stream" || aURI.scheme == "ftp")
  926.     return "";   // temporary fix for bug 120327
  927.  
  928.   // First try the extension from the filename
  929.   const stdURLContractID = "@mozilla.org/network/standard-url;1";
  930.   const stdURLIID = Components.interfaces.nsIURL;
  931.   var url = Components.classes[stdURLContractID].createInstance(stdURLIID);
  932.   url.filePath = aFilename;
  933.  
  934.   var ext = url.fileExtension;
  935.  
  936.   // This mirrors some code in nsExternalHelperAppService::DoContent
  937.   // Use the filename first and then the URI if that fails
  938.  
  939.   var mimeInfo = getMIMEInfoForType(aContentType, ext);
  940.  
  941.   if (ext && mimeInfo && mimeInfo.ExtensionExists(ext)) {
  942.     return ext;
  943.   }
  944.  
  945.   // Well, that failed.  Now try the extension from the URI
  946.   var urlext;
  947.   try {
  948.     url = aURI.QueryInterface(Components.interfaces.nsIURL);
  949.     urlext = url.fileExtension;
  950.   } catch (e) {
  951.   }
  952.  
  953.   if (urlext && mimeInfo && mimeInfo.ExtensionExists(urlext)) {
  954.     return urlext;
  955.   }
  956.   else {
  957.     try {
  958.       return mimeInfo.primaryExtension;
  959.     }
  960.     catch (e) {
  961.       // Fall back on the extensions in the filename and URI for lack
  962.       // of anything better.
  963.       return ext || urlext;
  964.     }
  965.   }
  966. }
  967.  
  968. function isDocumentType(aContentType)
  969. {
  970.   switch (aContentType) {
  971.   case "text/html":
  972.     return true;
  973.   case "text/xml":
  974.   case "application/xhtml+xml":
  975.   case "application/xml":
  976.     return false; // XXX Disables Save As Complete until it works for XML
  977.   }
  978.   return false;
  979. }
  980.  
  981. function getCharsetforSave(aDocument)
  982. {
  983.   if (aDocument)
  984.     return aDocument.characterSet;
  985.  
  986.   if (document.commandDispatcher.focusedWindow)
  987.     return document.commandDispatcher.focusedWindow.document.characterSet;
  988.  
  989.   return  window._content.document.characterSet;
  990.   return false;
  991. }
  992.  
  993. function SwitchTextEntryDirection(aElement) {
  994.   if (window.getComputedStyle(aElement, "").direction == "ltr")
  995.     aElement.style.direction = "rtl";
  996.   else
  997.     aElement.style.direction = "ltr";
  998. }
  999.  
  1000.  
  1001.