MailNews:Creating New Account Types
This page aims to provide a detailed guide on creating new account types from extensions for Thunderbird and SeaMonkey. This is still a work in progress, heavily dependent on my (jcranmer's) personal tree, where some critical components are merely patches in my tree and on bugzilla (where the latter may not be the most up-to-date).
The Account Manager
The best I can describe the account manager is that it is a hydra of components, managing several slightly different, but distinct, components. Primarily, these are servers, accounts, and identities. Folders, messages, message headers, databases, URLs, message DB views, the folder cache, and even more end up becoming part of this mess of topics to cover, the full scope of which is beyond the scope of this article. Needless to say, I will provide a sufficient overview to allow you to create a new account type.
For a diagram-based view of what is going on, see emre's diagrams on the subject. For other views, I invite you to run make documentation on the mozilla codebase to generate doxygen graphs and pages for the key components. This documentation can also be accessed at db48x's site, although I will warn you that he is using the experimental SVG output for doxygen which is quite obviously not quite production-ready.
Step 1: Account types
TODO: nsIMsgProtocolInfo seems to fall through the cracks of doxygen; fix that
The first thing to do when designing a new account type is to pick an internal name. This name should probably consist of the typical characters: alphanumerics, underscores, and dashes; this name will be used heavily as URI schemes and as portions of CIDs. For sake of simplicity, let's assume that the new account type is "acct" (don't actually pick this).
Defining account types requires that you implement a few interfaces. The most important ones are nsIMsgProtocolInfo, and nsIMsgIncomingServer, while other interfaces are important if you do crazier stuff, which you most likely will. Unfortunately, most of these interfaces involve a lot of repetitive code, while the nice implementations that do the magic for us are, naturally, native C++ code that JS-based implementations are unable to provide.
nsIMsgProtocolInfo
TODO: Investigate where nsIMsgProtocolInfo is used
Our first interface to implement is nsIMsgProtocolInfo, which defines basic parameters of the account type. A fair amount appears to be special casing for local folders. The contract ID is important; set it to be @mozilla.org/messenger/protocol/info;1?type=acct in our running example. Assuming you can generate the XPCOM overhead yourself, the following is an example of what to use:
function accountInfo() {
this._prefs = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Ci.nsIPrefService)
.getBranch("acct.");
}
accountInfo.prototype = {
// This variable represents the pref-based directory to store all server-
// specific configurations, like News/ or ImapMail/
get defaultLocalPath() {
// Good idea to set this as a default pref in your extension.
var pref = this._prefs.getComplexValue("root", Ci.nsIRelativeFilePref);
return pref.file;
},
set defultLocalPath(path) {
var newPref = Components.classes["@mozilla.org/pref-relativefile;1"]
.createInstance(Ci.nsIRelativeFilePref);
newPref.relativeToKey = "ProfD";
newPref.file = path;
this._prefs.setComplexValue("root", Ci.nsIRelativeFilePref, newPref);
},
// Return the IID of the server for account wizard magic. You should only be
// changing this value if you define your own incoming server for advanced
// account wizard magic.
get serverIID() {return Ci.nsIMsgIncomingServer;},
getDefaultServerPort : function (isSecure) {
return isSecure ? 443 : 80;
},
// True if you need a username
get requiresUsername() {return false;},
// True if the pretty name should be the email address.
get preflightPrettyNameWithEmailAddress() {return false;},
// True if you can delete this account type
get canDelete() {return true;},
get canLoginAtStartup() {return true;},
// True if you can duplicate this account type
get canDuplicate() {return true;},
// Do we have an "inbox" for this account type?
get canGetMessages() {return false;},
// Can we use junk controls on these messages?
get canGetIncomingMessages() {return false;},
// Can we request new message notifications ("biff")?
get defaultDoBiff() {return false;},
get showComposeMsgLink() {return false;},
get specialFoldersDeletionAllowed() {return false;}
};
All of the options--except the first three--are simple true/false boolean attributes that ask whether or not an account can do specific things. Full, up-to-date documentation is available at the IDL file; note that, in a few cases, the attribute name is a poor guideline for what it actually does. These defaults should be sufficient for most people, although a lot varies on what account type you are actually providing.
The first two are special attributes that require you to think somewhat before responding. First is the default local path, a directory under which all server-specific configuration servers are stored: this is essentially your Mail/ or ImapMail folders for your specific implementation. The catch is that this is actually pref-based, where the pref is de-facto of the form "mail.root.acct-rel"; the "rel" is there for backwards-compatibility reasons.
Second is the IID of the server. This is simply an interface that has special properties you can set with some account wizard magic; you can set this to return Ci.nsIMsgIncomingServer or even omit it if you do not actually need special properties.
The third non-boolean property is the default port, with an argument that tells you whether or not the port is secure. If you scrape from the web, you could set the port to return -1 or do an 80/443 combination like I do here. It's not terribly important.
nsIMsgIncomingServer
The second piece of the account type puzzle is the incoming server. Of all the parts related to account types, this one is the worst. Most of the attributes are really pref-based, although some key ones are not. A few of the attributes are merely helper functions, and some are not even used at all! It is expected that this class will be extremely pared in the post-TB 3 time frame as part of a general account manager overhaul.
TODO: Write me! Now!
Step 2: Account Wizard Overlays
TODO: Write me! Now!