diff options
Diffstat (limited to 'mailnews/import/content')
-rw-r--r-- | mailnews/import/content/fieldMapImport.js | 186 | ||||
-rw-r--r-- | mailnews/import/content/fieldMapImport.xul | 68 | ||||
-rw-r--r-- | mailnews/import/content/import-test.html | 36 | ||||
-rw-r--r-- | mailnews/import/content/importDialog.js | 1066 | ||||
-rw-r--r-- | mailnews/import/content/importDialog.xul | 143 |
5 files changed, 1499 insertions, 0 deletions
diff --git a/mailnews/import/content/fieldMapImport.js b/mailnews/import/content/fieldMapImport.js new file mode 100644 index 000000000..cd0f2d5da --- /dev/null +++ b/mailnews/import/content/fieldMapImport.js @@ -0,0 +1,186 @@ +/* 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/. */ + +var importService; +var fieldMap = null; +var recordNum = 0; +var addInterface = null; +var dialogResult = null; +var gPreviousButton; +var gNextButton; +var gMoveUpButton; +var gMoveDownButton; +var gListbox; +var gSkipFirstRecordButton; + +function OnLoadFieldMapImport() +{ + top.importService = Components.classes["@mozilla.org/import/import-service;1"] + .getService(Components.interfaces.nsIImportService); + + // We need a field map object... + // assume we have one passed in? or just make one? + if (window.arguments && window.arguments[0]) { + top.fieldMap = window.arguments[0].fieldMap; + top.addInterface = window.arguments[0].addInterface; + top.dialogResult = window.arguments[0].result; + } + if (top.fieldMap == null) { + top.fieldMap = top.importService.CreateNewFieldMap(); + top.fieldMap.DefaultFieldMap( top.fieldMap.numMozFields); + } + + gMoveUpButton = document.getElementById("upButton"); + gMoveDownButton = document.getElementById("downButton"); + gPreviousButton = document.getElementById("previous"); + gNextButton = document.getElementById("next"); + gListbox = document.getElementById("fieldList"); + gSkipFirstRecordButton = document.getElementById("skipFirstRecord"); + + // Set the state of the skip first record button + gSkipFirstRecordButton.checked = top.fieldMap.skipFirstRecord; + + ListFields(); + Browse(1); + gListbox.selectedItem = gListbox.getItemAtIndex(0); + disableMoveButtons(); +} + +function IndexInMap( index) +{ + var count = top.fieldMap.mapSize; + for (var i = 0; i < count; i++) { + if (top.fieldMap.GetFieldMap( i) == index) + return( true); + } + + return( false); +} + +function ListFields() { + if (top.fieldMap == null) + return; + + var count = top.fieldMap.mapSize; + var index; + var i; + for (i = 0; i < count; i++) { + index = top.fieldMap.GetFieldMap( i); + AddFieldToList(top.fieldMap.GetFieldDescription( index), index, top.fieldMap.GetFieldActive( i)); + } + + count = top.fieldMap.numMozFields; + for (i = 0; i < count; i++) { + if (!IndexInMap( i)) + AddFieldToList(top.fieldMap.GetFieldDescription( i), i, false); + } +} + +function CreateField( name, index, on) +{ + var item = document.createElement('listitem'); + item.setAttribute('field-index', index); + item.setAttribute('type', "checkbox"); + var cell = document.createElement('listcell'); + var cCell = document.createElement( 'listcell'); + cCell.setAttribute('type', "checkbox"); + cCell.setAttribute( 'label', name); + if (on == true) + cCell.setAttribute( 'checked', "true"); + item.appendChild( cCell); + cell.setAttribute( "class", "importsampledata"); + cell.setAttribute( 'label', ""); + item.appendChild( cell); + return( item); +} + +function AddFieldToList(name, index, on) +{ + var item = CreateField(name, index, on); + gListbox.appendChild(item); +} + +function itemClicked(event) +{ + if (event.button == 0) { + var on = gListbox.selectedItem.firstChild.getAttribute('checked'); + gListbox.selectedItem.firstChild.setAttribute('checked', (on != "true")); + } +} + +// The "Move Up/Move Down" buttons should move the items in the left column +// up/down but the values in the right column should not change. +function moveItem(up) +{ + var selectedItem = gListbox.selectedItem; + var swapPartner = (up ? gListbox.getPreviousItem(selectedItem, 1) + : gListbox.getNextItem(selectedItem, 1)); + + var tmpLabel = swapPartner.lastChild.getAttribute('label'); + swapPartner.lastChild.setAttribute('label', selectedItem.lastChild.getAttribute('label')); + selectedItem.lastChild.setAttribute('label', tmpLabel); + + var newItemPosition = (up ? selectedItem.nextSibling : selectedItem); + gListbox.insertBefore(swapPartner, newItemPosition); + gListbox.ensureElementIsVisible(selectedItem); + disableMoveButtons(); +} + +function disableMoveButtons() +{ + var selectedIndex = gListbox.selectedIndex; + gMoveUpButton.disabled = (selectedIndex == 0); + gMoveDownButton.disabled = (selectedIndex == (gListbox.getRowCount() - 1)); +} + +function ShowSampleData(data) +{ + var fields = data.split("\n"); + for (var i = 0; i < gListbox.getRowCount(); i++) + gListbox.getItemAtIndex(i).lastChild.setAttribute('label', (i < fields.length) ? fields[i] : ''); +} + +function FetchSampleData(num) +{ + if (!top.addInterface) + return false; + + var data = top.addInterface.GetData( "sampleData-" + num); + if (!(data instanceof Components.interfaces.nsISupportsString)) + return false; + ShowSampleData( data.data); + return true; +} + +function Browse(step) +{ + recordNum += step; + if (FetchSampleData(recordNum - 1)) + document.getElementById('recordNumber').setAttribute('value', ("" + recordNum)); + + gPreviousButton.disabled = (recordNum == 1); + gNextButton.disabled = (addInterface.GetData("sampleData-" + recordNum) == null); +} + +function FieldImportOKButton() +{ + var max = gListbox.getRowCount(); + var fIndex; + var on; + // Ensure field map is the right size + top.fieldMap.SetFieldMapSize(max); + + for (var i = 0; i < max; i++) { + fIndex = gListbox.getItemAtIndex(i).getAttribute( 'field-index'); + on = gListbox.getItemAtIndex(i).firstChild.getAttribute('checked'); + top.fieldMap.SetFieldMap( i, fIndex); + top.fieldMap.SetFieldActive( i, (on == "true")); + } + + top.fieldMap.skipFirstRecord = gSkipFirstRecordButton.checked; + + top.dialogResult.ok = true; + + return true; +} diff --git a/mailnews/import/content/fieldMapImport.xul b/mailnews/import/content/fieldMapImport.xul new file mode 100644 index 000000000..abaca10ba --- /dev/null +++ b/mailnews/import/content/fieldMapImport.xul @@ -0,0 +1,68 @@ +<?xml version="1.0"?> +<!-- 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/. --> + +<?xml-stylesheet href="chrome://communicator/skin/" type="text/css"?> + +<!DOCTYPE dialog SYSTEM "chrome://messenger/locale/fieldMapImport.dtd"> + +<dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + buttons="accept,cancel" + title="&fieldMapImport.title;" + style="&fieldMapImport.size;" + ondialogaccept="FieldImportOKButton();" + onload="OnLoadFieldMapImport();"> + + <script type="application/javascript" src="chrome://messenger/content/fieldMapImport.js"/> + + <hbox align="center"> + <label value="&fieldMapImport.recordNumber;"/> + <label id="recordNumber"/> + <spacer flex="1"/> + <button id="previous" oncommand="Browse(-1);" + label="&fieldMapImport.previous.label;" + accesskey="&fieldMapImport.previous.accesskey;"/> + <button id="next" oncommand="Browse(1);" + label="&fieldMapImport.next.label;" + accesskey="&fieldMapImport.next.accesskey;"/> + </hbox> + + <hbox align="center"> + <checkbox id="skipFirstRecord" + label="&fieldMapImport.skipFirstRecord.label;" + accesskey="&fieldMapImport.skipFirstRecord.accessKey;"/> + </hbox> + + <separator class="thin"/> + <label control="fieldList">&fieldMapImport.text;</label> + <separator class="thin"/> + + <!-- field list --> + <hbox flex="1"> + <listbox id="fieldList" flex="1" onselect="disableMoveButtons();" + onclick="itemClicked(event);"> + <listcols> + <listcol flex="7"/> + <listcol flex="13"/> + </listcols> + + <listhead> + <listheader id="fieldNameHeader" label="&fieldMapImport.fieldListTitle;"/> + <listheader id="sampleDataHeader" label="&fieldMapImport.dataTitle;"/> + </listhead> + </listbox> + + <vbox> + <spacer flex="1"/> + <button id="upButton" class="up" label="&fieldMapImport.up.label;" + accesskey="&fieldMapImport.up.accesskey;" + oncommand="moveItem(true);"/> + <button id="downButton" class="down" label="&fieldMapImport.down.label;" + accesskey="&fieldMapImport.down.accesskey;" + oncommand="moveItem(false);"/> + <spacer flex="1"/> + </vbox> + </hbox> + +</dialog> diff --git a/mailnews/import/content/import-test.html b/mailnews/import/content/import-test.html new file mode 100644 index 000000000..ef9c5ed7f --- /dev/null +++ b/mailnews/import/content/import-test.html @@ -0,0 +1,36 @@ +<!-- 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/. --> + +<html> +<body> + +<script type="application/javascript"> + +function toImport(importType) +{ + /* + window.openDialog("chrome:/messenger/content/fieldMapImport.xul", + "fieldMapImportDialog", + "chrome,modal"); + */ + window.openDialog("chrome:/messenger/content/importDialog.xul", + "", + "chrome,modal", + {importType:importType}); + +} + + +</script> + +<p> +<form name="form"> +<input type="button" value="Import Address Books" onclick="toImport( 'addressbook');"><br> +<input type="button" value="Import Mail" onclick="toImport( 'mail');"><br> +<input type="button" value="Import Settings" onclick="toImport( 'settings');"><br> +<input type="button" value="Import Filters" onclick="toImport( 'filters');"><br> +<form> + +</body> +</html> diff --git a/mailnews/import/content/importDialog.js b/mailnews/import/content/importDialog.js new file mode 100644 index 000000000..2ad7c6fb3 --- /dev/null +++ b/mailnews/import/content/importDialog.js @@ -0,0 +1,1066 @@ +/* -*- Mode: Javascript; tab-width: 2; 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/. */ + +"use strict"; + +Components.utils.import("resource:///modules/mailServices.js"); +Components.utils.import("resource://gre/modules/Services.jsm"); + +var gImportType = null; +var gImportMsgsBundle; +var gFeedsBundle; +var gImportService = null; +var gSuccessStr = null; +var gErrorStr = null; +var gInputStr = null; +var gProgressInfo = null; +var gSelectedModuleName = null; +var gAddInterface = null; +var gNewFeedAcctCreated = false; + +var Ci = Components.interfaces; +var nsISupportsString = Ci.nsISupportsString; + +function OnLoadImportDialog() +{ + gImportMsgsBundle = document.getElementById("bundle_importMsgs"); + gFeedsBundle = document.getElementById("bundle_feeds"); + gImportService = Components.classes["@mozilla.org/import/import-service;1"] + .getService(Ci.nsIImportService); + + gProgressInfo = { }; + gProgressInfo.progressWindow = null; + gProgressInfo.importInterface = null; + gProgressInfo.mainWindow = window; + gProgressInfo.intervalState = 0; + gProgressInfo.importSuccess = false; + gProgressInfo.importType = null; + gProgressInfo.localFolderExists = false; + + gSuccessStr = Components.classes["@mozilla.org/supports-string;1"] + .createInstance(nsISupportsString); + gErrorStr = Components.classes["@mozilla.org/supports-string;1"] + .createInstance(nsISupportsString); + gInputStr = Components.classes["@mozilla.org/supports-string;1"] + .createInstance(nsISupportsString); + + // look in arguments[0] for parameters + if (("arguments" in window) && window.arguments.length >= 1 && + ("importType" in window.arguments[0]) && window.arguments[0].importType) + { + // keep parameters in global for later + gImportType = window.arguments[0].importType; + gProgressInfo.importType = gImportType; + } + else + { + gImportType = "all"; + gProgressInfo.importType = "all"; + } + + SetUpImportType(); + + // on startup, set the focus to the control element + // for accessibility reasons. + // if we used the wizardOverlay, we would get this for free. + // see bug #101874 + document.getElementById("importFields").focus(); +} + + +function SetUpImportType() +{ + // set dialog title + document.getElementById("importFields").value = gImportType; + + // Mac migration not working right now, so disable it. + if (Services.appinfo.OS == "Darwin") + { + document.getElementById("allRadio").setAttribute("disabled", "true"); + if (gImportType == "all") + document.getElementById("importFields").value = "addressbook"; + } + + let descriptionDeck = document.getElementById("selectDescriptionDeck"); + descriptionDeck.selectedIndex = 0; + if (gImportType == "feeds") + { + descriptionDeck.selectedIndex = 1; + ListFeedAccounts(); + } + else + ListModules(); +} + + +function SetDivText(id, text) +{ + var div = document.getElementById(id); + + if (div) { + if (!div.hasChildNodes()) { + var textNode = document.createTextNode(text); + div.appendChild(textNode); + } + else if (div.childNodes.length == 1) { + div.childNodes[0].nodeValue = text; + } + } +} + +function CheckIfLocalFolderExists() +{ + try { + if (MailServices.accounts.localFoldersServer) + gProgressInfo.localFolderExists = true; + } + catch (ex) { + gProgressInfo.localFolderExists = false; + } +} + +function ImportDialogOKButton() +{ + var listbox = document.getElementById("moduleList"); + var deck = document.getElementById("stateDeck"); + var header = document.getElementById("header"); + var progressMeterEl = document.getElementById("progressMeter"); + progressMeterEl.mode = "determined"; + var progressStatusEl = document.getElementById("progressStatus"); + var progressTitleEl = document.getElementById("progressTitle"); + + // better not mess around with navigation at this point + var nextButton = document.getElementById("forward"); + nextButton.setAttribute("disabled", "true"); + var backButton = document.getElementById("back"); + backButton.setAttribute("disabled", "true"); + + if (listbox && (listbox.selectedCount == 1)) + { + let module = ""; + let name = ""; + gImportType = document.getElementById("importFields").value; + let index = listbox.selectedItem.getAttribute("list-index"); + if (index == -1) + return false; + if (gImportType == "feeds") + module = "Feeds"; + else + { + module = gImportService.GetModule(gImportType, index); + name = gImportService.GetModuleName(gImportType, index); + } + gSelectedModuleName = name; + if (module) + { + // Fix for Bug 57839 & 85219 + // We use localFoldersServer(in nsIMsgAccountManager) to check if Local Folder exists. + // We need to check localFoldersServer before importing "mail", "settings", or "filters". + // Reason: We will create an account with an incoming server of type "none" after + // importing "mail", so the localFoldersServer is valid even though the Local Folder + // is not created. + if (gImportType == "mail" || gImportType == "settings" || gImportType == "filters") + CheckIfLocalFolderExists(); + + let meterText = ""; + let error = {}; + switch(gImportType) + { + case "mail": + if (ImportMail(module, gSuccessStr, gErrorStr)) + { + // We think it was a success, either, we need to + // wait for the import to finish + // or we are done! + if (gProgressInfo.importInterface == null) { + ShowImportResults(true, 'Mail'); + return true; + } + else { + meterText = gImportMsgsBundle.getFormattedString('MailProgressMeterText', + [ name ]); + header.setAttribute("description", meterText); + + progressStatusEl.setAttribute("label", ""); + progressTitleEl.setAttribute("label", meterText); + + deck.selectedIndex = 2; + gProgressInfo.progressWindow = window; + gProgressInfo.intervalState = setInterval(ContinueImportCallback, 100); + return true; + } + } + else + { + ShowImportResults(false, 'Mail'); + // Re-enable the next button, as we are here, because the user cancelled the picking. + // Enable next, so they can try again. + nextButton.removeAttribute("disabled"); + // Also enable back button so that users can pick other import options. + backButton.removeAttribute("disabled"); + return false; + } + break; + + case "feeds": + if (ImportFeeds()) + { + // Successful completion of pre processing and launch of async import. + meterText = document.getElementById("description").textContent; + header.setAttribute("description", meterText); + + progressStatusEl.setAttribute("label", ""); + progressTitleEl.setAttribute("label", meterText); + progressMeterEl.mode = "undetermined"; + + deck.selectedIndex = 2; + return true; + } + else + { + // Re-enable the next button, as we are here, because the user cancelled the picking. + // Enable next, so they can try again. + nextButton.removeAttribute("disabled"); + // Also enable back button so that users can pick other import options. + backButton.removeAttribute("disabled"); + return false; + } + break; + + case "addressbook": + if (ImportAddress(module, gSuccessStr, gErrorStr)) { + // We think it was a success, either, we need to + // wait for the import to finish + // or we are done! + if (gProgressInfo.importInterface == null) { + ShowImportResults(true, 'Address'); + return true; + } + else { + meterText = gImportMsgsBundle.getFormattedString('AddrProgressMeterText', + [ name ]); + header.setAttribute("description", meterText); + + progressStatusEl.setAttribute("label", ""); + progressTitleEl.setAttribute("label", meterText); + + deck.selectedIndex = 2; + gProgressInfo.progressWindow = window; + gProgressInfo.intervalState = setInterval(ContinueImportCallback, 100); + + return true; + } + } + else + { + ShowImportResults(false, 'Address'); + // Re-enable the next button, as we are here, because the user cancelled the picking. + // Enable next, so they can try again. + nextButton.removeAttribute("disabled"); + // Also enable back button so that users can pick other import options. + backButton.removeAttribute("disabled"); + return false; + } + break; + + case "settings": + error.value = null; + let newAccount = {}; + if (!ImportSettings(module, newAccount, error)) + { + if (error.value) + ShowImportResultsRaw(gImportMsgsBundle.getString("ImportSettingsFailed"), + null, false); + // Re-enable the next button, as we are here, because the user cancelled the picking. + // Enable next, so they can try again. + nextButton.removeAttribute("disabled"); + // Also enable back button so that users can pick other import options. + backButton.removeAttribute("disabled"); + return false; + } + else + ShowImportResultsRaw( + gImportMsgsBundle.getFormattedString("ImportSettingsSuccess", [ name ]), + null, true); + break; + + case "filters": + error.value = null; + if (!ImportFilters(module, error)) + { + if (error.value) + ShowImportResultsRaw( + gImportMsgsBundle.getFormattedString("ImportFiltersFailed", [ name ]), + error.value, false); + // Re-enable the next button, as we are here, because the user cancelled the picking. + // Enable next, so they can try again. + nextButton.removeAttribute("disabled"); + // Also enable back button so that users can pick other import options. + backButton.removeAttribute("disabled"); + return false; + } + else + { + if (error.value) + ShowImportResultsRaw( + gImportMsgsBundle.getFormattedString('ImportFiltersPartial', [ name ]), + error.value, true); + else + ShowImportResultsRaw( + gImportMsgsBundle.getFormattedString('ImportFiltersSuccess', [ name ]), + null, true); + } + break; + } + } + } + + return true; +} + +function SetStatusText(val) +{ + var progressStatus = document.getElementById("progressStatus"); + progressStatus.setAttribute("label", val); +} + +function SetProgress(val) +{ + var progressMeter = document.getElementById("progressMeter"); + progressMeter.value = val; +} + +function ContinueImportCallback() +{ + gProgressInfo.mainWindow.ContinueImport(gProgressInfo); +} + +function ImportSelectionChanged() +{ + let listbox = document.getElementById('moduleList'); + let acctNameBox = document.getElementById('acctName-box'); + if (listbox && (listbox.selectedCount == 1)) + { + let index = listbox.selectedItem.getAttribute("list-index"); + if (index == -1) + return; + acctNameBox.setAttribute('style', 'visibility: hidden;'); + if (gImportType == "feeds") + { + if (index == 0) + { + SetDivText('description', gFeedsBundle.getString('ImportFeedsNewAccount')); + let defaultName = gFeedsBundle.getString("feeds-accountname"); + document.getElementById("acctName").value = defaultName; + acctNameBox.removeAttribute('style'); + } + else + SetDivText('description', gFeedsBundle.getString('ImportFeedsExistingAccount')); + } + else + SetDivText("description", gImportService.GetModuleDescription(gImportType, index)); + } +} + +function CompareImportModuleName(a, b) +{ + if (a.name > b.name) + return 1; + if (a.name < b.name) + return -1; + return 0; +} + +function ListModules() { + if (gImportService == null) + return; + + var body = document.getElementById("moduleList"); + while (body.hasChildNodes()) { + body.lastChild.remove(); + } + + var count = gImportService.GetModuleCount(gImportType); + var i; + + var moduleArray = new Array(count); + for (i = 0; i < count; i++) { + moduleArray[i] = { name: gImportService.GetModuleName(gImportType, i), index: i }; + } + + // sort the array of modules by name, so that they'll show up in the right order + moduleArray.sort(CompareImportModuleName); + + for (i = 0; i < count; i++) { + AddModuleToList(moduleArray[i].name, moduleArray[i].index); + } +} + +function AddModuleToList(moduleName, index) +{ + var body = document.getElementById("moduleList"); + + var item = document.createElement('listitem'); + item.setAttribute('label', moduleName); + + // Temporarily skip Outlook Import which are busted (Bug 1175055). + if (moduleName == "Outlook") { + item.setAttribute('list-index', -1); + item.setAttribute('disabled', true); + item.setAttribute('tooltiptext', "Currently disabled due to bug 1175055"); + } else { + item.setAttribute('list-index', index); + } + body.appendChild(item); +} + +function ListFeedAccounts() { + let body = document.getElementById("moduleList"); + while (body.hasChildNodes()) + body.lastChild.remove(); + + // Add item to allow for new account creation. + let item = document.createElement("listitem"); + item.setAttribute("label", gFeedsBundle.getString('ImportFeedsCreateNewListItem')); + item.setAttribute("list-index", 0); + body.appendChild(item); + + let index = 0; + let feedRootFolders = FeedUtils.getAllRssServerRootFolders(); + + feedRootFolders.forEach(function(rootFolder) { + item = document.createElement("listitem"); + item.setAttribute("label", rootFolder.prettyName); + item.setAttribute("list-index", ++index); + item.server = rootFolder.server; + body.appendChild(item); + }, this); + + if (index) + // If there is an existing feed account, select the first one. + body.selectedIndex = 1; +} + +function ContinueImport(info) { + var isMail = info.importType == 'mail'; + var clear = true; + var deck; + var pcnt; + + if (info.importInterface) { + if (!info.importInterface.ContinueImport()) { + info.importSuccess = false; + clearInterval(info.intervalState); + if (info.progressWindow != null) { + deck = document.getElementById("stateDeck"); + deck.selectedIndex = 3; + info.progressWindow = null; + } + + ShowImportResults(false, isMail ? 'Mail' : 'Address'); + } + else if ((pcnt = info.importInterface.GetProgress()) < 100) { + clear = false; + if (info.progressWindow != null) { + if (pcnt < 5) + pcnt = 5; + SetProgress(pcnt); + if (isMail) { + let mailName = info.importInterface.GetData("currentMailbox"); + if (mailName) { + mailName = mailName.QueryInterface(Ci.nsISupportsString); + if (mailName) + SetStatusText(mailName.data); + } + } + } + } + else { + dump("*** WARNING! sometimes this shows results too early. \n"); + dump(" something screwy here. this used to work fine.\n"); + clearInterval(info.intervalState); + info.importSuccess = true; + if (info.progressWindow) { + deck = document.getElementById("stateDeck"); + deck.selectedIndex = 3; + info.progressWindow = null; + } + + ShowImportResults(true, isMail ? 'Mail' : 'Address'); + } + } + if (clear) { + info.intervalState = null; + info.importInterface = null; + } +} + + +function ShowResults(doesWantProgress, result) +{ + if (result) + { + if (doesWantProgress) + { + let deck = document.getElementById("stateDeck"); + let header = document.getElementById("header"); + let progressStatusEl = document.getElementById("progressStatus"); + let progressTitleEl = document.getElementById("progressTitle"); + + let meterText = gImportMsgsBundle.getFormattedString("AddrProgressMeterText", [ name ]); + header.setAttribute("description", meterText); + + progressStatusEl.setAttribute("label", ""); + progressTitleEl.setAttribute("label", meterText); + + deck.selectedIndex = 2; + gProgressInfo.progressWindow = window; + gProgressInfo.intervalState = setInterval(ContinueImportCallback, 100); + } + else + { + ShowImportResults(true, 'Address'); + } + } + else + { + ShowImportResults(false, 'Address'); + } + + return true; +} + +function ShowImportResults(good, module) +{ + // String keys for ImportSettingsSuccess, ImportSettingsFailed, + // ImportMailSuccess, ImportMailFailed, ImportAddressSuccess, + // ImportAddressFailed, ImportFiltersSuccess, and ImportFiltersFailed. + var modSuccess = 'Import' + module + 'Success'; + var modFailed = 'Import' + module + 'Failed'; + + // The callers seem to set 'good' to true even if there's something + // in the error log. So we should only make it a success case if + // error log/str is empty. + var results, title; + var moduleName = gSelectedModuleName ? gSelectedModuleName : ""; + if (good && !gErrorStr.data) { + title = gImportMsgsBundle.getFormattedString(modSuccess, [ moduleName ]); + results = gSuccessStr.data; + } + else if (gErrorStr.data) { + title = gImportMsgsBundle.getFormattedString(modFailed, [ moduleName ]); + results = gErrorStr.data; + } + + if (results && title) + ShowImportResultsRaw(title, results, good); +} + +function ShowImportResultsRaw(title, results, good) +{ + SetDivText("status", title); + var header = document.getElementById("header"); + header.setAttribute("description", title); + dump("*** results = " + results + "\n"); + attachStrings("results", results); + var deck = document.getElementById("stateDeck"); + deck.selectedIndex = 3; + var nextButton = document.getElementById("forward"); + nextButton.label = nextButton.getAttribute("finishedval"); + nextButton.removeAttribute("disabled"); + var cancelButton = document.getElementById("cancel"); + cancelButton.setAttribute("disabled", "true"); + var backButton = document.getElementById("back"); + backButton.setAttribute("disabled", "true"); + + // If the Local Folder doesn't exist, create it after successfully + // importing "mail" and "settings" + var checkLocalFolder = (gProgressInfo.importType == "mail" || + gProgressInfo.importType == "settings"); + if (good && checkLocalFolder && !gProgressInfo.localFolderExists) { + MailServices.accounts.createLocalMailAccount(); + } +} + +function attachStrings(aNode, aString) +{ + var attachNode = document.getElementById(aNode); + if (!aString) { + attachNode.parentNode.setAttribute("hidden", "true"); + return; + } + var strings = aString.split("\n"); + for (let string of strings) { + if (string) { + let currNode = document.createTextNode(string); + attachNode.appendChild(currNode); + let br = document.createElementNS("http://www.w3.org/1999/xhtml", 'br'); + attachNode.appendChild(br); + } + } +} + +/* + Import Settings from a specific module, returns false if it failed + and true if successful. A "local mail" account is returned in newAccount. + This is only useful in upgrading - import the settings first, then + import mail into the account returned from ImportSettings, then + import address books. + An error string is returned as error.value +*/ +function ImportSettings(module, newAccount, error) { + var setIntf = module.GetImportInterface("settings"); + if (!(setIntf instanceof Ci.nsIImportSettings)) { + error.value = gImportMsgsBundle.getString('ImportSettingsBadModule'); + return false; + } + + // determine if we can auto find the settings or if we need to ask the user + var location = {}; + var description = {}; + var result = setIntf.AutoLocate(description, location); + if (!result) { + // In this case, we couldn't find the settings + if (location.value != null) { + // Settings were not found, however, they are specified + // in a file, so ask the user for the settings file. + let filePicker = Components.classes["@mozilla.org/filepicker;1"].createInstance(); + if (filePicker instanceof Ci.nsIFilePicker) { + let file = null; + try { + filePicker.init(window, + gImportMsgsBundle.getString("ImportSelectSettings"), + filePicker.modeOpen); + filePicker.appendFilters(filePicker.filterAll); + filePicker.show(); + file = filePicker.file; + } + catch(ex) { + file = null; + error.value = null; + return false; + } + if (file != null) { + setIntf.SetLocation(file); + } + else { + error.value = null; + return false; + } + } + else { + error.value = gImportMsgsBundle.getString('ImportSettingsNotFound'); + return false; + } + } + else { + error.value = gImportMsgsBundle.getString('ImportSettingsNotFound'); + return false; + } + } + + // interesting, we need to return the account that new + // mail should be imported into? + // that's really only useful for "Upgrade" + result = setIntf.Import(newAccount); + if (!result) { + error.value = gImportMsgsBundle.getString('ImportSettingsFailed'); + } + return result; +} + +function ImportMail(module, success, error) { + if (gProgressInfo.importInterface || gProgressInfo.intervalState) { + error.data = gImportMsgsBundle.getString('ImportAlreadyInProgress'); + return false; + } + + gProgressInfo.importSuccess = false; + + var mailInterface = module.GetImportInterface("mail"); + if (!(mailInterface instanceof Ci.nsIImportGeneric)) { + error.data = gImportMsgsBundle.getString('ImportMailBadModule'); + return false; + } + + var loc = mailInterface.GetData("mailLocation"); + + if (loc == null) { + // No location found, check to see if we can ask the user. + if (mailInterface.GetStatus("canUserSetLocation") != 0) { + let filePicker = Components.classes["@mozilla.org/filepicker;1"].createInstance(); + if (filePicker instanceof Ci.nsIFilePicker) { + try { + filePicker.init(window, + gImportMsgsBundle.getString("ImportSelectMailDir"), + filePicker.modeGetFolder); + filePicker.appendFilters(filePicker.filterAll); + filePicker.show(); + if (filePicker.file && (filePicker.file.path.length > 0)) + mailInterface.SetData("mailLocation", filePicker.file); + else + return false; + } catch(ex) { + // don't show an error when we return! + return false; + } + } + else { + error.data = gImportMsgsBundle.getString('ImportMailNotFound'); + return false; + } + } + else { + error.data = gImportMsgsBundle.getString('ImportMailNotFound'); + return false; + } + } + + if (mailInterface.WantsProgress()) { + if (mailInterface.BeginImport(success, error)) { + gProgressInfo.importInterface = mailInterface; + // intervalState = setInterval(ContinueImport, 100); + return true; + } + else + return false; + } + else + return mailInterface.BeginImport(success, error); +} + + +// The address import! A little more complicated than the mail import +// due to field maps... +function ImportAddress(module, success, error) { + if (gProgressInfo.importInterface || gProgressInfo.intervalState) { + error.data = gImportMsgsBundle.getString('ImportAlreadyInProgress'); + return false; + } + + gProgressInfo.importSuccess = false; + + gAddInterface = module.GetImportInterface("addressbook"); + if (!(gAddInterface instanceof Ci.nsIImportGeneric)) { + error.data = gImportMsgsBundle.getString('ImportAddressBadModule'); + return false; + } + + var loc = gAddInterface.GetStatus("autoFind"); + if (loc == 0) { + loc = gAddInterface.GetData("addressLocation"); + if ((loc instanceof Ci.nsIFile) && !loc.exists) + loc = null; + } + + if (loc == null) { + // Couldn't find the address book, see if we can + // as the user for the location or not? + if (gAddInterface.GetStatus("canUserSetLocation") == 0) { + // an autofind address book that could not be found! + error.data = gImportMsgsBundle.getString('ImportAddressNotFound'); + return false; + } + + let filePicker = Components.classes["@mozilla.org/filepicker;1"].createInstance(); + if (!(filePicker instanceof Ci.nsIFilePicker)) { + error.data = gImportMsgsBundle.getString('ImportAddressNotFound'); + return false; + } + + // The address book location was not found. + // Determine if we need to ask for a directory + // or a single file. + let file = null; + let fileIsDirectory = false; + if (gAddInterface.GetStatus("supportsMultiple") != 0) { + // ask for dir + try { + filePicker.init(window, + gImportMsgsBundle.getString("ImportSelectAddrDir"), + filePicker.modeGetFolder); + filePicker.appendFilters(filePicker.filterAll); + filePicker.show(); + if (filePicker.file && (filePicker.file.path.length > 0)) { + file = filePicker.file; + fileIsDirectory = true; + } + else { + file = null; + } + } catch(ex) { + file = null; + } + } + else { + // ask for file + try { + filePicker.init(window, + gImportMsgsBundle.getString("ImportSelectAddrFile"), + filePicker.modeOpen); + let addressbookBundle = document.getElementById("bundle_addressbook"); + if (gSelectedModuleName == + document.getElementById("bundle_vcardImportMsgs") + .getString("vCardImportName")) { + filePicker.appendFilter(addressbookBundle.getString('VCFFiles'), "*.vcf"); + } else { + filePicker.appendFilter(addressbookBundle.getString('LDIFFiles'), "*.ldi; *.ldif"); + filePicker.appendFilter(addressbookBundle.getString('CSVFiles'), "*.csv"); + filePicker.appendFilter(addressbookBundle.getString('TABFiles'), "*.tab; *.txt"); + filePicker.appendFilters(filePicker.filterAll); + } + + if (filePicker.show() == filePicker.returnCancel) + return false; + + if (filePicker.file && (filePicker.file.path.length > 0)) + file = filePicker.file; + else + file = null; + } catch(ex) { + dump("ImportAddress(): failure when picking a file to import: " + ex + "\n"); + file = null; + } + } + + if (file == null) { + return false; + } + + if (!fileIsDirectory && (file.fileSize == 0)) { + let errorText = gImportMsgsBundle.getFormattedString("ImportEmptyAddressBook", + [filePicker.file.leafName]); + + Services.prompt.alert(window, document.title, errorText); + return false; + } + gAddInterface.SetData("addressLocation", file); + } + + var map = gAddInterface.GetData("fieldMap"); + if (map instanceof Ci.nsIImportFieldMap) { + let result = {}; + result.ok = false; + window.openDialog( + "chrome://messenger/content/fieldMapImport.xul", + "", + "chrome,modal,titlebar", + { fieldMap: map, + addInterface: gAddInterface, + result: result }); + + if (!result.ok) + return false; + } + + if (gAddInterface.WantsProgress()) { + if (gAddInterface.BeginImport(success, error)) { + gProgressInfo.importInterface = gAddInterface; + // intervalState = setInterval(ContinueImport, 100); + return true; + } + return false; + } + + return gAddInterface.BeginImport(success, error); +} + +/* + Import filters from a specific module. + Returns false if it failed and true if it succeeded. + An error string is returned as error.value. +*/ +function ImportFilters(module, error) +{ + if (gProgressInfo.importInterface || gProgressInfo.intervalState) { + error.data = gImportMsgsBundle.getString('ImportAlreadyInProgress'); + return false; + } + + gProgressInfo.importSuccess = false; + + var filtersInterface = module.GetImportInterface("filters"); + if (!(filtersInterface instanceof Ci.nsIImportFilters)) { + error.data = gImportMsgsBundle.getString('ImportFiltersBadModule'); + return false; + } + + return filtersInterface.Import(error); +} + +/* + Import feeds. +*/ +function ImportFeeds() +{ + // Get file to open from filepicker. + let openFile = FeedSubscriptions.opmlPickOpenFile(); + if (!openFile) + return false; + + let acctName; + let acctNewExist = gFeedsBundle.getString("ImportFeedsExisting"); + let fileName = openFile.path; + let server = document.getElementById("moduleList").selectedItem.server; + gNewFeedAcctCreated = false; + + if (!server) + { + // Create a new Feeds account. + acctName = document.getElementById("acctName").value; + server = FeedUtils.createRssAccount(acctName).incomingServer; + acctNewExist = gFeedsBundle.getString("ImportFeedsNew"); + gNewFeedAcctCreated = true; + } + + acctName = server.rootFolder.prettyName; + + let callback = function(aStatusReport, aLastFolder , aFeedWin) + { + let message = gFeedsBundle.getFormattedString("ImportFeedsDone", + [fileName, acctNewExist, acctName]); + ShowImportResultsRaw(message + " " + aStatusReport, null, true); + document.getElementById("back").removeAttribute("disabled"); + + let subscriptionsWindow = Services.wm.getMostRecentWindow("Mail:News-BlogSubscriptions"); + if (subscriptionsWindow) + { + let feedWin = subscriptionsWindow.FeedSubscriptions; + if (aLastFolder) + feedWin.FolderListener.folderAdded(aLastFolder); + feedWin.mActionMode = null; + feedWin.updateButtons(feedWin.mView.currentItem); + feedWin.clearStatusInfo(); + feedWin.updateStatusItem("statusText", aStatusReport); + } + } + + if (!FeedSubscriptions.importOPMLFile(openFile, server, callback)) + return false; + + let subscriptionsWindow = Services.wm.getMostRecentWindow("Mail:News-BlogSubscriptions"); + if (subscriptionsWindow) + { + let feedWin = subscriptionsWindow.FeedSubscriptions; + feedWin.mActionMode = feedWin.kImportingOPML; + feedWin.updateButtons(null); + let statusReport = gFeedsBundle.getString("subscribe-loading"); + feedWin.updateStatusItem("statusText", statusReport); + feedWin.updateStatusItem("progressMeter", "?"); + } + + return true; +} + +function SwitchType(newType) +{ + if (gImportType == newType) + return; + + gImportType = newType; + gProgressInfo.importType = newType; + + SetUpImportType(); + + SetDivText('description', ""); +} + + +function next() +{ + var deck = document.getElementById("stateDeck"); + switch (deck.selectedIndex) { + case "0": + let backButton = document.getElementById("back"); + backButton.removeAttribute("disabled"); + let radioGroup = document.getElementById("importFields"); + + if (radioGroup.value == "all") + { + let args = { closeMigration: true }; + let SEAMONKEY_ID = "{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}"; + if (Services.appinfo.ID == SEAMONKEY_ID) { + window.openDialog("chrome://communicator/content/migration/migration.xul", + "", "chrome,dialog,modal,centerscreen"); + } else { + // Running as Thunderbird or its clone. + window.openDialog("chrome://messenger/content/migration/migration.xul", + "", "chrome,dialog,modal,centerscreen", null, null, null, args); + } + if (args.closeMigration) + close(); + } + else + { + SwitchType(radioGroup.value); + deck.selectedIndex = 1; + document.getElementById("modulesFound").selectedIndex = + (document.getElementById("moduleList").itemCount > 0) ? 0 : 1; + SelectFirstItem(); + enableAdvance(); + } + break; + case "1": + ImportDialogOKButton(); + break; + case "3": + close(); + break; + } +} + +function SelectFirstItem() +{ + var listbox = document.getElementById("moduleList"); + if ((listbox.selectedIndex == -1) && (listbox.itemCount > 0)) + listbox.selectedIndex = 0; + ImportSelectionChanged(); +} + +function enableAdvance() +{ + var listbox = document.getElementById("moduleList"); + var nextButton = document.getElementById("forward"); + if (listbox.selectedCount > 0) + nextButton.removeAttribute("disabled"); + else + nextButton.setAttribute("disabled", "true"); +} + +function back() +{ + var deck = document.getElementById("stateDeck"); + var backButton = document.getElementById("back"); + var nextButton = document.getElementById("forward"); + switch (deck.selectedIndex) { + case "1": + backButton.setAttribute("disabled", "true"); + nextButton.label = nextButton.getAttribute("nextval"); + nextButton.removeAttribute("disabled"); + deck.selectedIndex = 0; + break; + case "3": + // Clear out the results box. + let results = document.getElementById("results"); + while (results.hasChildNodes()) + results.lastChild.remove(); + + // Reset the next button. + nextButton.label = nextButton.getAttribute("nextval"); + nextButton.removeAttribute("disabled"); + + // Enable the cancel button again. + document.getElementById("cancel").removeAttribute("disabled"); + + // If a new Feed account has been created, rebuild the list. + if (gNewFeedAcctCreated) + ListFeedAccounts(); + + // Now go back to the second page. + deck.selectedIndex = 1; + break; + } +} diff --git a/mailnews/import/content/importDialog.xul b/mailnews/import/content/importDialog.xul new file mode 100644 index 000000000..383585f83 --- /dev/null +++ b/mailnews/import/content/importDialog.xul @@ -0,0 +1,143 @@ +<?xml version="1.0"?> +<!-- 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/. --> + +<?xml-stylesheet href="chrome://messenger/skin/dialogs.css" type="text/css"?> + +<!DOCTYPE window [ +<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" > +%brandDTD; +<!ENTITY % importDTD SYSTEM "chrome://messenger/locale/importDialog.dtd" > +%importDTD; +]> + +<window xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + onload="OnLoadImportDialog()" +#ifdef XP_MACOSX + style="width: &window.macWidth; !important;" +#else + style="width: &window.width; !important;" +#endif + title="&importDialog.windowTitle;"> + + <stringbundle id="bundle_importMsgs" src="chrome://messenger/locale/importMsgs.properties"/> + <stringbundle id="bundle_addressbook" src="chrome://messenger/locale/addressbook/addressBook.properties"/> + <stringbundle id="bundle_vcardImportMsgs" src="chrome://messenger/locale/vCardImportMsgs.properties"/> + <stringbundle id="bundle_feeds" src="chrome://messenger-newsblog/locale/newsblog.properties"/> + <script type="application/javascript" src="chrome://messenger/content/importDialog.js"/> + <script type="application/javascript" src="chrome://messenger-newsblog/content/feed-subscriptions.js"/> + + <keyset id="dialogKeys"/> + + <hbox class="box-header" id="header" + title="&importTitle.label;" + description="&importShortDesc.label;"/> + + <deck id="stateDeck" selectedIndex="0" style="min-height: 30em"> + <vbox class="wizard-box"> + <description>&importDescription1.label;</description> + <description>&importDescription2.label;</description> + <separator/> + <radiogroup id="importFields"> + <radio id="allRadio" + value="all" + label="&importAll.label;" + accesskey="&importAll.accesskey;"/> + <separator/> + <label control="importFields">&select.label;</label> + <separator class="thin"/> + <vbox class="indent"> + <radio id="addressbookRadio" + value="addressbook" + label="&importAddressbook.label;" + accesskey="&importAddressbook.accesskey;"/> + <radio id="mailRadio" + value="mail" + label="&importMail.label;" + accesskey="&importMail.accesskey;"/> + <radio id="feedsRadio" + value="feeds" + label="&importFeeds.label;" + accesskey="&importFeeds.accesskey;"/> + <radio id="settingsRadio" + value="settings" + label="&importSettings.label;" + accesskey="&importSettings.accesskey;"/> + <radio id="filtersRadio" + value="filters" + label="&importFilters.label;" + accesskey="&importFilters.accesskey;"/> + </vbox> + </radiogroup> + </vbox> + <vbox class="wizard-box"> + <deck id="modulesFound" + selectedIndex="0"> + <vbox> + <deck id="selectDescriptionDeck" + selectedIndex="0"> + <label control="moduleList" + value="&selectDescription.label;" + accesskey="&selectDescription.accesskey;"/> + <label control="moduleList" + value="&selectDescriptionB.label;" + accesskey="&selectDescription.accesskey;"/> + </deck> + <listbox id="moduleList" flex="3" + onselect="ImportSelectionChanged(); enableAdvance();"/> + </vbox> + <label>&noModulesFound.label;</label> + </deck> + <grid flex="1"> + <columns><column flex="1"/></columns> + <rows> + <row> + <description control="moduleList" id="description" class="box-padded"/> + </row> + <row> + <hbox id="acctName-box" flex="1" style="visibility: hidden;"> + <label control="acctName" class="box-padded" + accesskey="&acctName.accesskey;" + value="&acctName.label;"/> + <textbox id="acctName" clickSelectsAll="true"/> + </hbox> + </row> + </rows> + </grid> + </vbox> + <vbox class="wizard-box"> + <spacer flex="1"/> + <groupbox> + <caption id="progressTitle" label="&title.label;"/> + <label class="indent" id="progressStatus" value="&processing.label;"/> + <vbox class="box-padded"> + <progressmeter id="progressMeter" mode="determined" value="5"/> + </vbox> + </groupbox> + </vbox> + <vbox class="wizard-box"> + <description id="status"/> + <hbox style="overflow: auto" class="inset" flex="1"> + <description id="results" flex="1"/> + </hbox> + </vbox> + </deck> + + <separator/> + + <separator class="groove"/> + + <hbox class="box-padded"> + <spacer flex="1"/> + <button id="back" label="&back.label;" disabled="true" + oncommand="back();"/> + <button id="forward" label="&forward.label;" nextval="&forward.label;" finishedval="&finish.label;" + oncommand="next();"/> + <separator orient="vertical"/> + <button id="cancel" label="&cancel.label;" + oncommand="close();"/> + </hbox> + +</window> |