Revision control
Copy as Markdown
Other Tools
/* 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,
'use strict';
(function (exports) {
var { cloudFileAccounts } = ChromeUtils.importESModule(
);
exports.CloudFileAccounts = class extends ExtensionCommon.ExtensionAPI {
onStartup() {
this._providerType = 'ext-' + this.extension.id;
// The "Thunderbird Send" cloud file provider is declared via the manifest
// `cloud_file` key, so Thunderbird registers it automatically on every
// startup — including on fresh, never-signed-in profiles where the
// built-in system add-on runs under automation. We keep a reference to the
// provider object so the background script can unregister it while signed
// out (hiding Send from the cloud file provider list and preferences) and
// re-register the very same instance on sign-in, which keeps the
this._capturedProvider =
cloudFileAccounts.getProviderForType(this._providerType) || null;
// When true, the provider must stay hidden even if Thunderbird registers
// it after the background script has already asked us to unregister it
// (the manifest registration and the background script race at startup).
this._keepUnregistered = false;
this._onProviderRegistered = this._onProviderRegistered.bind(this);
cloudFileAccounts.on('providerRegistered', this._onProviderRegistered);
}
onShutdown(isAppShutdown) {
if (isAppShutdown) {
return;
}
cloudFileAccounts.off('providerRegistered', this._onProviderRegistered);
}
// EventEmitter invokes listeners as (eventName, ...args), so rather than
// depend on the emitted argument we re-check the registry by our type.
_onProviderRegistered() {
const provider = cloudFileAccounts.getProviderForType(this._providerType);
if (!provider) {
return;
}
// Remember the provider instance so it can be re-registered on sign-in.
this._capturedProvider = provider;
// If we are meant to stay signed out, immediately undo the registration.
if (this._keepUnregistered) {
cloudFileAccounts.unregisterProvider(this._providerType);
}
}
getAPI(_context) {
const providerType = 'ext-' + this.extension.id;
// Arrow functions keep `this` bound to the ExtensionAPI instance so the
// register/unregister handlers can read and update the captured provider
// and the _keepUnregistered flag set up in onStartup().
return {
CloudFileAccounts: {
createAccount: async (type, configured) => {
try {
// Check if the provider is registered
const provider = cloudFileAccounts.getProviderForType(type);
if (!provider) {
return {
success: false,
error: `Cloud file provider '${type}' is not registered. The extension may not be fully loaded yet.`,
};
}
// Check if an account with this type already exists
const existingAccount = cloudFileAccounts.accounts.find(
(account) => account.type === type
);
if (existingAccount) {
return {
success: true,
alreadyExists: true,
accountId: existingAccount.accountKey,
message: `Cloud file account of type '${type}' already exists.`,
};
}
// Create the account
const account = cloudFileAccounts.createAccount(type);
if (!account) {
return {
success: false,
error: `Failed to create cloud file account of type '${type}'.`,
};
}
// Set the configured status
account.configured = configured;
return {
success: true,
accountId: account.accountKey,
message: `Cloud file account created successfully with type '${type}'.`,
};
} catch (error) {
return {
success: false,
error: `Error creating cloud file account: ${error.message}`,
};
}
},
// Re-register the Send provider (e.g. on sign-in). Idempotent: a
// no-op if the provider is already in the registry.
registerProvider: async () => {
this._keepUnregistered = false;
if (cloudFileAccounts.getProviderForType(providerType)) {
return { success: true, alreadyRegistered: true };
}
if (!this._capturedProvider) {
return {
success: false,
error: `No cloud file provider '${providerType}' available to register.`,
};
}
try {
cloudFileAccounts.registerProvider(
providerType,
this._capturedProvider
);
return { success: true };
} catch (error) {
return {
success: false,
error: `Error registering cloud file provider: ${error.message}`,
};
}
},
// Hide the Send provider while signed out. Idempotent: a no-op if the
// provider is not currently registered.
unregisterProvider: async () => {
// Stay hidden even if Thunderbird registers the provider after this
// call (manifest registration vs. background script startup race).
this._keepUnregistered = true;
const provider = cloudFileAccounts.getProviderForType(providerType);
if (!provider) {
return { success: true, alreadyUnregistered: true };
}
// Keep the instance so we can re-register it on sign-in.
this._capturedProvider = provider;
try {
cloudFileAccounts.unregisterProvider(providerType);
return { success: true };
} catch (error) {
return {
success: false,
error: `Error unregistering cloud file provider: ${error.message}`,
};
}
},
},
};
}
};
})(this);