1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, you can obtain one at http://mozilla.org/MPL/2.0/. */
4
5const EXPORTED_SYMBOLS = ["localAccountUtils"];
6
7// MailServices
8const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
9const { MailServices } = ChromeUtils.import(
10  "resource:///modules/MailServices.jsm"
11);
12
13// Local Mail Folders. Requires prior setup of profile directory
14
15var localAccountUtils = {
16  inboxFolder: undefined,
17  incomingServer: undefined,
18  rootFolder: undefined,
19  msgAccount: undefined,
20
21  _localAccountInitialized: false,
22  _mailboxStoreContractID: undefined,
23
24  pluggableStores: [
25    "@mozilla.org/msgstore/berkeleystore;1",
26    "@mozilla.org/msgstore/maildirstore;1",
27  ],
28
29  clearAll() {
30    this._localAccountInitialized = false;
31    if (this.msgAccount) {
32      MailServices.accounts.removeAccount(this.msgAccount);
33    }
34    this.incomingServer = undefined;
35    this.msgAccount = undefined;
36    this.inboxFolder = undefined;
37    this.rootFolder = undefined;
38  },
39
40  loadLocalMailAccount(storeID) {
41    if (
42      (storeID && storeID == this._mailboxStoreContractID) ||
43      (!storeID && this._localAccountInitialized)
44    ) {
45      return;
46    }
47
48    this.clearAll();
49    if (storeID) {
50      Services.prefs.setCharPref("mail.serverDefaultStoreContractID", storeID);
51    }
52
53    this._mailboxStoreContractID = storeID;
54    MailServices.accounts.createLocalMailAccount();
55
56    this.incomingServer = MailServices.accounts.localFoldersServer;
57    this.msgAccount = MailServices.accounts.FindAccountForServer(
58      this.incomingServer
59    );
60
61    this.rootFolder = this.incomingServer.rootMsgFolder.QueryInterface(
62      Ci.nsIMsgLocalMailFolder
63    );
64
65    // Note: Inbox is not created automatically when there is no deferred server,
66    // so we need to create it.
67    this.inboxFolder = this.rootFolder
68      .createLocalSubfolder("Inbox")
69      .QueryInterface(Ci.nsIMsgLocalMailFolder);
70    // a local inbox should have a Mail flag!
71    this.inboxFolder.setFlag(Ci.nsMsgFolderFlags.Mail);
72
73    // Force an initialization of the Inbox folder database.
74    this.inboxFolder.prettyName;
75
76    this._localAccountInitialized = true;
77  },
78
79  /**
80   * Create an nsIMsgIncomingServer and an nsIMsgAccount to go with it.
81   *
82   * @param aType The type of the server (pop3, imap etc).
83   * @param aPort The port the server is on.
84   * @param aUsername The username for the server.
85   * @param aPassword The password for the server.
86   * @param aHostname The hostname for the server (defaults to localhost).
87   * @return The newly-created nsIMsgIncomingServer.
88   */
89  create_incoming_server(
90    aType,
91    aPort,
92    aUsername,
93    aPassword,
94    aHostname = "localhost"
95  ) {
96    let serverAndAccount = localAccountUtils.create_incoming_server_and_account(
97      aType,
98      aPort,
99      aUsername,
100      aPassword,
101      aHostname
102    );
103    return serverAndAccount.server;
104  },
105
106  /**
107   * Create an nsIMsgIncomingServer and an nsIMsgAccount to go with it.
108   * There are no identities created for the account.
109   *
110   * @param aType The type of the server (pop3, imap etc).
111   * @param aPort The port the server is on.
112   * @param aUsername The username for the server.
113   * @param aPassword The password for the server.
114   * @param aHostname The hostname for the server (defaults to localhost).
115   * @return An object with the newly-created nsIMsgIncomingServer as the
116             "server" property and the newly-created nsIMsgAccount as the
117             "account" property.
118   */
119  create_incoming_server_and_account(
120    aType,
121    aPort,
122    aUsername,
123    aPassword,
124    aHostname = "localhost"
125  ) {
126    let server = MailServices.accounts.createIncomingServer(
127      aUsername,
128      aHostname,
129      aType
130    );
131    server.port = aPort;
132    if (aUsername != null) {
133      server.username = aUsername;
134    }
135    if (aPassword != null) {
136      server.password = aPassword;
137    }
138
139    server.valid = false;
140
141    let account = MailServices.accounts.createAccount();
142    account.incomingServer = server;
143    if (aType == "pop3") {
144      // Several tests expect that mail is deferred to the local folders account,
145      // so do that.
146      this.loadLocalMailAccount();
147      server.QueryInterface(Ci.nsIPop3IncomingServer);
148      server.deferredToAccount = this.msgAccount.key;
149    }
150    server.valid = true;
151
152    return { server, account };
153  },
154
155  /**
156   * Create an outgoing nsISmtpServer with the given parameters.
157   *
158   * @param aPort The port the server is on.
159   * @param aUsername The username for the server
160   * @param aPassword The password for the server
161   * @param aHostname The hostname for the server (defaults to localhost).
162   * @return The newly-created nsISmtpServer.
163   */
164  create_outgoing_server(aPort, aUsername, aPassword, aHostname = "localhost") {
165    let server = MailServices.smtp.createServer();
166    server.hostname = aHostname;
167    server.port = aPort;
168    server.authMethod = Ci.nsMsgAuthMethod.none;
169    return server;
170  },
171
172  /**
173   * Associate the given outgoing server with the given account.
174   * It does so by creating a new identity in the account using the given outgoing
175   * server.
176   *
177   * @param {nsIMsgAccount} aIncoming  The account to associate.
178   * @param {nsISmtpServer} aOutgoingServer  The outgoing server to associate.
179   * @param {bool} aSetAsDefault  Whether to set the outgoing server as the default for
180   *                              the account.
181   */
182  associate_servers(aIncoming, aOutgoingServer, aSetAsDefault = false) {
183    if (!(aIncoming instanceof Ci.nsIMsgAccount)) {
184      throw new Error("aIncoming isn't an account");
185    }
186
187    let identity = MailServices.accounts.createIdentity();
188    identity.smtpServerKey = aOutgoingServer.key;
189
190    aIncoming.addIdentity(identity);
191
192    if (aSetAsDefault) {
193      aIncoming.defaultIdentity = identity;
194    }
195  },
196};
197
198// Somehow profile-after-change is not triggered in xpcshell tests, here we
199// manually run the getService, so that correct smtp and send modules are loaded
200// according to the pref values.
201Cc["@mozilla.org/messengercompose/send-module-loader;1"].getService();
202Cc["@mozilla.org/messengercompose/smtp-module-loader;1"].getService();
203