int nsMsgSendPart::Write() { int status = 0; char *separator = nsnull; bool needToWriteCRLFAfterEncodedBody = false; #define PUSHLEN(str, length) \ do { \ status = mime_write_message_body(m_state, str, length); \ if (status < 0) 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) ) return 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 == nsnull, "not-null buffer"); PRInt32 length = 0; PRInt64 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)) { PRUint32 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 (status < 0) 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 (status < 0) 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 (status < 0) 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; nsLineBuffer<char> *lineBuffer; rv = NS_InitLineBuffer(&lineBuffer); NS_ENSURE_SUCCESS(rv, rv); while (more) { // NS_ReadLine doesn't return line termination chars. rv = NS_ReadLine(inputStream.get(), lineBuffer, 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. } } PR_Free(lineBuffer); } while (status >= 0) { PRUint32 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 (status < 0) goto FAIL; if (bytesRead < MIME_BUFFER_SIZE) break; } } if (m_encoder_data) { status = MIME_EncoderDestroy(m_encoder_data, false); m_encoder_data = nsnull; needToWriteCRLFAfterEncodedBody = !m_parent; if (status < 0) 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 (status < 0) goto FAIL; if (status == 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; }
int nsMsgSendPart::Write() { int status = 0; char *separator = nsnull; PRBool needToWriteCRLFAfterEncodedBody = PR_FALSE; #define PUSHLEN(str, length) \ do { \ status = mime_write_message_body(m_state, str, length); \ if (status < 0) 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_filespec) && (!m_mainpart) ) return SKIP_EMPTY_PART; if (m_mainpart && m_type && PL_strcmp(m_type, TEXT_HTML) == 0) { if (m_filespec) { // The "insert HTML links" code requires a memory buffer, // so read the file into memory. NS_ASSERTION(m_buffer == nsnull, "not-null buffer"); PRInt32 length = 0; if (m_filespec->Valid()) length = m_filespec->GetFileSize(); m_buffer = (char *) PR_Malloc(sizeof(char) * (length + 1)); if (m_buffer) { nsInputFileStream file(*m_filespec); if (file.is_open()) { length = file.read(m_buffer, length); file.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 (status < 0) 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 (status < 0) goto FAIL; } /* Now make sure there's a Content-Type header. */ if (!content_type_header) { NS_ASSERTION(m_type && *m_type, "null ptr"); PRBool 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] == nsCRT::LF) content_type_header[--L] = 0; if (content_type_header[L-1] == nsCRT::CR) 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 = PR_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 (status < 0) goto FAIL; } else if (m_filespec) { nsInputFileStream myStream(*m_filespec); if (!myStream.is_open()) { // mysteriously disappearing? nsCOMPtr<nsIMsgSendReport> sendReport; m_state->GetSendReport(getter_AddRefs(sendReport)); if (sendReport) { nsAutoString error_msg; nsAutoString path; NS_CopyNativeToUnicode( nsDependentCString(m_filespec->GetNativePathCString()), path); nsMsgBuildErrorMessageByID(NS_MSG_UNABLE_TO_OPEN_TMP_FILE, error_msg, &path, nsnull); sendReport->SetMessage(nsIMsgSendReport::process_Current, error_msg.get(), PR_FALSE); } status = NS_MSG_UNABLE_TO_OPEN_TMP_FILE; goto FAIL; } /* 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. PRBool skipping = PR_FALSE; while (1) { char *line; if (myStream.eof()) line = nsnull; else { buffer[0] = '\0'; myStream.readline(buffer, MIME_BUFFER_SIZE-3); line = buffer; } if (!line) break; /* EOF */ if (skipping) { if (*line == ' ' || *line == '\t') continue; else skipping = PR_FALSE; } int hdrLen = PL_strlen(buffer); if ((hdrLen < 2) || (buffer[hdrLen-2] != nsCRT::CR)) { // if the line doesn't end with CRLF, // ... make it end with CRLF. if ( (hdrLen == 0) || ((buffer[hdrLen-1] != nsCRT::CR) && (buffer[hdrLen-1] != nsCRT::LF)) ) hdrLen++; buffer[hdrLen-1] = '\015'; buffer[hdrLen] = '\012'; buffer[hdrLen+1] = '\0'; } 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 = PR_TRUE; continue; } PUSH(line); if (*line == nsCRT::CR || *line == nsCRT::LF) { break; // Now can do normal reads for the body. } } } while (!myStream.eof()) { if ((status = myStream.read(buffer, MIME_BUFFER_SIZE)) < 0) { nsCOMPtr<nsIMsgSendReport> sendReport; m_state->GetSendReport(getter_AddRefs(sendReport)); if (sendReport) { nsAutoString error_msg; nsAutoString path; NS_CopyNativeToUnicode(nsDependentCString(m_filespec->GetNativePathCString()), path); nsMsgBuildErrorMessageByID(NS_MSG_UNABLE_TO_OPEN_FILE, error_msg, &path, nsnull); sendReport->SetMessage(nsIMsgSendReport::process_Current, error_msg.get(), PR_FALSE); status = NS_MSG_UNABLE_TO_OPEN_FILE; goto FAIL; } } status = PushBody(buffer, status); if (status < 0) goto FAIL; } } if (m_encoder_data) { status = MIME_EncoderDestroy(m_encoder_data, PR_FALSE); m_encoder_data = nsnull; needToWriteCRLFAfterEncodedBody = !m_parent; if (status < 0) goto FAIL; } // // Ok, from here we loop and drive the the output of all children // for this message. // if (m_numchildren > 0) { PRBool writeSeparator = PR_TRUE; for (int i = 0 ; i < m_numchildren ; i ++) { if (writeSeparator) { PUSH(CRLF); PUSH("--"); PUSH(separator); PUSH(CRLF); } status = m_children[i]->Write(); if (status < 0) goto FAIL; if (status == SKIP_EMPTY_PART) writeSeparator = PR_FALSE; else writeSeparator = PR_TRUE; } PUSH(CRLF); PUSH("--"); PUSH(separator); PUSH("--"); PUSH(CRLF); } else if (needToWriteCRLFAfterEncodedBody) PUSH(CRLF); FAIL: PR_FREEIF(separator); return status; }