Fix for bug 112625. When decomosing a message to file, we need to parse children of a multipart/alternative part. R=cavin, SR=mscott

This commit is contained in:
ducarroz%netscape.com 2002-02-19 05:32:06 +00:00
parent 58dd9abb3a
commit ab48b42be3
3 changed files with 130 additions and 129 deletions

View File

@ -1376,7 +1376,7 @@ mime_parse_stream_complete (nsMIMESession *stream)
if( PL_strcasestr(mdd->messageBody->type, "text/html"))
composeFormat = nsIMsgCompFormat::HTML;
else if ( PL_strcasestr(mdd->messageBody->type, "text/plain") ||
PL_strcasecmp(mdd->messageBody->type, "text") )
!PL_strcasecmp(mdd->messageBody->type, "text") )
composeFormat = nsIMsgCompFormat::PlainText;
else
{
@ -1684,24 +1684,20 @@ mime_decompose_file_init_fn ( void *stream_closure, MimeHeaders *headers )
if (!mdd || !headers)
return -1;
if ( !mdd->options->is_multipart_msg )
if (mdd->options->decompose_init_count)
{
if (mdd->options->decompose_init_count)
{
mdd->options->decompose_init_count++;
NS_ASSERTION(mdd->curAttachment, "missing attachment in mime_decompose_file_init_fn");
if (mdd->curAttachment) {
char *ct = MimeHeaders_get(headers, HEADER_CONTENT_TYPE, PR_TRUE, PR_FALSE);
if (ct)
NS_MsgSACopy(&(mdd->curAttachment->type), ct);
PR_FREEIF(ct);
}
return 0;
}
else {
mdd->options->decompose_init_count++;
mdd->options->decompose_init_count++;
NS_ASSERTION(mdd->curAttachment, "missing attachment in mime_decompose_file_init_fn");
if (mdd->curAttachment) {
char *ct = MimeHeaders_get(headers, HEADER_CONTENT_TYPE, PR_TRUE, PR_FALSE);
if (ct)
NS_MsgSACopy(&(mdd->curAttachment->type), ct);
PR_FREEIF(ct);
}
return 0;
}
else
mdd->options->decompose_init_count++;
nAttachments = mdd->attachments_count;
@ -1945,11 +1941,8 @@ mime_decompose_file_close_fn ( void *stream_closure )
if ( !mdd || !mdd->tmpFileStream )
return -1;
if ( !mdd->options->is_multipart_msg )
{
if ( --mdd->options->decompose_init_count > 0 )
if ( --mdd->options->decompose_init_count > 0 )
return 0;
}
if (mdd->decoder_data) {
MimeDecoderDestroy(mdd->decoder_data, PR_FALSE);
@ -1958,7 +1951,10 @@ mime_decompose_file_close_fn ( void *stream_closure )
if (mdd->tmpFileStream->GetIStream())
mdd->tmpFileStream->close();
delete mdd->tmpFileStream;
mdd->tmpFileStream = nsnull;
delete mdd->tmpFileSpec;
mdd->tmpFileSpec = nsnull;
@ -1973,8 +1969,8 @@ mime_bridge_create_draft_stream(
nsMimeOutputType format_out)
{
int status = 0;
nsMIMESession *stream = NULL;
struct mime_draft_data *mdd = NULL;
nsMIMESession *stream = nsnull;
struct mime_draft_data *mdd = nsnull;
MimeObject *obj;
if ( !uri )

View File

@ -44,18 +44,18 @@
#define MIME_SUPERCLASS mimeMultipartClass
MimeDefClass(MimeMultipartAlternative, MimeMultipartAlternativeClass,
mimeMultipartAlternativeClass, &MIME_SUPERCLASS);
mimeMultipartAlternativeClass, &MIME_SUPERCLASS);
static int MimeMultipartAlternative_initialize (MimeObject *);
static void MimeMultipartAlternative_finalize (MimeObject *);
static int MimeMultipartAlternative_parse_eof (MimeObject *, PRBool);
static int MimeMultipartAlternative_create_child(MimeObject *);
static int MimeMultipartAlternative_parse_child_line (MimeObject *, char *,
PRInt32, PRBool);
PRInt32, PRBool);
static int MimeMultipartAlternative_close_child(MimeObject *);
static PRBool MimeMultipartAlternative_display_part_p(MimeObject *self,
MimeHeaders *sub_hdrs);
MimeHeaders *sub_hdrs);
static int MimeMultipartAlternative_discard_cached_part(MimeObject *);
static int MimeMultipartAlternative_display_cached_part(MimeObject *);
@ -83,7 +83,7 @@ MimeMultipartAlternative_initialize (MimeObject *obj)
PR_ASSERT(!malt->part_buffer);
malt->part_buffer = MimePartBufferCreate();
if (!malt->part_buffer)
return MIME_OUT_OF_MEMORY;
return MIME_OUT_OF_MEMORY;
return ((MimeObjectClass*)&MIME_SUPERCLASS)->initialize(obj);
}
@ -93,15 +93,15 @@ MimeMultipartAlternative_cleanup(MimeObject *obj)
{
MimeMultipartAlternative *malt = (MimeMultipartAlternative *) obj;
if (malt->buffered_hdrs)
{
MimeHeaders_free(malt->buffered_hdrs);
malt->buffered_hdrs = 0;
}
{
MimeHeaders_free(malt->buffered_hdrs);
malt->buffered_hdrs = 0;
}
if (malt->part_buffer)
{
MimePartBufferDestroy(malt->part_buffer);
malt->part_buffer = 0;
}
{
MimePartBufferDestroy(malt->part_buffer);
malt->part_buffer = 0;
}
}
@ -127,10 +127,10 @@ MimeMultipartAlternative_parse_eof (MimeObject *obj, PRBool abort_p)
/* If there's a cached part we haven't written out yet, do it now.
*/
if (malt->buffered_hdrs && !abort_p)
{
status = MimeMultipartAlternative_display_cached_part(obj);
if (status < 0) return status;
}
{
status = MimeMultipartAlternative_display_cached_part(obj);
if (status < 0) return status;
}
MimeMultipartAlternative_cleanup(obj);
@ -145,39 +145,39 @@ MimeMultipartAlternative_create_child(MimeObject *obj)
MimeMultipartAlternative *malt = (MimeMultipartAlternative *) obj;
if (MimeMultipartAlternative_display_part_p (obj, mult->hdrs))
{
/* If this part is potentially displayable, begin populating the cache
with it. If there's something in the cache already, discard it
first. (Just because this part is displayable doesn't mean we will
display it -- of two consecutive displayable parts, it is the second
one that gets displayed.)
*/
int status;
mult->state = MimeMultipartPartFirstLine;
{
/* If this part is potentially displayable, begin populating the cache
with it. If there's something in the cache already, discard it
first. (Just because this part is displayable doesn't mean we will
display it -- of two consecutive displayable parts, it is the second
one that gets displayed.)
*/
int status;
mult->state = MimeMultipartPartFirstLine;
status = MimeMultipartAlternative_discard_cached_part(obj);
if (status < 0) return status;
status = MimeMultipartAlternative_discard_cached_part(obj);
if (status < 0) return status;
PR_ASSERT(!malt->buffered_hdrs);
malt->buffered_hdrs = MimeHeaders_copy(mult->hdrs);
if (!malt->buffered_hdrs) return MIME_OUT_OF_MEMORY;
return 0;
}
PR_ASSERT(!malt->buffered_hdrs);
malt->buffered_hdrs = MimeHeaders_copy(mult->hdrs);
if (!malt->buffered_hdrs) return MIME_OUT_OF_MEMORY;
return 0;
}
else
{
/* If this part is not displayable, then we're done -- all that is left
to do is to flush out the part that is currently in the cache.
*/
mult->state = MimeMultipartEpilogue;
return MimeMultipartAlternative_display_cached_part(obj);
}
{
/* If this part is not displayable, then we're done -- all that is left
to do is to flush out the part that is currently in the cache.
*/
mult->state = MimeMultipartEpilogue;
return MimeMultipartAlternative_display_cached_part(obj);
}
}
static int
MimeMultipartAlternative_parse_child_line (MimeObject *obj,
char *line, PRInt32 length,
PRBool first_line_p)
char *line, PRInt32 length,
PRBool first_line_p)
{
MimeMultipartAlternative *malt = (MimeMultipartAlternative *) obj;
@ -195,15 +195,15 @@ MimeMultipartAlternative_close_child(MimeObject *obj)
MimeMultipart *mult = (MimeMultipart *) obj;
MimeMultipartAlternative *malt = (MimeMultipartAlternative *) obj;
/* PR_ASSERT(malt->part_buffer); Some Mac brokenness trips this...
/* PR_ASSERT(malt->part_buffer); Some Mac brokenness trips this...
if (!malt->part_buffer) return -1; */
if (malt->part_buffer)
MimePartBufferClose(malt->part_buffer);
MimePartBufferClose(malt->part_buffer);
/* PR_ASSERT(mult->hdrs); I expect the Mac trips this too */
/* PR_ASSERT(mult->hdrs); I expect the Mac trips this too */
if (mult->hdrs)
MimeHeaders_free(mult->hdrs);
MimeHeaders_free(mult->hdrs);
mult->hdrs = 0;
return 0;
@ -212,26 +212,26 @@ MimeMultipartAlternative_close_child(MimeObject *obj)
static PRBool
MimeMultipartAlternative_display_part_p(MimeObject *self,
MimeHeaders *sub_hdrs)
MimeHeaders *sub_hdrs)
{
char *ct = MimeHeaders_get (sub_hdrs, HEADER_CONTENT_TYPE, PR_TRUE, PR_FALSE);
/* RFC 1521 says:
Receiving user agents should pick and display the last format
they are capable of displaying. In the case where one of the
alternatives is itself of type "multipart" and contains unrecognized
sub-parts, the user agent may choose either to show that alternative,
an earlier alternative, or both.
Receiving user agents should pick and display the last format
they are capable of displaying. In the case where one of the
alternatives is itself of type "multipart" and contains unrecognized
sub-parts, the user agent may choose either to show that alternative,
an earlier alternative, or both.
Ugh. If there is a multipart subtype of alternative, we simply show
that, without descending into it to determine if any of its sub-parts
are themselves unknown.
Ugh. If there is a multipart subtype of alternative, we simply show
that, without descending into it to determine if any of its sub-parts
are themselves unknown.
*/
MimeObjectClass *clazz = mime_find_class (ct, sub_hdrs, self->options, PR_FALSE);
PRBool result = (clazz
? clazz->displayable_inline_p(clazz, sub_hdrs)
: PR_FALSE);
? clazz->displayable_inline_p(clazz, sub_hdrs)
: PR_FALSE);
PR_FREEIF(ct);
return result;
}
@ -242,12 +242,12 @@ MimeMultipartAlternative_discard_cached_part(MimeObject *obj)
MimeMultipartAlternative *malt = (MimeMultipartAlternative *) obj;
if (malt->buffered_hdrs)
{
MimeHeaders_free(malt->buffered_hdrs);
malt->buffered_hdrs = 0;
}
{
MimeHeaders_free(malt->buffered_hdrs);
malt->buffered_hdrs = 0;
}
if (malt->part_buffer)
MimePartBufferReset (malt->part_buffer);
MimePartBufferReset (malt->part_buffer);
return 0;
}
@ -259,68 +259,70 @@ MimeMultipartAlternative_display_cached_part(MimeObject *obj)
int status;
char *ct = (malt->buffered_hdrs
? MimeHeaders_get (malt->buffered_hdrs, HEADER_CONTENT_TYPE,
PR_TRUE, PR_FALSE)
: 0);
? MimeHeaders_get (malt->buffered_hdrs, HEADER_CONTENT_TYPE,
PR_TRUE, PR_FALSE)
: 0);
const char *dct = (((MimeMultipartClass *) obj->clazz)->default_part_type);
MimeObject *body;
PRBool multipart_p;
/* Don't pass in NULL as the content-type (this means that the
auto-uudecode-hack won't ever be done for subparts of a
multipart, but only for untyped children of message/rfc822.
auto-uudecode-hack won't ever be done for subparts of a
multipart, but only for untyped children of message/rfc822.
*/
body = mime_create(((ct && *ct) ? ct : (dct ? dct: TEXT_PLAIN)),
malt->buffered_hdrs, obj->options);
malt->buffered_hdrs, obj->options);
PR_FREEIF(ct);
if (!body) return MIME_OUT_OF_MEMORY;
multipart_p = mime_typep(body, (MimeObjectClass *) &mimeMultipartClass);
status = ((MimeContainerClass *) obj->clazz)->add_child(obj, body);
if (status < 0)
{
mime_free(body);
return status;
}
{
mime_free(body);
return status;
}
#ifdef MIME_DRAFTS
if ( obj->options &&
obj->options->decompose_file_p &&
!multipart_p &&
obj->options->decompose_file_init_fn )
{
status = obj->options->decompose_file_init_fn (
obj->options->stream_closure,
malt->buffered_hdrs);
if (status < 0) return status;
}
/* if this object is a child of a multipart/related object, the parent is
taking care of decomposing the whole part, don't need to do it at this level.
However, we still have to call decompose_file_init_fn and decompose_file_close_fn
in order to set the correct content-type. But don't call MimePartBufferRead
*/
PRBool multipartChild = mime_typep(obj->parent, (MimeObjectClass *) &mimeMultipartClass);
PRBool decomposeFile = obj->options &&
obj->options->decompose_file_p &&
obj->options->decompose_file_init_fn &&
!mime_typep(body, (MimeObjectClass *) &mimeMultipartClass);
if (decomposeFile)
{
status = obj->options->decompose_file_init_fn (
obj->options->stream_closure,
malt->buffered_hdrs);
if (status < 0) return status;
}
#endif /* MIME_DRAFTS */
/* Now that we've added this new object to our list of children,
start its parser going. */
start its parser going. */
status = body->clazz->parse_begin(body);
if (status < 0) return status;
#ifdef MIME_DRAFTS
if ( obj->options &&
obj->options->decompose_file_p &&
!multipart_p &&
obj->options->decompose_file_output_fn )
status = MimePartBufferRead (malt->part_buffer,
obj->options->decompose_file_output_fn,
obj->options->stream_closure);
if (decomposeFile && !multipartChild)
status = MimePartBufferRead (malt->part_buffer,
obj->options->decompose_file_output_fn,
obj->options->stream_closure);
else
#endif /* MIME_DRAFTS */
status = MimePartBufferRead (malt->part_buffer,
/* The (nsresult (*) ...) cast is to turn the
`void' argument into `MimeObject'. */
((nsresult (*) (char *, PRInt32, void *))
body->clazz->parse_buffer),
body);
status = MimePartBufferRead (malt->part_buffer,
/* The (nsresult (*) ...) cast is to turn the
`void' argument into `MimeObject'. */
((nsresult (*) (char *, PRInt32, void *))
body->clazz->parse_buffer),
body);
if (status < 0) return status;
@ -333,12 +335,10 @@ MimeMultipartAlternative_display_cached_part(MimeObject *obj)
if (status < 0) return status;
#ifdef MIME_DRAFTS
if ( obj->options &&
obj->options->decompose_file_p &&
!multipart_p &&
obj->options->decompose_file_close_fn ) {
status = obj->options->decompose_file_close_fn ( obj->options->stream_closure );
if (status < 0) return status;
if (decomposeFile)
{
status = obj->options->decompose_file_close_fn ( obj->options->stream_closure );
if (status < 0) return status;
}
#endif /* MIME_DRAFTS */

View File

@ -189,10 +189,15 @@ MimeObject_parse_begin (MimeObject *obj)
}
/* Decide whether this object should be output or not... */
if (!obj->options || !obj->options->output_fn)
obj->output_p = PR_FALSE;
if (!obj->options || !obj->options->output_fn
/* if we are decomposing the message in files and processing a multipart object,
we must not output it without parsing it first */
|| (obj->options->decompose_file_p && obj->options->decompose_file_output_fn &&
mime_typep(obj, (MimeObjectClass*) &mimeMultipartClass))
)
obj->output_p = PR_FALSE;
else if (!obj->options->part_to_load)
obj->output_p = PR_TRUE;
obj->output_p = PR_TRUE;
else
{
char *id = mime_part_address(obj);