From 3613b75b68c5edb1e955250b4c653428e77b3315 Mon Sep 17 00:00:00 2001 From: "scott%scott-macgregor.org" Date: Tue, 15 Feb 2005 00:31:07 +0000 Subject: [PATCH] Bug #282174 --> Podcasting support for Thunderbird Add a custom mime part header that specifies a URL for the attachment. This mime header is used by Thunderbird's RSS reader and eventually by the code to handle storing attachments separately from the message. Removes an obsolete attachment attribute called notDownloaded and replaces it with isExternalAttachment. sr=bienvenu a=sspitzer --- mail/base/content/msgHdrViewOverlay.js | 15 ++-- mail/extensions/newsblog/content/FeedItem.js | 69 +++++++++++++++++-- .../newsblog/content/feed-parser.js | 6 ++ mailnews/base/public/nsIMessenger.idl | 6 +- .../resources/content/msgHdrViewOverlay.js | 14 ++-- mailnews/base/src/nsMessenger.cpp | 26 ++++--- mailnews/compose/public/nsIMsgSend.idl | 2 +- .../mime/emitters/src/nsMimeBaseEmitter.cpp | 4 +- .../mime/emitters/src/nsMimeBaseEmitter.h | 2 +- .../mime/emitters/src/nsMimeHtmlEmitter.cpp | 4 +- .../mime/emitters/src/nsMimeHtmlEmitter.h | 2 +- .../mime/emitters/src/nsMimeXmlEmitter.cpp | 2 +- mailnews/mime/emitters/src/nsMimeXmlEmitter.h | 2 +- mailnews/mime/public/nsIMimeMiscStatus.idl | 32 ++++----- mailnews/mime/src/mimei.cpp | 24 +++++-- mailnews/mime/src/mimei.h | 2 + mailnews/mime/src/mimemoz2.cpp | 28 ++++---- mailnews/mime/src/mimemoz2.h | 2 +- 18 files changed, 165 insertions(+), 77 deletions(-) diff --git a/mail/base/content/msgHdrViewOverlay.js b/mail/base/content/msgHdrViewOverlay.js index 6c87413e400..8f93cfa33b8 100644 --- a/mail/base/content/msgHdrViewOverlay.js +++ b/mail/base/content/msgHdrViewOverlay.js @@ -151,7 +151,7 @@ var currentHeaderData = {}; // .contentType --> the content type of the attachment // url --> an imap, or mailbox url which can be used to fetch the message // uri --> an RDF URI which refers to the message containig the attachment -// notDownloaded --> boolean flag stating whether the attachment is downloaded or not. +// isExternalAttachment --> boolean flag stating whether the attachment is an attachment which is a URL that refers to the attachment location var currentAttachments = new Array(); // createHeaderEntry --> our constructor method which creates a header Entry @@ -413,7 +413,7 @@ var messageHeaderSink = { this.onEndHeaders(); }, - handleAttachment: function(contentType, url, displayName, uri, notDownloaded) + handleAttachment: function(contentType, url, displayName, uri, isExternalAttachment) { // presentation level change....don't show vcards as external attachments in the UI. // libmime already renders them inline. @@ -430,7 +430,7 @@ var messageHeaderSink = { } } - currentAttachments.push (new createNewAttachmentInfo(contentType, url, displayName, uri, notDownloaded)); + currentAttachments.push (new createNewAttachmentInfo(contentType, url, displayName, uri, isExternalAttachment)); // if we have an attachment, set the MSG_FLAG_ATTACH flag on the hdr // this will cause the "message with attachment" icon to show up // in the thread pane @@ -1056,13 +1056,13 @@ function CreateFilter(emailAddressNode) // createnewAttachmentInfo --> constructor method for creating new attachment object which goes into the // data attachment array. -function createNewAttachmentInfo(contentType, url, displayName, uri, notDownloaded) +function createNewAttachmentInfo(contentType, url, displayName, uri, isExternalAttachment) { this.contentType = contentType; this.url = url; this.displayName = displayName; this.uri = uri; - this.notDownloaded = notDownloaded; + this.isExternalAttachment = isExternalAttachment; } function dofunc(aFunctionName, aFunctionArg) @@ -1080,7 +1080,7 @@ function saveAttachment(aAttachment) messenger.saveAttachment(aAttachment.contentType, aAttachment.url, encodeURIComponent(aAttachment.displayName), - aAttachment.messageUri); + aAttachment.messageUri, aAttachment.isExternalAttachment); } function openAttachment(aAttachment) @@ -1088,7 +1088,7 @@ function openAttachment(aAttachment) messenger.openAttachment(aAttachment.contentType, aAttachment.url, encodeURIComponent(aAttachment.displayName), - aAttachment.messageUri); + aAttachment.messageUri, aAttachment.isExternalAttachment); } function printAttachment(aAttachment) @@ -1167,6 +1167,7 @@ function cloneAttachment(aAttachment) obj.url = aAttachment.url; obj.displayName = aAttachment.displayName; obj.messageUri = aAttachment.uri; + obj.isExternalAttachment = aAttachment.isExternalAttachment; return obj; } diff --git a/mail/extensions/newsblog/content/FeedItem.js b/mail/extensions/newsblog/content/FeedItem.js index aad2b823a2c..f7ee6beb0a8 100755 --- a/mail/extensions/newsblog/content/FeedItem.js +++ b/mail/extensions/newsblog/content/FeedItem.js @@ -42,6 +42,8 @@ const SECONDS_TO_MILLISECONDS = 1000; const MINUTES_TO_MILLISECONDS = MINUTES_TO_SECONDS * SECONDS_TO_MILLISECONDS; const HOURS_TO_MILLISECONDS = HOURS_TO_MINUTES * MINUTES_TO_MILLISECONDS; const MSG_FLAG_NEW = 0x10000; +const ENCLOSURE_BOUNDARY_PREFIX = "--------------"; // 14 dashes +const ENCLOSURE_HEADER_BOUNDARY_PREFIX = "------------"; // 12 dashes const MESSAGE_TEMPLATE = "\n\ \n\ @@ -108,6 +110,7 @@ FeedItem.prototype = feed: null, description: null, content: null, + enclosure: null, // we currently only support one enclosure per feed item... title: "(no subject)", // TO DO: this needs to be localized author: "anonymous", mURL: null, @@ -400,12 +403,26 @@ FeedItem.prototype = 'From: ' + this.author + '\n' + 'MIME-Version: 1.0\n' + 'Subject: ' + this.title + '\n' + - 'Content-Type: text/html; charset=' + this.characterSet + '\n' + 'Content-Transfer-Encoding: 8bit\n' + - 'Content-Base: ' + this.mURL + '\n' + - '\n' + - this.content; - + 'Content-Base: ' + this.mURL + '\n'; + + if (this.enclosure && this.enclosure.mFileName) + { + var boundaryID = source.length + this.enclosure.mLength; + source += 'Content-Type: multipart/mixed;\n boundary="' + ENCLOSURE_HEADER_BOUNDARY_PREFIX + boundaryID + '"' + '\n\n' + + 'This is a multi-part message in MIME format.\n' + ENCLOSURE_BOUNDARY_PREFIX + boundaryID + '\n' + + 'Content-Type: text/html; charset=' + + this.characterSet + '\n' + + 'Content-Transfer-Encoding: 8bit\n' + + this.content; + source += this.enclosure.convertToAttachment(boundaryID); + } + else + { + source += 'Content-Type: text/html; charset=' + this.characterSet + '\n' + + '\n' + this.content; + + } + debug(this.identity + " is " + source.length + " characters long"); // Get the folder and database storing the feed's messages and headers. @@ -417,6 +434,48 @@ FeedItem.prototype = } }; + +// A feed enclosure is to RSS what an attachment is for e-mail. We make enclosures look +// like attachments in the UI. + +function FeedEnclosure(aURL, aContentType, aLength) +{ + this.mURL = aURL; + this.mContentType = aContentType; + this.mLength = aLength; + + // generate a fileName from the URL + if (this.mURL) + { + var ioService = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService); + var enclosureURL = ioService.newURI(this.mURL, null, null).QueryInterface(Components.interfaces.nsIURL); + if (enclosureURL) + this.mFileName = enclosureURL.fileName; + } +} + +FeedEnclosure.prototype = +{ + mURL: "", + mContentType: "", + mLength: 0, + mFileName: "", + + // returns a string that looks like an e-mail attachment + // which represents the enclosure. + convertToAttachment: function(aBoundaryID) + { + return '\n' + + ENCLOSURE_BOUNDARY_PREFIX + aBoundaryID + '\n' + + 'Content-Type: ' + this.mContentType + '; name="' + this.mFileName + '"\n' + + 'X-Mozilla-External-Attachment-URL: ' + this.mURL + '\n' + + 'Content-Disposition: attachment; filename="' + this.mFileName + '"\n\n' + + 'This MIME attachment is stored separately from the message.\n' + + ENCLOSURE_BOUNDARY_PREFIX + aBoundaryID + '--' + '\n'; + + } +}; + function W3CToIETFDate(dateString) { // Converts a W3C-DTF (subset of ISO 8601) date string to an IETF date string. // W3C-DTF is described in this note: http://www.w3.org/TR/NOTE-datetime diff --git a/mail/extensions/newsblog/content/feed-parser.js b/mail/extensions/newsblog/content/feed-parser.js index 38c8dbb6900..d5a2b02bef1 100644 --- a/mail/extensions/newsblog/content/feed-parser.js +++ b/mail/extensions/newsblog/content/feed-parser.js @@ -162,6 +162,12 @@ FeedParser.prototype = if (content) item.content = converter.ConvertFromUnicode(content); + // Handle an enclosure (if present) + var enclosureNode = itemNode.getElementsByTagName("enclosure")[0]; + if (enclosureNode) + item.enclosure = new FeedEnclosure(enclosureNode.getAttribute("url"), + enclosureNode.getAttribute("type"), + enclosureNode.getAttribute("length")); parsedItems[i] = item; } diff --git a/mailnews/base/public/nsIMessenger.idl b/mailnews/base/public/nsIMessenger.idl index 3a892d8538b..b2e842af214 100644 --- a/mailnews/base/public/nsIMessenger.idl +++ b/mailnews/base/public/nsIMessenger.idl @@ -47,7 +47,7 @@ interface nsIDOMWindowInternal; interface nsITransactionManager; interface nsIMsgMessageService; -[scriptable, uuid(f0f5b18b-9fb8-44d8-ad41-8d837d89fa0c)] +[scriptable, uuid(15AECD24-4687-43d6-84DC-0BA21F093244)] interface nsIMessenger : nsISupports { const long eUnknown = 0; @@ -101,8 +101,8 @@ interface nsIMessenger : nsISupports { void sendUnsentMessages(in nsIMsgIdentity aIdentity, in nsIMsgWindow aMsgWindow); void SetDocumentCharset(in string characterSet); void saveAs(in string aURI, in boolean aAsFile, in nsIMsgIdentity aIdentity, in wstring aMsgFilename); - void openAttachment(in string contentTpe, in string url, in string displayName, in string messageUri); - void saveAttachment(in string contentTpe, in string url, in string displayName, in string messageUri); + void openAttachment(in string contentTpe, in string url, in string displayName, in string messageUri, in boolean isExternalAttachment); + void saveAttachment(in string contentTpe, in string url, in string displayName, in string messageUri, in boolean isExternalAttachment); void saveAllAttachments(in unsigned long count, [array, size_is(count)] in string contentTypeArray, [array, size_is(count)] in string urlArray, [array, size_is(count)] in string displayNameArray, [array, size_is(count)] in string messageUriArray); diff --git a/mailnews/base/resources/content/msgHdrViewOverlay.js b/mailnews/base/resources/content/msgHdrViewOverlay.js index 4678ea3ba67..00ab5059776 100644 --- a/mailnews/base/resources/content/msgHdrViewOverlay.js +++ b/mailnews/base/resources/content/msgHdrViewOverlay.js @@ -138,7 +138,7 @@ var currentHeaderData = {}; // .contentType --> the content type of the attachment // url --> an imap, or mailbox url which can be used to fetch the message // uri --> an RDF URI which refers to the message containig the attachment -// notDownloaded --> boolean flag stating whether the attachment is downloaded or not. +// isExternalAttachment --> boolean flag stating whether the attachment is external or not. var currentAttachments = new Array(); // createHeaderEntry --> our constructor method which creates a header Entry @@ -380,7 +380,7 @@ var messageHeaderSink = { this.onEndHeaders(); }, - handleAttachment: function(contentType, url, displayName, uri, notDownloaded) + handleAttachment: function(contentType, url, displayName, uri, isExternalAttachment) { // presentation level change....don't show vcards as external attachments in the UI. // libmime already renders them inline. @@ -396,7 +396,7 @@ var messageHeaderSink = { } } - currentAttachments.push (new createNewAttachmentInfo(contentType, url, displayName, uri, notDownloaded)); + currentAttachments.push (new createNewAttachmentInfo(contentType, url, displayName, uri, isExternalAttachment)); // if we have an attachment, set the MSG_FLAG_ATTACH flag on the hdr // this will cause the "message with attachment" icon to show up // in the thread pane @@ -900,13 +900,13 @@ function CreateFilter(emailAddressNode) // createnewAttachmentInfo --> constructor method for creating new attachment object which goes into the // data attachment array. -function createNewAttachmentInfo(contentType, url, displayName, uri, notDownloaded) +function createNewAttachmentInfo(contentType, url, displayName, uri, isExternalAttachment) { this.contentType = contentType; this.url = url; this.displayName = displayName; this.uri = uri; - this.notDownloaded = notDownloaded; + this.isExternalAttachment = isExternalAttachment; } createNewAttachmentInfo.prototype.saveAttachment = function saveAttachment() @@ -914,7 +914,7 @@ createNewAttachmentInfo.prototype.saveAttachment = function saveAttachment() messenger.saveAttachment(this.contentType, this.url, encodeURIComponent(this.displayName), - this.uri); + this.uri, false); } createNewAttachmentInfo.prototype.openAttachment = function openAttachment() @@ -922,7 +922,7 @@ createNewAttachmentInfo.prototype.openAttachment = function openAttachment() messenger.openAttachment(this.contentType, this.url, encodeURIComponent(this.displayName), - this.uri); + this.uri, false); } createNewAttachmentInfo.prototype.printAttachment = function printAttachment() diff --git a/mailnews/base/src/nsMessenger.cpp b/mailnews/base/src/nsMessenger.cpp index 8d6a086af8d..608e4cd478a 100644 --- a/mailnews/base/src/nsMessenger.cpp +++ b/mailnews/base/src/nsMessenger.cpp @@ -722,15 +722,22 @@ nsMessenger::SaveAttachment(nsIFileSpec * fileSpec, NS_IMETHODIMP nsMessenger::OpenAttachment(const char * aContentType, const char * aURL, const - char * aDisplayName, const char * aMessageUri) + char * aDisplayName, const char * aMessageUri, PRBool aIsExternalAttachment) { nsresult rv = NS_OK; - nsCOMPtr messageService; - rv = GetMessageServiceFromURI(aMessageUri, getter_AddRefs(messageService)); - if (messageService) + + // open external attachments inside our message pane which in turn should trigger the + // helper app dialog... + if (aIsExternalAttachment) + rv = OpenURL(aURL); + else { - rv = messageService->OpenAttachment(aContentType, aDisplayName, aURL, aMessageUri, mDocShell, mMsgWindow, nsnull); + nsCOMPtr messageService; + rv = GetMessageServiceFromURI(aMessageUri, getter_AddRefs(messageService)); + if (messageService) + rv = messageService->OpenAttachment(aContentType, aDisplayName, aURL, aMessageUri, mDocShell, mMsgWindow, nsnull); } + return rv; } @@ -767,13 +774,14 @@ nsMessenger::SaveAttachmentToFolder(const char * contentType, const char * url, NS_IMETHODIMP nsMessenger::SaveAttachment(const char * contentType, const char * url, - const char * displayName, const char * messageUri) + const char * displayName, const char * messageUri, PRBool aIsExternalAttachment) { NS_ENSURE_ARG_POINTER(url); -#ifdef DEBUG_MESSENGER - printf("nsMessenger::SaveAttachment(%s)\n",url); -#endif + // open external attachments inside our message pane which in turn should trigger the + // helper app dialog... + if (aIsExternalAttachment) + return OpenURL(url); nsresult rv = NS_ERROR_OUT_OF_MEMORY; nsCOMPtr filePicker = diff --git a/mailnews/compose/public/nsIMsgSend.idl b/mailnews/compose/public/nsIMsgSend.idl index f64c0b76107..d3cebfe3810 100644 --- a/mailnews/compose/public/nsIMsgSend.idl +++ b/mailnews/compose/public/nsIMsgSend.idl @@ -116,7 +116,7 @@ struct nsMsgAttachmentData char *x_mac_type, *x_mac_creator; // Mac-specific data that should show up as optional parameters // to the content-type header. - PRBool notDownloaded; // Flag for IMAP parts on demand status + PRBool isExternalAttachment; // Flag for determining if the attachment is external }; diff --git a/mailnews/mime/emitters/src/nsMimeBaseEmitter.cpp b/mailnews/mime/emitters/src/nsMimeBaseEmitter.cpp index 9e1e73044b7..b6aa4ecbd05 100644 --- a/mailnews/mime/emitters/src/nsMimeBaseEmitter.cpp +++ b/mailnews/mime/emitters/src/nsMimeBaseEmitter.cpp @@ -392,7 +392,7 @@ nsMimeBaseEmitter::GetOutputListener(nsIStreamListener **listener) // Attachment handling routines nsresult nsMimeBaseEmitter::StartAttachment(const char *name, const char *contentType, const char *url, - PRBool aNotDownloaded) + PRBool aIsExternalAttachment) { // Ok, now we will setup the attachment info mCurrentAttachment = (attachmentInfoType *) PR_NEWZAP(attachmentInfoType); @@ -403,7 +403,7 @@ nsMimeBaseEmitter::StartAttachment(const char *name, const char *contentType, co mCurrentAttachment->displayName = nsCRT::strdup(name); mCurrentAttachment->urlSpec = nsCRT::strdup(url); mCurrentAttachment->contentType = nsCRT::strdup(contentType); - mCurrentAttachment->notDownloaded = aNotDownloaded; + mCurrentAttachment->isExternalAttachment = aIsExternalAttachment; } return NS_OK; diff --git a/mailnews/mime/emitters/src/nsMimeBaseEmitter.h b/mailnews/mime/emitters/src/nsMimeBaseEmitter.h index fca6510d905..44cd56fc63f 100644 --- a/mailnews/mime/emitters/src/nsMimeBaseEmitter.h +++ b/mailnews/mime/emitters/src/nsMimeBaseEmitter.h @@ -73,7 +73,7 @@ typedef struct { char *displayName; char *urlSpec; char *contentType; - PRBool notDownloaded; + PRBool isExternalAttachment; } attachmentInfoType; // diff --git a/mailnews/mime/emitters/src/nsMimeHtmlEmitter.cpp b/mailnews/mime/emitters/src/nsMimeHtmlEmitter.cpp index 4f02226665d..e38cd057025 100644 --- a/mailnews/mime/emitters/src/nsMimeHtmlEmitter.cpp +++ b/mailnews/mime/emitters/src/nsMimeHtmlEmitter.cpp @@ -368,7 +368,7 @@ nsresult nsMimeHtmlDisplayEmitter::StartAttachment(const char *name, const char *contentType, const char *url, - PRBool aNotDownloaded) + PRBool aIsExternalAttachment) { nsresult rv = NS_OK; nsCOMPtr headerSink; @@ -412,7 +412,7 @@ nsMimeHtmlDisplayEmitter::StartAttachment(const char *name, headerSink->HandleAttachment(contentType, url /* was escapedUrl */, unicodeHeaderValue, uriString, - aNotDownloaded); + aIsExternalAttachment); nsCRT::free(escapedUrl); mSkipAttachment = PR_TRUE; diff --git a/mailnews/mime/emitters/src/nsMimeHtmlEmitter.h b/mailnews/mime/emitters/src/nsMimeHtmlEmitter.h index 6517945bdf8..a33c0652370 100644 --- a/mailnews/mime/emitters/src/nsMimeHtmlEmitter.h +++ b/mailnews/mime/emitters/src/nsMimeHtmlEmitter.h @@ -62,7 +62,7 @@ public: // Attachment handling routines NS_IMETHOD StartAttachment(const char *name, const char *contentType, const char *url, - PRBool aNotDownloaded); + PRBool aIsExternalAttachment); NS_IMETHOD AddAttachmentField(const char *field, const char *value); NS_IMETHOD EndAttachment(); NS_IMETHOD EndAllAttachments(); diff --git a/mailnews/mime/emitters/src/nsMimeXmlEmitter.cpp b/mailnews/mime/emitters/src/nsMimeXmlEmitter.cpp index a8dcfd38cc7..354b19f6c96 100644 --- a/mailnews/mime/emitters/src/nsMimeXmlEmitter.cpp +++ b/mailnews/mime/emitters/src/nsMimeXmlEmitter.cpp @@ -186,7 +186,7 @@ nsMimeXmlEmitter::EndHeader() // Attachment handling routines nsresult nsMimeXmlEmitter::StartAttachment(const char *name, const char *contentType, const char *url, - PRBool aNotDownloaded) + PRBool aIsExternalAttachment) { char buf[128]; diff --git a/mailnews/mime/emitters/src/nsMimeXmlEmitter.h b/mailnews/mime/emitters/src/nsMimeXmlEmitter.h index 4210cba6ea7..024dda2b804 100644 --- a/mailnews/mime/emitters/src/nsMimeXmlEmitter.h +++ b/mailnews/mime/emitters/src/nsMimeXmlEmitter.h @@ -61,7 +61,7 @@ public: // Attachment handling routines NS_IMETHOD StartAttachment(const char *name, const char *contentType, const char *url, - PRBool aNotDownloaded); + PRBool aIsExternalAttachment); NS_IMETHOD AddAttachmentField(const char *field, const char *value); NS_IMETHOD EndAttachment(); diff --git a/mailnews/mime/public/nsIMimeMiscStatus.idl b/mailnews/mime/public/nsIMimeMiscStatus.idl index 7741793ed2f..d280eeb162e 100644 --- a/mailnews/mime/public/nsIMimeMiscStatus.idl +++ b/mailnews/mime/public/nsIMimeMiscStatus.idl @@ -61,25 +61,25 @@ interface nsIMimeMiscStatus : nsISupports{ // that are discovered by mime. We can use this when displaying a message to update // the msg header in JS. [scriptable, uuid(34362984-C7A0-47b2-8BA3-6B67C4AD986F)] -interface nsIMsgHeaderSink : nsISupports { +interface nsIMsgHeaderSink : nsISupports +{ + // You must finish consuming the iterators before returning from processHeaders. aHeaderNames and aHeaderValues will ALWAYS have the same + // number of elements in them + void processHeaders(in nsIUTF8StringEnumerator aHeaderNames, in nsIUTF8StringEnumerator aHeaderValues, in boolean dontCollectAddress); - // You must finish consuming the iterators before returning from processHeaders. aHeaderNames and aHeaderValues will ALWAYS have the same - // number of elements in them - void processHeaders(in nsIUTF8StringEnumerator aHeaderNames, in nsIUTF8StringEnumerator aHeaderValues, in boolean dontCollectAddress); - - void handleAttachment(in string contentType, in string url, in wstring displayName, in string - uri, in boolean aNotDownloaded); - void onEndAllAttachments(); + void handleAttachment(in string contentType, in string url, in wstring displayName, in string uri, + in boolean aNotDownloaded); + void onEndAllAttachments(); - // onEndMsgHeaders is called after libmime is done processing a message. At this point it is safe for - // elements like the UI to update junk status, process return receipts, etc. - void onEndMsgHeaders(in nsIMsgMailNewsUrl url); + // onEndMsgHeaders is called after libmime is done processing a message. At this point it is safe for + // elements like the UI to update junk status, process return receipts, etc. + void onEndMsgHeaders(in nsIMsgMailNewsUrl url); - // onEndMsgDownload is triggered when layout says it is actually done rendering - // the message body in the UI. - void onEndMsgDownload(in nsIMsgMailNewsUrl url); + // onEndMsgDownload is triggered when layout says it is actually done rendering + // the message body in the UI. + void onEndMsgDownload(in nsIMsgMailNewsUrl url); - attribute nsISupports securityInfo; + attribute nsISupports securityInfo; - void onMsgHasRemoteContent(in nsIMsgDBHdr aMsgHdr); + void onMsgHasRemoteContent(in nsIMsgDBHdr aMsgHdr); }; diff --git a/mailnews/mime/src/mimei.cpp b/mailnews/mime/src/mimei.cpp index aad015d1343..150c3a46e29 100644 --- a/mailnews/mime/src/mimei.cpp +++ b/mailnews/mime/src/mimei.cpp @@ -112,6 +112,7 @@ void getMsgHdrForCurrentURL(MimeDisplayOptions *opts, nsIMsgDBHdr ** aMsgHdr); #endif #define IMAP_EXTERNAL_CONTENT_HEADER "X-Mozilla-IMAP-Part" +#define EXTERNAL_ATTACHMENT_URL_HEADER "X-Mozilla-External-Attachment-URL" /* ========================================================================== Allocation and destruction @@ -1069,14 +1070,23 @@ mime_part_address(MimeObject *obj) char * mime_imap_part_address(MimeObject *obj) { - char *imap_part = 0; - if (!obj || !obj->headers) - return 0; - - imap_part = MimeHeaders_get(obj->headers, - IMAP_EXTERNAL_CONTENT_HEADER, PR_FALSE, PR_FALSE); + if (!obj || !obj->headers) + return 0; + else + return MimeHeaders_get(obj->headers, IMAP_EXTERNAL_CONTENT_HEADER, PR_FALSE, PR_FALSE); +} - return imap_part; +/* Returns a full URL if the current mime object has a EXTERNAL_ATTACHMENT_URL_HEADER + header. + Return value must be freed by the caller. +*/ +char * +mime_external_attachment_url(MimeObject *obj) +{ + if (!obj || !obj->headers) + return 0; + else + return MimeHeaders_get(obj->headers, EXTERNAL_ATTACHMENT_URL_HEADER, PR_FALSE, PR_FALSE); } #ifdef ENABLE_SMIME diff --git a/mailnews/mime/src/mimei.h b/mailnews/mime/src/mimei.h index 080d4a53735..6ed77a2afc4 100644 --- a/mailnews/mime/src/mimei.h +++ b/mailnews/mime/src/mimei.h @@ -301,6 +301,8 @@ extern char *mime_part_address(MimeObject *obj); */ extern char *mime_imap_part_address(MimeObject *obj); +extern char *mime_external_attachment_url(MimeObject *obj); + /* Puts a part-number into a URL. If append_p is true, then the part number is appended to any existing part-number already in that URL; otherwise, it replaces it. diff --git a/mailnews/mime/src/mimemoz2.cpp b/mailnews/mime/src/mimemoz2.cpp index fa7a59dfcad..f9f178bd80f 100644 --- a/mailnews/mime/src/mimemoz2.cpp +++ b/mailnews/mime/src/mimemoz2.cpp @@ -195,8 +195,6 @@ ProcessBodyAsAttachment(MimeObject *obj, nsMsgAttachmentData **data) // if this is an IMAP part. tmpURL = mime_set_url_imap_part(url, id_imap, id); rv = nsMimeNewURI(&(tmp->url), tmpURL, nsnull); - - tmp->notDownloaded = PR_TRUE; } else { @@ -304,6 +302,7 @@ GenerateAttachmentData(MimeObject *object, const char *aMessageURL, MimeDisplayO nsXPIDLCString imappart; nsXPIDLCString part; PRBool isIMAPPart; + PRBool isExternalAttachment = PR_FALSE; /* be sure the object has not be marked as Not to be an attachment */ if (object->dontShowAsAttachment) @@ -333,7 +332,15 @@ GenerateAttachmentData(MimeObject *object, const char *aMessageURL, MimeDisplayO PR_Free(no_part_url); } else - urlSpec = mime_set_url_part(aMessageURL, part.get(), PR_TRUE); + { + // if the mime object contains an external attachment URL, then use it, otherwise + // fall back to creating an attachment url based on the message URI and the + // part number. + urlSpec = mime_external_attachment_url(object); + isExternalAttachment = urlSpec ? PR_TRUE : PR_FALSE; + if (!urlSpec) + urlSpec = mime_set_url_part(aMessageURL, part.get(), PR_TRUE); + } } if (!urlSpec) @@ -341,6 +348,7 @@ GenerateAttachmentData(MimeObject *object, const char *aMessageURL, MimeDisplayO if ((options->format_out == nsMimeOutput::nsMimeMessageBodyDisplay) && (nsCRT::strncasecmp(aMessageURL, urlSpec, strlen(urlSpec)) == 0)) return NS_OK; + nsMsgAttachmentData *tmp = &(aAttachData[attIndex++]); nsresult rv = nsMimeNewURI(&(tmp->url), urlSpec, nsnull); @@ -351,6 +359,7 @@ GenerateAttachmentData(MimeObject *object, const char *aMessageURL, MimeDisplayO tmp->real_type = object->content_type ? nsCRT::strdup(object->content_type) : nsnull; tmp->real_encoding = object->encoding ? nsCRT::strdup(object->encoding) : nsnull; + tmp->isExternalAttachment = isExternalAttachment; PRInt32 i; char *charset = nsnull; @@ -453,13 +462,6 @@ GenerateAttachmentData(MimeObject *object, const char *aMessageURL, MimeDisplayO } ValidateRealName(tmp, object->headers); - if (isIMAPPart) - { - // If we get here, we should mark this attachment as not being - // downloaded. - tmp->notDownloaded = PR_TRUE; - } - return NS_OK; } @@ -629,7 +631,7 @@ NotifyEmittersOfAttachmentList(MimeDisplayOptions *opt, if ( tmp->url ) tmp->url->GetSpec(spec); - mimeEmitterStartAttachment(opt, tmp->real_name, tmp->real_type, spec.get(), tmp->notDownloaded); + mimeEmitterStartAttachment(opt, tmp->real_name, tmp->real_type, spec.get(), tmp->isExternalAttachment); mimeEmitterAddAttachmentField(opt, HEADER_X_MOZILLA_PART_URL, spec.get()); if ( (opt->format_out == nsMimeOutput::nsMimeMessageQuoting) || @@ -1799,7 +1801,7 @@ mimeEmitterAddAllHeaders(MimeDisplayOptions *opt, const char *allheaders, const extern "C" nsresult mimeEmitterStartAttachment(MimeDisplayOptions *opt, const char *name, const char *contentType, const char *url, - PRBool aNotDownloaded) + PRBool aIsExternalAttachment) { // Check for draft processing... if (NoEmitterProcessing(opt->format_out)) @@ -1812,7 +1814,7 @@ mimeEmitterStartAttachment(MimeDisplayOptions *opt, const char *name, const char if (msd->output_emitter) { nsIMimeEmitter *emitter = (nsIMimeEmitter *)msd->output_emitter; - return emitter->StartAttachment(name, contentType, url, aNotDownloaded); + return emitter->StartAttachment(name, contentType, url, aIsExternalAttachment); } return NS_ERROR_FAILURE; diff --git a/mailnews/mime/src/mimemoz2.h b/mailnews/mime/src/mimemoz2.h index 2a38afb28ca..6f5f9b9ea67 100644 --- a/mailnews/mime/src/mimemoz2.h +++ b/mailnews/mime/src/mimemoz2.h @@ -184,7 +184,7 @@ extern "C" nsresult mimeEmitterAddAttachmentField(MimeDisplayOptions *opt, c extern "C" nsresult mimeEmitterAddHeaderField(MimeDisplayOptions *opt, const char *field, const char *value); extern "C" nsresult mimeEmitterAddAllHeaders(MimeDisplayOptions *opt, const char *allheaders, const PRInt32 allheadersize); extern "C" nsresult mimeEmitterStartAttachment(MimeDisplayOptions *opt, const char *name, const char *contentType, const char *url, - PRBool aNotDownloaded); + PRBool aIsExternalAttachment); extern "C" nsresult mimeEmitterEndAttachment(MimeDisplayOptions *opt); extern "C" nsresult mimeEmitterEndAllAttachments(MimeDisplayOptions *opt); extern "C" nsresult mimeEmitterStartBody(MimeDisplayOptions *opt, PRBool bodyOnly, const char *msgID, const char *outCharset);