bug 349586 - Add migrator. Patch by jminta with contributions by lilmatt and ctalbert. r=ctalbert,lilmatt,jminta ui-r=mvl

This commit is contained in:
mattwillis%gmail.com 2006-11-14 01:56:57 +00:00
Родитель fccd194c6e
Коммит eb8377421f
12 изменённых файлов: 1051 добавлений и 9 удалений

Просмотреть файл

@ -49,8 +49,6 @@ const MODE_TRUNCATE = 0x20;
const MODE_SYNC = 0x40;
const MODE_EXCL = 0x80;
var gItems = new Array();
/**
* loadEventsFromFile
* shows a file dialog, reads the selected file(s) and tries to parse events from it.
@ -104,7 +102,7 @@ function loadEventsFromFile(aCalendar)
{
inputStream.init( fp.file, MODE_RDONLY, 0444, {} );
gItems = importer.importFromStream(inputStream, {});
var items = importer.importFromStream(inputStream, {});
inputStream.close();
}
catch(ex)
@ -113,7 +111,7 @@ function loadEventsFromFile(aCalendar)
}
if (aCalendar) {
putItemsIntoCal(aCalendar);
putItemsIntoCal(aCalendar, items);
return;
}
@ -123,11 +121,11 @@ function loadEventsFromFile(aCalendar)
if (count.value == 1) {
// There's only one calendar, so it's silly to ask what calendar
// the user wants to import into.
putItemsIntoCal(calendars[0]);
putItemsIntoCal(calendars[0], items);
} else {
// Ask what calendar to import into
var args = new Object();
args.onOk = putItemsIntoCal;
args.onOk = function putItems(aCal) { putItemsIntoCal(aCal, items); };
args.promptText = getCalStringBundle().GetStringFromName("importPrompt");
openDialog("chrome://calendar/content/chooseCalendarDialog.xul",
"_blank", "chrome,titlebar,modal,resizable", args);
@ -135,7 +133,7 @@ function loadEventsFromFile(aCalendar)
}
}
function putItemsIntoCal(destCal) {
function putItemsIntoCal(destCal, aItems) {
// Set batch for the undo/redo transaction manager
startBatchTransaction();
@ -162,7 +160,7 @@ function putItemsIntoCal(destCal) {
lastError = aStatus;
}
// See if it is time to end the calendar's batch.
if (count == gItems.length) {
if (count == aItems.length) {
destCal.endBatch();
if (failedCount)
showError(failedCount+" items failed to import. The last error was: "+lastError.toString());
@ -170,7 +168,7 @@ function putItemsIntoCal(destCal) {
}
}
for each (item in gItems) {
for each (item in aItems) {
// XXX prompt when finding a duplicate.
try {
destCal.addItem(item, listener);

Просмотреть файл

@ -0,0 +1,779 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Calendar migration code
*
* The Initial Developer of the Original Code is
* Joey Minta <jminta@gmail.com>
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Matthew Willis <mattwillis@gmail.com>
* Clint Talbert <cmtalbert@myfastmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
const Cc = Components.classes;
const Ci = Components.interfaces;
const SUNBIRD_UID = "{718e30fb-e89b-41dd-9da7-e25a45638b28}";
const FIREFOX_UID = "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}";
//
// The front-end wizard bits.
//
var gMigrateWizard = {
/**
* Called from onload of the migrator window. Takes all of the migrators
* that were passed in via window.arguments and adds them to checklist. The
* user can then check these off to migrate the data from those sources.
*/
loadMigrators: function gmw_load() {
var listbox = document.getElementById("datasource-list");
//XXX Once we have branding for lightning, this hack can go away
var sbs = Cc["@mozilla.org/intl/stringbundle;1"]
.getService(Ci.nsIStringBundleService);
var props = sbs.createBundle("chrome://calendar/locale/migration.properties");
if (gDataMigrator.isLightning()) {
var wizard = document.getElementById("migration-wizard");
var desc = document.getElementById("wizard-desc");
// Since we don't translate "Lightning"...
wizard.title = props.formatStringFromName("migrationTitle",
["Lightning"],
1);
desc.textContent = props.formatStringFromName("migrationDescription",
["Lightning"],
1);
}
LOG("migrators: " + window.arguments.length);
for each (var migrator in window.arguments[0]) {
var listItem = document.createElement("listitem");
var checkCell = document.createElement("listcell");
checkCell.setAttribute("type", "checkbox");
checkCell.setAttribute("checked", true);
listItem.appendChild(checkCell);
var nameCell = document.createElement("listcell");
nameCell.setAttribute("label", migrator.title);
listItem.appendChild(nameCell);
listItem.migrator = migrator;
listbox.appendChild(listItem);
}
},
/**
* Called from the second page of the wizard. Finds all of the migrators
* that were checked and begins migrating their data. Also controls the
* progress dialog so the user can see what is happening. (somewhat)
*/
migrateChecked: function gmw_migrate() {
var migrators = [];
// Get all the checked migrators into an array
var listbox = document.getElementById("datasource-list");
for (var i = listbox.childNodes.length-1; i >= 0; i--) {
LOG("Checking child node: " + listbox.childNodes[i].firstChild);
if (listbox.childNodes[i].firstChild.getAttribute("checked")) {
LOG("Adding migrator");
migrators.push(listbox.childNodes[i].migrator);
}
}
// If no migrators were checked, then we're done
if (migrators.length == 0) {
window.close();
}
// Don't let the user get away while we're migrating
//XXX may want to wire this into the 'cancel' function once that's
// written
var wizard = document.getElementById("migration-wizard");
wizard.canAdvance = false;
wizard.canRewind = false;
// We're going to need this for the progress meter's description
var sbs = Cc["@mozilla.org/intl/stringbundle;1"]
.getService(Ci.nsIStringBundleService);
var props = sbs.createBundle("chrome://calendar/locale/migration.properties");
var label = document.getElementById("progress-label");
var meter = document.getElementById("migrate-progressmeter");
var i = 0;
var nextMig = 0;
// Because some of our migrators involve async code, we need this
// call-back function so we know when to start the next migrator.
function getNextMigrator() {
if (migrators[i]) {
var mig = migrators[i];
// Increment i to point to the next migrator
i++;
LOG("starting migrator: " + mig.title);
label.value = props.formatStringFromName("migratingApp",
[mig.title],
1);
meter.value = (i-1)/migrators.length*100;
mig.args.push(getNextMigrator);
try {
mig.migrate.apply(mig, mig.args);
} catch (e) {
LOG("Failed to migrate: " + mig.title);
LOG(e);
getNextMigrator();
}
} else {
LOG("migration done");
wizard.canAdvance = true;
label.value = props.GetStringFromName("finished");
meter.value = 100;
gMigrateWizard.setCanRewindFalse();
}
}
// And get the first migrator
getNextMigrator();
},
setCanRewindFalse: function gmw_finish() {
document.getElementById('migration-wizard').canRewind = false;
}
};
//
// The more back-end data detection bits
//
function dataMigrator(aTitle, aMigrateFunction, aArguments) {
this.title = aTitle;
this.migrate = aMigrateFunction;
this.args = aArguments;
}
var gDataMigrator = {
mIsLightning: null,
mIsInFirefox: false,
mPlatform: null,
mDirService: null,
mIoService: null,
/**
* Properly caches the service so that it doesn't load on startup
*/
get dirService() {
if (!this.mDirService) {
this.mDirService = Cc["@mozilla.org/file/directory_service;1"]
.getService(Ci.nsIProperties);
}
return this.mDirService;
},
get ioService() {
if (!this.mIoService) {
this.mIoService = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService);
}
return this.mIoService;
},
/**
* Gets the value for mIsLightning, and sets it if this.mIsLightning is
* not initialized. This is used by objects outside gDataMigrator to
* access the mIsLightning member.
*/
isLightning: function is_ltn() {
if (this.mIsLightning == null) {
var appInfo = Cc["@mozilla.org/xre/app-info;1"]
.getService(Ci.nsIXULAppInfo);
this.mIsLightning = !(appInfo.ID == SUNBIRD_UID);
return this.mIsLightning;
}
// else mIsLightning is initialized, return the value
return this.mIsLightning;
},
/**
* Call to do a general data migration (for a clean profile) Will run
* through all of the known migrator-checkers. These checkers will return
* an array of valid dataMigrator objects, for each kind of data they find.
* If there is at least one valid migrator, we'll pop open the migration
* wizard, otherwise, we'll return silently.
*/
checkAndMigrate: function gdm_migrate() {
var appInfo = Cc["@mozilla.org/xre/app-info;1"]
.getService(Ci.nsIXULAppInfo);
this.mIsLightning = !(appInfo.ID == SUNBIRD_UID)
LOG("mIsLightning is: " + this.mIsLightning);
if (appInfo.ID == FIREFOX_UID) {
this.mIsInFirefox = true;
// We can't handle Firefox Lightning yet
LOG("Holy cow, you're Firefox-Lightning! sorry, can't help.");
return;
}
var xulRuntime = Cc["@mozilla.org/xre/app-info;1"]
.getService(Ci.nsIXULRuntime);
this.mPlatform = xulRuntime.OS.toLowerCase();
LOG("mPlatform is: " + this.mPlatform);
var DMs = [];
var migrators = [this.checkOldCal, this.checkEvolution,
this.checkIcal];
// XXX also define a category and an interface here for pluggability
for each (var migrator in migrators) {
var migs = migrator.call(this);
for each (var dm in migs) {
DMs.push(dm);
}
}
if (DMs.length == 0) {
// No migration available
return;
}
LOG("DMs: " + DMs.length);
var url = "chrome://calendar/content/migration.xul";
#ifdef XP_MACOSX
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator);
var win = wm.getMostRecentWindow("Calendar:MigrationWizard");
if (win) {
win.focus();
} else {
openDialog(url, "migration", "centerscreen,chrome,resizable=no", DMs);
}
#else
openDialog(url, "migration", "modal,centerscreen,chrome,resizable=no", DMs);
#endif
},
/**
* Checks to see if we can find any traces of an older moz-cal program.
* This could be either the old calendar-extension, or Sunbird 0.2. If so,
* it offers to move that data into our new storage format. Also, if we're
* if we're Lightning, it will disable the old calendar extension, since it
* conflicts with us.
*/
checkOldCal: function gdm_calold() {
LOG("Checking for the old calendar extension/app");
// First things first. If we are Lightning and the calendar extension
// is installed, we have to nuke it. The old extension defines some of
// the same paths as we do, and the resulting file conflicts result in
// first-class badness. getCompositeCalendar is a conflicting function
// that exists in Lighnting's version of calendarUtils.js. If it isn't
// defined, we have a conflict.
if (this.isLightning() && !("getCompositeCalendar" in window)) {
// We can't use our normal helper-functions, because those might
// conflict too.
var sbs = Cc["@mozilla.org/intl/stringbundle;1"]
.getService(Ci.nsIStringBundleService);
var props = sbs.createBundle("chrome://calendar/locale/migration.properties");
var brand = sbs.createBundle("chrome://branding/locale/brand.properties");
var appName = brand.GetStringFromName("brandShortName");
// Tell the user we're going to disable and restart
var promptService = Cc["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Ci.nsIPromptService);
promptService.alert(window,
props.GetStringFromName("disableExtTitle"),
props.formatStringFromName("disableExtText",
[brand],1));
// Kiiillllll...
var em = Cc["@mozilla.org/extensions/manager;1"]
.getService(Ci.nsIExtensionManager);
em.disableItem("{8e117890-a33f-424b-a2ea-deb272731365}");
promptService.alert(window, getString("disableDoneTitle"),
getString("disableExtDone"));
var startup = Cc["@mozilla.org/toolkit/app-startup;1"]
.getService(Ci.nsIAppStartup);
startup.quit(Ci.nsIAppStartup.eRestart |
Ci.nsIAppStartup.eAttemptQuit);
}
// This is the function that the migration wizard will call to actually
// migrate the data. It's defined here because we may use it multiple
// times (with different aProfileDirs), for instance if there is both
// a Thunderbird and Firefox cal-extension
function extMigrator(aProfileDir, aCallback) {
// Get the old datasource
var dataSource = aProfileDir.clone();
dataSource.append("CalendarManager.rdf");
if (!dataSource.exists()) {
return;
}
// Let this be a lesson to anyone designing APIs. The RDF API is so
// impossibly confusing that it's actually simpler/cleaner/shorter
// to simply parse as XML and use the better DOM APIs.
var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
.createInstance(Ci.nsIXMLHttpRequest);
req.open('GET', "file://" + dataSource.path, true);
req.onreadystatechange = function calext_onreadychange() {
if (req.readyState == 4) {
LOG(req.responseText);
parseAndMigrate(req.responseXML, aCallback)
}
};
req.send(null);
}
// Callback from the XHR above. Parses CalendarManager.rdf and imports
// the data describe therein.
function parseAndMigrate(aDoc, aCallback) {
// For duplicate detection
var calManager = getCalendarManager();
var uris = [];
for each (var oldCal in calManager.getCalendars({})) {
uris.push(oldCal.uri);
}
function getRDFAttr(aNode, aAttr) {
return aNode.getAttributeNS("http://home.netscape.com/NC-rdf#",
aAttr);
}
const RDFNS = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
var nodes = aDoc.getElementsByTagNameNS(RDFNS, "Description");
LOG("nodes: " + nodes.length);
for (var i = 0; i < nodes.length; i++) {
LOG("Beginning cal node");
var cal;
var node = nodes[i];
if (getRDFAttr(node, "remote") == "false") {
LOG("not remote");
var localFile = Cc["@mozilla.org/file/local;1"]
.createInstance(Ci.nsILocalFile);
localFile.initWithPath(getRDFAttr(node, "path"));
cal = gDataMigrator.importICSToStorage(localFile);
} else {
// Remote subscription
// XXX check for duplicates
var url = makeURL(getRDFAttr(node, "remotePath"));
cal = calManager.createCalendar("ics", url);
}
cal.name = getRDFAttr(node, "name");
calManager.setCalendarPref(cal, "color",
getRDFAttr(node, "color"));
}
aCallback();
}
var migrators = [];
// Look in our current profile directory, in case we're upgrading in
// place
var profileDir = this.dirService.get("ProfD", Ci.nsILocalFile);
profileDir.append("Calendar");
if (profileDir.exists()) {
LOG("Found old extension directory in current app");
var title;
if (this.mIsLightning) {
title = "Mozilla Calendar Extension";
} else {
title = "Sunbird 0.2";
}
migrators.push(new dataMigrator(title, extMigrator, [profileDir]));
}
// Check the profiles of the various other moz-apps for calendar data
var profiles = [];
// Do they use Firefox?
var ffPro, sbProf, tbProf;
if ((ffProf = this.getFirefoxProfile())) {
profiles.push(ffProf);
}
if (this.mIsLightning) {
// If we're lightning, check Sunbird
if ((sbProf = this.getSunbirdProfile())) {
profiles.push(sbProf);
}
} else {
// Otherwise, check Thunderbird
if ((tbProf = this.getThunderbirdProfile())) {
profiles.push(tbProf);
}
}
// Now check all of the profiles in each of these folders for data
for each (var prof in profiles) {
var dirEnum = prof.directoryEntries;
while (dirEnum.hasMoreElements()) {
var profile = dirEnum.getNext().QueryInterface(Ci.nsIFile);
if (profile.isFile()) {
continue;
} else {
profile.append("Calendar");
if (profile.exists()) {
LOG("Found old extension directory at" + profile.path);
var title = "Mozilla Calendar";
migrators.push(new dataMigrator(title, extMigrator, [profile]));
}
}
}
}
return migrators;
},
/**
* Checks to see if Apple's iCal is installed and offers to migrate any data
* the user has created in it.
*/
checkIcal: function gdm_ical() {
LOG("Checking for ical data");
function icalMigrate(aDataDir, aCallback) {
aDataDir.append("Sources");
var dirs = aDataDir.directoryEntries;
var calManager = getCalendarManager();
var i = 1;
while(dirs.hasMoreElements()) {
var dataDir = dirs.getNext().QueryInterface(Ci.nsIFile);
var dataStore = dataDir.clone();
dataStore.append("corestorage.ics");
if (!dataStore.exists()) {
continue;
}
var chars = [];
var fileStream = Cc["@mozilla.org/network/file-input-stream;1"]
.createInstance(Ci.nsIFileInputStream);
fileStream.init(dataStore, 0x01, 0444, {});
var convStream = Cc["@mozilla.org/intl/converter-input-stream;1"]
.getService(Ci.nsIConverterInputStream);
convStream.init(fileStream, 'UTF-8', 0, 0x0000);
var tmpStr = {};
var str = "";
while (convStream.readString(-1, tmpStr)) {
str += tmpStr.value;
}
// Strip out the timezone definitions, since it makes the file
// invalid otherwise
var index = str.indexOf(";TZID=");
while (index != -1) {
var endIndex = str.indexOf(':', index);
var otherEnd = str.indexOf(';', index+2);
if (otherEnd < endIndex) {
endIndex = otherEnd;
}
var sub = str.substring(index, endIndex);
str = str.replace(sub, "", "g");
index = str.indexOf(";TZID=");
}
var tempFile = gDataMigrator.dirService.get("TmpD", Ci.nsIFile);
tempFile.append("icalTemp.ics");
tempFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0600);
var tempUri = gDataMigrator.ioService.newFileURI(tempFile);
var stream = Cc["@mozilla.org/network/file-output-stream;1"]
.createInstance(Ci.nsIFileOutputStream);
stream.init(tempFile, 0x2A, 0600, 0);
var convStream = Cc["@mozilla.org/intl/converter-output-stream;1"]
.getService(Ci.nsIConverterOutputStream);
convStream.init(stream, 'UTF-8', 0, 0x0000);
convStream.writeString(str);
var cal = gDataMigrator.importICSToStorage(tempFile);
cal.name = "iCalendar"+i;
i++;
}
LOG("icalMig making callback");
aCallback();
}
var profileDir = this.dirService.get("ProfD", Ci.nsILocalFile);
var icalSpec = profileDir.path;
var icalFile;
if (!this.isLightning()) {
var diverge = icalSpec.indexOf("Sunbird");
if (diverge == -1) {
return [];
}
icalSpec = icalSpec.substr(0, diverge);
icalFile = Cc["@mozilla.org/file/local;1"]
.createInstance(Ci.nsILocalFile);
icalFile.initWithPath(icalSpec);
} else {
var diverge = icalSpec.indexOf("Thunderbird");
if (diverge == -1) {
return [];
}
icalSpec = icalSpec.substr(0, diverge);
icalFile = Cc["@mozilla.org/file/local;1"]
.createInstance(Ci.nsILocalFile);
icalFile.initWithPath(icalSpec);
icalFile.append("Application Support");
}
icalFile.append("iCal");
if (icalFile.exists()) {
return [new dataMigrator("Apple iCal", icalMigrate, [icalFile])];
}
return [];
},
/**
* Checks to see if Evolution is installed and offers to migrate any data
* stored there.
*/
checkEvolution: function gdm_evolution() {
LOG("Checking for evolution data");
function evoMigrate(aDataDir, aCallback) {
aDataDir.append("Sources");
var dirs = aDataDir.directoryEntries;
var calManager = getCalendarManager();
var i = 1;
while(dirs.hasMoreElements()) {
var dataDir = dirs.getNext().QueryInterface(Ci.nsIFile);
var dataStore = dataDir.clone();
dataStore.append("calendar.ics");
if (!dataStore.exists()) {
continue;
}
var cal = gDataMigrator.importICSToStorage(dataStore);
//XXX
cal.name = "Evolution"+i;
i++;
}
aCallback();
}
var profileDir = this.dirService.get("ProfD", Ci.nsILocalFile);
var evoSpec = profileDir.path;
var evoFile;
if (!this.mIsLightning) {
var diverge = evoSpec.indexOf(".mozilla");
if (diverge == -1) {
return [];
}
evoSpec = evoSpec.substr(0, diverge);
evoFile = Cc["@mozilla.org/file/local;1"]
.createInstance(Ci.nsILocalFile);
evoFile.initWithPath(evoSpec);
} else {
var diverge = evoSpec.indexOf(".thunderbird");
if (diverge == -1) {
return [];
}
evoSpec = evoSpec.substr(0, diverge);
evoFile = Cc["@mozilla.org/file/local;1"]
.createInstance(Ci.nsILocalFile);
evoFile.initWithPath(evoSpec);
}
evoFile.append(".evolution");
evoFile.append("calendar");
evoFile.append("local");
evoFile.append("system");
if (evoFile.exists()) {
return [new dataMigrator("Evolution", evoMigrate, [evoFile])];
}
return [];
},
importICSToStorage: function migrateIcsStorage(icsFile) {
var calManager = getCalendarManager();
var uris = [];
for each (var oldCal in calManager.getCalendars({})) {
uris.push(oldCal.uri.spec);
}
var uri = 'moz-profile-calendar://?id=';
var i = 1;
while (uris.indexOf(uri+i) != -1) {
i++;
}
var cal = calManager.createCalendar("storage", makeURL(uri+i));
var icsImporter = Cc["@mozilla.org/calendar/import;1?type=ics"]
.getService(Ci.calIImporter);
var inputStream = Cc["@mozilla.org/network/file-input-stream;1"]
.createInstance(Ci.nsIFileInputStream);
inputStream.init(icsFile, MODE_RDONLY, 0444, {} );
var items = icsImporter.importFromStream(inputStream, {});
// Defined in import-export.js
putItemsIntoCal(cal, items);
calManager.registerCalendar(cal);
return cal;
},
/**
* Helper functions for getting the profile directory of various MozApps
* (Getting the profile dir is way harder than it should be.)
*
* Sunbird:
* Unix: ~jdoe/.mozilla/sunbird/
* Windows: %APPDATA%\Mozilla\Sunbird\Profiles
* Mac OS X: ~jdoe/Library/Application Support/Sunbird/Profiles
*
* Firefox:
* Unix: ~jdoe/.mozilla/firefox/
* Windows: %APPDATA%\Mozilla\Firefox\Profiles
* Mac OS X: ~jdoe/Library/Application Support/Firefox/Profiles
*
* Thunderbird:
* Unix: ~jdoe/.thunderbird/
* Windows: %APPDATA%\Thunderbird\Profiles
* Mac OS X: ~jdoe/Library/Thunderbird/Profiles
*
* Notice that Firefox and Sunbird follow essentially the same pattern, so
* we group them with getNormalProfile
*/
getFirefoxProfile: function gdm_getFF() {
return this.getNormalProfile("Firefox");
},
getThunderbirdProfile: function gdm_getTB() {
var profileDir = this.dirService.get("ProfD", Ci.nsILocalFile);
var appSpec = this.ioService.newFileURI(profileDir).path;
var localFile = Cc["@mozilla.org/file/local;1"]
.createInstance(Ci.nsILocalFile);
var truncate;
if (this.mIsLightning) {
truncate = appSpec.indexOf("Profiles");
appSpec = appSpec.substr(0, truncate);
localFile.initWithPath(appSpec);
localFile.append("Profiles");
} else {
// Now it gets ugly
switch (this.mPlatform) {
case "darwin": // Mac OS X
truncate = appSpec.indexOf("Application");
appSpec = appSpec.substr(0, truncate);
localFile.initWithPath(appSpec);
localFile.append("Thunderbird");
localFile.append("Profiles");
break;
case "winnt":
truncate = appSpec.indexOf("Mozilla");
appSpec = appSpec.substr(0, truncate);
localFile.initWithPath(appSpec);
localFile.append("Thunderbird");
localFile.append("Profiles");
break;
default: // Unix
truncate = appSpec.indexOf(".mozilla");
appSpec = appSpec.substr(0, truncate);
localFile.append(".thunderbird");
}
}
return localFile;
},
getSunbirdProfile: function gdm_getSB() {
return this.getNormalProfile("Sunbird");
},
getNormalProfile: function gdm_getNorm(aAppName) {
var profileDir = this.dirService.get("ProfD", Ci.nsILocalFile);
var appSpec = this.ioService.newFileURI(profileDir).path;
var localFile = Cc["@mozilla.org/file/local;1"]
.createInstance(Ci.nsILocalFile);
// This variable marks the path-index where the current profile diverges
// from the aAppName profile. We'll cut off the path here and then
// append the known path to the aAppName profile.
var truncate;
if (this.isLightning()) { // We're in Thunderbird
switch (this.mPlatform) {
case "darwin": // Mac OS X
truncate = appSpec.indexOf("Thunderbird");
appSpec = appSpec.substr(0, truncate);
localFile.initWithPath(appSpec);
localFile.append("Application Support");
localFile.append(aAppName);
localFile.append("Profiles");
break;
case "winnt":
truncate = appSpec.indexOf("Thunderbird");
appSpec = appSpec.substr(0, truncate);
localFile.initWithPath(appSpec);
localFile.append("Mozilla");
localFile.append(aAppName);
localFile.append("Profiles");
break;
default: // Unix
truncate = appSpec.indexOf(".thunderbird");
appSpec = appSpec.substr(0, truncate);
localFile.initWithPath(appSpec);
localFile.append(".mozilla");
localFile.append(aAppName.toLowerCase());
break;
}
} else {
switch (this.mPlatform) {
// On Mac and Windows, we can just remove the "Sunbird" and
// replace it with "Firefox" to get to Firefox
case "darwin": // Mac OS X
case "winnt":
idx = appSpec.indexOf("Sunbird");
appSpec = appSpec.substr(0, idx);
localFile.initWithPath(appSpec);
localFile.append(aAppName);
localFile.append("Profiles");
break;
default: // Unix
idx = appSpec.indexOf("sunbird");
appSpec = appSpec.substr(0, idx);
localFile.initWithPath(ffSpec);
localFile.append(aAppName.toLowerCase());
break;
}
}
if (localFile.exists()) {
return localFile;
}
return null;
}
};
function LOG(aString) {
if (!getPrefSafe("calendar.migration.log", false)) {
return;
}
var consoleService = Cc["@mozilla.org/consoleservice;1"]
.getService(Ci.nsIConsoleService);
consoleService.logStringMessage(aString);
dump(aString+"\n");
}

Просмотреть файл

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- ***** BEGIN LICENSE BLOCK *****
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
- http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the
- License.
-
- The Original Code is Calendar migration code.
-
- The Initial Developer of the Original Code is
- Joey Minta <jminta@gmail.com>
- Portions created by the Initial Developer are Copyright (C) 2006
- the Initial Developer. All Rights Reserved.
-
- Contributor(s):
-
- Alternatively, the contents of this file may be used under the terms of
- either the GNU General Public License Version 2 or later (the "GPL"), or
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- in which case the provisions of the GPL or the LGPL are applicable instead
- of those above. If you wish to allow use of your version of this file only
- under the terms of either the GPL or the LGPL, and not to allow others to
- use your version of this file under the terms of the MPL, indicate your
- decision by deleting the provisions above and replace them with the notice
- and other provisions required by the LGPL or the GPL. If you do not delete
- the provisions above, a recipient may use your version of this file under
- the terms of any one of the MPL, the GPL or the LGPL.
-
- ***** END LICENSE BLOCK ***** -->
<!-- Style sheets -->
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<!DOCTYPE dialog
[
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
%brandDTD;
<!ENTITY % migrationDtd SYSTEM "chrome://calendar/locale/migration.dtd">
%migrationDtd;
]>
<wizard id="migration-wizard"
title="&migration.title;"
windowtype="Calendar:MigrationWizard"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="gMigrateWizard.loadMigrators()"
branded="true"
persist="screenX screenY">
<script type="application/x-javascript" src="chrome://calendar/content/migration.js"/>
<script type="application/x-javascript" src="chrome://calendar/content/import-export.js"/>
<script type="application/x-javascript" src="chrome://calendar/content/calendarUtils.js"/>
<wizardpage id="wizardPage1"
pageid="initialPage"
next="progressPage"
label="&migration.welcome;"
description="&migration.list.description;">
<description id="wizard-desc">&migration.list.description;</description>
<listbox id="datasource-list" flex="1">
<listcols>
<listcol/>
<listcol flex="1"/>
</listcols>
</listbox>
</wizardpage>
<wizardpage id="wizardPage2"
pageid="progressPage"
label="&migration.importing;"
onpageshow="gMigrateWizard.migrateChecked()"
description="&migration.progress.description;">
<description>&migration.progress.description;</description>
<vbox flex="1">
<progressmeter id="migrate-progressmeter" mode="determined"
value="0" flex="1"/>
<label value="" flex="1" id="progress-label"/>
</vbox>
</wizardpage>
</wizard>

Просмотреть файл

@ -29,6 +29,8 @@ calendar.jar:
content/calendar/calErrorPrompt.xul (content/calErrorPrompt.xul)
content/calendar/chooseCalendarDialog.xul (content/chooseCalendarDialog.xul)
content/calendar/import-export.js (content/import-export.js)
* content/calendar/migration.js (content/migration.js)
content/calendar/migration.xul (content/migration.xul)
content/calendar/preferences/editCategory.xul (content/preferences/editCategory.xul)
% skin calendar classic/1.0 %skin/classic/calendar/
#expand skin/classic/calendar/cal-icon32.png (themes/__THEME__/cal-icon32.png)

Просмотреть файл

@ -1,5 +1,6 @@
content lightning jar:chrome/lightning.jar!/content/lightning/
locale lightning en-US jar:chrome/lightning-en-US.jar!/locale/en-US/lightning/
overlay chrome://messenger/content/messenger.xul chrome://lightning/content/lightning-migration.xul
overlay chrome://messenger/content/messenger.xul chrome://lightning/content/messenger-overlay-sidebar.xul
overlay chrome://messenger/content/preferences/preferences.xul chrome://lightning/content/messenger-overlay-preferences.xul
overlay chrome://messenger/content/messenger.xul chrome://lightning/content/messenger-overlay-toolbar.xul

Просмотреть файл

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- ***** BEGIN LICENSE BLOCK *****
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
- http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the
- License.
-
- The Original Code is Calendar migration code
-
- The Initial Developer of the Original Code is
- Joey Minta <jminta@gmail.com>
- Portions created by the Initial Developer are Copyright (C) 2006
- the Initial Developer. All Rights Reserved.
-
- Contributor(s):
-
- Alternatively, the contents of this file may be used under the terms of
- either the GNU General Public License Version 2 or later (the "GPL"), or
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- in which case the provisions of the GPL or the LGPL are applicable instead
- of those above. If you wish to allow use of your version of this file only
- under the terms of either the GPL or the LGPL, and not to allow others to
- use your version of this file under the terms of the MPL, indicate your
- decision by deleting the provisions above and replace them with the notice
- and other provisions required by the LGPL or the GPL. If you do not delete
- the provisions above, a recipient may use your version of this file under
- the terms of any one of the MPL, the GPL or the LGPL.
-
- ***** END LICENSE BLOCK ***** -->
<!-- The old calendar extension, if it is installed in the same profile as
- Lightning, will break Lightning because it ships several files that
- have the same chrome address as files that Lightning ships. This file
- exists so we can check for whether that extension is installed and nuke it
- in that case. Note that this check *cannot* be done in any file that may
- die as a result of the conflict (including messanger-overlay-sidebar.js).
- Nor can it depend on files which may conflict, like calendarUtils.js.
-->
<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
<?xul-overlay href="chrome://global/content/dialogOverlay.xul"?>
<!-- DTD File with all strings specific to the file -->
<!DOCTYPE overlay
[
]>
<overlay id="ltnMigrationOverlay"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/x-javascript" src="chrome://calendar/content/migration.js"/>
<script type="application/x-javascript"><![CDATA[
function checkOld() {
document.removeEventListener("load", checkOld, true);
var calMgr = Components.classes["@mozilla.org/calendar/manager;1"]
.getService(Components.interfaces.calICalendarManager);
var cals = calMgr.getCalendars({});
if (!cals.length) {
// There are no calendars, so we are running for the first time
gDataMigrator.checkAndMigrate();
}
}
document.addEventListener("load", checkOld, true);
]]></script>
<deck id="displayDeck"/>
</overlay>

Просмотреть файл

@ -9,6 +9,7 @@ lightning.jar:
content/lightning/agenda-tree.js (content/agenda-tree.js)
content/lightning/lightning-standalone.xul (content/lightning-standalone.xul)
content/lightning/messenger-overlay-preferences.xul (content/messenger-overlay-preferences.xul)
content/lightning/lightning-migration.xul (content/lightning-migration.xul)
content/lightning/lightning-preferences.xul (content/lightning-preferences.xul)
content/lightning/lightning-preferences.js (content/lightning-preferences.js)
content/lightning/messenger-overlay-toolbar.xul (content/messenger-overlay-toolbar.xul)
@ -131,6 +132,8 @@ calendar-en-US.jar:
locale/en-US/calendar/wcap.properties (/calendar/locales/en-US/chrome/calendar/wcap.properties)
locale/en-US/calendar/dateFormat.properties (/calendar/locales/en-US/chrome/calendar/dateFormat.properties)
locale/en-US/calendar/menuOverlay.dtd (/calendar/locales/en-US/chrome/calendar/menuOverlay.dtd)
locale/en-US/calendar/migration.dtd (/calendar/locales/en-US/chrome/calendar/migration.dtd)
locale/en-US/calendar/migration.properties (/calendar/locales/en-US/chrome/calendar/migration.properties)
locale/en-US/calendar/preferences/alarms.dtd (/calendar/locales/en-US/chrome/calendar/preferences/alarms.dtd)
locale/en-US/calendar/preferences/categories.dtd (/calendar/locales/en-US/chrome/calendar/preferences/categories.dtd)
locale/en-US/calendar/preferences/general.dtd (/calendar/locales/en-US/chrome/calendar/preferences/general.dtd)

Просмотреть файл

@ -0,0 +1,42 @@
<!-- ***** BEGIN LICENSE BLOCK *****
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
- http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the
- License.
-
- The Original Code is Calendar migration code.
-
- The Initial Developer of the Original Code is
- Joey Minta <jminta@gmail.com>
- Portions created by the Initial Developer are Copyright (C) 2006
- the Initial Developer. All Rights Reserved.
-
- Contributor(s):
-
- Alternatively, the contents of this file may be used under the terms of
- either the GNU General Public License Version 2 or later (the "GPL"), or
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- in which case the provisions of the GPL or the LGPL are applicable instead
- of those above. If you wish to allow use of your version of this file only
- under the terms of either the GPL or the LGPL, and not to allow others to
- use your version of this file under the terms of the MPL, indicate your
- decision by deleting the provisions above and replace them with the notice
- and other provisions required by the LGPL or the GPL. If you do not delete
- the provisions above, a recipient may use your version of this file under
- the terms of any one of the MPL, the GPL or the LGPL.
-
- ***** END LICENSE BLOCK ***** -->
<!ENTITY migration.title "&brandFullName;: Data Import">
<!ENTITY migration.welcome "Welcome">
<!ENTITY migration.importing "Importing">
<!ENTITY migration.list.description "&brandShortName; can import calendar data from many popular applications. Data from the following applications were found on your computer. Please select which of these you would like to import data from.">
<!ENTITY migration.progress.description "Importing selected data">
<!ENTITY migration.finished.description "Data import complete">

Просмотреть файл

@ -0,0 +1,46 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is Calendar migration code.
#
# The Initial Developer of the Original Code is
# Joey Minta <jminta@gmail.com>
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Matthew Willis <lilmatt@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
migratingApp = Migrating %1$S…
# The next two lines are duplicated from migration.dtd until there is branding
# for lightning
migrationTitle = %1$S: Data Import
migrationDescription=%1$S can import calendar data from many popular applications. Data from the following applications were found on your computer. Please select which of these you would like to import data from.
finished = Complete
disableExtTitle = Incompatible Extension Found
disableExtText = You have the old Mozilla Calendar Extension installed which is not compatible with Lightning. It will be disabled and %1$S will restart.

Просмотреть файл

@ -25,6 +25,8 @@ calendar-@AB_CD@.jar:
locale/@AB_CD@/calendar/email.properties (%chrome/calendar/email.properties)
locale/@AB_CD@/calendar/global.dtd (%chrome/calendar/global.dtd)
locale/@AB_CD@/calendar/menuOverlay.dtd (%chrome/calendar/menuOverlay.dtd)
locale/@AB_CD@/calendar/migration.dtd (%chrome/calendar/migration.dtd)
locale/@AB_CD@/calendar/migration.properties (%chrome/calendar/migration.properties)
locale/@AB_CD@/calendar/overlay.dtd (%chrome/calendar/overlay.dtd)
locale/@AB_CD@/calendar/preferences/advanced.dtd (%chrome/calendar/preferences/advanced.dtd)
locale/@AB_CD@/calendar/preferences/alarms.dtd (%chrome/calendar/preferences/alarms.dtd)

Просмотреть файл

@ -275,6 +275,13 @@ function initCalendarManager()
homeCalendar.name = name;
composite.addCalendar(homeCalendar);
// Wrapping this in a try/catch block, as if any of the migration code
// fails, the app may not load.
try {
gDataMigrator.checkAndMigrate();
} catch (e) {
Components.utils.reportError("Migrator error: " + e);
}
}
calMgr.addObserver(calCalendarManagerObserver);
composite.addObserver(calCompositeCalendarObserver);

Просмотреть файл

@ -76,6 +76,7 @@
<script type="application/x-javascript" src="chrome://calendar/content/unifinder.js"/>
<script type="application/x-javascript" src="chrome://calendar/content/unifinderToDo.js"/>
<script type="application/x-javascript" src="chrome://calendar/content/calendar-views.js"/>
<script type="application/x-javascript" src="chrome://calendar/content/migration.js"/>
<!-- NEEDED FOR APPLICATION SUPPORT -->
<script type="application/x-javascript" src="chrome://calendar/content/applicationUtil.js"/>