summaryrefslogtreecommitdiffstats
path: root/mailnews/compose/src/nsMsgSendPart.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mailnews/compose/src/nsMsgSendPart.cpp')
-rw-r--r--mailnews/compose/src/nsMsgSendPart.cpp779
1 files changed, 779 insertions, 0 deletions
diff --git a/mailnews/compose/src/nsMsgSendPart.cpp b/mailnews/compose/src/nsMsgSendPart.cpp
new file mode 100644
index 000000000..a33dabf33
--- /dev/null
+++ b/mailnews/compose/src/nsMsgSendPart.cpp
@@ -0,0 +1,779 @@
+/* -*- Mode: C++; 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/. */
+#include "nsMsgLocalFolderHdrs.h"
+#include "nsMsgSend.h"
+#include "nsMsgSendPart.h"
+#include "nsIMimeConverter.h"
+#include "nsCOMPtr.h"
+#include "nsIComponentManager.h"
+#include "nsMsgI18N.h"
+#include "nsMsgCompUtils.h"
+#include "nsMsgMimeCID.h"
+#include "nsMimeTypes.h"
+#include "prmem.h"
+#include "nsMsgPrompts.h"
+#include "nsNativeCharsetUtils.h"
+#include "nsNetUtil.h"
+#include "nsISeekableStream.h"
+#include "nsReadLine.h"
+#include "nsILineInputStream.h"
+#include "nsComposeStrings.h"
+#include "mozilla/mailnews/MimeEncoder.h"
+
+static char *mime_mailto_stream_read_buffer = 0;
+
+int32_t nsMsgSendPart::M_counter = 0;
+
+nsMsgSendPart::nsMsgSendPart(nsIMsgSend* state, const char *part_charset)
+{
+ PL_strncpy(m_charset_name, (part_charset ? part_charset : "UTF-8"), sizeof(m_charset_name)-1);
+ m_charset_name[sizeof(m_charset_name)-1] = '\0';
+ m_children = nullptr;
+ m_numchildren = 0;
+ // if we're not added as a child, the default part number will be "1".
+ m_partNum = "1";
+ SetMimeDeliveryState(state);
+
+ m_parent = nullptr;
+ m_buffer = nullptr;
+ m_type = nullptr;
+ m_other = nullptr;
+ m_strip_sensitive_headers = false;
+
+ m_firstBlock = false;
+ m_needIntlConversion = false;
+
+ m_mainpart = false;
+ m_just_hit_CR = false;
+}
+
+
+nsMsgSendPart::~nsMsgSendPart()
+{
+ for (int i=0 ; i < m_numchildren; i++)
+ delete m_children[i];
+
+ delete [] m_children;
+ PR_FREEIF(m_buffer);
+ PR_FREEIF(m_other);
+ PR_FREEIF(m_type);
+}
+
+nsresult nsMsgSendPart::CopyString(char** dest, const char* src)
+{
+ NS_ASSERTION(src, "src null");
+
+ PR_FREEIF(*dest);
+ if (!src)
+ *dest = PL_strdup("");
+ else
+ *dest = PL_strdup(src);
+
+ return *dest? NS_OK : NS_ERROR_OUT_OF_MEMORY;
+}
+
+
+nsresult nsMsgSendPart::SetFile(nsIFile *file)
+{
+ m_file = file;
+ return NS_OK;
+}
+
+
+nsresult nsMsgSendPart::SetBuffer(const char* buffer)
+{
+ PR_FREEIF(m_buffer);
+ return CopyString(&m_buffer, buffer);
+}
+
+
+nsresult nsMsgSendPart::SetType(const char* type)
+{
+ PR_FREEIF(m_type);
+ m_type = PL_strdup(type);
+ return m_type ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
+}
+
+
+nsresult nsMsgSendPart::SetOtherHeaders(const char* other)
+{
+ return CopyString(&m_other, other);
+}
+
+nsresult nsMsgSendPart::SetMimeDeliveryState(nsIMsgSend *state)
+{
+ m_state = state;
+ if (GetNumChildren() > 0)
+ {
+ for (int i = 0; i < GetNumChildren(); i++)
+ {
+ nsMsgSendPart *part = GetChild(i);
+ if (part)
+ part->SetMimeDeliveryState(state);
+ }
+ }
+ return NS_OK;
+}
+
+nsresult nsMsgSendPart::AppendOtherHeaders(const char* more)
+{
+ if (!m_other)
+ return SetOtherHeaders(more);
+
+ if (!more || !*more)
+ return NS_OK;
+
+ char* tmp = (char *) PR_Malloc(sizeof(char) * (PL_strlen(m_other) + PL_strlen(more) + 2));
+ if (!tmp)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ PL_strcpy(tmp, m_other);
+ PL_strcat(tmp, more);
+ PR_FREEIF(m_other);
+ m_other = tmp;
+
+ return NS_OK;
+}
+
+
+nsresult nsMsgSendPart::SetMainPart(bool value)
+{
+ m_mainpart = value;
+ return NS_OK;
+}
+
+nsresult nsMsgSendPart::AddChild(nsMsgSendPart* child)
+{
+ m_numchildren++;
+ nsMsgSendPart** tmp = new nsMsgSendPart* [m_numchildren];
+ if (tmp == nullptr) return NS_ERROR_OUT_OF_MEMORY;
+ for (int i=0 ; i<m_numchildren-1 ; i++) {
+ tmp[i] = m_children[i];
+ }
+ delete [] m_children;
+ m_children = tmp;
+ m_children[m_numchildren - 1] = child;
+ child->m_parent = this;
+ nsCString partNum(m_partNum);
+ partNum.Append(".");
+ partNum.AppendInt(m_numchildren);
+ child->m_partNum = partNum;
+ return NS_OK;
+}
+
+nsMsgSendPart * nsMsgSendPart::DetachChild(int32_t whichOne)
+{
+ nsMsgSendPart *returnValue = nullptr;
+
+ NS_ASSERTION(whichOne >= 0 && whichOne < m_numchildren, "parameter out of range");
+ if (whichOne >= 0 && whichOne < m_numchildren)
+ {
+ returnValue = m_children[whichOne];
+
+ if (m_numchildren > 1)
+ {
+ nsMsgSendPart** tmp = new nsMsgSendPart* [m_numchildren-1];
+ if (tmp != nullptr)
+ {
+ // move all the other kids over
+ for (int i=0 ; i<m_numchildren-1 ; i++)
+ {
+ if (i >= whichOne)
+ tmp[i] = m_children[i+1];
+ else
+ tmp[i] = m_children[i];
+ }
+ delete [] m_children;
+ m_children = tmp;
+ m_numchildren--;
+ }
+ }
+ else
+ {
+ delete [] m_children;
+ m_children = nullptr;
+ m_numchildren = 0;
+ }
+ }
+
+ if (returnValue)
+ returnValue->m_parent = nullptr;
+
+ return returnValue;
+}
+
+nsMsgSendPart* nsMsgSendPart::GetChild(int32_t which)
+{
+ NS_ASSERTION(which >= 0 && which < m_numchildren, "parameter out of range");
+ if (which >= 0 && which < m_numchildren) {
+ return m_children[which];
+ }
+ return nullptr;
+}
+
+
+
+nsresult nsMsgSendPart::PushBody(const char* buffer, int32_t length)
+{
+ nsresult status = NS_OK;
+ const char* encoded_data = buffer;
+
+ if (m_encoder)
+ {
+ status = m_encoder->Write(encoded_data, length);
+ }
+ else
+ {
+ // Merely translate all linebreaks to CRLF.
+ const char *in = encoded_data;
+ const char *end = in + length;
+ char *buffer, *out;
+
+
+ buffer = mime_get_stream_write_buffer();
+ // XXX -1 is not a valid nsresult
+ NS_ENSURE_TRUE(buffer, static_cast<nsresult>(-1));
+
+ NS_ASSERTION(encoded_data != buffer, "encoded_data == buffer");
+ out = buffer;
+
+ for (; in < end; in++) {
+ if (m_just_hit_CR) {
+ m_just_hit_CR = false;
+ if (*in == '\n') {
+ // The last thing we wrote was a CRLF from hitting a CR.
+ // So, we don't want to do anything from a following LF;
+ // we want to ignore it.
+ continue;
+ }
+ }
+ if (*in == '\r' || *in == '\n') {
+ /* Write out the newline. */
+ *out++ = '\r';
+ *out++ = '\n';
+
+ status = mime_write_message_body(m_state, buffer,
+ out - buffer);
+ if (NS_FAILED(status)) return status;
+ out = buffer;
+
+ if (*in == '\r') {
+ m_just_hit_CR = true;
+ }
+
+ out = buffer;
+ } else {
+
+ /* Fix for bug #95985. We can't assume that all lines are shorter
+ than 4096 chars (MIME_BUFFER_SIZE), so we need to test
+ for this here. sfraser.
+ */
+ if (out - buffer >= MIME_BUFFER_SIZE)
+ {
+ status = mime_write_message_body(m_state, buffer, out - buffer);
+ if (NS_FAILED(status)) return status;
+
+ out = buffer;
+ }
+
+ *out++ = *in;
+ }
+ }
+
+ /* Flush the last line. */
+ if (out > buffer) {
+ status = mime_write_message_body(m_state, buffer, out - buffer);
+ if (NS_FAILED(status)) return status;
+ out = buffer;
+ }
+ }
+
+ if (encoded_data && encoded_data != buffer) {
+ PR_Free((char *) encoded_data);
+ }
+
+ return status;
+}
+
+
+/* Partition the headers into those which apply to the message as a whole;
+those which apply to the message's contents; and the Content-Type header
+itself. (This relies on the fact that all body-related headers begin with
+"Content-".)
+
+ (How many header parsers are in this program now?)
+ */
+static nsresult
+divide_content_headers(const char *headers,
+ char **message_headers,
+ char **content_headers,
+ char **content_type_header)
+{
+ const char *tail;
+ char *message_tail, *content_tail, *type_tail;
+ int L = 0;
+ if (headers)
+ L = PL_strlen(headers);
+
+ if (L == 0)
+ return NS_OK;
+
+ *message_headers = (char *)PR_Malloc(L+1);
+ if (!*message_headers)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ *content_headers = (char *)PR_Malloc(L+1);
+ if (!*content_headers) {
+ PR_Free(*message_headers);
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ *content_type_header = (char *)PR_Malloc(L+1);
+ if (!*content_type_header) {
+ PR_Free(*message_headers);
+ PR_Free(*content_headers);
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ message_tail = *message_headers;
+ content_tail = *content_headers;
+ type_tail = *content_type_header;
+ tail = headers;
+
+ while (*tail)
+ {
+ const char *head = tail;
+ char **out;
+ while(true) {
+ /* Loop until we reach a newline that is not followed by whitespace.
+ */
+ if (tail[0] == 0 ||
+ ((tail[0] == '\r' || tail[0] == '\n') &&
+ !(tail[1] == ' ' || tail[1] == '\t' || tail[1] == '\n')))
+ {
+ /* Swallow the whole newline. */
+ if (tail[0] == '\r' && tail[1] == '\n')
+ tail++;
+ if (*tail)
+ tail++;
+ break;
+ }
+ tail++;
+ }
+
+ /* Decide which block this header goes into.
+ */
+ if (!PL_strncasecmp(head, "Content-Type:", 13))
+ out = &type_tail;
+ else
+ if (!PL_strncasecmp(head, "Content-", 8))
+ out = &content_tail;
+ else
+ out = &message_tail;
+
+ memcpy(*out, head, (tail-head));
+ *out += (tail-head);
+ }
+
+ *message_tail = 0;
+ *content_tail = 0;
+ *type_tail = 0;
+
+ if (!**message_headers) {
+ PR_Free(*message_headers);
+ *message_headers = 0;
+ }
+
+ if (!**content_headers) {
+ PR_Free(*content_headers);
+ *content_headers = 0;
+ }
+
+ if (!**content_type_header) {
+ PR_Free(*content_type_header);
+ *content_type_header = 0;
+ }
+
+#ifdef DEBUG
+ // ### mwelch Because of the extreme difficulty we've had with
+ // duplicate part headers, I'm going to put in an
+ // ASSERT here which makes sure that no duplicate
+ // Content-Type or Content-Transfer-Encoding headers
+ // leave here undetected.
+ const char* tmp;
+ if (*content_type_header) {
+ tmp = PL_strstr(*content_type_header, "Content-Type");
+ if (tmp) {
+ tmp++; // get past the first occurrence
+ NS_ASSERTION(!PL_strstr(tmp, "Content-Type"), "Content-part already present");
+ }
+ }
+
+ if (*content_headers) {
+ tmp = PL_strstr(*content_headers, "Content-Transfer-Encoding");
+ if (tmp) {
+ tmp++; // get past the first occurrence
+ NS_ASSERTION(!PL_strstr(tmp, "Content-Transfer-Encoding"), "Content-Transfert already present");
+ }
+ }
+#endif // DEBUG
+
+ return NS_OK;
+}
+
+#define SKIP_EMPTY_PART 1966
+
+nsresult
+nsMsgSendPart::Write()
+{
+ nsresult status = NS_OK;
+ char *separator = nullptr;
+ bool needToWriteCRLFAfterEncodedBody = false;
+
+#define PUSHLEN(str, length) \
+ do { \
+ status = mime_write_message_body(m_state, str, length); \
+ if (NS_FAILED(status)) goto FAIL; \
+ } while (0) \
+
+#define PUSH(str) PUSHLEN(str, PL_strlen(str))
+
+ // rhp: Suppress the output of parts that are empty!
+ if ( (m_parent) &&
+ (m_numchildren == 0) &&
+ ( (!m_buffer) || (!*m_buffer) ) &&
+ (!m_file) &&
+ (!m_mainpart) )
+ // XXX SKIP_EMPTY_PART (= 1966) is not a valid nsresult
+ return static_cast<nsresult>(SKIP_EMPTY_PART);
+
+ if (m_mainpart && m_type && PL_strcmp(m_type, TEXT_HTML) == 0)
+ {
+ if (m_file)
+ {
+ // The "insert HTML links" code requires a memory buffer,
+ // so read the file into memory.
+ NS_ASSERTION(m_buffer == nullptr, "not-null buffer");
+ int32_t length = 0;
+ int64_t fileSize;
+ if (NS_SUCCEEDED(m_file->GetFileSize(&fileSize)))
+ length = fileSize;
+
+ m_buffer = (char *) PR_Malloc(sizeof(char) * (length + 1));
+ if (m_buffer)
+ {
+ nsCOMPtr<nsIInputStream> inputFile;
+ nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inputFile), m_file);
+ if (NS_SUCCEEDED(rv))
+ {
+ uint32_t bytesRead;
+ rv = inputFile->Read(m_buffer, length, &bytesRead);
+ inputFile->Close();
+ m_buffer[length] = '\0';
+ }
+ else
+ PR_Free(m_buffer);
+ }
+ }
+ }
+
+ if (m_parent && m_parent->m_type &&
+ !PL_strcasecmp(m_parent->m_type, MULTIPART_DIGEST) &&
+ m_type &&
+ (!PL_strcasecmp(m_type, MESSAGE_RFC822) ||
+ !PL_strcasecmp(m_type, MESSAGE_NEWS)))
+ {
+ // If we're in a multipart/digest, and this document is of type
+ // message/rfc822, then it's appropriate to emit no headers.
+ //
+ }
+ else
+ {
+ char *message_headers = 0;
+ char *content_headers = 0;
+ char *content_type_header = 0;
+ status = divide_content_headers(m_other,
+ &message_headers,
+ &content_headers,
+ &content_type_header);
+ if (NS_FAILED(status))
+ goto FAIL;
+
+ /* First, write out all of the headers that refer to the message
+ itself (From, Subject, MIME-Version, etc.)
+ */
+ if (message_headers)
+ {
+ PUSH(message_headers);
+ PR_Free(message_headers);
+ message_headers = 0;
+ }
+
+ /* Now allow the crypto library to (potentially) insert some text
+ (it may want to wrap the body in an envelope.) */
+ if (!m_parent) {
+ status = m_state->BeginCryptoEncapsulation();
+ if (NS_FAILED(status)) goto FAIL;
+ }
+
+ /* Now make sure there's a Content-Type header.
+ */
+ if (!content_type_header)
+ {
+ NS_ASSERTION(m_type && *m_type, "null ptr");
+ bool needsCharset = mime_type_needs_charset(m_type ? m_type : TEXT_PLAIN);
+ if (needsCharset)
+ {
+ content_type_header = PR_smprintf("Content-Type: %s; charset=%s" CRLF,
+ (m_type ? m_type : TEXT_PLAIN), m_charset_name);
+ }
+ else
+ content_type_header = PR_smprintf("Content-Type: %s" CRLF,
+ (m_type ? m_type : TEXT_PLAIN));
+ if (!content_type_header)
+ {
+ if (content_headers)
+ PR_Free(content_headers);
+ status = NS_ERROR_OUT_OF_MEMORY;
+ goto FAIL;
+ }
+ }
+
+ /* If this is a compound object, tack a boundary string onto the
+ Content-Type header. this
+ */
+ if (m_numchildren > 0)
+ {
+ int L;
+ char *ct2;
+ NS_ASSERTION(m_type, "null ptr");
+
+ if (!separator)
+ {
+ separator = mime_make_separator("");
+ if (!separator)
+ {
+ status = NS_ERROR_OUT_OF_MEMORY;
+ goto FAIL;
+ }
+ }
+
+ L = PL_strlen(content_type_header);
+
+ if (content_type_header[L-1] == '\n')
+ content_type_header[--L] = 0;
+ if (content_type_header[L-1] == '\r')
+ content_type_header[--L] = 0;
+
+ ct2 = PR_smprintf("%s;\r\n boundary=\"%s\"" CRLF, content_type_header, separator);
+ PR_Free(content_type_header);
+ if (!ct2)
+ {
+ if (content_headers)
+ PR_Free(content_headers);
+ status = NS_ERROR_OUT_OF_MEMORY;
+ goto FAIL;
+ }
+
+ content_type_header = ct2;
+ }
+
+ // Now write out the Content-Type header...
+ NS_ASSERTION(content_type_header && *content_type_header, "null ptr");
+ PUSH(content_type_header);
+ PR_Free(content_type_header);
+ content_type_header = 0;
+
+ /* ...followed by all of the other headers that refer to the body of
+ the message (Content-Transfer-Encoding, Content-Dispositon, etc.)
+ */
+ if (content_headers)
+ {
+ PUSH(content_headers);
+ PR_Free(content_headers);
+ content_headers = 0;
+ }
+ }
+
+ PUSH(CRLF); // A blank line, to mark the end of headers.
+
+ m_firstBlock = true;
+ /* only convert if we need to tag charset */
+ m_needIntlConversion = mime_type_needs_charset(m_type);
+
+ if (m_buffer)
+ {
+ status = PushBody(m_buffer, PL_strlen(m_buffer));
+ if (NS_FAILED(status))
+ goto FAIL;
+ }
+ else if (m_file)
+ {
+ nsCOMPtr<nsIInputStream> inputStream;
+ nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), m_file);
+ if (NS_FAILED(rv))
+ {
+ // mysteriously disappearing?
+ nsCOMPtr<nsIMsgSendReport> sendReport;
+ m_state->GetSendReport(getter_AddRefs(sendReport));
+ if (sendReport)
+ {
+ nsAutoString error_msg;
+ nsMsgBuildMessageWithTmpFile(m_file, error_msg);
+ sendReport->SetMessage(nsIMsgSendReport::process_Current, error_msg.get(), false);
+ }
+ status = NS_MSG_UNABLE_TO_OPEN_TMP_FILE;
+ goto FAIL;
+ }
+
+ nsCString curLine;
+ bool more = true;
+
+ /* Kludge to avoid having to allocate memory on the toy computers... */
+ if (!mime_mailto_stream_read_buffer)
+ {
+ mime_mailto_stream_read_buffer = (char *) PR_Malloc(MIME_BUFFER_SIZE);
+ if (!mime_mailto_stream_read_buffer)
+ {
+ status = NS_ERROR_OUT_OF_MEMORY;
+ goto FAIL;
+ }
+ }
+
+ char *buffer = mime_mailto_stream_read_buffer;
+ if (m_strip_sensitive_headers)
+ {
+ // We are attaching a message, so we should be careful to
+ // strip out certain sensitive internal header fields.
+ bool skipping = false;
+ nsAutoPtr<nsLineBuffer<char> > lineBuffer(new nsLineBuffer<char>);
+ NS_ENSURE_TRUE(lineBuffer, NS_ERROR_OUT_OF_MEMORY);
+
+ while (more)
+ {
+ // NS_ReadLine doesn't return line termination chars.
+ rv = NS_ReadLine(inputStream.get(), lineBuffer.get(), curLine, &more);
+
+ curLine.Append(CRLF);
+
+ char *line = (char *) curLine.get();
+ if (skipping) {
+ if (*line == ' ' || *line == '\t')
+ continue;
+ else
+ skipping = false;
+ }
+
+ if (!PL_strncasecmp(line, "From -", 6) ||
+ !PL_strncasecmp(line, "BCC:", 4) ||
+ !PL_strncasecmp(line, "FCC:", 4) ||
+ !PL_strncasecmp(line, CONTENT_LENGTH ":", CONTENT_LENGTH_LEN+1) ||
+ !PL_strncasecmp(line, "Lines:", 6) ||
+ !PL_strncasecmp(line, "Status:", 7) ||
+ !PL_strncasecmp(line, X_MOZILLA_STATUS ":", X_MOZILLA_STATUS_LEN+1) ||
+ !PL_strncasecmp(line, X_MOZILLA_STATUS2 ":", X_MOZILLA_STATUS2_LEN+1) ||
+ !PL_strncasecmp(line, X_MOZILLA_DRAFT_INFO ":", X_MOZILLA_DRAFT_INFO_LEN+1) ||
+ !PL_strncasecmp(line, X_MOZILLA_NEWSHOST ":", X_MOZILLA_NEWSHOST_LEN+1) ||
+ !PL_strncasecmp(line, X_UIDL ":", X_UIDL_LEN+1) ||
+ !PL_strncasecmp(line, "X-VM-", 5)) /* hi Kyle */
+ {
+ skipping = true;
+ continue;
+ }
+
+ PUSH(line);
+
+ if (curLine.Length() == 2) {
+ nsCOMPtr <nsISeekableStream> seekableStream = do_QueryInterface(inputStream);
+ // seek back the amount of data left in the line buffer...
+ seekableStream->Seek(nsISeekableStream::NS_SEEK_CUR, lineBuffer->start - lineBuffer->end);
+ break; // Now can do normal reads for the body.
+ }
+ }
+ lineBuffer = nullptr;
+ }
+
+ while (NS_SUCCEEDED(status))
+ {
+ uint32_t bytesRead;
+ nsresult rv = inputStream->Read(buffer, MIME_BUFFER_SIZE, &bytesRead);
+ if (NS_FAILED(rv))
+ {
+ nsCOMPtr<nsIMsgSendReport> sendReport;
+ m_state->GetSendReport(getter_AddRefs(sendReport));
+ if (sendReport)
+ {
+ nsAutoString error_msg;
+ nsMsgBuildMessageWithFile(m_file, error_msg);
+ sendReport->SetMessage(nsIMsgSendReport::process_Current, error_msg.get(), false);
+ status = NS_MSG_UNABLE_TO_OPEN_FILE;
+ goto FAIL;
+ }
+ }
+ status = PushBody(buffer, bytesRead);
+ if (NS_FAILED(status))
+ goto FAIL;
+ if (bytesRead < MIME_BUFFER_SIZE)
+ break;
+ }
+ }
+
+ if (m_encoder)
+ {
+ nsresult rv = m_encoder->Flush();
+ m_encoder = nullptr;
+ needToWriteCRLFAfterEncodedBody = !m_parent;
+ if (NS_FAILED(rv))
+ {
+ // XXX -1 is not a valid nsresult
+ status = static_cast<nsresult>(-1);
+ goto FAIL;
+ }
+ }
+
+ //
+ // Ok, from here we loop and drive the the output of all children
+ // for this message.
+ //
+ if (m_numchildren > 0)
+ {
+ bool writeSeparator = true;
+
+ for (int i = 0 ; i < m_numchildren ; i ++)
+ {
+ if (writeSeparator)
+ {
+ PUSH(CRLF);
+ PUSH("--");
+
+ PUSH(separator);
+ PUSH(CRLF);
+ }
+
+ status = m_children[i]->Write();
+ if (NS_FAILED(status))
+ goto FAIL;
+
+ // XXX SKIP_EMPTY_PART (= 1966) is not a valid nsresult
+ if (status == static_cast<nsresult>(SKIP_EMPTY_PART))
+ writeSeparator = false;
+ else
+ writeSeparator = true;
+ }
+
+ PUSH(CRLF);
+ PUSH("--");
+ PUSH(separator);
+ PUSH("--");
+ PUSH(CRLF);
+ }
+ else if (needToWriteCRLFAfterEncodedBody)
+ PUSH(CRLF);
+
+FAIL:
+ PR_FREEIF(separator);
+ return status;
+}
+