Bug 1762688 - Implement expunge/onlineCopy in ImapService.jsm. r=mkmelin
- Remove unused return value of nsIImapService.expunge - Implement streamMessage in ImapMessageService.jsm - Enable test_compactOfflineStore. Differential Revision: https://phabricator.services.mozilla.com/D150883 Depends on D150313 --HG-- extra : rebase_source : 3ae28eb16d0784b73529dae293abdf660a731353
This commit is contained in:
Родитель
627353f83c
Коммит
af0394f26d
|
@ -88,13 +88,10 @@ interface nsIImapService : nsISupports
|
|||
* @param aImapMailFolder the folder to expunge
|
||||
* @param aUrlListener url listener, can be null
|
||||
* @param aMsgWindow msg window url is running in, can be null
|
||||
*
|
||||
* @returns the url created to run the expunge.
|
||||
*/
|
||||
void expunge(in nsIMsgFolder aImapMailFolder,
|
||||
in nsIUrlListener aUrlListener,
|
||||
in nsIMsgWindow aMsgWindow,
|
||||
out nsIURI aURL);
|
||||
in nsIMsgWindow aMsgWindow);
|
||||
|
||||
/**
|
||||
* Issue a STATUS on the target folder.
|
||||
|
|
|
@ -78,7 +78,9 @@ class ImapChannel {
|
|||
if (this._readFromLocalCache()) {
|
||||
return;
|
||||
}
|
||||
} catch (e) {}
|
||||
} catch (e) {
|
||||
this._logger.warn(e);
|
||||
}
|
||||
|
||||
this._readFromServer();
|
||||
}
|
||||
|
@ -96,7 +98,7 @@ class ImapChannel {
|
|||
return false;
|
||||
}
|
||||
|
||||
let hdr = this.URI.folder.getMessageHeader(this._msgKey);
|
||||
let hdr = this.URI.folder.GetMessageHeader(this._msgKey);
|
||||
let stream = this.URI.folder.getLocalMsgStream(hdr);
|
||||
let pump = Cc["@mozilla.org/network/input-stream-pump;1"].createInstance(
|
||||
Ci.nsIInputStreamPump
|
||||
|
|
|
@ -213,6 +213,7 @@ class ImapClient {
|
|||
* @param {number} flags - The internal flags number to update.
|
||||
*/
|
||||
updateMesageFlags(action, folder, urlListener, messageIds, flags) {
|
||||
this._urlListener = urlListener;
|
||||
let getCommand = () => {
|
||||
// _supportedFlags is available after _actionSelectResponse.
|
||||
let flagsStr = ImapUtils.flagsToString(flags, this._supportedFlags);
|
||||
|
@ -232,6 +233,39 @@ class ImapClient {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send EXPUNGE command to a folder.
|
||||
* @param {nsIMsgFolder} folder - The associated folder.
|
||||
*/
|
||||
expunge(folder) {
|
||||
this._actionFolderCommand(folder, () => {
|
||||
this._nextAction = () => this._actionDone();
|
||||
this._sendTagged("EXPUNGE");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Move or copy messages from a folder to another folder.
|
||||
* @param {nsIMsgFolder} folder - The source folder.
|
||||
* @param {nsIMsgFolder} folder - The target folder.
|
||||
* @param {string} messageIds - The message identifiers.
|
||||
* @param {boolean} idsAreUids - If true messageIds are UIDs, otherwise,
|
||||
* messageIds are sequences.
|
||||
* @param {boolean} isMove - If true, use MOVE command when supported.
|
||||
*/
|
||||
copy(folder, dstFolder, messageIds, idsAreUids, isMove) {
|
||||
let command = idsAreUids ? "UID " : "";
|
||||
command +=
|
||||
isMove && this._capabilities.includes("MOVE")
|
||||
? "MOVE " // rfc6851
|
||||
: "COPY ";
|
||||
command += messageIds + ` "${this._getServerFolderName(dstFolder)}"`;
|
||||
this._actionFolderCommand(folder, () => {
|
||||
this._nextAction = () => this._actionDone();
|
||||
this._sendTagged(command);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Send IDLE command to the server.
|
||||
*/
|
||||
|
@ -672,6 +706,25 @@ class ImapClient {
|
|||
}
|
||||
this._send(token, true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute an action with a folder selected.
|
||||
* @param {nsIMsgFolder} folder - The folder to select.
|
||||
* @param {function} actionInFolder - The action to execute.
|
||||
*/
|
||||
_actionFolderCommand(folder, actionInFolder) {
|
||||
if (this.folder == folder) {
|
||||
// If already in the folder, execute the action now.
|
||||
actionInFolder();
|
||||
} else {
|
||||
// Send the SELECT command and queue the action.
|
||||
this.folder = folder;
|
||||
this._actionAfterSelectFolder = actionInFolder;
|
||||
this._nextAction = this._actionSelectResponse;
|
||||
this._sendTagged(`SELECT "${this._getServerFolderName(folder)}"`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send LSUB or LIST command depending on the server capabilities.
|
||||
*/
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const EXPORTED_SYMBOLS = ["ImapMessageService"];
|
||||
const EXPORTED_SYMBOLS = ["ImapMessageService", "ImapMessageMessageService"];
|
||||
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
|
@ -21,7 +21,7 @@ XPCOMUtils.defineLazyModuleGetters(lazy, {
|
|||
/**
|
||||
* @implements {nsIMsgMessageService}
|
||||
*/
|
||||
class ImapMessageService {
|
||||
class BaseMessageService {
|
||||
QueryInterface = ChromeUtils.generateQI(["nsIMsgMessageService"]);
|
||||
|
||||
SaveMessageToDisk(
|
||||
|
@ -75,6 +75,46 @@ class ImapMessageService {
|
|||
return imapUrl;
|
||||
}
|
||||
|
||||
streamMessage(messageUri, consumer, msgWindow, urlListener, localOnly) {
|
||||
let { host, folderName, key } = this._decomposeMessageUri(messageUri);
|
||||
let imapUrl = Services.io
|
||||
.newURI(`imap://${host}/fetch>UID>/${folderName}>${key}`)
|
||||
.QueryInterface(Ci.nsIImapUrl);
|
||||
imapUrl.localFetchOnly = localOnly;
|
||||
|
||||
let folder = lazy.MailUtils.getOrCreateFolder(
|
||||
`imap://${host}/${folderName}`
|
||||
);
|
||||
|
||||
let mailnewsUrl = imapUrl.QueryInterface(Ci.nsIMsgMailNewsUrl);
|
||||
mailnewsUrl.folder = folder;
|
||||
mailnewsUrl.msgWindow = msgWindow;
|
||||
mailnewsUrl.msgIsInLocalCache = folder.hasMsgOffline(key);
|
||||
if (urlListener) {
|
||||
mailnewsUrl.RegisterListener(urlListener);
|
||||
}
|
||||
|
||||
return MailServices.imap.fetchMessage(
|
||||
imapUrl,
|
||||
Ci.nsIImapUrl.nsImapMsgFetchPeek,
|
||||
folder,
|
||||
folder.QueryInterface(Ci.nsIImapMessageSink),
|
||||
msgWindow,
|
||||
consumer,
|
||||
key,
|
||||
false,
|
||||
{}
|
||||
);
|
||||
}
|
||||
|
||||
messageURIToMsgHdr(messageUri) {
|
||||
let { host, folderName, key } = this._decomposeMessageUri(messageUri);
|
||||
let folder = lazy.MailUtils.getOrCreateFolder(
|
||||
`imap://${host}/${folderName}`
|
||||
);
|
||||
return folder.GetMessageHeader(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a message uri to hostname, folder and message key.
|
||||
* @param {string} uri - The imap-message:// url to parse.
|
||||
|
@ -88,6 +128,20 @@ class ImapMessageService {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A message service for imap://.
|
||||
*/
|
||||
class ImapMessageService extends BaseMessageService {}
|
||||
|
||||
ImapMessageService.prototype.classID = Components.ID(
|
||||
"{d63af753-c2f3-4f1d-b650-9d12229de8ad}"
|
||||
);
|
||||
|
||||
/**
|
||||
* A message service for imap-message://.
|
||||
*/
|
||||
class ImapMessageMessageService extends BaseMessageService {}
|
||||
|
||||
ImapMessageMessageService.prototype.classID = Components.ID(
|
||||
"{2532ae4f-a852-4c96-be45-1308ba23d62e}"
|
||||
);
|
||||
|
|
|
@ -36,6 +36,12 @@ var imapJSModules = [
|
|||
"@mozilla.org/messenger/messageservice;1?type=imap",
|
||||
"ImapMessageService",
|
||||
],
|
||||
[
|
||||
"ImapMessageMessageService",
|
||||
"{2532ae4f-a852-4c96-be45-1308ba23d62e}",
|
||||
"@mozilla.org/messenger/messageservice;1?type=imap-message",
|
||||
"ImapMessageService",
|
||||
],
|
||||
[
|
||||
"ImapProtocolHandler",
|
||||
"{ebb06c58-6ccd-4bde-9087-40663e0388ae}",
|
||||
|
@ -56,9 +62,15 @@ ImapModuleLoader.prototype = {
|
|||
Ci.nsIComponentRegistrar
|
||||
);
|
||||
|
||||
for (let [moduleName, interfaceId, contractId] of imapJSModules) {
|
||||
for (let [
|
||||
moduleName,
|
||||
interfaceId,
|
||||
contractId,
|
||||
fileName,
|
||||
] of imapJSModules) {
|
||||
fileName = fileName || moduleName;
|
||||
// Load a module.
|
||||
let scope = ChromeUtils.import(`resource:///modules/${moduleName}.jsm`);
|
||||
let scope = ChromeUtils.import(`resource:///modules/${fileName}.jsm`);
|
||||
|
||||
// Register a module.
|
||||
let classId = Components.ID(interfaceId);
|
||||
|
|
|
@ -135,6 +135,49 @@ class ImapService {
|
|||
channel.asyncOpen(streamListener);
|
||||
}
|
||||
}
|
||||
|
||||
expunge(folder, urlListener, msgWindow) {
|
||||
this._withClient(folder, client => {
|
||||
client.startRunningUrl(urlListener, msgWindow);
|
||||
client.onReady = () => {
|
||||
client.expunge(folder);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
onlineMessageCopy(
|
||||
folder,
|
||||
messageIds,
|
||||
dstFolder,
|
||||
idsAreUids,
|
||||
isMove,
|
||||
urlListener,
|
||||
outURL,
|
||||
copyState,
|
||||
msgWindow
|
||||
) {
|
||||
this._withClient(folder, client => {
|
||||
let runningUrl = client.startRunningUrl(urlListener, msgWindow);
|
||||
runningUrl.QueryInterface(Ci.nsIImapUrl).imapAction = isMove
|
||||
? Ci.nsIImapUrl.nsImapOnlineMove
|
||||
: Ci.nsIImapUrl.nsImapOnlineCopy;
|
||||
client.onReady = () => {
|
||||
client.copy(folder, dstFolder, messageIds, idsAreUids, isMove);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Do some actions with a connection.
|
||||
* @param {nsIMsgFolder} folder - The associated folder.
|
||||
* @param {Function} handler - A callback function to take a ImapClient
|
||||
* instance, and do some actions.
|
||||
*/
|
||||
_withClient(folder, handler) {
|
||||
let server = folder.QueryInterface(Ci.nsIMsgImapMailFolder)
|
||||
.imapIncomingServer;
|
||||
server.wrappedJSObject.withClient(handler);
|
||||
}
|
||||
}
|
||||
|
||||
ImapService.prototype.classID = Components.ID(
|
||||
|
|
|
@ -1300,7 +1300,7 @@ NS_IMETHODIMP nsImapMailFolder::Expunge(nsIUrlListener* aListener,
|
|||
do_GetService(NS_IMAPSERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return imapService->Expunge(this, aListener, aMsgWindow, nullptr);
|
||||
return imapService->Expunge(this, aListener, aMsgWindow);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsImapMailFolder::CompactAll(nsIUrlListener* aListener,
|
||||
|
@ -6970,10 +6970,11 @@ nsImapMailFolder::CopyMessages(
|
|||
allMessageCountNotifications,
|
||||
false); // disable message count notification
|
||||
|
||||
nsCOMPtr<nsIURI> resultUrl;
|
||||
nsCOMPtr<nsISupports> copySupport = do_QueryInterface(m_copyState);
|
||||
rv = imapService->OnlineMessageCopy(srcFolder, messageIds, this, true,
|
||||
isMove, urlListener, nullptr,
|
||||
copySupport, msgWindow);
|
||||
rv = imapService->OnlineMessageCopy(
|
||||
srcFolder, messageIds, this, true, isMove, urlListener,
|
||||
getter_AddRefs(resultUrl), copySupport, msgWindow);
|
||||
if (NS_SUCCEEDED(rv) && m_copyState->m_allowUndo) {
|
||||
RefPtr<nsImapMoveCopyMsgTxn> undoMsgTxn = new nsImapMoveCopyMsgTxn;
|
||||
if (!undoMsgTxn ||
|
||||
|
|
|
@ -1445,11 +1445,11 @@ NS_IMETHODIMP nsImapService::UpdateFolderStatus(nsIMsgFolder* aImapMailFolder,
|
|||
// Expunge, used to "compress" an imap folder,removes deleted messages.
|
||||
NS_IMETHODIMP nsImapService::Expunge(nsIMsgFolder* aImapMailFolder,
|
||||
nsIUrlListener* aUrlListener,
|
||||
nsIMsgWindow* aMsgWindow, nsIURI** aURL) {
|
||||
nsIMsgWindow* aMsgWindow) {
|
||||
NS_ENSURE_ARG_POINTER(aImapMailFolder);
|
||||
|
||||
return FolderCommand(aImapMailFolder, aUrlListener, "/Expunge>",
|
||||
nsIImapUrl::nsImapExpungeFolder, aMsgWindow, aURL);
|
||||
nsIImapUrl::nsImapExpungeFolder, aMsgWindow, nullptr);
|
||||
}
|
||||
|
||||
/* old-stle biff that doesn't download headers */
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
* and returns success.
|
||||
*/
|
||||
|
||||
var { setTimeout } = ChromeUtils.import("resource://gre/modules/Timer.jsm");
|
||||
var { MessageGenerator } = ChromeUtils.import(
|
||||
"resource://testing-common/mailnews/MessageGenerator.jsm"
|
||||
);
|
||||
|
@ -161,9 +162,11 @@ add_task(async function compactOfflineStore() {
|
|||
let listener = new PromiseTestUtils.PromiseUrlListener();
|
||||
gRootFolder.compactAll(listener, null);
|
||||
await listener.promise;
|
||||
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
});
|
||||
|
||||
add_task(function test_checkCompactionResult() {
|
||||
add_task(function test_checkCompactionResult1() {
|
||||
checkOfflineStore(gImapInboxOfflineStoreSize);
|
||||
});
|
||||
|
||||
|
@ -176,7 +179,7 @@ add_task(async function pendingRemoval() {
|
|||
await listener.promise;
|
||||
});
|
||||
|
||||
add_task(function test_checkCompactionResult() {
|
||||
add_task(function test_checkCompactionResult2() {
|
||||
let tmpFile = gRootFolder.filePath;
|
||||
tmpFile.append("nstmp");
|
||||
Assert.ok(!tmpFile.exists());
|
||||
|
|
|
@ -6,7 +6,6 @@ run-sequentially =
|
|||
prefs =
|
||||
mailnews.imap.jsmodule=false
|
||||
|
||||
[test_compactOfflineStore.js]
|
||||
[test_copyThenMove.js]
|
||||
[test_customCommandReturnsFetchResponse.js]
|
||||
[test_dod.js]
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
[test_bccProperty.js]
|
||||
[test_bug460636.js]
|
||||
[test_chunkLastLF.js]
|
||||
[test_compactOfflineStore.js]
|
||||
[test_converterImap.js]
|
||||
[test_mailboxes.js]
|
||||
[test_imapPasswordFailure.js]
|
||||
|
|
|
@ -6,7 +6,6 @@ run-sequentially =
|
|||
prefs =
|
||||
mailnews.imap.jsmodule=false
|
||||
|
||||
[test_compactOfflineStore.js]
|
||||
[test_copyThenMove.js]
|
||||
[test_customCommandReturnsFetchResponse.js]
|
||||
[test_dontStatNoSelect.js]
|
||||
|
|
Загрузка…
Ссылка в новой задаче