fix 204350, handling of message/rfc822 attachments opened in standalone msg window, sr=mscott

This commit is contained in:
bienvenu%nventure.com 2005-10-27 14:07:10 +00:00
parent ed89039ff1
commit fc1f4f0336
9 changed files with 237 additions and 158 deletions

View File

@ -617,6 +617,7 @@ nsMessenger::LoadURL(nsIDOMWindowInternal *aWin, const char *aURL)
NS_ENSURE_TRUE(!uriString.IsEmpty(), NS_ERROR_FAILURE);
PRBool loadingFromFile = PR_FALSE;
PRBool getDummyMsgHdr = PR_FALSE;
PRInt64 fileSize;
if (StringBeginsWith(uriString, NS_LITERAL_STRING("file:")))
@ -634,7 +635,10 @@ nsMessenger::LoadURL(nsIDOMWindowInternal *aWin, const char *aURL)
uriString.ReplaceSubstring(NS_LITERAL_STRING("file:"), NS_LITERAL_STRING("mailbox:"));
uriString.Append(NS_LITERAL_STRING("&number=0"));
loadingFromFile = PR_TRUE;
getDummyMsgHdr = PR_TRUE;
}
else if (FindInReadable(NS_LITERAL_STRING("type=application/x-message-display"), uriString))
getDummyMsgHdr = PR_TRUE;
nsCOMPtr<nsIURI> uri;
rv = NS_NewURI(getter_AddRefs(uri), uriString);
@ -645,21 +649,25 @@ nsMessenger::LoadURL(nsIDOMWindowInternal *aWin, const char *aURL)
if (msgurl)
{
msgurl->SetMsgWindow(mMsgWindow);
if (loadingFromFile)
if (loadingFromFile || getDummyMsgHdr)
{
nsCOMPtr <nsIMailboxUrl> mailboxUrl = do_QueryInterface(msgurl, &rv);
mailboxUrl->SetMessageSize((PRUint32) fileSize);
nsCOMPtr <nsIMsgHeaderSink> headerSink;
// need to tell the header sink to capture some headers to create a fake db header
// so we can do reply to a .eml file or a rfc822 msg attachment.
mMsgWindow->GetMsgHeaderSink(getter_AddRefs(headerSink));
if (headerSink)
if (loadingFromFile)
{
nsCOMPtr <nsIMsgDBHdr> dummyHeader;
headerSink->GetDummyMsgHeader(getter_AddRefs(dummyHeader));
if (dummyHeader)
nsCOMPtr <nsIMailboxUrl> mailboxUrl = do_QueryInterface(msgurl, &rv);
mailboxUrl->SetMessageSize((PRUint32) fileSize);
}
if (getDummyMsgHdr)
{
nsCOMPtr <nsIMsgHeaderSink> headerSink;
// need to tell the header sink to capture some headers to create a fake db header
// so we can do reply to a .eml file or a rfc822 msg attachment.
mMsgWindow->GetMsgHeaderSink(getter_AddRefs(headerSink));
if (headerSink)
{
dummyHeader->SetMessageSize((PRUint32) fileSize);
nsCOMPtr <nsIMsgDBHdr> dummyHeader;
headerSink->GetDummyMsgHeader(getter_AddRefs(dummyHeader));
if (dummyHeader && loadingFromFile)
dummyHeader->SetMessageSize((PRUint32) fileSize);
}
}
}
@ -805,7 +813,7 @@ nsMessenger::OpenAttachment(const char * aContentType, const char * aURL, const
rv = messageService->OpenAttachment(aContentType, aDisplayName, aURL, aMessageUri, mDocShell, mMsgWindow, nsnull);
}
return rv;
return rv;
}
NS_IMETHODIMP
@ -1391,7 +1399,7 @@ nsMessenger::MsgHdrFromURI(const char *aUri, nsIMsgDBHdr **aMsgHdr)
nsCOMPtr <nsIMsgMessageService> msgService;
nsresult rv;
if (!strncmp(aUri, "file:", 5))
if (!strncmp(aUri, "file:", 5) || PL_strstr(aUri, "type=application/x-message-display"))
{
nsCOMPtr <nsIMsgHeaderSink> headerSink;
mMsgWindow->GetMsgHeaderSink(getter_AddRefs(headerSink));

View File

@ -979,7 +979,8 @@ NS_IMETHODIMP nsMsgDBView::ReloadMessageWithAllParts()
return NS_OK;
nsCAutoString forceAllParts(m_currentlyDisplayedMsgUri);
forceAllParts.AppendLiteral("?fetchCompleteMessage=true");
forceAllParts += (forceAllParts.FindChar('?') == kNotFound) ? "?" : "&";
forceAllParts.AppendLiteral("fetchCompleteMessage=true");
return mMessengerInstance->OpenURL(forceAllParts.get());
}

View File

@ -100,6 +100,7 @@
#include "nsImapProtocol.h"
#include "nsIMsgMailSession.h"
#include "nsIStreamConverterService.h"
#include "nsNetUtil.h"
#include "nsInt64.h"
#define PREF_MAIL_ROOT_IMAP "mail.root.imap" // old - for backward compatibility only
@ -313,6 +314,10 @@ NS_IMETHODIMP nsImapService::GetUrlForUri(const char *aMessageURI, nsIURI **aURL
{
nsresult rv = NS_OK;
if (PL_strstr(aMessageURI, "&type=application/x-message-display"))
return NS_NewURI(aURL, aMessageURI);
nsCOMPtr<nsIMsgFolder> folder;
nsXPIDLCString msgKey;
rv = DecomposeImapURI(aMessageURI, getter_AddRefs(folder), getter_Copies(msgKey));
@ -482,7 +487,37 @@ NS_IMETHODIMP nsImapService::DisplayMessage(const char* aMessageURI,
nsXPIDLCString mimePart;
nsCAutoString folderURI;
nsMsgKey key;
nsCAutoString messageURI(aMessageURI);
PRInt32 typeIndex = messageURI.Find("&type=application/x-message-display");
if (typeIndex != kNotFound)
{
// This happens with forward inline of a message/rfc822 attachment opened in
// a standalone msg window.
// So, just cut to the chase and call AsyncOpen on a channel.
nsCOMPtr <nsIURI> uri;
messageURI.Cut(typeIndex, sizeof("&type=application/x-message-display") - 1);
rv = NS_NewURI(getter_AddRefs(uri), messageURI.get());
NS_ENSURE_SUCCESS(rv, rv);
if (aURL)
NS_IF_ADDREF(*aURL = uri);
nsCOMPtr<nsIStreamListener> aStreamListener = do_QueryInterface(aDisplayConsumer, &rv);
if (NS_SUCCEEDED(rv) && aStreamListener)
{
nsCOMPtr<nsIChannel> aChannel;
nsCOMPtr<nsILoadGroup> aLoadGroup;
nsCOMPtr<nsIMsgMailNewsUrl> mailnewsUrl = do_QueryInterface(uri, &rv);
if (NS_SUCCEEDED(rv) && mailnewsUrl)
mailnewsUrl->GetLoadGroup(getter_AddRefs(aLoadGroup));
rv = NewChannel(uri, getter_AddRefs(aChannel));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsISupports> aCtxt = do_QueryInterface(uri);
// now try to open the channel passing in our display consumer as the listener
return aChannel->AsyncOpen(aStreamListener, aCtxt);
}
}
rv = DecomposeImapURI(aMessageURI, getter_AddRefs(folder), getter_Copies(msgKey));
if (msgKey.IsEmpty())
return NS_MSG_MESSAGE_NOT_FOUND;

View File

@ -461,6 +461,8 @@ nsresult nsMailboxProtocol::LoadUrl(nsIURI * aURL, nsISupports * aConsumer)
PRBool convertData = PR_FALSE;
// need to check if we're fetching an rfc822 part in order to
// quote a message.
if (m_mailboxAction == nsIMailboxUrl::ActionFetchMessage)
{
nsCOMPtr<nsIMsgMailNewsUrl> msgUrl = do_QueryInterface(m_runningUrl, &rv);

View File

@ -182,6 +182,9 @@ nsresult nsMailboxService::FetchMessage(const char* aMessageURI,
nsMailboxAction actionToUse = mailboxAction;
nsCOMPtr <nsIURI> url;
nsCAutoString uriString(aMessageURI);
if (!strncmp(aMessageURI, "file:", 5))
{
PRInt64 fileSize;
@ -221,7 +224,18 @@ nsresult nsMailboxService::FetchMessage(const char* aMessageURI,
}
else
{
rv = PrepareMessageUrl(aMessageURI, aUrlListener, actionToUse , getter_AddRefs(mailboxurl), aMsgWindow);
// this happens with forward inline of message/rfc822 attachment
// opened in a stand-alone msg window.
PRInt32 typeIndex = typeIndex = uriString.Find("&type=application/x-message-display");
if (typeIndex != kNotFound)
{
uriString.Cut(typeIndex, sizeof("&type=application/x-message-display") - 1);
rv = NS_NewURI(getter_AddRefs(url), uriString.get());
mailboxurl = do_QueryInterface(url);
}
else
rv = PrepareMessageUrl(aMessageURI, aUrlListener, actionToUse , getter_AddRefs(mailboxurl), aMsgWindow);
if (NS_SUCCEEDED(rv))
{
@ -318,17 +332,6 @@ NS_IMETHODIMP nsMailboxService::OpenAttachment(const char *aContentType,
{
nsCOMPtr <nsIURI> URL;
nsCAutoString urlString(aUrl);
// strip out ?type=application/x-message-display because it confuses libmime
PRInt32 typeIndex = urlString.Find("?type=application/x-message-display");
if (typeIndex != kNotFound)
{
urlString.Cut(typeIndex, sizeof("?type=application/x-message-display") - 1);
// we also need to replace the next '&' with '?'
PRInt32 firstPartIndex = urlString.FindChar('&');
if (firstPartIndex != kNotFound)
urlString.SetCharAt('?', firstPartIndex);
}
urlString += "&type=";
urlString += aContentType;
urlString += "&filename=";
@ -389,7 +392,8 @@ nsMailboxService::SaveMessageToDisk(const char *aMessageURI,
NS_IMETHODIMP nsMailboxService::GetUrlForUri(const char *aMessageURI, nsIURI **aURL, nsIMsgWindow *aMsgWindow)
{
if (!strncmp(aMessageURI, "file:", 5))
if (!strncmp(aMessageURI, "file:", 5) || PL_strstr(aMessageURI, "type=application/x-message-display")
|| !strncmp(aMessageURI, "mailbox:", 8))
return NS_NewURI(aURL, aMessageURI);
nsresult rv = NS_OK;

View File

@ -2082,6 +2082,10 @@ mime_bridge_create_draft_stream(
if (NS_SUCCEEDED(aURL->GetSpec(urlString)))
{
PRInt32 typeIndex = urlString.Find("&type=application/x-message-display");
if (typeIndex != kNotFound)
urlString.Cut(typeIndex, sizeof("&type=application/x-message-display") - 1);
mdd->url_name = ToNewCString(urlString);
if (!(mdd->url_name))
goto FAIL;

View File

@ -1372,6 +1372,16 @@ mime_set_url_part(const char *url, const char *part, PRBool append_p)
if (!url || !part) return 0;
nsCAutoString urlString(url);
PRInt32 typeIndex = urlString.Find("?type=application/x-message-display");
if (typeIndex != kNotFound)
{
urlString.Cut(typeIndex, sizeof("?type=application/x-message-display") - 1);
if (urlString.CharAt(typeIndex) == '&')
urlString.SetCharAt('?', typeIndex);
url = urlString.get();
}
for (s = url; *s; s++)
{
if (*s == '?')
@ -1389,7 +1399,7 @@ mime_set_url_part(const char *url, const char *part, PRBool append_p)
;
part_end = s;
break;
}
}
}
result = (char *) PR_MALLOC(strlen(url) + strlen(part) + 10);
@ -1641,18 +1651,18 @@ mime_parse_url_options(const char *url, MimeDisplayOptions *options)
if (! q) return 0;
q++;
while (*q)
{
const char *end, *value, *name_end;
for (end = q; *end && *end != '&'; end++)
;
for (value = q; *value != '=' && value < end; value++)
;
name_end = value;
if (value < end) value++;
if (name_end <= q)
;
else if (!nsCRT::strncasecmp ("headers", q, name_end - q))
{
{
const char *end, *value, *name_end;
for (end = q; *end && *end != '&'; end++)
;
for (value = q; *value != '=' && value < end; value++)
;
name_end = value;
if (value < end) value++;
if (name_end <= q)
;
else if (!nsCRT::strncasecmp ("headers", q, name_end - q))
{
if (end > value && !nsCRT::strncasecmp ("only", value, end-value))
options->headers = MimeHeadersOnly;
else if (end > value && !nsCRT::strncasecmp ("none", value, end-value))
@ -1669,116 +1679,114 @@ mime_parse_url_options(const char *url, MimeDisplayOptions *options)
options->headers = MimeHeadersCitation;
else
options->headers = default_headers;
}
else if (!nsCRT::strncasecmp ("part", q, name_end - q))
{
PR_FREEIF (options->part_to_load);
if (end > value)
{
options->part_to_load = (char *) PR_MALLOC(end - value + 1);
if (!options->part_to_load)
return MIME_OUT_OF_MEMORY;
memcpy(options->part_to_load, value, end-value);
options->part_to_load[end-value] = 0;
}
}
else if (!nsCRT::strncasecmp ("rot13", q, name_end - q))
{
if (end <= value || !nsCRT::strncasecmp ("true", value, end - value))
options->rot13_p = PR_TRUE;
else
options->rot13_p = PR_FALSE;
}
}
else if (!nsCRT::strncasecmp ("part", q, name_end - q) &&
options->format_out != nsMimeOutput::nsMimeMessageBodyQuoting)
{
PR_FREEIF (options->part_to_load);
if (end > value)
{
options->part_to_load = (char *) PR_MALLOC(end - value + 1);
if (!options->part_to_load)
return MIME_OUT_OF_MEMORY;
memcpy(options->part_to_load, value, end-value);
options->part_to_load[end-value] = 0;
}
}
else if (!nsCRT::strncasecmp ("rot13", q, name_end - q))
{
options->rot13_p = end <= value || !nsCRT::strncasecmp ("true", value, end - value);
}
q = end;
if (*q)
q++;
}
q = end;
if (*q)
q++;
}
/* Compatibility with the "?part=" syntax used in the old (Mozilla 2.0)
/* Compatibility with the "?part=" syntax used in the old (Mozilla 2.0)
MIME parser.
Basically, the problem is that the old part-numbering code was totally
busted: here's a comparison of the old and new numberings with a pair
of hypothetical messages (one with a single part, and one with nested
containers.)
NEW: OLD: OR:
message/rfc822
image/jpeg 1 0 0
Basically, the problem is that the old part-numbering code was totally
busted: here's a comparison of the old and new numberings with a pair
of hypothetical messages (one with a single part, and one with nested
containers.)
NEW: OLD: OR:
message/rfc822
image/jpeg 1 0 0
message/rfc822
multipart/mixed 1 0 0
text/plain 1.1 1 1
image/jpeg 1.2 2 2
message/rfc822 1.3 - 3
text/plain 1.3.1 3 -
message/rfc822 1.4 - 4
multipart/mixed 1.4.1 4 -
text/plain 1.4.1.1 4.1 -
image/jpeg 1.4.1.2 4.2 -
text/plain 1.5 5 5
message/rfc822
multipart/mixed 1 0 0
text/plain 1.1 1 1
image/jpeg 1.2 2 2
message/rfc822 1.3 - 3
text/plain 1.3.1 3 -
message/rfc822 1.4 - 4
multipart/mixed 1.4.1 4 -
text/plain 1.4.1.1 4.1 -
image/jpeg 1.4.1.2 4.2 -
text/plain 1.5 5 5
The "NEW" column is how the current code counts. The "OLD" column is
what "?part=" references would do in 3.0b4 and earlier; you'll see that
you couldn't directly refer to the child message/rfc822 objects at all!
But that's when it got really weird, because if you turned on
"Attachments As Links" (or used a URL like "?inline=false&part=...")
then you got a totally different numbering system (seen in the "OR"
column.) Gag!
The "NEW" column is how the current code counts. The "OLD" column is
what "?part=" references would do in 3.0b4 and earlier; you'll see that
you couldn't directly refer to the child message/rfc822 objects at all!
But that's when it got really weird, because if you turned on
"Attachments As Links" (or used a URL like "?inline=false&part=...")
then you got a totally different numbering system (seen in the "OR"
column.) Gag!
So, the problem is, ClariNet had been using these part numbers in their
HTML news feeds, as a sleazy way of transmitting both complex HTML layouts
and images using NNTP as transport, without invoking HTTP.
So, the problem is, ClariNet had been using these part numbers in their
HTML news feeds, as a sleazy way of transmitting both complex HTML layouts
and images using NNTP as transport, without invoking HTTP.
The following clause is to provide some small amount of backward
compatibility. By looking at that table, one can see that in the new
model, "part=0" has no meaning, and neither does "part=2" or "part=3"
and so on.
The following clause is to provide some small amount of backward
compatibility. By looking at that table, one can see that in the new
model, "part=0" has no meaning, and neither does "part=2" or "part=3"
and so on.
"part=1" is ambiguous between the old and new way, as is any part
specification that has a "." in it.
"part=1" is ambiguous between the old and new way, as is any part
specification that has a "." in it.
So, the compatibility hack we do here is: if the part is "0", then map
that to "1". And if the part is >= "2", then prepend "1." to it (so that
we map "2" to "1.2", and "3" to "1.3".)
So, the compatibility hack we do here is: if the part is "0", then map
that to "1". And if the part is >= "2", then prepend "1." to it (so that
we map "2" to "1.2", and "3" to "1.3".)
This leaves the URLs compatible in the cases of:
This leaves the URLs compatible in the cases of:
= single part messages
= references to elements of a top-level multipart except the first
= single part messages
= references to elements of a top-level multipart except the first
and leaves them incompatible for:
and leaves them incompatible for:
= the first part of a top-level multipart
= all elements deeper than the outermost part
= the first part of a top-level multipart
= all elements deeper than the outermost part
Life s#$%s when you don't properly think out things that end up turning
into de-facto standards...
*/
if (options->part_to_load &&
!PL_strchr(options->part_to_load, '.')) /* doesn't contain a dot */
{
if (!nsCRT::strcmp(options->part_to_load, "0")) /* 0 */
{
PR_Free(options->part_to_load);
options->part_to_load = nsCRT::strdup("1");
if (!options->part_to_load)
return MIME_OUT_OF_MEMORY;
}
else if (nsCRT::strcmp(options->part_to_load, "1")) /* not 1 */
{
const char *prefix = "1.";
char *s = (char *) PR_MALLOC(strlen(options->part_to_load) +
strlen(prefix) + 1);
if (!s) return MIME_OUT_OF_MEMORY;
PL_strcpy(s, prefix);
PL_strcat(s, options->part_to_load);
PR_Free(options->part_to_load);
options->part_to_load = s;
}
}
Life s#$%s when you don't properly think out things that end up turning
into de-facto standards...
*/
if (options->part_to_load &&
!PL_strchr(options->part_to_load, '.')) /* doesn't contain a dot */
{
if (!nsCRT::strcmp(options->part_to_load, "0")) /* 0 */
{
PR_Free(options->part_to_load);
options->part_to_load = nsCRT::strdup("1");
if (!options->part_to_load)
return MIME_OUT_OF_MEMORY;
}
else if (nsCRT::strcmp(options->part_to_load, "1")) /* not 1 */
{
const char *prefix = "1.";
char *s = (char *) PR_MALLOC(strlen(options->part_to_load) +
strlen(prefix) + 1);
if (!s) return MIME_OUT_OF_MEMORY;
PL_strcpy(s, prefix);
PL_strcat(s, options->part_to_load);
PR_Free(options->part_to_load);
options->part_to_load = s;
}
}
return 0;
}
@ -1954,6 +1962,18 @@ mime_get_base_url(const char *url)
return nsnull;
const char *s = strrchr(url, '?');
if (s && !strncmp(s, "?type=application/x-message-display", sizeof("?type=application/x-message-display") - 1))
{
const char *nextTerm = strchr(s, '&');
s = (nextTerm) ? nextTerm : s + strlen(s) - 1;
}
// we need to keep the ?number part of the url, or we won't know
// which local message the part belongs to.
if (s && *s && *(s+1) && !strncmp(s + 1, "number=", sizeof("number=") - 1))
{
const char *nextTerm = strchr(++s, '&');
s = (nextTerm) ? nextTerm : s + strlen(s) - 1;
}
char *result = (char *) PR_MALLOC(strlen(url) + 1);
NS_ASSERTION(result, "out of memory");
if (!result)

View File

@ -408,7 +408,7 @@ nsStreamConverter::DetermineOutputFormat(const char *aUrl, nsMimeOutputType *aNe
// is this is a part that should just come out raw
const char *part = FindQueryElementData(queryPart, "part=");
if (part)
if (part && !mToType.Equals("application/vnd.mozilla.xul+xml"))
{
// default for parts
mOutputFormat = "raw";
@ -1101,6 +1101,9 @@ NS_IMETHODIMP nsStreamConverter::AsyncConvertData(const char *aFromType,
aChannel = do_QueryInterface(aCtxt, &rv);
}
mFromType = aFromType;
mToType = aToType;
NS_ASSERTION(aChannel && NS_SUCCEEDED(rv), "mailnews mime converter has to have the channel passed in...");
if (NS_FAILED(rv)) return rv;

View File

@ -107,6 +107,8 @@ private:
nsCOMPtr<nsIMsgIdentity> mIdentity;
nsCString mOriginalMsgURI;
nsCString mFromType;
nsCString mToType;
#ifdef DEBUG_mscott
PRTime mConvertContentTime;
#endif