home *** CD-ROM | disk | FTP | other *** search
/ Revista do CD-ROM 97 / CD-ROM 97 / CD-ROM 97.iso / internet / ghostzilla / ghsetup.exe / chrome / comm.jar / content / communicator / contentAreaUtils.js < prev    next >
Encoding:
JavaScript  |  2002-06-13  |  26.6 KB  |  774 lines

  1. /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* ***** BEGIN LICENSE BLOCK *****
  3.  * Version: NPL 1.1/GPL 2.0/LGPL 2.1
  4.  *
  5.  * The contents of this file are subject to the Netscape Public License
  6.  * Version 1.1 (the "License"); you may not use this file except in
  7.  * compliance with the License. You may obtain a copy of the License at
  8.  * http://www.mozilla.org/NPL/
  9.  *
  10.  * Software distributed under the License is distributed on an "AS IS" basis,
  11.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12.  * for the specific language governing rights and limitations under the
  13.  * License.
  14.  *
  15.  * The Original Code is mozilla.org code.
  16.  *
  17.  * The Initial Developer of the Original Code is
  18.  * Netscape Communications Corporation.
  19.  * Portions created by the Initial Developer are Copyright (C) 1998
  20.  * the Initial Developer. All Rights Reserved.
  21.  *
  22.  * Contributor(s):
  23.  *   Ben Goodger <ben@netscape.com> (Save File)
  24.  *
  25.  * Alternatively, the contents of this file may be used under the terms of
  26.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  27.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  28.  * in which case the provisions of the GPL or the LGPL are applicable instead
  29.  * of those above. If you wish to allow use of your version of this file only
  30.  * under the terms of either the GPL or the LGPL, and not to allow others to
  31.  * use your version of this file under the terms of the NPL, indicate your
  32.  * decision by deleting the provisions above and replace them with the notice
  33.  * and other provisions required by the GPL or the LGPL. If you do not delete
  34.  * the provisions above, a recipient may use your version of this file under
  35.  * the terms of any one of the NPL, the GPL or the LGPL.
  36.  *
  37.  * ***** END LICENSE BLOCK ***** */
  38.  
  39. /**
  40.  * Determine whether or not a given focused DOMWindow is in the content
  41.  * area.
  42.  **/
  43. function isDocumentFrame(aFocusedWindow)
  44. {
  45.   var contentFrames = _content.frames;
  46.   if (contentFrames.length) {
  47.     for (var i = 0; i < contentFrames.length; ++i) {
  48.       if (aFocusedWindow == contentFrames[i])
  49.         return true;
  50.     }
  51.   }
  52.   return false;
  53. }
  54.  
  55. function urlSecurityCheck(url, doc)
  56. {
  57.   // URL Loading Security Check
  58.   var focusedWindow = doc.commandDispatcher.focusedWindow;
  59.   var sourceWin = isDocumentFrame(focusedWindow) ? focusedWindow.location.href : focusedWindow._content.location.href;
  60.   const nsIScriptSecurityManager = Components.interfaces.nsIScriptSecurityManager;
  61.   var secMan = Components.classes["@mozilla.org/scriptsecuritymanager;1"].getService().
  62.                     QueryInterface(nsIScriptSecurityManager);
  63.   try {
  64.     secMan.checkLoadURIStr(sourceWin, url, nsIScriptSecurityManager.STANDARD);
  65.   } catch (e) {
  66.       throw "Load of " + url + " denied.";
  67.   }
  68. }
  69.  
  70. function getReferrer(doc)
  71. {
  72.   var focusedWindow = doc.commandDispatcher.focusedWindow;
  73.   var sourceURL =
  74.     isDocumentFrame(focusedWindow) ? focusedWindow.location.href : focusedWindow._content.location.href;
  75.   try {
  76.     var uri = Components.classes["@mozilla.org/network/standard-url;1"].createInstance(Components.interfaces.nsIURI);
  77.     uri.spec = sourceURL;
  78.     return uri;
  79.   } catch (e) {
  80.     return null;
  81.   }
  82. }
  83.  
  84. function openNewWindowWith(url)
  85. {
  86.   urlSecurityCheck(url, document);
  87.   var newWin;
  88.   var wintype = document.firstChild.getAttribute('windowtype');
  89.   var referrer = getReferrer(document);
  90.  
  91.   // if and only if the current window is a browser window and it has a document with a character
  92.   // set, then extract the current charset menu setting from the current document and use it to
  93.   // initialize the new browser window...
  94.   if (window && (wintype == "navigator:browser") &&
  95.     window._content && window._content.document) {
  96.     var DocCharset = window._content.document.characterSet;
  97.     var charsetArg = "charset="+DocCharset;
  98.  
  99.     //we should "inherit" the charset menu setting in a new window
  100.     newWin = window.openDialog( getBrowserURL(), "_blank", "chrome,all,dialog=no", url, charsetArg, true, referrer );
  101.   }
  102.   else { // forget about the charset information.
  103.     newWin = window.openDialog( getBrowserURL(), "_blank", "chrome,all,dialog=no", url, null, true, referrer );
  104.   }
  105. }
  106.  
  107. function openNewTabWith(url)
  108. {
  109.   urlSecurityCheck(url, document);
  110.   var wintype = document.firstChild.getAttribute('windowtype');
  111.   var referrer = getReferrer(document);
  112.  
  113.   if (window && (wintype == "navigator:browser")) {
  114.     var browser = getBrowser();
  115.     var t = browser.addTab(url, referrer); // open link in new tab
  116.     /* [ghzil]: disabled the if() so it always opens in the foreground {
  117.     if (pref && !pref.getBoolPref("browser.tabs.loadInBackground"))
  118.     } [ghzil] */
  119.       browser.selectedTab = t;
  120.   }
  121. }
  122.  
  123. // [ghzil]: added this one {
  124. function openNewTabWithBackground(url)
  125. {
  126.   urlSecurityCheck(url, document);
  127.   var wintype = document.firstChild.getAttribute('windowtype');
  128.   var referrer = getReferrer(document);
  129.  
  130.   if (window && (wintype == "navigator:browser")) {
  131.     var browser = getBrowser();
  132.     var t = browser.addTab(url, referrer); // open link in new tab
  133.   }
  134. }
  135. // } [ghzil]
  136.  
  137.  
  138. function findParentNode(node, parentNode)
  139. {
  140.   if (node && node.nodeType == Node.TEXT_NODE) {
  141.     node = node.parentNode;
  142.   }
  143.   while (node) {
  144.     var nodeName = node.localName;
  145.     if (!nodeName)
  146.       return null;
  147.     nodeName = nodeName.toLowerCase();
  148.     if (nodeName == "body" || nodeName == "html" ||
  149.         nodeName == "#document") {
  150.       return null;
  151.     }
  152.     if (nodeName == parentNode)
  153.       return node;
  154.     node = node.parentNode;
  155.   }
  156.   return null;
  157. }
  158.  
  159. // Clientelle: (Make sure you don't break any of these)
  160. //  - File    ->  Save Page/Frame As...
  161. //  - Context ->  Save Page/Frame As...
  162. //  - Context ->  Save Link As...
  163. //  - Context ->  Save Image As...
  164. //  - Shift-Click Save Link As
  165. //
  166. // Try saving each of these types:
  167. // - A complete webpage using File->Save Page As, and Context->Save Page As
  168. // - A webpage as HTML only using the above methods
  169. // - A webpage as Text only using the above methods
  170. // - An image with an extension (e.g. .jpg) in its file name, using
  171. //   Context->Save Image As...
  172. // - An image without an extension (e.g. a banner ad on cnn.com) using
  173. //   the above method.
  174. // - A linked document using Save Link As...
  175. // - A linked document using shift-click Save Link As...
  176. //
  177. function saveURL(aURL, aFileName, aFilePickerTitleKey, aShouldBypassCache)
  178. {
  179.   saveInternal(aURL, null, aFileName, aFilePickerTitleKey, aShouldBypassCache);
  180. }
  181.  
  182. function saveFrameDocument()
  183. {
  184.   var focusedWindow = document.commandDispatcher.focusedWindow;
  185.   if (isDocumentFrame(focusedWindow))
  186.     saveDocument(focusedWindow.document);
  187. }
  188.  
  189. function saveDocument(aDocument)
  190. {
  191.   // In both cases here, we want to use cached data because the
  192.   // document is currently visible.
  193.   if (aDocument)
  194.     saveInternal(aDocument.location.href, aDocument, false);
  195.   else
  196.     saveInternal(_content.location.href, null, false);
  197. }
  198.  
  199. function saveInternal(aURL, aDocument,
  200.                       aFileName, aFilePickerTitleKey,
  201.                       aShouldBypassCache)
  202. {
  203.   var data = {
  204.     url: aURL,
  205.     fileName: aFileName,
  206.     filePickerTitle: aFilePickerTitleKey,
  207.     document: aDocument,
  208.     bypassCache: aShouldBypassCache,
  209.     window: window
  210.   };
  211.   var sniffer = new nsHeaderSniffer(aURL, foundHeaderInfo, data);
  212. }
  213.  
  214. function foundHeaderInfo(aSniffer, aData)
  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.applyDecodingForType(contentType) &&
  228.         (!urlExt || helperAppService.applyDecodingForExtension(urlExt))) {
  229.       shouldDecode = true;
  230.     }
  231.   }
  232.   catch (e) {
  233.   }
  234.  
  235.   var fp = makeFilePicker();
  236.   var titleKey = aData.filePickerTitle || "SaveLinkTitle";
  237.   var bundle = getStringBundle();
  238.   fp.init(window, bundle.GetStringFromName(titleKey),
  239.           Components.interfaces.nsIFilePicker.modeSave);
  240.  
  241.  
  242.   var isDocument = aData.document != null && isDocumentType(contentType);
  243.   if (!isDocument && !shouldDecode && contentEncodingType) {
  244.     // The data is encoded, we are not going to decode it, and this is not a
  245.     // document save so we won't be doing a "save as, complete" (which would
  246.     // break if we reset the type here).  So just set our content type to
  247.     // correspond to the outermost encoding so we get extensions and the like
  248.     // right.
  249.     contentType = contentEncodingType;
  250.   }
  251.  
  252.   appendFiltersForContentType(fp, contentType,
  253.                               isDocument ? MODE_COMPLETE : MODE_FILEONLY);
  254.  
  255.   const prefSvcContractID = "@mozilla.org/preferences-service;1";
  256.   const prefSvcIID = Components.interfaces.nsIPrefService;
  257.   var prefs = Components.classes[prefSvcContractID].getService(prefSvcIID).getBranch("browser.download.");
  258.  
  259.   const nsILocalFile = Components.interfaces.nsILocalFile;
  260.   try {
  261.     fp.displayDirectory = prefs.getComplexValue("dir", nsILocalFile);
  262.   }
  263.   catch (e) {
  264.   }
  265.  
  266.   if (isDocument) {
  267.     try {
  268.       fp.filterIndex = prefs.getIntPref("save_converter_index");
  269.     }
  270.     catch (e) {
  271.     }
  272.   }
  273.  
  274.   // Determine what the 'default' string to display in the File Picker dialog
  275.   // should be.
  276.   var defaultFileName = getDefaultFileName(aData.fileName,
  277.                                            aSniffer.suggestedFileName,
  278.                                            aSniffer.uri,
  279.                                            aData.document);
  280.   var defaultExtension = getDefaultExtension(defaultFileName, aSniffer.uri, contentType);
  281.   fp.defaultExtension = defaultExtension;
  282.   fp.defaultString = getNormalizedLeafName(defaultFileName, defaultExtension);
  283.  
  284.   if (fp.show() == Components.interfaces.nsIFilePicker.returnCancel || !fp.file)
  285.     return;
  286.  
  287.   if (isDocument)
  288.     prefs.setIntPref("save_converter_index", fp.filterIndex);
  289.   var directory = fp.file.parent.QueryInterface(nsILocalFile);
  290.   prefs.setComplexValue("dir", nsILocalFile, directory);
  291.  
  292.   fp.file.leafName = validateFileName(fp.file.leafName);
  293.  
  294.   // If we're saving a document, and are saving either in complete mode or
  295.   // as converted text, pass the document to the web browser persist component.
  296.   // If we're just saving the HTML (second option in the list), send only the URI.
  297.   var source = (isDocument && fp.filterIndex != 1) ? aData.document : aSniffer.uri;
  298.   var persistArgs = {
  299.     source      : source,
  300.     contentType : (isDocument && fp.filterIndex == 2) ? "text/plain" : contentType,
  301.     target      : fp.file,
  302.     postData    : aData.document ? getPostData() : null,
  303.     bypassCache : aData.bypassCache
  304.   };
  305.  
  306.   var persist = makeWebBrowserPersist();
  307.  
  308.   // Calculate persist flags.
  309.   const nsIWBP = Components.interfaces.nsIWebBrowserPersist;
  310.   const flags = nsIWBP.PERSIST_FLAGS_NO_CONVERSION | nsIWBP.PERSIST_FLAGS_REPLACE_EXISTING_FILES;
  311.   if (aData.bypassCache)
  312.     persist.persistFlags = flags | nsIWBP.PERSIST_FLAGS_BYPASS_CACHE;
  313.   else
  314.     persist.persistFlags = flags | nsIWBP.PERSIST_FLAGS_FROM_CACHE;
  315.  
  316.   if (shouldDecode)
  317.     persist.persistFlags &= ~nsIWBP.PERSIST_FLAGS_NO_CONVERSION;
  318.  
  319.   // Create download and initiate it (below)
  320.   var dl = Components.classes["@mozilla.org/download;1"].createInstance(Components.interfaces.nsIDownload);
  321.  
  322.   if (isDocument && fp.filterIndex != 1) {
  323.     // Saving a Document, not a URI:
  324.     var filesFolder = null;
  325.     if (persistArgs.contentType != "text/plain") {
  326.       // Create the local directory into which to save associated files.
  327.       const lfContractID = "@mozilla.org/file/local;1";
  328.       const lfIID = Components.interfaces.nsILocalFile;
  329.       filesFolder = Components .classes[lfContractID].createInstance(lfIID);
  330.       filesFolder.initWithPath(persistArgs.target.path);
  331.  
  332.       var nameWithoutExtension = filesFolder.leafName;
  333.       nameWithoutExtension = nameWithoutExtension.substring(0, nameWithoutExtension.lastIndexOf("."));
  334.       var filesFolderLeafName = getStringBundle().formatStringFromName("filesFolder",
  335.                                                                        [nameWithoutExtension],
  336.                                                                        1);
  337.  
  338.       filesFolder.leafName = filesFolderLeafName;
  339.     }
  340.  
  341.     var encodingFlags = 0;
  342.     if (persistArgs.contentType == "text/plain") {
  343.       encodingFlags |= nsIWBP.ENCODE_FLAGS_FORMATTED;
  344.       encodingFlags |= nsIWBP.ENCODE_FLAGS_ABSOLUTE_LINKS;
  345.       encodingFlags |= nsIWBP.ENCODE_FLAGS_NOFRAMES_CONTENT;
  346.     }
  347.  
  348.     const kWrapColumn = 80;
  349.     dl.init(aSniffer.uri, persistArgs.target, null, null, null, persist);
  350.     persist.saveDocument(persistArgs.source, persistArgs.target, filesFolder,
  351.                          persistArgs.contentType, encodingFlags, kWrapColumn);
  352.   } else {
  353.     dl.init(source, persistArgs.target, null, null, null, persist);
  354.     persist.saveURI(source, persistArgs.postData, persistArgs.target);
  355.   }
  356. }
  357.  
  358. function nsHeaderSniffer(aURL, aCallback, aData)
  359. {
  360.   this.mCallback = aCallback;
  361.   this.mData = aData;
  362.  
  363.   this.uri = makeURL(aURL);
  364.  
  365.   this.linkChecker = Components.classes["@mozilla.org/network/urichecker;1"]
  366.     .createInstance().QueryInterface(Components.interfaces.nsIURIChecker);
  367.  
  368.   var flags;
  369.   if (aData.bypassCache) {
  370.     flags = Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE;
  371.   } else {
  372.     flags = Components.interfaces.nsIRequest.LOAD_FROM_CACHE;
  373.   }
  374.  
  375.   this.linkChecker.asyncCheckURI(aURL, this, null, flags);
  376. }
  377.  
  378. nsHeaderSniffer.prototype = {
  379.  
  380.   // ---------- nsISupports methods ----------
  381.   QueryInterface: function (iid) {
  382.     if (!iid.equals(Components.interfaces.nsIRequestObserver) &&
  383.         !iid.equals(Components.interfaces.nsISupports) &&
  384.         !iid.equals(Components.interfaces.nsIInterfaceRequestor) &&
  385.         !iid.equals(Components.interfaces.nsIAuthPrompt)) {
  386.       throw Components.results.NS_ERROR_NO_INTERFACE;
  387.     }
  388.     return this;
  389.   },
  390.  
  391.   // ---------- nsIInterfaceRequestor methods ----------
  392.   getInterface : function(iid) {
  393.     return this.QueryInterface(iid);
  394.   },
  395.  
  396.   // ---------- nsIAuthPrompt methods ----------
  397.   prompt : function(dlgTitle, text, pwrealm, savePW, defaultText, result)
  398.   {
  399.     dump("authprompt prompt! pwrealm="+pwrealm+"\n");
  400.     var promptServ = this.promptService;
  401.     if (!promptServ)
  402.       return false;
  403.     var saveCheck = {value:savePW};
  404.     return promptServ.prompt(window, dlgTitle, text, defaultText, pwrealm, saveCheck);
  405.   },
  406.   promptUsernameAndPassword : function(dlgTitle, text, pwrealm, savePW, user, pw)
  407.   {
  408.     dump("authprompt promptUsernameAndPassword!  "+dlgTitle+" "+text+", pwrealm="+pwrealm+"\n");
  409.     var promptServ = this.promptService;
  410.     if (!promptServ)
  411.       return false;
  412.     var saveCheck = {value:savePW};
  413.     return promptServ.promptUsernameAndPassword(window, dlgTitle, text, user, pw, pwrealm, saveCheck);
  414.   },
  415.   promptPassword : function(dlgTitle, text, pwrealm, savePW, pw)
  416.   {
  417.     dump("auth promptPassword!  "+dlgTitle+" "+text+", pwrealm="+pwrealm+"\n");
  418.     var promptServ = this.promptService;
  419.     if (!promptServ)
  420.       return false;
  421.  
  422.     var saveCheck = {value:savePW};
  423.     return promptServ.promptPassword(window, dlgTitle, text, pw, pwrealm, saveCheck);
  424.   },
  425.  
  426.   // ---------- nsIRequestObserver methods ----------
  427.   onStartRequest: function (aRequest, aContext) { },
  428.  
  429.   onStopRequest: function (aRequest, aContext, aStatus) {
  430.     try {
  431.       if (aStatus == 0) { // NS_BINDING_SUCCEEDED, so there's something there
  432.         var linkChecker = aRequest.QueryInterface(Components.interfaces.nsIURIChecker);
  433.         var channel = linkChecker.baseRequest.QueryInterface(Components.interfaces.nsIChannel);
  434.         this.contentType = channel.contentType;
  435.         try {
  436.           var httpChannel = channel.QueryInterface(Components.interfaces.nsIHttpChannel);
  437.           this.contentEncodingType = null;
  438.           // There may be content-encodings on the channel.  Multiple content
  439.           // encodings are allowed, eg "Content-Encoding: gzip, uuencode".  This
  440.           // header would mean that the content was first gzipped and then
  441.           // uuencoded.  The encoding enumerator returns MIME types
  442.           // corresponding to each encoding starting from the end, so the first
  443.           // thing it returns corresponds to the outermost encoding.
  444.           var encodingEnumerator = httpChannel.contentEncodings;
  445.           if (encodingEnumerator && encodingEnumerator.hasMoreElements()) {
  446.             try {
  447.               this.contentEncodingType =
  448.                 encodingEnumerator.getNext().
  449.                   QueryInterface(Components.interfaces.nsISupportsString).data;
  450.             } catch (e) {
  451.             }
  452.           }
  453.           this.mContentDisposition = httpChannel.getResponseHeader("content-disposition");
  454.         }
  455.         catch (e) {
  456.         }
  457.         if (!this.contentType || this.contentType == "application/x-unknown-content-type") {
  458.           // We didn't get a type from the server.  Fall back on other type detection mechanisms
  459.           throw "Unknown Type";
  460.         }
  461.       }
  462.       else {
  463.         dump("Error saving link aStatus = 0x" + aStatus.toString(16) + "\n");
  464.         var bundle = getStringBundle();
  465.         var errorTitle = bundle.GetStringFromName("saveLinkErrorTitle");
  466.         var errorMsg = bundle.GetStringFromName("saveLinkErrorMsg");
  467.         const promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
  468.         promptService.alert(this.mData.window, errorTitle, errorMsg);
  469.         return;
  470.       }
  471.     }
  472.     catch (e) {
  473.       if (this.mData.document) {
  474.         this.contentType = this.mData.document.contentType;
  475.       } else {
  476.         try {
  477.           var url = this.uri.QueryInterface(Components.interfaces.nsIURL);
  478.           var ext = url.fileExtension;
  479.           if (ext) {
  480.             var mimeInfo = getMIMEInfoForExtension(ext);
  481.             if (mimeInfo)
  482.               this.contentType = mimeInfo.MIMEType;
  483.           }
  484.         }
  485.         catch (e) {
  486.           // Not much we can do here.  Give up.
  487.         }
  488.       }
  489.     }
  490.     this.mCallback(this, this.mData);
  491.   },
  492.  
  493.   // ------------------------------------------------
  494.  
  495.   get promptService()
  496.   {
  497.     var promptSvc;
  498.     try {
  499.       promptSvc = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService();
  500.       promptSvc = promptSvc.QueryInterface(Components.interfaces.nsIPromptService);
  501.     }
  502.     catch (e) {}
  503.     return promptSvc;
  504.   },
  505.  
  506.   get suggestedFileName()
  507.   {
  508.     var filename = "";
  509.     var name = this.mContentDisposition;
  510.     if (name) {
  511.       const filenamePrefix = "filename=";
  512.       var ix = name.indexOf(filenamePrefix);
  513.       if (ix >= 0) {
  514.         // Adjust ix to point to start of actual name
  515.         ix += filenamePrefix.length;
  516.         filename = name.substr(ix, name.length);
  517.         if (filename != "") {
  518.           ix = filename.lastIndexOf(";");
  519.           if (ix > 0)
  520.             filename = filename.substr(0, ix);
  521.  
  522.           filename = filename.replace(/^"|"$/g, "");
  523.         }
  524.       }
  525.     }
  526.     return filename;
  527.   }
  528.  
  529. };
  530.  
  531. const MODE_COMPLETE = 0;
  532. const MODE_FILEONLY = 1;
  533.  
  534. function appendFiltersForContentType(aFilePicker, aContentType, aSaveMode)
  535. {
  536.   var bundle = getStringBundle();
  537.  
  538.   switch (aContentType) {
  539.   case "text/html":
  540.     if (aSaveMode == MODE_COMPLETE)
  541.       aFilePicker.appendFilter(bundle.GetStringFromName("WebPageCompleteFilter"), "*.htm; *.html");
  542.     aFilePicker.appendFilter(bundle.GetStringFromName("WebPageHTMLOnlyFilter"), "*.htm; *.html");
  543.     if (aSaveMode == MODE_COMPLETE)
  544.       aFilePicker.appendFilter(bundle.GetStringFromName("TextOnlyFilter"), "*.txt");
  545.     break;
  546.   default:
  547.     var mimeInfo = getMIMEInfoForType(aContentType);
  548.     if (mimeInfo) {
  549.       var extCount = { };
  550.       var extList = { };
  551.       mimeInfo.GetFileExtensions(extCount, extList);
  552.  
  553.       var extString = "";
  554.       for (var i = 0; i < extCount.value; ++i) {
  555.         if (i > 0)
  556.           extString += "; "; // If adding more than one extension, separate by semi-colon
  557.         extString += "*." + extList.value[i];
  558.       }
  559.  
  560.       if (extCount.value > 0) {
  561.         aFilePicker.appendFilter(mimeInfo.Description, extString);
  562.       } else {
  563.         aFilePicker.appendFilter(bundle.GetStringFromName("AllFilesFilter"), "*.*");
  564.       }
  565.     }
  566.     else
  567.       aFilePicker.appendFilter(bundle.GetStringFromName("AllFilesFilter"), "*.*");
  568.     break;
  569.   }
  570. }
  571.  
  572. function getPostData()
  573. {
  574.   try {
  575.     var sessionHistory = getWebNavigation().sessionHistory;
  576.     entry = sessionHistory.getEntryAtIndex(sessionHistory.index, false);
  577.     entry = entry.QueryInterface(Components.interfaces.nsISHEntry);
  578.     return entry.postData;
  579.   }
  580.   catch (e) {
  581.   }
  582.   return null;
  583. }
  584.  
  585. function getStringBundle()
  586. {
  587.   const bundleURL = "chrome://communicator/locale/contentAreaCommands.properties";
  588.  
  589.   const sbsContractID = "@mozilla.org/intl/stringbundle;1";
  590.   const sbsIID = Components.interfaces.nsIStringBundleService;
  591.   const sbs = Components.classes[sbsContractID].getService(sbsIID);
  592.  
  593.   const lsContractID = "@mozilla.org/intl/nslocaleservice;1";
  594.   const lsIID = Components.interfaces.nsILocaleService;
  595.   const ls = Components.classes[lsContractID].getService(lsIID);
  596.   var appLocale = ls.GetApplicationLocale();
  597.   return sbs.createBundle(bundleURL, appLocale);
  598. }
  599.  
  600. function makeWebBrowserPersist()
  601. {
  602.   const persistContractID = "@mozilla.org/embedding/browser/nsWebBrowserPersist;1";
  603.   const persistIID = Components.interfaces.nsIWebBrowserPersist;
  604.   return Components.classes[persistContractID].createInstance(persistIID);
  605. }
  606.  
  607. function makeProgressDialog()
  608. {
  609.   const progressDialogContractID = "@mozilla.org/progressdialog;1";
  610.   const progressDialogIID = Components.interfaces.nsIProgressDialog;
  611.   return Components.classes[progressDialogContractID].createInstance(progressDialogIID);
  612. }
  613.  
  614. function makeURL(aURL)
  615. {
  616.   var ioService = Components.classes["@mozilla.org/network/io-service;1"]
  617.                 .getService(Components.interfaces.nsIIOService);
  618.   return ioService.newURI(aURL, null, null);
  619.  
  620. }
  621.  
  622. function makeFilePicker()
  623. {
  624.   const fpContractID = "@mozilla.org/filepicker;1";
  625.   const fpIID = Components.interfaces.nsIFilePicker;
  626.   return Components.classes[fpContractID].createInstance(fpIID);
  627. }
  628.  
  629. function makeTempFile()
  630. {
  631.   const mimeTypes = "TmpD";
  632.   const flContractID = "@mozilla.org/file/directory_service;1";
  633.   const flIID = Components.interfaces.nsIProperties;
  634.   var fileLocator = Components.classes[flContractID].getService(flIID);
  635.   var tempFile = fileLocator.get(mimeTypes, Components.interfaces.nsIFile);
  636.   tempFile.append("~sav" + Math.floor(Math.random() * 1000) + ".tmp");
  637.   return tempFile;
  638. }
  639.  
  640. function getMIMEService()
  641. {
  642.   const mimeSvcContractID = "@mozilla.org/mime;1";
  643.   const mimeSvcIID = Components.interfaces.nsIMIMEService;
  644.   const mimeSvc = Components.classes[mimeSvcContractID].getService(mimeSvcIID);
  645.   return mimeSvc;
  646. }
  647.  
  648. function getMIMEInfoForExtension(aExtension)
  649. {
  650.   try {
  651.     return getMIMEService().GetFromExtension(aExtension);
  652.   }
  653.   catch (e) {
  654.   }
  655.   return null;
  656. }
  657.  
  658. function getMIMEInfoForType(aMIMEType)
  659. {
  660.   try {
  661.     return getMIMEService().GetFromMIMEType(aMIMEType);
  662.   }
  663.   catch (e) {
  664.   }
  665.   return null;
  666. }
  667.  
  668. function getDefaultFileName(aDefaultFileName, aNameFromHeaders, aDocumentURI, aDocument)
  669. {
  670.   if (aNameFromHeaders)
  671.     return validateFileName(aNameFromHeaders);  // 1) Use the name suggested by the HTTP headers
  672.  
  673.   var url = aDocumentURI.QueryInterface(Components.interfaces.nsIURL);
  674.   if (url.fileName != "")
  675.     return url.fileName;                        // 2) Use the actual file name, if present
  676.  
  677.   if (aDocument && aDocument.title != "")
  678.     return validateFileName(aDocument.title)    // 3) Use the document title
  679.  
  680.   if (aDefaultFileName)
  681.     return validateFileName(aDefaultFileName);  // 4) Use the caller-provided name, if any
  682.  
  683.   return aDocumentURI.host;                     // 5) Use the host.
  684. }
  685.  
  686. function validateFileName(aFileName)
  687. {
  688.   var re = /[\/]+/g;
  689.   if (navigator.appVersion.indexOf("Windows") != -1) {
  690.     re = /[\\\/\|]+/g;
  691.     aFileName = aFileName.replace(/[\"]+/g, "'");
  692.     aFileName = aFileName.replace(/[\*\:\?]+/g, " ");
  693.     aFileName = aFileName.replace(/[\<]+/g, "(");
  694.     aFileName = aFileName.replace(/[\>]+/g, ")");
  695.   }
  696.   else if (navigator.appVersion.indexOf("Macintosh") != -1)
  697.     re = /[\:\/]+/g;
  698.  
  699.   return aFileName.replace(re, "_");
  700. }
  701.  
  702. function getNormalizedLeafName(aFile, aDefaultExtension)
  703. {
  704.   if (!aDefaultExtension)
  705.     return aFile;
  706.  
  707.   // Fix up the file name we're saving to to include the default extension
  708.   const stdURLContractID = "@mozilla.org/network/standard-url;1";
  709.   const stdURLIID = Components.interfaces.nsIURL;
  710.   var url = Components.classes[stdURLContractID].createInstance(stdURLIID);
  711.   url.filePath = aFile;
  712.  
  713.   if (url.fileExtension != aDefaultExtension) {
  714.     return aFile + "." + aDefaultExtension;
  715.   }
  716.  
  717.   return aFile;
  718. }
  719.  
  720. function getDefaultExtension(aFilename, aURI, aContentType)
  721. {
  722.   // This mirrors some code in nsExternalHelperAppService::DoContent
  723.   // Use the filename first and then the URI if that fails
  724.  
  725.   var mimeInfo = getMIMEInfoForType(aContentType);
  726.  
  727.   // First try the extension from the filename
  728.   const stdURLContractID = "@mozilla.org/network/standard-url;1";
  729.   const stdURLIID = Components.interfaces.nsIURL;
  730.   var url = Components.classes[stdURLContractID].createInstance(stdURLIID);
  731.   url.filePath = aFilename;
  732.  
  733.   var ext = url.fileExtension;
  734.  
  735.   if (ext && mimeInfo && mimeInfo.ExtensionExists(ext)) {
  736.     return ext;
  737.   }
  738.  
  739.   // Well, that failed.  Now try the extension from the URI
  740.   var urlext;
  741.   try {
  742.     url = aURI.QueryInterface(Components.interfaces.nsIURL);
  743.     urlext = url.fileExtension;
  744.   } catch (e) {
  745.   }
  746.  
  747.   if (urlext && mimeInfo && mimeInfo.ExtensionExists(urlext)) {
  748.     return urlext;
  749.   }
  750.   else {
  751.     try {
  752.       return mimeInfo.primaryExtension;
  753.     }
  754.     catch (e) {
  755.       // Fall back on the extensions in the filename and URI for lack
  756.       // of anything better.
  757.       return ext || urlext;
  758.     }
  759.   }
  760. }
  761.  
  762. function isDocumentType(aContentType)
  763. {
  764.   switch (aContentType) {
  765.   case "text/html":
  766.     return true;
  767.   case "text/xml":
  768.   case "application/xhtml+xml":
  769.   case "application/xml":
  770.     return false; // XXX Disables Save As Complete until it works for XML
  771.   }
  772.   return false;
  773. }
  774.