Fix bug 591744 - All calendars and events lost after restart [Error: Timezone Service not initialized]. r=nomisvai
authorPhilipp Kewisch <mozilla@kewis.ch>
Thu, 03 Feb 2011 10:44:14 +0100
changeset 7066 3f15521039b127a06a8aad3128cb9886d06e54b6
parent 7065 81ced12283af37e831545bf684c0dd4255dc3c8e
child 7067 c51913c44f242036112df133b7d455172b2da9f0
push idunknown
push userunknown
push dateunknown
reviewersnomisvai
bugs591744
Fix bug 591744 - All calendars and events lost after restart [Error: Timezone Service not initialized]. r=nomisvai
calendar/base/src/calTimezoneService.js
calendar/lightning/locales/jar.mn
calendar/locales/jar.mn
calendar/timezones/install.rdf
calendar/timezones/jar.mn
--- a/calendar/base/src/calTimezoneService.js
+++ b/calendar/base/src/calTimezoneService.js
@@ -157,144 +157,127 @@ calTimezoneService.prototype = {
         let ret = Components.classes["@mozilla.org/storage/statement-wrapper;1"]
                             .createInstance(Components.interfaces.mozIStorageStatementWrapper);
         ret.initialize(statement);
         return ret;
     },
 
     // nsIStartupService
     startup: function startup(aCompleteListener) {
-        this.initialize(aCompleteListener);
+        this.ensureInitialized(aCompleteListener);
     },
 
     shutdown: function shutdown(aCompleteListener) {
         Services.prefs.removeObserver("calendar.timezone.local", this);
 
         try {
             this.mDb.close();
             this.mDb = null;
         } catch (e) {
             cal.ERROR("Error closing timezone database: " + e);
         }
 
         aCompleteListener.onResult(null, Components.results.NS_OK);
     },
 
-    ensureInitialized: function() {
+    ensureInitialized: function(aCompleteListener) {
         if (!this.mSelectByTzid) {
-            cal.ERROR("Calling Timezone Service before its initialized!\nStack: " + cal.STACK(10));
-            throw Components.results.NS_ERROR_NOT_INITIALIZED;
+            this.initialize(aCompleteListener);
         }
     },
 
     _initDB: function _initDB(sqlTzFile) {
         try {
-            sqlTzFile.append("timezones.sqlite");
             cal.LOG("[calTimezoneService] using " + sqlTzFile.path);
             let dbService = Components.classes["@mozilla.org/storage/service;1"]
                                       .getService(Components.interfaces.mozIStorageService);
             this.mDb = dbService.openDatabase(sqlTzFile);
-            this.mSelectByTzid = this.createStatement("SELECT * FROM tz_data WHERE tzid = :tzid LIMIT 1");
+            if (this.mDb) {
+                this.mSelectByTzid = this.createStatement("SELECT * FROM tz_data WHERE tzid = :tzid LIMIT 1");
 
-            let selectVersion = this.createStatement("SELECT version FROM tz_version LIMIT 1");
-            try {
-                if (selectVersion.step()) {
-                    this.mVersion = selectVersion.row.version;
+                let selectVersion = this.createStatement("SELECT version FROM tz_version LIMIT 1");
+                try {
+                    if (selectVersion.step()) {
+                        this.mVersion = selectVersion.row.version;
+                    }
+                } finally {
+                    selectVersion.reset();
                 }
-            } finally {
-                selectVersion.reset();
+                cal.LOG("[calTimezoneService] timezones version: " + this.mVersion);
+                return true;
             }
-            cal.LOG("[calTimezoneService] timezones version: " + this.mVersion);
-
         } catch (exc) {
-            let msg = cal.calGetString("calendar", "missingCalendarTimezonesError");
-            cal.ERROR(msg);
-            showError(msg);
+            cal.ERROR("Error setting up timezone database: "  + exc);
         }
+        return false;
     },
 
     initialize: function calTimezoneService_initialize(aCompleteListener) {
-        // This function contains a lot of async calls. Please make sure you
-        // return this function in each control path.
-        function done() {
-            aCompleteListener.onResult(null, Components.results.NS_OK);
-        }
+        // Helper function to convert an nsIURI to a nsIFile
+        function toFile(uriSpec) {
+            let uri = cal.makeURL(uriSpec);
 
-        // Helper function to convert an nsIURI to a nsIFile
-        function toFile(uri) {
             if (uri.schemeIs("file")) {
                 let handler = cal.getIOService().getProtocolHandler("file")
                                  .QueryInterface(Components.interfaces.nsIFileProtocolHandler);
                 return handler.getFileFromURLSpec(uri.spec);
+            } else if (uri.schemeIs("resource")) {
+                let handler = cal.getIOService().getProtocolHandler("resource")
+                                 .QueryInterface(Components.interfaces.nsIResProtocolHandler);
+                let newUriSpec;
+                try { 
+                    newUriSpec = handler.resolveURI(uri);
+                } catch (e) {
+                    // Possibly the resource location is not registered, return
+                    // null to indicate error
+                    return null;
+                }
+
+                // Otherwise let this function convert the new uri spec to a file
+                return toFile(newUriSpec);
             } else {
-                cal.ERROR("Unknown timezones.sqlite location: " + uri.spec);
+                cal.ERROR("Unknown timezones.sqlite location: " + uriSpec);
             }
             return null;
         }
 
         let self = this;
-        const kCalendarTimezonesXpiId = "calendar-timezones@mozilla.org";
-        AddonManager.getAddonByID(kCalendarTimezonesXpiId, function getTimezoneExt(aAddon) {
-            if (aAddon) {
-                // The addon was found, extract the timezone stuff
-                let sqlTzFile = toFile(aAddon.getResourceURI(''));
-                let bundleURL = "chrome://calendar-timezones/locale/timezones.properties";
-
-                self._initDB(sqlTzFile);
-                g_stringBundle = cal.calGetStringBundle(bundleURL);
-                return done();
-            } else {
-                // No addon found. Possibly we have the timezone data
-                // bundled.
-                if (cal.isSunbird()) {
-                    // Sunbird doesn't bundle the timezone extension
-                    let msg = cal.calGetString("calendar", "missingCalendarTimezonesError");
-                    cal.ERROR(msg);
-                    showError(msg);
-                    return done();
-                } else {
-                    const kLightningXpiId = "{e2fda1a4-762b-4020-b5ad-a41df1933103}";
-                    AddonManager.getAddonByID(kLightningXpiId, function getLightningExt(aAddon) {
-                        let bundleURL;
-                        let sqlTzFile;
-                        if (aAddon) {
-                            sqlTzFile = toFile(aAddon.getResourceURI(''));
-                            bundleURL = "chrome://lightning/locale/timezones.properties";
-                        } else {
-                            // No Lightning? Possibly we're running a unit test.
-                            let dirSvc = Components.classes["@mozilla.org/file/directory_service;1"]
-                                                   .getService(Components.interfaces.nsIProperties);
-                            sqlTzFile = dirSvc.get("CurProcD", Components.interfaces.nsILocalFile);
-                            sqlTzFile.append("extensions");
-                            sqlTzFile.append(kCalendarTimezonesXpiId);
-                            cal.WARN("### USING " + sqlTzFile.path);
-                            self._initDB(sqlTzFile);
-
-                            let bundleFile = sqlTzFile.clone();
-                            bundleFile.append("chrome");
-                            bundleFile.append("calendar-timezones-en-US.jar");
-
-                            bundleURL = "jar:" + getIOService().newFileURI(bundleFile).spec + "!/locale/en-US/timezones.properties";
-                        }
-
-                        self._initDB(sqlTzFile);
-                        g_stringBundle = cal.calGetStringBundle(bundleURL);
-                        return done();
-                    });
-
-                    // Async calls made, no further action
-                    return null;
-                }
+        function tryTzUri(uriSpec) {
+            let canInit = false;
+            let sqlTzFile = toFile(uriSpec);
+            if (sqlTzFile) {
+                canInit = self._initDB(sqlTzFile);
             }
 
-            // If this line is reached, then you've forgotten to return
-            // somewhere above. Please check!
-            cal.ERROR("Missing return statements in calTimezoneService.js!");
-            return null;
-        });
+            return canInit;
+        }
+            
+        // First, lets try getting the file from our timezone extension
+        let canInit = tryTzUri("resource://calendar-timezones/timezones.sqlite");
+        let bundleURL = "chrome://calendar-timezones/locale/timezones.properties";
+                               
+        if (!canInit) {
+            // If that fails, we might have the file bundled
+            canInit = tryTzUri("resource://calendar/timezones.sqlite");
+            bundleURL = "chrome://calendar/locale/timezones.properties"
+        }
+
+        if (canInit) {
+            // Seems like a success, make the bundle url global
+            g_stringBundle = cal.calGetStringBundle(bundleURL);
+        } else {
+            // Otherwise, we have to give up. Show an error and fail hard!
+            let msg = cal.calGetString("calendar", "missingCalendarTimezonesError");
+            cal.ERROR(msg);
+            showError(msg);
+        }
+
+        if (aCompleteListener) {
+            aCompleteListener.onResult(null, Components.results.NS_OK);
+        }
     },
 
     // calITimezoneProvider:
     getTimezone: function calTimezoneService_getTimezone(tzid) {
         this.ensureInitialized();
         if (tzid.indexOf("/mozilla.org/") == 0) {
             // We know that our former tzids look like "/mozilla.org/<dtstamp>/continent/..."
             // The ending of the mozilla prefix is the index of that slash before the
--- a/calendar/lightning/locales/jar.mn
+++ b/calendar/lightning/locales/jar.mn
@@ -1,7 +1,6 @@
 #filter substitution
 
 lightning-@AB_CD@.jar:
 % locale lightning @AB_CD@ %locale/@AB_CD@/lightning/
   locale/@AB_CD@/lightning/lightning.dtd         (%chrome/lightning/lightning.dtd)
   locale/@AB_CD@/lightning/lightning.properties  (%chrome/lightning/lightning.properties)
-  locale/@AB_CD@/lightning/timezones.properties  (%chrome/calendar/timezones.properties)
--- a/calendar/locales/jar.mn
+++ b/calendar/locales/jar.mn
@@ -15,16 +15,17 @@ calendar-@AB_CD@.jar:
     locale/@AB_CD@/calendar/calendar-subscriptions-dialog.dtd  (%chrome/calendar/calendar-subscriptions-dialog.dtd)
     locale/@AB_CD@/calendar/categories.properties          (%chrome/calendar/categories.properties)
     locale/@AB_CD@/calendar/dateFormat.properties          (%chrome/calendar/dateFormat.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/provider-uninstall.dtd         (%chrome/calendar/provider-uninstall.dtd)
+    locale/@AB_CD@/calendar/timezones.properties           (%chrome/calendar/timezones.properties)
     locale/@AB_CD@/calendar/wcap.properties                (%chrome/calendar/providers/wcap/wcap.properties)
     locale/@AB_CD@/calendar/preferences/advanced.dtd       (%chrome/calendar/preferences/advanced.dtd)
     locale/@AB_CD@/calendar/preferences/alarms.dtd         (%chrome/calendar/preferences/alarms.dtd)
     locale/@AB_CD@/calendar/preferences/categories.dtd     (%chrome/calendar/preferences/categories.dtd)
 *   locale/@AB_CD@/calendar/preferences/connection.dtd     (%chrome/calendar/preferences/connection.dtd)
     locale/@AB_CD@/calendar/preferences/general.dtd        (%chrome/calendar/preferences/general.dtd)
     locale/@AB_CD@/calendar/preferences/preferences.dtd    (%chrome/calendar/preferences/preferences.dtd)
     locale/@AB_CD@/calendar/preferences/timezones.dtd      (%chrome/calendar/preferences/timezones.dtd)
--- a/calendar/timezones/install.rdf
+++ b/calendar/timezones/install.rdf
@@ -67,16 +67,17 @@
         <!-- Seamonkey -->
         <em:id>{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}</em:id>
         <em:minVersion>2.0</em:minVersion>
         <em:maxVersion>@SEAMONKEY_VERSION@</em:maxVersion>
        </Description>
      </em:targetApplication>
 
     <em:name>Timezone Definitions for Mozilla Calendar</em:name>
+    <em:unpack>true</em:unpack>
     <em:description>Timezone definitions required by Sunbird and Lightning</em:description>
     <em:creator>Mozilla Calendar Project</em:creator>
     <em:iconURL>chrome://calendar-timezones/skin/addon-icon32.png</em:iconURL>
 #if 0
     <em:homepageURL>https://addons.mozilla.org/en-US/thunderbird/addon/xxx todo</em:homepageURL>
 #endif
   </Description>
 </RDF>
--- a/calendar/timezones/jar.mn
+++ b/calendar/timezones/jar.mn
@@ -1,5 +1,6 @@
 #filter substitution
 
 calendar-timezones.jar:
+% resource calendar-timezones .
 % skin calendar-timezones classic/1.0 %skin/
     skin/addon-icon32.png                                   (addon-icon32.png)