/* -*- Mode: JavaScript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * 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/. */ Components.utils.import("resource:///modules/gloda/mimemsg.js"); Components.utils.import("resource:///modules/mailServices.js"); Components.utils.import("resource://gre/modules/Services.jsm"); // This global is for SeaMonkey compatibility. var gShowFeedSummary; var FeedMessageHandler = { gShowSummary: true, gToggle: false, kSelectOverrideWebPage: 0, kSelectOverrideSummary: 1, kSelectFeedDefault: 2, kOpenWebPage: 0, kOpenSummary: 1, kOpenToggleInMessagePane: 2, kOpenLoadInBrowser: 3, /** * How to load message on threadpane select. */ get onSelectPref() { return Services.prefs.getIntPref("rss.show.summary"); }, set onSelectPref(val) { Services.prefs.setIntPref("rss.show.summary", val); ReloadMessage(); }, /** * Load web page on threadpane select. */ get loadWebPageOnSelectPref() { return Services.prefs.getIntPref("rss.message.loadWebPageOnSelect") ? true : false; }, /** * How to load message on open (enter/dbl click in threadpane, contextmenu). */ get onOpenPref() { return Services.prefs.getIntPref("rss.show.content-base"); }, set onOpenPref(val) { Services.prefs.setIntPref("rss.show.content-base", val); }, /** * Determine if a message is a feed message. Prior to Tb15, a message had to * be in an rss acount type folder. In Tb15 and later, a flag is set on the * message itself upon initial store; the message can be moved to any folder. * * @param nsIMsgDBHdr aMsgHdr - the message. * * @return true if message is a feed, false if not. */ isFeedMessage: function(aMsgHdr) { return (aMsgHdr instanceof Components.interfaces.nsIMsgDBHdr) && ((aMsgHdr.flags & Components.interfaces.nsMsgMessageFlags.FeedMsg) || (aMsgHdr.folder && aMsgHdr.folder.server.type == "rss")); }, /** * Determine whether to show a feed message summary or load a web page in the * message pane. * * @param nsIMsgDBHdr aMsgHdr - the message. * @param bool aToggle - true if in toggle mode, false otherwise. * * @return true if summary is to be displayed, false if web page. */ shouldShowSummary: function(aMsgHdr, aToggle) { // Not a feed message, always show summary (the message). if (!this.isFeedMessage(aMsgHdr)) return true; // Notified of a summary reload when toggling, reset toggle and return. if (!aToggle && this.gToggle) return !(this.gToggle = false); let showSummary = true; this.gToggle = aToggle; // Thunderbird 2 rss messages with 'Show article summary' not selected, // ie message body constructed to show web page in an iframe, can't show // a summary - notify user. let browser = getBrowser(); let contentDoc = browser ? browser.contentDocument : null; let rssIframe = contentDoc ? contentDoc.getElementById("_mailrssiframe") : null; if (rssIframe) { if (this.gToggle || this.onSelectPref == this.kSelectOverrideSummary) this.gToggle = false; return false; } if (aToggle) // Toggle mode, flip value. return gShowFeedSummary = this.gShowSummary = !this.gShowSummary; let wintype = document.documentElement.getAttribute("windowtype"); let tabMail = document.getElementById("tabmail"); let messageTab = tabMail && tabMail.currentTabInfo.mode.type == "message"; let messageWindow = wintype == "mail:messageWindow"; switch (this.onSelectPref) { case this.kSelectOverrideWebPage: showSummary = false; break; case this.kSelectOverrideSummary: showSummary = true break; case this.kSelectFeedDefault: // Get quickmode per feed folder pref from feeds.rdf. If the feed // message is not in a feed account folder (hence the folder is not in // the feeds database), or FZ_QUICKMODE property is not found (possible // in pre renovation urls), err on the side of showing the summary. // For the former, toggle or global override is necessary; for the // latter, a show summary checkbox toggle in Subscribe dialog will set // one on the path to bliss. let folder = aMsgHdr.folder, targetRes; try { targetRes = FeedUtils.getParentTargetForChildResource( folder.URI, FeedUtils.FZ_QUICKMODE, folder.server); } catch (ex) { // Not in a feed account folder or other error. FeedUtils.log.info("FeedMessageHandler.shouldShowSummary: could not " + "get summary pref for this folder"); } showSummary = targetRes && targetRes.QueryInterface(Ci.nsIRDFLiteral). Value == "false" ? false : true; break; } gShowFeedSummary = this.gShowSummary = showSummary; if (messageWindow || messageTab) { // Message opened in either standalone window or tab, due to either // message open pref (we are here only if the pref is 0 or 1) or // contextmenu open. switch (this.onOpenPref) { case this.kOpenToggleInMessagePane: // Opened by contextmenu, use the value derived above. // XXX: allow a toggle via crtl? break; case this.kOpenWebPage: showSummary = false; break; case this.kOpenSummary: showSummary = true; break; } } // Auto load web page in browser on select, per pref; shouldShowSummary() is // always called first to 1)test if feed, 2)get summary pref, so do it here. if (this.loadWebPageOnSelectPref) setTimeout(FeedMessageHandler.loadWebPage, 20, aMsgHdr, {browser:true}); return showSummary; }, /** * Load a web page for feed messages. Use MsgHdrToMimeMessage() to get * the content-base url from the message headers. We cannot rely on * currentHeaderData; it has not yet been streamed at our entry point in * displayMessageChanged(), and in the case of a collapsed message pane it * is not streamed. * * @param nsIMsgDBHdr aMessageHdr - the message. * @param {obj} aWhere - name value=true pair, where name is in: * 'messagepane', 'browser', 'tab', 'window'. */ loadWebPage: function(aMessageHdr, aWhere) { MsgHdrToMimeMessage(aMessageHdr, null, function(aMsgHdr, aMimeMsg) { if (aMimeMsg && aMimeMsg.headers["content-base"] && aMimeMsg.headers["content-base"][0]) { let url = aMimeMsg.headers["content-base"], uri; try { let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"] .createInstance(Ci.nsIScriptableUnicodeConverter); converter.charset = "UTF-8"; url = converter.ConvertToUnicode(url); uri = Services.io.newURI(url, null, null); url = uri.spec; } catch (ex) { FeedUtils.log.info("FeedMessageHandler.loadWebPage: " + "invalid Content-Base header url - " + url); return; } if (aWhere.browser) Components.classes["@mozilla.org/uriloader/external-protocol-service;1"] .getService(Components.interfaces.nsIExternalProtocolService) .loadURI(uri); else if (aWhere.messagepane) { let loadFlag = getBrowser().webNavigation.LOAD_FLAGS_NONE; getBrowser().webNavigation.loadURI(url, loadFlag, null, null, null); } else if (aWhere.tab) openContentTab(url, "tab", "^"); else if (aWhere.window) openContentTab(url, "window", "^"); } else FeedUtils.log.info("FeedMessageHandler.loadWebPage: could not get " + "Content-Base header url for this message"); }); }, /** * Display summary or load web page for feed messages. Caller should already * know if the message is a feed message. * * @param nsIMsgDBHdr aMsgHdr - the message. * @param bool aShowSummary - true if summary is to be displayed, false if * web page. */ setContent: function(aMsgHdr, aShowSummary) { if (aShowSummary) { // Only here if toggling to summary in 3pane. if (this.gToggle && gDBView && GetNumSelectedMessages() == 1) ReloadMessage(); } else { let browser = getBrowser(); if (browser && browser.contentDocument && browser.contentDocument.body) browser.contentDocument.body.hidden = true; // If in a non rss folder, hide possible remote content bar on a web // page load, as it doesn't apply. if ("msgNotificationBar" in window) gMessageNotificationBar.clearMsgNotifications(); this.loadWebPage(aMsgHdr, {messagepane:true}); this.gToggle = false; } } } function openSubscriptionsDialog(aFolder) { // Check for an existing feed subscriptions window and focus it. let subscriptionsWindow = Services.wm.getMostRecentWindow("Mail:News-BlogSubscriptions"); if (subscriptionsWindow) { if (aFolder) { subscriptionsWindow.FeedSubscriptions.selectFolder(aFolder); subscriptionsWindow.FeedSubscriptions.mView.treeBox.ensureRowIsVisible( subscriptionsWindow.FeedSubscriptions.mView.selection.currentIndex); } subscriptionsWindow.focus(); } else { window.openDialog("chrome://messenger-newsblog/content/feed-subscriptions.xul", "", "centerscreen,chrome,dialog=no,resizable", { folder: aFolder}); } } // Special case attempts to reply/forward/edit as new RSS articles. For // messages stored prior to Tb15, we are here only if the message's folder's // account server is rss and feed messages moved to other types will have their // summaries loaded, as viewing web pages only happened in an rss account. // The user may choose whether to load a summary or web page link by ensuring // the current feed message is being viewed as either a summary or web page. function openComposeWindowForRSSArticle(aMsgComposeWindow, aMsgHdr, aMessageUri, aType, aFormat, aIdentity, aMsgWindow) { // Ensure right content is handled for web pages in window/tab. let tabmail = document.getElementById("tabmail"); let is3pane = tabmail && tabmail.selectedTab && tabmail.selectedTab.mode ? tabmail.selectedTab.mode.type == "folder" : false; let showingwebpage = ("FeedMessageHandler" in window) && !is3pane && FeedMessageHandler.onOpenPref == FeedMessageHandler.kOpenWebPage; if (gShowFeedSummary && !showingwebpage) { // The user is viewing the summary. MailServices.compose.OpenComposeWindow(aMsgComposeWindow, aMsgHdr, aMessageUri, aType, aFormat, aIdentity, aMsgWindow); } else { // Set up the compose message and get the feed message's web page link. let Cc = Components.classes; let Ci = Components.interfaces; let msgHdr = aMsgHdr; let type = aType; let msgComposeType = Ci.nsIMsgCompType; let subject = msgHdr.mime2DecodedSubject; let fwdPrefix = Services.prefs.getCharPref("mail.forward_subject_prefix"); fwdPrefix = fwdPrefix ? fwdPrefix + ": " : ""; let params = Cc["@mozilla.org/messengercompose/composeparams;1"] .createInstance(Ci.nsIMsgComposeParams); let composeFields = Cc["@mozilla.org/messengercompose/composefields;1"] .createInstance(Ci.nsIMsgCompFields); if (type == msgComposeType.Reply || type == msgComposeType.ReplyAll || type == msgComposeType.ReplyToSender || type == msgComposeType.ReplyToGroup || type == msgComposeType.ReplyToSenderAndGroup) { subject = "Re: " + subject; } else if (type == msgComposeType.ForwardInline || type == msgComposeType.ForwardAsAttachment) { subject = fwdPrefix + subject; } params.composeFields = composeFields; params.composeFields.subject = subject; params.composeFields.characterSet = msgHdr.Charset; params.composeFields.body = ""; params.bodyIsLink = false; params.identity = aIdentity; try { // The feed's web page url is stored in the Content-Base header. MsgHdrToMimeMessage(msgHdr, null, function(aMsgHdr, aMimeMsg) { if (aMimeMsg && aMimeMsg.headers["content-base"] && aMimeMsg.headers["content-base"][0]) { let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"] .createInstance(Ci.nsIScriptableUnicodeConverter); converter.charset = "UTF-8"; let url = converter.ConvertToUnicode(aMimeMsg.headers["content-base"]); params.composeFields.body = url; params.bodyIsLink = true; MailServices.compose.OpenComposeWindowWithParams(null, params); } else // No content-base url, use the summary. MailServices.compose.OpenComposeWindow(aMsgComposeWindow, aMsgHdr, aMessageUri, aType, aFormat, aIdentity, aMsgWindow); }, false, {saneBodySize: true}); } catch (ex) { // Error getting header, use the summary. MailServices.compose.OpenComposeWindow(aMsgComposeWindow, aMsgHdr, aMessageUri, aType, aFormat, aIdentity, aMsgWindow); } } }