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