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