/** By Dean Brundage Originally published here: http://blog.deanandadie.net/2010/06/easy-thunderbird-account-management-using-mcd/ */ /* "Inheritance" helper http://www.sitepoint.com/blogs/2006/01/17/javascript-inheritance/ copy all of parent's prototype functions to descendant */ function copyPrototype(parent, descendant) { var sConstructor = parent.toString(); var aMatch = sConstructor.match( /\s*function (.*)\(/ ); if( aMatch != null ) { descendant.prototype[aMatch[1]] = parent; } for (var m in parent.prototype) { descendant.prototype[m] = parent.prototype[m]; } }; /* "Base" for the Mail.xxxx objects This requires the PreferenceFactory prototype covered in a previous post: http://blog.deanandadie.net/2010/05/manufacturing-user-preferences-for-mcd/ */ function Mail() { this.PreferenceFactory(); // super this.addPrefBranch("mail"); return this; } copyPrototype( PreferenceFactory, Mail ); Mail.prototype.joinIds = function(collection,separator) { if( ! separator ) separator = ","; if( collection ) { ret = collection[0].id for( i = 1; i < collection.length; i++ ) ret = ret + separator + collection[i].id; } return ret; }; /* A thunderbird email "account" consists of Mail.Server -- A mail server (IMAP or POP) Mail.SMTPServer -- A SMTP server One or more Mail.Identities -- Email address and name A thunderbird local folders "account" has only one Mail.Server, nothing else Yup, local folders are "servers" */ /* Object to manage accounts I recommend managing mail accounts with the AccountManager unless you know what you are doing. var myAccount = AccountManager.newAccount(); myAccount.doStuff(); */ var AccountManager = new Mail(); AccountManager.accounts = []; AccountManager.addPrefBranch("accountmanager"); /* Create a new account Alerts Thunderbird to the presence of the new account See Mail.Account for valid options */ AccountManager.newAccount = function(opts) { if( ! opts ) opts = { }; acct = new Mail.Account(opts); if( opts.isDefault ) { acct.useSMTPServer( new Mail.SMTPServer(opts) ); this.setDefaultAccount(acct,opts.lockLevel); } else { acct.useSMTPServer( Mail.SMTPServer.defaultServer ); } this.accounts.push(acct); this.setPref( "accounts", this.joinIds(this.accounts) ); return acct; } AccountManager.setDefaultAccount = function(account,lockLevel) { this.setPref("defaultaccount", account.id, lockLevel ); /* It's possible to create an account before setting the default SMTP server. Clean them up if this new account is the default (Expect Mail.Account to inform Mail.SMTPServer of the new default) */ for( i = 0; i < this.accounts.length; i++ ) this.accounts[i].useSMTPServer(Mail.SMTPServer.defaultServer); } AccountManager.setLocalFolders = function(folders,lockLevel) { this.setPref("localfoldersserver", folders.id, lockLevel); } /* Creates a new generic mail account (identity, server, smtp) Arguments opts: A hash of options. Valid options are: "isDefault": true | false (default false) "label": string - A unique label for this account, server & identity "lockLevel": "default" | "lock" | "pref" (default "default") "type": imap | pop | localFolder This prototype creates an object representing an email account It exposes some objects: myAccount.directoryServer // The (optional) LDAP2Server object myAccount.identities // An array of identites myAccount.server // The IMAP/POP/LocalFolder Mail.Server object myAccount.smtpServer // The Mail.SMTPServer object (The LDAP2Server object is detailed in a separate post on http://blog.deanandadie.net/) */ Mail.Account = function(opts) { if( ! opts ) opts = { }; if( ! opts.type ) throw("What's my type?"); this.Mail(); // "super" this.id = "account" + ++Mail.Account.count; if( opts.label ) { this.id = opts.label + "-" + this.id; } // Our preference branch is mail.account.accountN this.addPrefBranch( [ "account", this.id ] ); this.identities = []; this.server = new Mail.Server(opts); // Need this either way if( opts.type.match(/^^imap$|^pop$/i) ) { this.server.setPref("type", opts.type, opts.lockLevel); // Important that addIdentity be before the SMTP server is set up this.addIdentity( new Mail.Identity(opts), opts.lockLevel ); } else if( opts.type.match(/^localFolders?$/i) ) { this.folders = this.server; AccountManager.setLocalFolders(this.folders); this.folders.setPref("type", "none", opts.lockLevel ); } else { throw("unrecognized Mail.Account type: " + opts.type); } this.useServer(this.server, opts.lockLevel); } copyPrototype( Mail, Mail.Account ); Mail.Account.count = 0; // Fake class variable // Expects a Mail.Identity object and, optionally, the preference locking level Mail.Account.prototype.addIdentity = function(identity,lockLevel) { if( identity ) { if( ! this.identities.contains(identity) ) { this.identities.push(identity); this.setPref("identities", this.joinIds(this.identities), lockLevel ); } } } /* Helper to set the SMTP server Expects a Mail.SMTPServer object & optionally, an options hash Valid options: lockLevel: lock | default | pref force: true | false */ Mail.Account.prototype.useDirectory = function(directory, opts) { if( ! opts ) opts = { }; if( directory ) { if( opts.force || typeof(this.directoryServer) == "undefined" ) { this.directoryServer = directory; for( i = 0; i < this.identities.length; i++ ) this.identities[i].useDirectory( this.directoryServer, opts ); } } } /* Helper to set the SMTP server Expects a Mail.SMTPServer object & optionally, an options hash Valid options: lockLevel: lock | default | pref force: true | false */ Mail.Account.prototype.useSMTPServer = function(smtp,opts) { if( ! opts ) opts = { }; if( smtp ) { if( opts.force || typeof(this.smtpServer) == "undefined" ) { this.smtpServer = smtp; for( i = 0; i < this.identities.length; i++ ) this.identities[i].useSMTPServer( this.smtpServer, opts ); } } } // Expects a Mail.Server object and, optionally, the preference locking level Mail.Account.prototype.useServer = function(server,lockLevel) { if( server ) this.setPref("server", server.id, lockLevel ); } /* Creates a new generic mail server Arguments opts: A hash of options. Valid options are: label: string - A unique label for this account, server & identity */ Mail.Server = function(opts) { if( ! opts ) opts = { }; this.Mail(); this.id = "server" + ++Mail.Server.count; if( opts.label ) { this.id = opts.label + "-" + this.id; } // Our preference branch is mail.server.serverN this.addPrefBranch( [ "server", this.id ] ); } copyPrototype( Mail, Mail.Server ); Mail.Server.count = 0; // Fake class variable /* Creates a new mail identity. (name, email address, etc) Arguments opts: A hash of options. Valid options are: "label": string - A unique label for this account, server & identity */ Mail.Identity = function(opts) { if( ! opts ) opts = { }; this.Mail(); this.id = "id" + ++Mail.Identity.count; if( opts.label ) { this.id = opts.label + "-" + this.id; } // Our preference branch is mail.identity.idN this.addPrefBranch( [ "identity", this.id ] ); this.hasSMTPServer = false; }; copyPrototype(Mail, Mail.Identity); Mail.Identity.count = 0; // Fake class variable /* Expects a LDAP2Server object and a hash of options Valid options: lockLevel: lock | default | pref */ Mail.Identity.prototype.useDirectory = function(ldap2Server,opts) { if( ! opts ) opts = { }; if( ldap2Server ) { this.setPref("directoryServer", "ldap_2.servers." + ldap2Server.id, opts.lockLevel); this.setPref("overrideGlobal_Pref", true, opts.lockLevel); } }; /* Expects a SMTPServer object and a hash of options Valid options: force: true | false lockLevel: lock | default | pref */ Mail.Identity.prototype.useSMTPServer = function(smtpServer,opts) { if( ! opts ) opts = { } if( smtpServer ) { if( opts.force || ! this.hasSMTPServer ) { this.setPref("smtpServer", smtpServer.id, opts.lockLevel); this.hasSMTPServer = true; } } }; /* Creates a new smtp server Artuments: opts: A hash of options. Valid options are: isDefault: true | false (default) label: A unique label for this smtp server Throws an error if there is already a default smtp server */ Mail.SMTPServer = function(opts) { if( ! opts ) opts = { }; this.Mail(); this.id = "smtp" + ++Mail.SMTPServer.count; if( opts.label ) { this.id = opts.label + "-" + this.id; } // Our perference branch is mail.smtpserver.smtpN this.addPrefBranch( [ "smtpserver", this.id ] ); if( opts.isDefault && Mail.SMTPServer.defaultServer ) throw("Default smtp server already configured to " + Mail.SMTPServer.defaultServer); if( opts.isDefault ) this.setDefault(); // Register this SMTP server if( ! Mail.SMTPServer.servers.contains(this) ) Mail.SMTPServer.servers.push(this); // Update mail.smtpservers to include the new one defaultPref("mail.smtpservers", this.joinIds(Mail.SMTPServer.servers) ); return this; }; copyPrototype(Mail, Mail.SMTPServer); // Some "class" variables Mail.SMTPServer.count = 0; Mail.SMTPServer.defaultServer = undefined; Mail.SMTPServer.servers = []; Mail.SMTPServer.prototype.setDefault = function() { Mail.SMTPServer.defaultServer = this; defaultPref("mail.smtp.defaultserver", Mail.SMTPServer.defaultServer.id ); }