From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- comm/mailnews/news/src/NewsDownloader.sys.mjs | 158 ++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 comm/mailnews/news/src/NewsDownloader.sys.mjs (limited to 'comm/mailnews/news/src/NewsDownloader.sys.mjs') diff --git a/comm/mailnews/news/src/NewsDownloader.sys.mjs b/comm/mailnews/news/src/NewsDownloader.sys.mjs new file mode 100644 index 0000000000..be94dfb96e --- /dev/null +++ b/comm/mailnews/news/src/NewsDownloader.sys.mjs @@ -0,0 +1,158 @@ +/* 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, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +var { MailServices } = ChromeUtils.import( + "resource:///modules/MailServices.jsm" +); +var { NntpUtils } = ChromeUtils.import("resource:///modules/NntpUtils.jsm"); + +/** + * Download articles in all subscribed newsgroups for offline use. + */ +export class NewsDownloader { + _logger = NntpUtils.logger; + + /** + * @param {nsIMsgWindow} msgWindow - The associated msg window. + * @param {nsIUrlListener} urlListener - Callback for the request. + */ + constructor(msgWindow, urlListener) { + this._msgWindow = msgWindow; + this._urlListener = urlListener; + + this._bundle = Services.strings.createBundle( + "chrome://messenger/locale/news.properties" + ); + } + + /** + * Actually start the download process. + */ + async start() { + this._logger.debug("Start downloading articles for offline use"); + let servers = MailServices.accounts.allServers.filter( + x => x.type == "nntp" + ); + // Download all servers concurrently. + await Promise.all( + servers.map(async server => { + let folders = server.rootFolder.descendants; + for (let folder of folders) { + if (folder.flags & Ci.nsMsgFolderFlags.Offline) { + // Download newsgroups set for offline use in a server one by one. + await this._downloadFolder(folder); + } + } + }) + ); + + this._urlListener.OnStopRunningUrl(null, Cr.NS_OK); + + this._logger.debug("Finished downloading articles for offline use"); + this._msgWindow.statusFeedback.showStatusString(""); + } + + /** + * Download articles in a newsgroup one by one. + * + * @param {nsIMsgFolder} folder - The newsgroup folder. + */ + async _downloadFolder(folder) { + this._logger.debug(`Start downloading ${folder.URI}`); + + folder.QueryInterface(Ci.nsIMsgNewsFolder).saveArticleOffline = true; + let keysToDownload = await this._getKeysToDownload(folder); + + let i = 0; + let total = keysToDownload.size; + for (let key of keysToDownload) { + await new Promise(resolve => { + MailServices.nntp.fetchMessage(folder, key, this._msgWindow, null, { + OnStartRunningUrl() {}, + OnStopRunningUrl() { + resolve(); + }, + }); + }); + this._msgWindow.statusFeedback.showStatusString( + this._bundle.formatStringFromName("downloadingArticlesForOffline", [ + ++i, + total, + folder.prettyName, + ]) + ); + } + + folder.saveArticleOffline = false; + } + + /** + * Use a search session to find articles that match the download settings + * and we don't already have. + * + * @param {nsIMsgFolder} folder - The newsgroup folder. + * @returns {Set} + */ + async _getKeysToDownload(folder) { + let searchSession = Cc[ + "@mozilla.org/messenger/searchSession;1" + ].createInstance(Ci.nsIMsgSearchSession); + let termValue = searchSession.createTerm().value; + + let downloadSettings = folder.downloadSettings; + if (downloadSettings.downloadUnreadOnly) { + termValue.attrib = Ci.nsMsgSearchAttrib.MsgStatus; + termValue.status = Ci.nsMsgMessageFlags.Read; + searchSession.addSearchTerm( + Ci.nsMsgSearchAttrib.MsgStatus, + Ci.nsMsgSearchOp.Isnt, + termValue, + true, + null + ); + } + if (downloadSettings.downloadByDate) { + termValue.attrib = Ci.nsMsgSearchAttrib.AgeInDays; + termValue.age = downloadSettings.ageLimitOfMsgsToDownload; + searchSession.addSearchTerm( + Ci.nsMsgSearchAttrib.AgeInDays, + Ci.nsMsgSearchOp.IsLessThan, + termValue, + true, + null + ); + } + termValue.attrib = Ci.nsMsgSearchAttrib.MsgStatus; + termValue.status = Ci.nsMsgMessageFlags.Offline; + searchSession.addSearchTerm( + Ci.nsMsgSearchAttrib.MsgStatus, + Ci.nsMsgSearchOp.Isnt, + termValue, + true, + null + ); + + let keysToDownload = new Set(); + await new Promise(resolve => { + searchSession.registerListener( + { + onSearchHit(hdr, folder) { + if (!(hdr.flags & Ci.nsMsgMessageFlags.Offline)) { + // Only need to download articles we don't already have. + keysToDownload.add(hdr.messageKey); + } + }, + onSearchDone: status => { + resolve(); + }, + }, + Ci.nsIMsgSearchSession.allNotifications + ); + searchSession.addScopeTerm(Ci.nsMsgSearchScope.localNews, folder); + searchSession.search(this._msgWindow); + }); + + return keysToDownload; + } +} -- cgit v1.2.3