nsresult nsMsgAttachmentHandler::ConvertToZipFile(nsILocalFileMac *aSourceFile) { // append ".zip" to the real file name nsCAutoString zippedName; nsresult rv = aSourceFile->GetNativeLeafName(zippedName); NS_ENSURE_SUCCESS(rv, rv); zippedName.AppendLiteral(".zip"); // create a temporary file that we'll work on nsCOMPtr <nsIFile> tmpFile; rv = nsMsgCreateTempFile(zippedName.get(), getter_AddRefs(tmpFile)); NS_ENSURE_SUCCESS(rv, rv); mEncodedWorkingFile = do_QueryInterface(tmpFile); // point our URL at the zipped temp file NS_NewFileURI(getter_AddRefs(mURL), mEncodedWorkingFile); // zip it! rv = nsSimpleZipper::Zip(aSourceFile, mEncodedWorkingFile); NS_ENSURE_SUCCESS(rv, rv); // set some metadata for this attachment, that will affect the MIME headers. m_type = APPLICATION_ZIP; m_realName = zippedName.get(); return NS_OK; }
nsresult nsMsgAttachmentHandler::ConvertToAppleEncoding(const nsCString &aFileURI, const nsCString &aFilePath, nsILocalFileMac *aSourceFile) { // convert the apple file to AppleDouble first, and then patch the // address in the url. //We need to retrieve the file type and creator... char fileInfo[32]; OSType type, creator; nsresult rv = aSourceFile->GetFileType(&type); if (NS_FAILED(rv)) return false; PR_snprintf(fileInfo, sizeof(fileInfo), "%X", type); m_xMacType = fileInfo; rv = aSourceFile->GetFileCreator(&creator); if (NS_FAILED(rv)) return false; PR_snprintf(fileInfo, sizeof(fileInfo), "%X", creator); m_xMacCreator = fileInfo; FSRef fsRef; aSourceFile->GetFSRef(&fsRef); bool sendResourceFork = HasResourceFork(&fsRef); // if we have a resource fork, check the filename extension, maybe we don't need the resource fork! if (sendResourceFork) { nsCOMPtr<nsIURL> fileUrl(do_CreateInstance(NS_STANDARDURL_CONTRACTID)); if (fileUrl) { rv = fileUrl->SetSpec(aFileURI); if (NS_SUCCEEDED(rv)) { nsCAutoString ext; rv = fileUrl->GetFileExtension(ext); if (NS_SUCCEEDED(rv) && !ext.IsEmpty()) { sendResourceFork = PL_strcasecmp(ext.get(), "TXT") && PL_strcasecmp(ext.get(), "JPG") && PL_strcasecmp(ext.get(), "GIF") && PL_strcasecmp(ext.get(), "TIF") && PL_strcasecmp(ext.get(), "HTM") && PL_strcasecmp(ext.get(), "HTML") && PL_strcasecmp(ext.get(), "ART") && PL_strcasecmp(ext.get(), "XUL") && PL_strcasecmp(ext.get(), "XML") && PL_strcasecmp(ext.get(), "CSS") && PL_strcasecmp(ext.get(), "JS"); } } } } // Only use appledouble if we aren't uuencoding. if( sendResourceFork ) { char *separator; separator = mime_make_separator("ad"); if (!separator) return NS_ERROR_OUT_OF_MEMORY; nsCOMPtr <nsIFile> tmpFile; nsresult rv = nsMsgCreateTempFile("appledouble", getter_AddRefs(tmpFile)); if (NS_SUCCEEDED(rv)) mEncodedWorkingFile = do_QueryInterface(tmpFile); if (!mEncodedWorkingFile) { PR_FREEIF(separator); return NS_ERROR_OUT_OF_MEMORY; } // // RICHIE_MAC - ok, here's the deal, we have a file that we need // to encode in appledouble encoding for the resource fork and put that // into the mEncodedWorkingFile location. Then, we need to patch the new file // spec into the array and send this as part of the 2 part appledouble/mime // encoded mime part. // AppleDoubleEncodeObject *obj = new (AppleDoubleEncodeObject); if (obj == NULL) { mEncodedWorkingFile = nsnull; PR_FREEIF(separator); return NS_ERROR_OUT_OF_MEMORY; } rv = MsgGetFileStream(mEncodedWorkingFile, getter_AddRefs(obj->fileStream)); if (NS_FAILED(rv) || !obj->fileStream) { PR_FREEIF(separator); delete obj; return NS_ERROR_OUT_OF_MEMORY; } PRInt32 bSize = AD_WORKING_BUFF_SIZE; char *working_buff = nsnull; while (!working_buff && (bSize >= 512)) { working_buff = (char *)PR_CALLOC(bSize); if (!working_buff) bSize /= 2; } if (!working_buff) { PR_FREEIF(separator); delete obj; return NS_ERROR_OUT_OF_MEMORY; } obj->buff = working_buff; obj->s_buff = bSize; // // Setup all the need information on the apple double encoder. // ap_encode_init(&(obj->ap_encode_obj), aFilePath.get(), separator); PRInt32 count; nsresult status = noErr; m_size = 0; while (status == noErr) { status = ap_encode_next(&(obj->ap_encode_obj), obj->buff, bSize, &count); if (status == noErr || status == errDone) { // // we got the encode data, so call the next stream to write it to the disk. // PRUint32 bytesWritten; obj->fileStream->Write(obj->buff, count, &bytesWritten); if (bytesWritten != (PRUint32) count) status = NS_MSG_ERROR_WRITING_FILE; } } ap_encode_end(&(obj->ap_encode_obj), (status >= 0)); // if this is true, ok, false abort if (obj->fileStream) obj->fileStream->Close(); PR_FREEIF(obj->buff); /* free the working buff. */ PR_FREEIF(obj); nsCOMPtr <nsIURI> fileURI; NS_NewFileURI(getter_AddRefs(fileURI), mEncodedWorkingFile); nsCOMPtr<nsIFileURL> theFileURL = do_QueryInterface(fileURI, &rv); NS_ENSURE_SUCCESS(rv,rv); nsCString newURLSpec; NS_ENSURE_SUCCESS(rv, rv); fileURI->GetSpec(newURLSpec); if (newURLSpec.IsEmpty()) { PR_FREEIF(separator); return NS_ERROR_OUT_OF_MEMORY; } if (NS_FAILED(nsMsgNewURL(getter_AddRefs(mURL), newURLSpec.get()))) { PR_FREEIF(separator); return NS_ERROR_OUT_OF_MEMORY; } // Now after conversion, also patch the types. char tmp[128]; PR_snprintf(tmp, sizeof(tmp), MULTIPART_APPLEDOUBLE ";\r\n boundary=\"%s\"", separator); PR_FREEIF(separator); m_type = tmp; } else { if ( sendResourceFork ) { // For now, just do the encoding, but in the old world we would ask the // user about doing this conversion printf("...we could ask the user about this conversion, but for now, nahh..\n"); } bool useDefault; char *macType, *macEncoding; if (m_type.IsEmpty() || m_type.LowerCaseEqualsLiteral(TEXT_PLAIN)) { # define TEXT_TYPE 0x54455854 /* the characters 'T' 'E' 'X' 'T' */ # define text_TYPE 0x74657874 /* the characters 't' 'e' 'x' 't' */ if (type != TEXT_TYPE && type != text_TYPE) { MacGetFileType(aSourceFile, &useDefault, &macType, &macEncoding); m_type = macType; } } // don't bother to set the types if we failed in getting the file info. } return NS_OK; }
nsresult nsMsgAttachmentHandler::SnarfAttachment(nsMsgCompFields *compFields) { NS_ASSERTION (! m_done, "Already done"); if (!mURL) return SnarfMsgAttachment(compFields); mCompFields = compFields; // First, get as file spec and create the stream for the // temp file where we will save this data nsCOMPtr <nsIFile> tmpFile; nsresult rv = nsMsgCreateTempFile("nsmail.tmp", getter_AddRefs(tmpFile)); NS_ENSURE_SUCCESS(rv, rv); mTmpFile = do_QueryInterface(tmpFile); mDeleteFile = true; rv = MsgNewBufferedFileOutputStream(getter_AddRefs(mOutFile), mTmpFile, -1, 00600); if (NS_FAILED(rv) || !mOutFile) { if (m_mime_delivery_state) { nsCOMPtr<nsIMsgSendReport> sendReport; m_mime_delivery_state->GetSendReport(getter_AddRefs(sendReport)); if (sendReport) { nsAutoString error_msg; nsMsgBuildMessageWithTmpFile(mTmpFile, error_msg); sendReport->SetMessage(nsIMsgSendReport::process_Current, error_msg.get(), false); } } mTmpFile->Remove(false); mTmpFile = nsnull; return NS_MSG_UNABLE_TO_OPEN_TMP_FILE; } nsCString sourceURISpec; mURL->GetSpec(sourceURISpec); #ifdef XP_MACOSX if (!m_bogus_attachment && StringBeginsWith(sourceURISpec, NS_LITERAL_CSTRING("file://"))) { // Unescape the path (i.e. un-URLify it) before making a FSSpec nsCAutoString filePath; filePath.Adopt(nsMsgGetLocalFileFromURL(sourceURISpec.get())); nsCAutoString unescapedFilePath; MsgUnescapeString(filePath, 0, unescapedFilePath); nsCOMPtr<nsILocalFile> sourceFile; NS_NewNativeLocalFile(unescapedFilePath, true, getter_AddRefs(sourceFile)); if (!sourceFile) return NS_ERROR_FAILURE; // check if it is a bundle. if it is, we'll zip it. // if not, we'll apple encode it (applesingle or appledouble) nsCOMPtr<nsILocalFileMac> macFile(do_QueryInterface(sourceFile)); bool isPackage; macFile->IsPackage(&isPackage); if (isPackage) rv = ConvertToZipFile(macFile); else rv = ConvertToAppleEncoding(sourceURISpec, unescapedFilePath, macFile); NS_ENSURE_SUCCESS(rv, rv); } #endif /* XP_MACOSX */ // // Ok, here we are, we need to fire the URL off and get the data // in the temp file // // Create a fetcher for the URL attachment... nsCOMPtr<nsIURLFetcher> fetcher = do_CreateInstance(NS_URLFETCHER_CONTRACTID, &rv); if (NS_FAILED(rv) || !fetcher) { if (NS_SUCCEEDED(rv)) return NS_ERROR_UNEXPECTED; else return rv; } return fetcher->FireURLRequest(mURL, mTmpFile, mOutFile, FetcherURLDoneCallback, this); }
nsresult nsMsgAttachmentHandler::SnarfMsgAttachment(nsMsgCompFields *compFields) { nsresult rv = NS_ERROR_INVALID_ARG; nsCOMPtr <nsIMsgMessageService> messageService; if (m_uri.Find("-message:", CaseInsensitiveCompare) != -1) { nsCOMPtr <nsIFile> tmpFile; rv = nsMsgCreateTempFile("nsmail.tmp", getter_AddRefs(tmpFile)); NS_ENSURE_SUCCESS(rv, rv); mTmpFile = do_QueryInterface(tmpFile); mDeleteFile = true; mCompFields = compFields; m_type = MESSAGE_RFC822; m_overrideType = MESSAGE_RFC822; if (!mTmpFile) { rv = NS_ERROR_FAILURE; goto done; } rv = MsgNewBufferedFileOutputStream(getter_AddRefs(mOutFile), mTmpFile, -1, 00600); if (NS_FAILED(rv) || !mOutFile) { if (m_mime_delivery_state) { nsCOMPtr<nsIMsgSendReport> sendReport; m_mime_delivery_state->GetSendReport(getter_AddRefs(sendReport)); if (sendReport) { nsAutoString error_msg; nsMsgBuildMessageWithTmpFile(mTmpFile, error_msg); sendReport->SetMessage(nsIMsgSendReport::process_Current, error_msg.get(), false); } } rv = NS_MSG_UNABLE_TO_OPEN_TMP_FILE; goto done; } nsCOMPtr<nsIURLFetcher> fetcher = do_CreateInstance(NS_URLFETCHER_CONTRACTID, &rv); if (NS_FAILED(rv) || !fetcher) { if (NS_SUCCEEDED(rv)) rv = NS_ERROR_UNEXPECTED; goto done; } rv = fetcher->Initialize(mTmpFile, mOutFile, FetcherURLDoneCallback, this); rv = GetMessageServiceFromURI(m_uri, getter_AddRefs(messageService)); if (NS_SUCCEEDED(rv) && messageService) { nsCAutoString uri(m_uri); uri += (uri.FindChar('?') == kNotFound) ? '?' : '&'; uri.Append("fetchCompleteMessage=true"); nsCOMPtr<nsIStreamListener> strListener; fetcher->QueryInterface(NS_GET_IID(nsIStreamListener), getter_AddRefs(strListener)); // initialize a new stream converter, that uses the strListener as its input // obtain the input stream listener from the new converter, // and pass the converter's input stream listener to DisplayMessage m_mime_parser = do_CreateInstance(NS_MAILNEWS_MIME_STREAM_CONVERTER_CONTRACTID, &rv); if (NS_FAILED(rv)) goto done; // Set us as the output stream for HTML data from libmime... nsCOMPtr<nsIMimeStreamConverter> mimeConverter = do_QueryInterface(m_mime_parser); if (mimeConverter) { mimeConverter->SetMimeOutputType(nsMimeOutput::nsMimeMessageDecrypt); mimeConverter->SetForwardInline(false); mimeConverter->SetIdentity(nsnull); mimeConverter->SetOriginalMsgURI(nsnull); } nsCOMPtr<nsIStreamListener> convertedListener = do_QueryInterface(m_mime_parser, &rv); if (NS_FAILED(rv)) goto done; nsCOMPtr<nsIURI> aURL; rv = messageService->GetUrlForUri(uri.get(), getter_AddRefs(aURL), nsnull); if (aURL) aURL->SetSpec(nsDependentCString(uri.get())); rv = NS_NewInputStreamChannel(getter_AddRefs(m_converter_channel), aURL, nsnull); if (NS_FAILED(rv)) goto done; rv = m_mime_parser->AsyncConvertData( "message/rfc822", "message/rfc822", strListener, m_converter_channel); if (NS_FAILED(rv)) goto done; rv = messageService->DisplayMessage(uri.get(), convertedListener, nsnull, nsnull, nsnull, nsnull); } } done: if (NS_FAILED(rv)) { if (mOutFile) { mOutFile->Close(); mOutFile = nsnull; } if (mTmpFile) { mTmpFile->Remove(false); mTmpFile = nsnull; } } return rv; }
int MimePartBufferWrite (MimePartBufferData *data, const char *buf, PRInt32 size) { NS_ASSERTION(data && buf && size > 0, "MimePartBufferWrite: Bad param"); if (!data || !buf || size <= 0) return -1; /* If we don't yet have a buffer (either memory or file) try and make a memory buffer. */ if (!data->part_buffer && !data->file_buffer) { int target_size = TARGET_MEMORY_BUFFER_SIZE; while (target_size > 0) { data->part_buffer = (char *) PR_MALLOC(target_size); if (data->part_buffer) break; /* got it! */ target_size -= TARGET_MEMORY_BUFFER_QUANTUM; /* decrease it and try again */ } if (data->part_buffer) data->part_buffer_size = target_size; else data->part_buffer_size = 0; data->part_buffer_fp = 0; } /* Ok, if at this point we still don't have either kind of buffer, try and make a file buffer. */ if (!data->part_buffer && !data->file_buffer) { nsCOMPtr <nsIFile> tmpFile; nsresult rv = nsMsgCreateTempFile("nsma", getter_AddRefs(tmpFile)); NS_ENSURE_SUCCESS(rv, MIME_UNABLE_TO_OPEN_TMP_FILE); data->file_buffer = do_QueryInterface(tmpFile); rv = MsgNewBufferedFileOutputStream(getter_AddRefs(data->output_file_stream), data->file_buffer, PR_WRONLY | PR_CREATE_FILE, 00600); NS_ENSURE_SUCCESS(rv, rv); } NS_ASSERTION(data->part_buffer || data->output_file_stream, "no part_buffer or file_stream"); /* If this buf will fit in the memory buffer, put it there. */ if (data->part_buffer && data->part_buffer_fp + size < data->part_buffer_size) { memcpy(data->part_buffer + data->part_buffer_fp, buf, size); data->part_buffer_fp += size; } /* Otherwise it won't fit; write it to the file instead. */ else { /* If the file isn't open yet, open it, and dump the memory buffer to it. */ if (!data->output_file_stream) { nsresult rv; if (!data->file_buffer) { nsCOMPtr <nsIFile> tmpFile; rv = nsMsgCreateTempFile("nsma", getter_AddRefs(tmpFile)); NS_ENSURE_SUCCESS(rv, MIME_UNABLE_TO_OPEN_TMP_FILE); data->file_buffer = do_QueryInterface(tmpFile); } rv = MsgNewBufferedFileOutputStream(getter_AddRefs(data->output_file_stream), data->file_buffer, PR_WRONLY | PR_CREATE_FILE, 00600); NS_ENSURE_SUCCESS(rv, MIME_UNABLE_TO_OPEN_TMP_FILE); if (data->part_buffer && data->part_buffer_fp) { PRUint32 bytesWritten; nsresult rv = data->output_file_stream->Write(data->part_buffer, data->part_buffer_fp, &bytesWritten); NS_ENSURE_SUCCESS(rv, rv); } PR_FREEIF(data->part_buffer); data->part_buffer_fp = 0; data->part_buffer_size = 0; } /* Dump this buf to the file. */ PRUint32 bytesWritten; nsresult rv = data->output_file_stream->Write (buf, size, &bytesWritten); if (NS_FAILED(rv) || (PRInt32) bytesWritten < size) return MIME_OUT_OF_MEMORY; } return 0; }
static int MimeMultipartRelated_parse_child_line (MimeObject *obj, const char *line, int32_t length, bool first_line_p) { MimeContainer *cont = (MimeContainer *) obj; MimeMultipartRelated *relobj = (MimeMultipartRelated *) obj; int status; MimeObject *kid; if (obj->options && !obj->options->write_html_p #ifdef MIME_DRAFTS && !obj->options->decompose_file_p #endif /* MIME_DRAFTS */ ) { /* Oh, just go do the normal thing... */ return ((MimeMultipartClass*)&MIME_SUPERCLASS)-> parse_child_line(obj, line, length, first_line_p); } /* Throw it away if this isn't the head object. (Someday, maybe we'll cache it instead.) */ PR_ASSERT(cont->nchildren > 0); if (cont->nchildren <= 0) return -1; kid = cont->children[cont->nchildren-1]; PR_ASSERT(kid); if (!kid) return -1; if (kid != relobj->headobj) return 0; /* Buffer this up (###tw much code duplication from mimemalt.c) */ /* If we don't yet have a buffer (either memory or file) try and make a memory buffer. */ if (!relobj->head_buffer && !relobj->file_buffer) { int target_size = 1024 * 50; /* try for 50k */ while (target_size > 0) { relobj->head_buffer = (char *) PR_MALLOC(target_size); if (relobj->head_buffer) break; /* got it! */ target_size -= (1024 * 5); /* decrease it and try again */ } if (relobj->head_buffer) { relobj->head_buffer_size = target_size; } else { relobj->head_buffer_size = 0; } relobj->head_buffer_fp = 0; } nsresult rv; /* Ok, if at this point we still don't have either kind of buffer, try and make a file buffer. */ if (!relobj->head_buffer && !relobj->file_buffer) { nsCOMPtr <nsIFile> file; rv = nsMsgCreateTempFile("nsma", getter_AddRefs(file)); NS_ENSURE_SUCCESS(rv, rv); relobj->file_buffer = do_QueryInterface(file); rv = MsgNewBufferedFileOutputStream(getter_AddRefs(relobj->output_file_stream), relobj->file_buffer, PR_WRONLY | PR_CREATE_FILE, 00600); NS_ENSURE_SUCCESS(rv, rv); } PR_ASSERT(relobj->head_buffer || relobj->output_file_stream); /* If this line will fit in the memory buffer, put it there. */ if (relobj->head_buffer && relobj->head_buffer_fp + length < relobj->head_buffer_size) { memcpy(relobj->head_buffer + relobj->head_buffer_fp, line, length); relobj->head_buffer_fp += length; } else { /* Otherwise it won't fit; write it to the file instead. */ /* If the file isn't open yet, open it, and dump the memory buffer to it. */ if (!relobj->output_file_stream) { if (!relobj->file_buffer) { nsCOMPtr <nsIFile> file; rv = nsMsgCreateTempFile("nsma", getter_AddRefs(file)); NS_ENSURE_SUCCESS(rv, rv); relobj->file_buffer = do_QueryInterface(file); } nsresult rv = MsgNewBufferedFileOutputStream(getter_AddRefs(relobj->output_file_stream), relobj->file_buffer, PR_WRONLY | PR_CREATE_FILE, 00600); NS_ENSURE_SUCCESS(rv, rv); if (relobj->head_buffer && relobj->head_buffer_fp) { uint32_t bytesWritten; status = relobj->output_file_stream->Write(relobj->head_buffer, relobj->head_buffer_fp, &bytesWritten); if (bytesWritten < relobj->head_buffer_fp) return MIME_UNABLE_TO_OPEN_TMP_FILE; } PR_FREEIF(relobj->head_buffer); relobj->head_buffer_fp = 0; relobj->head_buffer_size = 0; } /* Dump this line to the file. */ uint32_t bytesWritten; rv = relobj->output_file_stream->Write(line, length, &bytesWritten); if ((int32_t) bytesWritten < length || NS_FAILED(rv)) return MIME_UNABLE_TO_OPEN_TMP_FILE; } return 0; }
nsresult nsMsgSendLater::StartNextMailFileSend(nsresult prevStatus) { bool hasMoreElements = false; if ((!mEnumerator) || NS_FAILED(mEnumerator->HasMoreElements(&hasMoreElements)) || !hasMoreElements) { // Notify that this message has finished being sent. NotifyListenersOnProgress(mTotalSendCount, mMessagesToSend.Count(), 100, 100); // EndSendMessages resets everything for us EndSendMessages(prevStatus, nullptr, mTotalSendCount, mTotalSentSuccessfully); // XXX Should we be releasing references so that we don't hold onto items // unnecessarily. return NS_OK; } // If we've already sent a message, and are sending more, send out a progress // update with 100% for both send and copy as we must have finished by now. if (mTotalSendCount) NotifyListenersOnProgress(mTotalSendCount, mMessagesToSend.Count(), 100, 100); nsCOMPtr<nsISupports> currentItem; nsresult rv = mEnumerator->GetNext(getter_AddRefs(currentItem)); NS_ENSURE_SUCCESS(rv, rv); mMessage = do_QueryInterface(currentItem); if (!mMessage) return NS_ERROR_NOT_AVAILABLE; if (!mMessageFolder) return NS_ERROR_UNEXPECTED; nsCString messageURI; mMessageFolder->GetUriForMsg(mMessage, messageURI); rv = nsMsgCreateTempFile("nsqmail.tmp", getter_AddRefs(mTempFile)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIMsgMessageService> messageService; rv = GetMessageServiceFromURI(messageURI, getter_AddRefs(messageService)); if (NS_FAILED(rv) && !messageService) return NS_ERROR_FACTORY_NOT_LOADED; ++mTotalSendCount; nsCString identityKey; rv = mMessage->GetStringProperty(HEADER_X_MOZILLA_IDENTITY_KEY, getter_Copies(identityKey)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIMsgIdentity> identity; rv = GetIdentityFromKey(identityKey.get(), getter_AddRefs(identity)); NS_ENSURE_SUCCESS(rv, rv); // Notify that we're just about to start sending this message NotifyListenersOnMessageStartSending(mTotalSendCount, mMessagesToSend.Count(), identity); // Setup what we need to parse the data stream correctly m_inhead = true; m_headersFP = 0; m_headersPosition = 0; m_bytesRead = 0; m_position = 0; m_flagsPosition = 0; m_headersSize = 0; PR_FREEIF(mLeftoverBuffer); // Now, get our stream listener interface and plug it into the DisplayMessage // operation AddRef(); rv = messageService->DisplayMessage(messageURI.get(), static_cast<nsIStreamListener*>(this), nullptr, nullptr, nullptr, nullptr); Release(); return rv; }