in mailnews/mime/src/mimemult.cpp [110:310]
static int MimeMultipart_parse_line(const char* line, int32_t length,
MimeObject* obj) {
MimeMultipart* mult = (MimeMultipart*)obj;
MimeContainer* container = (MimeContainer*)obj;
int status = 0;
MimeMultipartBoundaryType boundary;
NS_ASSERTION(line && *line, "empty line in multipart parse_line");
if (!line || !*line) return -1;
NS_ASSERTION(!obj->closed_p, "obj shouldn't already be closed");
if (obj->closed_p) return -1;
/* If we're supposed to write this object, but aren't supposed to convert
it to HTML, simply pass it through unaltered. */
if (obj->output_p && obj->options && !obj->options->write_html_p &&
obj->options->output_fn &&
obj->options->format_out != nsMimeOutput::nsMimeMessageAttach)
return MimeObject_write(obj, line, length, true);
if (mult->state == MimeMultipartEpilogue) /* already done */
boundary = MimeMultipartBoundaryTypeNone;
else
boundary =
((MimeMultipartClass*)obj->clazz)->check_boundary(obj, line, length);
if (boundary == MimeMultipartBoundaryTypeTerminator ||
boundary == MimeMultipartBoundaryTypeSeparator) {
/* Match! Close the currently-open part, move on to the next
state, and discard this line.
*/
bool endOfPart = (mult->state != MimeMultipartPreamble);
if (endOfPart) status = ((MimeMultipartClass*)obj->clazz)->close_child(obj);
if (status < 0) return status;
if (boundary == MimeMultipartBoundaryTypeTerminator)
mult->state = MimeMultipartEpilogue;
else {
mult->state = MimeMultipartHeaders;
/* Reset the header parser for this upcoming part. */
NS_ASSERTION(!mult->hdrs, "mult->hdrs should be null here");
if (mult->hdrs) MimeHeaders_free(mult->hdrs);
mult->hdrs = MimeHeaders_new();
if (!mult->hdrs) return MIME_OUT_OF_MEMORY;
if (obj->options && obj->options->state &&
obj->options->state->partsToStrip.Length() > 0) {
nsAutoCString newPart(mime_part_address(obj));
newPart.Append('.');
newPart.AppendInt(container->nchildren + 1);
obj->options->state->strippingPart = false;
// check if this is a sub-part of a part we're stripping.
for (uint32_t partIndex = 0;
partIndex < obj->options->state->partsToStrip.Length();
partIndex++) {
nsCString& curPartToStrip =
obj->options->state->partsToStrip[partIndex];
if (newPart.Find(curPartToStrip) == 0 &&
(newPart.Length() == curPartToStrip.Length() ||
newPart.CharAt(curPartToStrip.Length()) == '.')) {
obj->options->state->strippingPart = true;
if (partIndex < obj->options->state->detachToFiles.Length())
obj->options->state->detachedFilePath =
obj->options->state->detachToFiles[partIndex];
break;
}
}
}
}
// if stripping out attachments, write the boundary line. Otherwise, return
// to ignore it.
if (obj->options &&
obj->options->format_out == nsMimeOutput::nsMimeMessageAttach) {
// Because MimeMultipart_parse_child_line strips out the
// the CRLF of the last line before the end of a part, we need to add that
// back in here.
if (endOfPart) MimeWriteAString(obj, nsLiteralCString(MSG_LINEBREAK));
status = MimeObject_write(obj, line, length, true);
}
return 0;
}
/* Otherwise, this isn't a boundary string. So do whatever it is we
should do with this line (parse it as a header, feed it to the
child part, ignore it, etc.) */
switch (mult->state) {
case MimeMultipartPreamble:
case MimeMultipartEpilogue:
/* Ignore this line. */
break;
case MimeMultipartHeaders:
/* Parse this line as a header for the sub-part. */
{
status = MimeHeaders_parse_line(line, length, mult->hdrs);
bool stripping = false;
if (status < 0) return status;
// If this line is blank, we're now done parsing headers, and should
// now examine the content-type to create this "body" part.
//
if (*line == '\r' || *line == '\n') {
if (obj->options && obj->options->state &&
obj->options->state->strippingPart) {
stripping = true;
bool detachingPart =
obj->options->state->detachedFilePath.Length() > 0;
nsAutoCString fileName;
fileName.Adopt(MimeHeaders_get_name(mult->hdrs, obj->options));
// clang-format off
if (detachingPart) {
char *contentType =
MimeHeaders_get(mult->hdrs, "Content-Type", false, false);
if (contentType) {
MimeWriteAString(obj, "Content-Type: "_ns);
MimeWriteAString(obj, nsDependentCString(contentType));
PR_Free(contentType);
}
MimeWriteAString(obj, nsLiteralCString(MSG_LINEBREAK));
MimeWriteAString(obj, "Content-Disposition: attachment; filename=\""_ns);
MimeWriteAString(obj, fileName);
MimeWriteAString(obj, "\""_ns MSG_LINEBREAK);
MimeWriteAString(obj, "X-Mozilla-External-Attachment-URL: "_ns);
MimeWriteAString(obj, obj->options->state->detachedFilePath);
MimeWriteAString(obj, nsLiteralCString(MSG_LINEBREAK));
MimeWriteAString(obj, "X-Mozilla-Altered: AttachmentDetached; date=\""_ns);
} else {
nsAutoCString header("Content-Type: text/x-moz-deleted; name=\"Deleted: ");
header.Append(fileName);
MimeWriteAString(obj, header);
MimeWriteAString(obj, "\""_ns MSG_LINEBREAK
"Content-Transfer-Encoding: 8bit"_ns MSG_LINEBREAK);
MimeWriteAString(obj, "Content-Disposition: inline; filename=\"Deleted: "_ns);
MimeWriteAString(obj, fileName);
MimeWriteAString(obj, "\""_ns MSG_LINEBREAK
"X-Mozilla-Altered: AttachmentDeleted; date=\""_ns);
}
nsCString result;
char timeBuffer[128];
PRExplodedTime now;
PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &now);
PR_FormatTimeUSEnglish(timeBuffer, sizeof(timeBuffer),
"%a %b %d %H:%M:%S %Y", &now);
MimeWriteAString(obj, nsDependentCString(timeBuffer));
MimeWriteAString(obj, "\""_ns MSG_LINEBREAK);
MimeWriteAString(obj, MSG_LINEBREAK
"You deleted an attachment from this message. The original "_ns
"MIME headers for the attachment were:"_ns MSG_LINEBREAK);
MimeHeaders_write_raw_headers(mult->hdrs, obj->options, false);
// clang-format on
}
int32_t old_nchildren = container->nchildren;
status = ((MimeMultipartClass*)obj->clazz)->create_child(obj);
if (status < 0) return status;
NS_ASSERTION(mult->state != MimeMultipartHeaders,
"mult->state shouldn't be MimeMultipartHeaders");
if (!stripping && container->nchildren > old_nchildren &&
obj->options &&
!mime_typep(obj,
(MimeObjectClass*)&mimeMultipartAlternativeClass)) {
// Notify emitter about content type and part path.
MimeObject* kid = container->children[container->nchildren - 1];
MimeMultipart_notify_emitter(kid);
}
}
break;
}
case MimeMultipartPartFirstLine:
/* Hand this line off to the sub-part. */
status = (((MimeMultipartClass*)obj->clazz)
->parse_child_line(obj, line, length, true));
if (status < 0) return status;
mult->state = MimeMultipartPartLine;
break;
case MimeMultipartPartLine:
/* Hand this line off to the sub-part. */
status = (((MimeMultipartClass*)obj->clazz)
->parse_child_line(obj, line, length, false));
if (status < 0) return status;
break;
default:
NS_ERROR("unexpected state in parse line");
return -1;
}
if (obj->options &&
obj->options->format_out == nsMimeOutput::nsMimeMessageAttach &&
(!(obj->options->state && obj->options->state->strippingPart) &&
mult->state != MimeMultipartPartLine))
return MimeObject_write(obj, line, length, false);
return 0;
}