diff options
Diffstat (limited to 'comm/suite/editor/base/content/publishprefs.js')
-rw-r--r-- | comm/suite/editor/base/content/publishprefs.js | 867 |
1 files changed, 867 insertions, 0 deletions
diff --git a/comm/suite/editor/base/content/publishprefs.js b/comm/suite/editor/base/content/publishprefs.js new file mode 100644 index 0000000000..4de3b4f282 --- /dev/null +++ b/comm/suite/editor/base/content/publishprefs.js @@ -0,0 +1,867 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/****************** Get publishing data methods *******************/ + +// Build an array of all publish site data obtained from prefs +function GetPublishSiteData() +{ + var publishBranch = GetPublishPrefsBranch(); + if (!publishBranch) + return null; + + // Array of site names - sorted, but don't put default name first + var siteNameList = GetSiteNameList(true, false); + if (!siteNameList) + return null; + + // Array of all site data + var siteArray = []; + + // We rewrite siteName prefs to eliminate names if data is bad + // and to be sure order is the same as sorted name list + try { + publishBranch.deleteBranch("site_name."); + } catch (e) {} + + // Get publish data using siteName as the key + var index = 0; + for (var i = 0; i < siteNameList.length; i++) + { + // Associated data uses site name as key + var publishData = GetPublishData_internal(publishBranch, siteNameList[i]); + if (publishData) + { + siteArray[index] = publishData; + SetPublishStringPref(publishBranch, "site_name."+index, siteNameList[i]); + index++; + } + else + { + try { + // Remove bad site prefs now + publishBranch.deleteBranch("site_data." + siteNameList[i] + "."); + } catch (e) {} + } + } + + SavePrefFile(); + + if (index == 0) // No Valid pref records found! + return null; + + + return siteArray; +} + +function GetDefaultPublishSiteName() +{ + var publishBranch = GetPublishPrefsBranch(); + var name = ""; + if (publishBranch) + name = GetPublishStringPref(publishBranch, "default_site"); + + return name; +} + +// Return object with all info needed to publish +// from database of sites previously published to. +function CreatePublishDataFromUrl(docUrl) +{ + if (!docUrl || IsUrlAboutBlank(docUrl) || GetScheme(docUrl) == "file") + return null; + + var pubSiteData = GetPublishSiteData(); + if (pubSiteData) + { + var dirObj = {}; + var index = FindSiteIndexAndDocDir(pubSiteData, docUrl, dirObj); + var publishData; + if (index != -1) + { + publishData = pubSiteData[index]; + publishData.docDir = FormatDirForPublishing(dirObj.value) + + //XXX Problem: OtherDir: How do we decide when to use the dir in + // publishSiteData (default DocDir) or docDir from current filepath? + publishData.otherDir = FormatDirForPublishing(pubSiteData[index].otherDir); + + publishData.filename = GetFilename(docUrl); + publishData.notInSiteData = false; + return publishData; + } + } + + // Document wasn't found in publish site database + // Create data just from URL + + // Extract username and password from docUrl + var userObj = {}; + var passObj = {}; + var pubUrl = StripUsernamePassword(docUrl, userObj, passObj); + + // Strip off filename + var lastSlash = pubUrl.lastIndexOf("\/"); + //XXX Look for "?", "=", and "&" ? + pubUrl = pubUrl.slice(0, lastSlash+1); + + var siteName = CreateSiteNameFromUrl(pubUrl, pubSiteData); + + publishData = { + siteName : siteName, + previousSiteName : siteName, + filename : GetFilename(docUrl), + username : userObj.value, + password : passObj.value, + savePassword : false, + publishUrl : pubUrl, + browseUrl : pubUrl, + docDir : "", + otherDir : "", + publishOtherFiles : true, + dirList : [""], + saveDirs : false, + notInSiteData : true + } + + return publishData; +} + +function CreateSiteNameFromUrl(url, publishSiteData) +{ + var host = GetHost(url); + var schemePostfix = " (" + GetScheme(url) + ")"; + var siteName = host + schemePostfix; + + if (publishSiteData) + { + // Look for duplicates. Append "-1" etc until unique name found + var i = 1; + var exists = false; + do { + exists = PublishSiteNameExists(siteName, publishSiteData, -1) + if (exists) + siteName = host + "-" + i + schemePostfix; + i++; + } + while (exists); + } + return siteName; +} + +// Similar to above, but in param is a site profile name +// Note that this is more efficient than getting from a URL, +// since we don't have to get all the sitedata but can key off of sitename. +// Caller must supply the current docUrl or just a filename +// If doc URL is supplied, we find the publish subdirectory if publishUrl is part of docUrl +function GetPublishDataFromSiteName(siteName, docUrlOrFilename) +{ + var publishBranch = GetPublishPrefsBranch(); + if (!publishBranch) + return null; + + var siteNameList = GetSiteNameList(false, false); + if (!siteNameList) + return null; + for (var i = 0; i < siteNameList.length; i++) + { + if (siteNameList[i] == siteName) + { + var publishData = GetPublishData_internal(publishBranch, siteName); + if (GetScheme(docUrlOrFilename)) + FillInMatchingPublishData(publishData, docUrlOrFilename); + else + publishData.filename = docUrlOrFilename; + + return publishData; + } + } + return null; +} + +function GetDefaultPublishData() +{ + var publishBranch = GetPublishPrefsBranch(); + if (!publishBranch) + return null; + + var siteName = GetPublishStringPref(publishBranch, "default_site"); + if (!siteName) + return null; + + return GetPublishData_internal(publishBranch, siteName); +} + +function GetPublishData_internal(publishBranch, siteName) +{ + if (!publishBranch || !siteName) + return null; + + var prefPrefix = "site_data." + siteName + "."; + + // We must have a publish url, else we ignore this site + // (siteData and siteNames for sites with incomplete data + // will get deleted by SavePublishSiteDataToPrefs) + var publishUrl = GetPublishStringPref(publishBranch, prefPrefix+"url"); + if (!publishUrl) + return null; + + var savePassword = false; + var publishOtherFiles = true; + try { + savePassword = publishBranch.getBoolPref(prefPrefix+"save_password"); + publishOtherFiles = publishBranch.getBoolPref(prefPrefix+"publish_other_files"); + } catch (e) {} + + var publishData = { + siteName : siteName, + previousSiteName : siteName, + filename : "", + username : GetPublishStringPref(publishBranch, prefPrefix+"username"), + savePassword : savePassword, + publishUrl : publishUrl, + browseUrl : GetPublishStringPref(publishBranch, prefPrefix+"browse_url"), + docDir : FormatDirForPublishing(GetPublishStringPref(publishBranch, prefPrefix+"doc_dir")), + otherDir : FormatDirForPublishing(GetPublishStringPref(publishBranch, prefPrefix+"other_dir")), + publishOtherFiles : publishOtherFiles, + saveDirs : false + } + + // Get password from PasswordManager + publishData.password = GetSavedPassword(publishData); + + // If password was found, user must have checked "Save password" + // checkbox in prompt outside of publishing, so override the pref we stored + if (publishData.password) + { + if (!savePassword) + { + try { + publishPrefsBranch.setBoolPref(prefPrefix+"save_password", true); + } catch (e) {} + } + publishData.savePassword = true; + } + + // Build history list of directories + // Always supply the root dir + publishData.dirList = [""]; + + // Get the rest from prefs + var dirPrefs; + try { + dirPrefs = publishBranch.getChildList(prefPrefix+"dir."); + } catch (e) {} + + if (dirPrefs && dirPrefs.length > 0) + { + if (dirPrefs.length > 1) + dirPrefs.sort(); + + for (var j = 0; j < dirPrefs.length; j++) + { + var dirName = GetPublishStringPref(publishBranch, dirPrefs[j]); + if (dirName) + publishData.dirList[j+1] = dirName; + } + } + + return publishData; +} + +/****************** Save publishing data methods *********************/ + +// Save the siteArray containing all current publish site data +function SavePublishSiteDataToPrefs(siteArray, defaultName) +{ + var publishBranch = GetPublishPrefsBranch(); + if (!publishBranch) + return false; + + try { + if (siteArray) + { + var defaultFound = false; + + // Clear existing names and data -- rebuild all site prefs + publishBranch.deleteBranch("site_name."); + publishBranch.deleteBranch("site_data."); + + for (var i = 0; i < siteArray.length; i++) + { + SavePublishData_Internal(publishBranch, siteArray[i], i); + if (!defaultFound) + defaultFound = defaultName == siteArray[i].siteName; + } + // Assure that we have a default name + if (siteArray.length && !defaultFound) + defaultName = siteArray[0].siteName; + } + + // Save default site name + SetPublishStringPref(publishBranch, "default_site", defaultName); + + // Force saving to file so next page edited finds these values + SavePrefFile(); + } + catch (ex) { return false; } + + return true; +} + +// Update prefs if publish site already exists +// or add prefs for a new site +function SavePublishDataToPrefs(publishData) +{ + if (!publishData || !publishData.publishUrl) + return false; + + var publishBranch = GetPublishPrefsBranch(); + if (!publishBranch) + return false; + + // Create name from URL if no site name is provided + if (!publishData.siteName) + publishData.siteName = CreateSiteNameFromUrl(publishData.publishUrl, publishData); + + var siteNamePrefs; + try { + siteNamePrefs = publishBranch.getChildList("site_name."); + } catch (e) {} + + if (!siteNamePrefs || siteNamePrefs.length == 0) + { + // We currently have no site prefs, so create them + var siteData = [publishData]; + return SavePublishSiteDataToPrefs(siteData, publishData.siteName); + } + + // Use "previous" name if available in case it was changed + var previousSiteName = ("previousSiteName" in publishData && publishData.previousSiteName) ? + publishData.previousSiteName : publishData.siteName; + + // Find site number of existing site or fall through at next available one + // (Number is arbitrary; needed to construct unique "site_name.x" pref string) + for (var i = 0; i < siteNamePrefs.length; i++) + { + var siteName = GetPublishStringPref(publishBranch, "site_name."+i); + + if (siteName == previousSiteName) + { + // Delete prefs for an existing site + try { + publishBranch.deleteBranch("site_data." + siteName + "."); + } catch (e) {} + break; + } + } + + // We've taken care of finding old duplicate, so be sure 'previous name' is current + publishData.previousSiteName = publishData.siteName; + + var ret = SavePublishData_Internal(publishBranch, publishData, i); + if (ret) + { + // Check if siteName was the default and we need to update that + var defaultSiteName = GetPublishStringPref(publishBranch, "default_site"); + if (previousSiteName == defaultSiteName + && publishData.siteName != defaultSiteName) + SetPublishStringPref(publishBranch, "default_site", publishData.siteName); + + SavePrefFile(); + + // Clear signal to save these data + if ("notInSiteData" in publishData && publishData.notInSiteData) + publishData.notInSiteData = false; + } + return ret; +} + +// Save data at a particular site number +function SavePublishData_Internal(publishPrefsBranch, publishData, siteIndex) +{ + if (!publishPrefsBranch || !publishData) + return false; + + SetPublishStringPref(publishPrefsBranch, "site_name."+siteIndex, publishData.siteName); + + FixupUsernamePasswordInPublishData(publishData); + + var prefPrefix = "site_data." + publishData.siteName + "." + + SetPublishStringPref(publishPrefsBranch, prefPrefix+"url", publishData.publishUrl); + SetPublishStringPref(publishPrefsBranch, prefPrefix+"browse_url", publishData.browseUrl); + SetPublishStringPref(publishPrefsBranch, prefPrefix+"username", publishData.username); + + try { + publishPrefsBranch.setBoolPref(prefPrefix+"save_password", publishData.savePassword); + publishPrefsBranch.setBoolPref(prefPrefix+"publish_other_files", publishData.publishOtherFiles); + } catch (e) {} + + // Save password using PasswordManager + // (If publishData.savePassword = false, this clears existing password) + SavePassword(publishData); + + SetPublishStringPref(publishPrefsBranch, prefPrefix+"doc_dir", + FormatDirForPublishing(publishData.docDir)); + + if (publishData.publishOtherFiles && publishData.otherDir) + SetPublishStringPref(publishPrefsBranch, prefPrefix+"other_dir", + FormatDirForPublishing(publishData.otherDir)); + + if ("saveDirs" in publishData && publishData.saveDirs) + { + if (publishData.docDir) + AppendNewDirToList(publishData, publishData.docDir); + + if (publishData.publishOtherFiles && publishData.otherDir + && publishData.otherDir != publishData.docDir) + AppendNewDirToList(publishData, publishData.otherDir); + } + + // Save array of subdirectories with site + if (publishData.dirList.length) + { + publishData.dirList.sort(); + var dirIndex = 0; + for (var j = 0; j < publishData.dirList.length; j++) + { + var dir = publishData.dirList[j]; + + // Don't store the root dir + if (dir && dir != "/") + { + SetPublishStringPref(publishPrefsBranch, prefPrefix + "dir." + dirIndex, dir); + dirIndex++; + } + } + } + + return true; +} + +function AppendNewDirToList(publishData, newDir) +{ + newDir = FormatDirForPublishing(newDir); + if (!publishData || !newDir) + return; + + if (!publishData.dirList) + { + publishData.dirList = [newDir]; + return; + } + + // Check if already in the list + for (var i = 0; i < publishData.dirList.length; i++) + { + // Don't add if already in the list + if (newDir == publishData.dirList[i]) + return; + } + // Add to end of list + publishData.dirList[publishData.dirList.length] = newDir; +} + +function RemovePublishSubdirectoryFromPrefs(publishData, removeDir) +{ + removeDir = FormatDirForPublishing(removeDir); + if (!publishData || !publishData.siteName || !removeDir) + return false; + + var publishBranch = GetPublishPrefsBranch(); + if (!publishBranch) + return false; + + var prefPrefix = "site_data." + publishData.siteName + "."; + + // Remove dir from the default dir prefs + if (publishData.docDir == removeDir) + { + publishData.docDir = ""; + SetPublishStringPref(publishBranch, prefPrefix+"doc_dir", ""); + } + + if (publishData.otherDir == removeDir) + { + publishData.otherDir = ""; + SetPublishStringPref(publishBranch, prefPrefix+"other_dir", ""); + } + + prefPrefix += "dir."; + + // Delete entire subdir list + try { + publishBranch.deleteBranch(prefPrefix); + } catch (e) {} + + // Rebuild prefs, skipping over site to remove + if (publishData.dirList.length) + { + var dirIndex = 0; + var docDirInList = false; + var otherDirInList = false; + for (var i = 0; i < publishData.dirList.length; i++) + { + var dir = publishData.dirList[i]; + if (dir == removeDir) + { + // Remove item from the dirList array + publishData.dirList.splice(i, 1); + --i; + } + else if (dir && dir != "/") // skip empty or root dir + { + // Save to prefs + SetPublishStringPref(publishBranch, prefPrefix + dirIndex, dir); + dirIndex++; + } + } + } + SavePrefFile(); + return true; +} + +function SetDefaultSiteName(name) +{ + if (name) + { + var publishBranch = GetPublishPrefsBranch(); + if (publishBranch) + SetPublishStringPref(publishBranch, "default_site", name); + + SavePrefFile(); + } +} + +function SavePrefFile() +{ + try { + Services.prefs.savePrefFile(null); + } + catch (e) {} +} + +/***************** Helper / utility methods ********************/ + +function GetPublishPrefsBranch() +{ + return Services.prefs.getBranch("editor.publish."); +} + +function GetSiteNameList(doSort, defaultFirst) +{ + var publishBranch = GetPublishPrefsBranch(); + if (!publishBranch) + return null; + + var siteNamePrefs; + try { + siteNamePrefs = publishBranch.getChildList("site_name."); + } catch (e) {} + + if (!siteNamePrefs || siteNamePrefs.length == 0) + return null; + + // Array of site names + var siteNameList = []; + var index = 0; + var defaultName = ""; + if (defaultFirst) + { + defaultName = GetPublishStringPref(publishBranch, "default_site"); + // This always sorts to top -- replace with real string below + siteNameList[0] = ""; + index++; + } + + for (var i = 0; i < siteNamePrefs.length; i++) + { + var siteName = GetPublishStringPref(publishBranch, siteNamePrefs[i]); + // Skip if siteName pref is empty or is default name + if (siteName && siteName != defaultName) + { + siteNameList[index] = siteName; + index++; + } + } + + if (siteNameList.length && doSort) + siteNameList.sort(); + + if (defaultName) + { + siteNameList[0] = defaultName; + index++; + } + + return siteNameList.length? siteNameList : null; +} + +function PublishSiteNameExists(name, publishSiteData, skipSiteIndex) +{ + if (!name) + return false; + + if (!publishSiteData) + { + publishSiteData = GetPublishSiteData(); + skipSiteIndex = -1; + } + + if (!publishSiteData) + return false; + + // Array of site names - sorted, but don't put default name first + for (var i = 0; i < publishSiteData.length; i++) + { + if (i != skipSiteIndex && name == publishSiteData[i].siteName) + return true; + } + return false; +} + +// Find index of a site record in supplied publish site database +// docUrl: Document URL with or without filename +// (Must end in "/" if no filename) +// dirObj.value = the directory of the document URL +// relative to the base publishing URL, using "" if none +// +// XXX: Currently finds the site with the longest-matching url; +// should we look for the shortest instead? Or match just the host portion? +function FindSiteIndexAndDocDir(publishSiteData, docUrl, dirObj) +{ + if (dirObj) + dirObj.value = ""; + + if (!publishSiteData || !docUrl || GetScheme(docUrl) == "file") + return -1; + + var siteIndex = -1; + var siteUrlLen = 0; + + for (var i = 0; i < publishSiteData.length; i++) + { + // Site publish or browse url needs to be contained in document URL, + // but that may also have a directory after the site base URL + // So we must examine all records to find the site URL that best + // matches the document URL: the longest-matching substring (XXX is this right?) + var lenObj = {value:0}; + var tempData = Clone(publishSiteData[i]); + + // Check if this site matches docUrl (returns length of match if found) + var len = FillInMatchingPublishData(tempData, docUrl); + + if (len > siteUrlLen) + { + siteIndex = i; + siteUrlLen = len; + if (dirObj) + dirObj.value = tempData.docDir; + + // Continue to find the site with longest-matching publishUrl + } + } + return siteIndex; +} + +// Look for a matching publish url within the document url +// (We need to look at both "publishUrl" and "browseUrl" in case we are editing +// an http: document but using ftp: to publish.) +// If match is found: +// Fill in the filename and subdirectory based on the docUrl and +// return the length of the docUrl with username+password stripped out +function FillInMatchingPublishData(publishData, docUrl) +{ + if (!publishData || !docUrl) + return 0; + + // Separate docUrl into the base url and filename + var lastSlash = docUrl.lastIndexOf("\/"); + var baseUrl = docUrl.slice(0, lastSlash+1); + var filename = docUrl.slice(lastSlash+1); + + // Strip username+password from docUrl because these + // are stored separately in publishData, never embedded in the publishUrl + // If both docUrl and publishData contain usernames, + // we must match that as well as the url + var username = {value:""}; + baseUrl = StripUsernamePassword(baseUrl, username); + username = username.value; + + var matchedLength = 0; + let pubUrlFound = publishData.publishUrl && baseUrl.startsWith(publishData.publishUrl); + let browseUrlFound = publishData.browseUrl && baseUrl.startsWith(publishData.browseUrl); + + if ((pubUrlFound || browseUrlFound) + && (!username || !publishData.username || username == publishData.username)) + { + // We found a match + matchedLength = pubUrlFound ? publishData.publishUrl.length + : publishData.browseUrl.length; + + if (matchedLength > 0) + { + publishData.filename = filename; + + // Subdirectory within the site is what's left in baseUrl after the matched portion + publishData.docDir = FormatDirForPublishing(baseUrl.slice(matchedLength)); + } + } + return matchedLength; +} + +// Prefs that don't exist will through an exception, +// so just return an empty string +function GetPublishStringPref(prefBranch, name) +{ + if (prefBranch && name) + { + try { + return prefBranch.getStringPref(name); + } catch (e) {} + } + return ""; +} + +function SetPublishStringPref(prefBranch, name, value) +{ + if (prefBranch && name) + { + try { + prefBranch.setStringPref(name, value); + } catch (e) {} + } +} + +// Assure that a publishing URL ends in "/", "=", "&" or "?" +// Username and password should always be extracted as separate fields +// and are not allowed to remain embedded in publishing URL +function FormatUrlForPublishing(url) +{ + url = TrimString(StripUsernamePassword(url)); + if (url) + { + var lastChar = url.charAt(url.length-1); + if (lastChar != "/" && lastChar != "=" && lastChar != "&" && lastChar != "?") + return (url + "/"); + } + return url; +} + +// Username and password present in publish url are +// extracted into the separate "username" and "password" fields +// of the publishData object +// Returns true if we did change the publishData +function FixupUsernamePasswordInPublishData(publishData) +{ + var ret = false; + if (publishData && publishData.publishUrl) + { + var userObj = {value:""}; + var passObj = {value:""}; + publishData.publishUrl = FormatUrlForPublishing(StripUsernamePassword(publishData.publishUrl, userObj, passObj)); + if (userObj.value) + { + publishData.username = userObj.value; + ret = true; + } + if (passObj.value) + { + publishData.password = passObj.value; + ret = true; + } + // While we're at it, be sure browse URL is proper format + publishData.browseUrl = FormatUrlForPublishing(publishData.browseUrl); + } + return ret; +} + +// Assure that a publishing directory ends with "/" and does not begin with "/" +// Input dir is assumed to be a subdirectory string, not a full URL or pathname +function FormatDirForPublishing(dir) +{ + dir = TrimString(dir); + + // The "//" case is an expected "typo" filter + // that simplifies code below! + if (!dir || dir == "/" || dir == "//") + return ""; + + // Remove leading "/" + if (dir.startsWith("/")) + dir = dir.slice(1); + + // Append "/" at the end if necessary + var dirLen = dir.length; + var lastChar = dir.charAt(dirLen-1); + if (dirLen > 1 && ["/", "=", "&", "?"].indexOf(lastChar) == -1) + dir += "/"; + + return dir; +} + +function GetSavedPassword(publishData) +{ + if (!publishData || !publishData.publishUrl) + return ""; + + let url = GetUrlForPasswordManager(publishData); + let logins = Services.logins.findLogins(url, null, url); + + for (let i = 0; i < logins.length; i++) { + if (logins[i].username == publishData.username) + return logins[i].password; + } + + return ""; +} + +function SavePassword(publishData) +{ + if (!publishData || !publishData.publishUrl || !publishData.username) + return false; + + let url = GetUrlForPasswordManager(publishData); + + // Remove existing entry by finding all logins that match. + let logins = Services.logins.findLogins(url, null, url); + + for (let i = 0; i < logins.length; i++) { + if (logins[i].username == publishData.username) { + Services.logins.removeLogin(logins[i]); + break; + } + } + + // If SavePassword is true, add new password. + if (publishData.savePassword) + { + let authInfo = Cc["@mozilla.org/login-manager/loginInfo;1"] + .createInstance(Ci.nsILoginInfo); + authInfo.init(url, null, url, publishData.username, publishData.password, + "", ""); + Services.logins.addLogin(authInfo); + } + + return true; +} + +function GetUrlForPasswordManager(publishData) +{ + if (!publishData || !publishData.publishUrl) + return false; + + let url = Services.io.newURI(publishData.publishUrl); + + if (url.scheme == "ftp" && publishData.username) + // Include username in the URL so we can handle multiple users per server + // in the password manager + url = url.scheme + "://" + publishData.username + "@" + url.hostPort; + else + url = url.scheme + "://" + url.hostPort; + + return url; +} |