nsresult nsEudoraMailbox::ImportMailbox(uint32_t *pBytes, bool *pAbort, const PRUnichar *pName, nsIFile *pSrc, nsIMsgFolder *dstFolder, int32_t *pMsgCount) { nsCOMPtr<nsIFile> tocFile; nsCOMPtr<nsIInputStream> srcInputStream; nsCOMPtr<nsIInputStream> tocInputStream; nsCOMPtr<nsIOutputStream> mailOutputStream; bool importWithoutToc = true; bool deleteToc = false; nsCOMPtr<nsIFile> mailFile; if (pMsgCount) *pMsgCount = 0; nsresult rv = pSrc->GetFileSize(&m_mailSize); rv = NS_NewLocalFileInputStream(getter_AddRefs(srcInputStream), pSrc); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIFile> srcFile(pSrc); // First, get the index file for this mailbox rv = FindTOCFile(pSrc, getter_AddRefs(tocFile), &deleteToc); if (NS_SUCCEEDED(rv) && tocFile) { IMPORT_LOG0("Reading euroda toc file: "); DUMP_FILENAME(tocFile, true); // Read the toc and import the messages rv = ImportMailboxUsingTOC(pBytes, pAbort, srcInputStream, tocFile, dstFolder, pMsgCount); // clean up if (deleteToc) DeleteFile(tocFile); // If we were able to import with the TOC, then we don't need to bother // importing without the TOC. if (NS_SUCCEEDED(rv)) { importWithoutToc = false; IMPORT_LOG0("Imported mailbox: "); DUMP_FILENAME(pSrc, false); IMPORT_LOG0(" Using TOC: "); DUMP_FILENAME(tocFile, true); } else { IMPORT_LOG0("*** Error importing with TOC - will import without TOC.\n"); } } // pSrc must be Released before returning if (importWithoutToc) { // The source file contains partially constructed mail messages, // and attachments. We should first investigate if we can use the mailnews msgCompose // stuff to do the work for us. If not we have to scan the mailboxes and do TONS // of work to properly reconstruct the message - Eudora is so nice that it strips things // like MIME headers, character encoding, and attachments - beautiful! rv = pSrc->GetFileSize(&m_mailSize); SimpleBufferTonyRCopiedOnce readBuffer; SimpleBufferTonyRCopiedOnce headers; SimpleBufferTonyRCopiedOnce body; SimpleBufferTonyRCopiedOnce copy; headers.m_convertCRs = true; body.m_convertCRs = true; copy.Allocate(kCopyBufferSize); readBuffer.Allocate(kMailReadBufferSize); ReadFileState state; state.offset = 0; state.size = m_mailSize; state.pFile = pSrc; IMPORT_LOG0("Reading mailbox\n"); if (NS_SUCCEEDED(rv)) { nsCString defaultDate; nsAutoCString bodyType; IMPORT_LOG0("Reading first message\n"); nsCOMPtr<nsIOutputStream> outputStream; nsCOMPtr<nsIMsgPluggableStore> msgStore; rv = dstFolder->GetMsgStore(getter_AddRefs(msgStore)); NS_ENSURE_SUCCESS(rv, rv); while (!*pAbort && NS_SUCCEEDED(rv = ReadNextMessage( &state, readBuffer, headers, body, defaultDate, bodyType, NULL))) { if (pBytes) *pBytes += body.m_writeOffset - 1 + headers.m_writeOffset - 1; nsCOMPtr<nsIMsgDBHdr> msgHdr; bool reusable; rv = msgStore->GetNewMsgOutputStream(dstFolder, getter_AddRefs(msgHdr), &reusable, getter_AddRefs(outputStream)); if (NS_FAILED(rv)) break; rv = ImportMessage(headers, body, defaultDate, bodyType, outputStream, pMsgCount); if (NS_SUCCEEDED(rv)) msgStore->FinishNewMessage(outputStream, msgHdr); else { msgStore->DiscardNewMessage(outputStream, msgHdr); IMPORT_LOG0( "*** Error importing message\n"); } if (!reusable) outputStream->Close(); if (!readBuffer.m_bytesInBuf && (state.offset >= state.size)) break; } if (outputStream) outputStream->Close(); } else { IMPORT_LOG0("*** Error creating file spec for composition\n"); } } return rv; }
nsresult nsEudoraMailbox::ImportMailboxUsingTOC( uint32_t *pBytes, bool *pAbort, nsIInputStream *pInputStream, nsIFile *tocFile, nsIMsgFolder *dstFolder, int32_t *pMsgCount) { nsresult rv = NS_OK; int64_t mailSize = m_mailSize; int64_t tocSize = 0; uint32_t saveBytes = pBytes ? *pBytes : 0; nsCOMPtr <nsIInputStream> tocInputStream; rv = tocFile->GetFileSize(&tocSize); // if the index or the mail file is empty then just // use the original mail file. if (!mailSize || !tocSize) return NS_ERROR_FAILURE; rv = NS_NewLocalFileInputStream(getter_AddRefs(tocInputStream), tocFile); NS_ENSURE_SUCCESS(rv, rv); SimpleBufferTonyRCopiedOnce readBuffer; SimpleBufferTonyRCopiedOnce headers; SimpleBufferTonyRCopiedOnce body; SimpleBufferTonyRCopiedOnce copy; int32_t tocOffset = kMsgFirstOffset; EudoraTOCEntry tocEntry; copy.Allocate(kCopyBufferSize); readBuffer.Allocate(kMailReadBufferSize); IMPORT_LOG0("Importing mailbox using TOC: "); DUMP_FILENAME(tocFile, true); nsCOMPtr<nsISeekableStream> tocSeekableStream = do_QueryInterface(tocInputStream); nsCOMPtr<nsISeekableStream> mailboxSeekableStream = do_QueryInterface(pInputStream); nsCOMPtr<nsIOutputStream> outputStream; nsCOMPtr<nsIMsgPluggableStore> msgStore; rv = dstFolder->GetMsgStore(getter_AddRefs(msgStore)); NS_ENSURE_SUCCESS(rv, rv); while (!*pAbort && (tocOffset < (int32_t)tocSize)) { if (NS_FAILED(rv = tocSeekableStream->Seek(nsISeekableStream::NS_SEEK_SET, tocOffset))) break; if (NS_FAILED(rv = ReadTOCEntry(tocInputStream, tocEntry))) break; nsCOMPtr<nsIMsgDBHdr> msgHdr; bool reusable; rv = msgStore->GetNewMsgOutputStream(dstFolder, getter_AddRefs(msgHdr), &reusable, getter_AddRefs(outputStream)); if (NS_FAILED(rv)) break; // Quick and dirty way to read in and parse the message the way the rest // of the code expects. nsCString defaultDate; nsAutoCString bodyType; ReadFileState state; // Seek to the start of the email message. mailboxSeekableStream->Seek(nsISeekableStream::NS_SEEK_SET, tocEntry.m_Offset); // We're fudging the data to make ReadNextMessage happy. In particular // state.size is meant to be the size of the entire file, because it's // assumed that ReadNextMessage will actually have to parse. We know // exactly how big the message is, so we simply set the "size" to be // immediately where the message ends. state.offset = tocEntry.m_Offset; state.pInputStream = pInputStream; state.size = state.offset + tocEntry.m_Length; if (NS_SUCCEEDED(rv = ReadNextMessage(&state, readBuffer, headers, body, defaultDate, bodyType, &tocEntry))) { rv = ImportMessage(headers, body, defaultDate, bodyType, outputStream, pMsgCount); if (pBytes) *pBytes += tocEntry.m_Length; if (NS_SUCCEEDED(rv)) msgStore->FinishNewMessage(outputStream, msgHdr); else { msgStore->DiscardNewMessage(outputStream, msgHdr); IMPORT_LOG0( "*** Error importing message\n"); } } // We currently don't consider an error from ReadNextMessage or ImportMessage to be fatal. // Reset the error back to no error in case this is the last time through the loop. rv = NS_OK; tocOffset += kMsgHeaderSize; if (!reusable) outputStream->Close(); } if (outputStream) outputStream->Close(); if (NS_SUCCEEDED(rv)) { IMPORT_LOG0(" finished\n"); } else { // We failed somewhere important enough that we kept the error. // Bail on all that we imported since we'll be importing everything // again using just the mailbox. IMPORT_LOG0("*** Error importing mailbox using TOC: "); // DUMP_FILENAME(pMail, true); // Reset pBytes back to where it was before we imported this mailbox. // This will likely result in a funky progress bar which will move // backwards, but that's probably the best we can do to keep the // progress accurate since we'll be re-importing the same mailbox. if (pBytes) *pBytes = saveBytes; // Set the message count back to 0. if (pMsgCount) *pMsgCount = 0; } return rv; }
nsresult nsEudoraMailbox::ImportMailboxUsingTOC( PRUint32 *pBytes, PRBool *pAbort, nsIInputStream *pInputStream, nsIFile *tocFile, nsIOutputStream *pDst, PRInt32 *pMsgCount) { nsresult rv = NS_OK; PRInt64 mailSize = m_mailSize; PRInt64 tocSize = 0; PRUint32 saveBytes = pBytes ? *pBytes : 0; nsCOMPtr <nsIInputStream> tocInputStream; rv = tocFile->GetFileSize( &tocSize); // if the index or the mail file is empty then just // use the original mail file. if (!mailSize || !tocSize) return NS_ERROR_FAILURE; rv = NS_NewLocalFileInputStream(getter_AddRefs(tocInputStream), tocFile); NS_ENSURE_SUCCESS(rv, rv); SimpleBufferTonyRCopiedOnce readBuffer; SimpleBufferTonyRCopiedOnce headers; SimpleBufferTonyRCopiedOnce body; SimpleBufferTonyRCopiedOnce copy; PRInt32 tocOffset = kMsgFirstOffset; EudoraTOCEntry tocEntry; copy.Allocate( kCopyBufferSize); readBuffer.Allocate(kMailReadBufferSize); IMPORT_LOG0( "Importing mailbox using TOC: "); DUMP_FILENAME( tocFile, PR_TRUE); nsCOMPtr <nsISeekableStream> tocSeekableStream = do_QueryInterface(tocInputStream); nsCOMPtr <nsISeekableStream> mailboxSeekableStream = do_QueryInterface(pInputStream); while (!*pAbort && (tocOffset < (PRInt32)tocSize)) { if ( NS_FAILED(rv = tocSeekableStream->Seek(nsISeekableStream::NS_SEEK_SET, tocOffset)) ) break; if ( NS_FAILED(rv = ReadTOCEntry(tocInputStream, tocEntry)) ) break; // Quick and dirty way to read in and parse the message the way the rest // of the code expects. nsCString defaultDate; nsCAutoString bodyType; ReadFileState state; // Seek to the start of the email message. mailboxSeekableStream->Seek(nsISeekableStream::NS_SEEK_SET, tocEntry.m_Offset); // We're fudging the data to make ReadNextMessage happy. In particular // state.size is meant to be the size of the entire file, because it's // assumed that ReadNextMessage will actually have to parse. We know // exactly how big the message is, so we simply set the "size" to be // immediately where the message ends. state.offset = tocEntry.m_Offset; state.pInputStream = pInputStream; state.size = state.offset + tocEntry.m_Length; if ( NS_SUCCEEDED(rv = ReadNextMessage(&state, readBuffer, headers, body, defaultDate, bodyType, &tocEntry) ) ) { rv = ImportMessage(headers, body, defaultDate, bodyType, pDst, pMsgCount); if (pBytes) *pBytes += tocEntry.m_Length; } // We currently don't consider an error from ReadNextMessage or ImportMessage to be fatal. // Reset the error back to no error in case this is the last time through the loop. rv = NS_OK; tocOffset += kMsgHeaderSize; } if ( NS_SUCCEEDED(rv) ) { IMPORT_LOG0( " finished\n"); } else { // We failed somewhere important enough that we kept the error. // Bail on all that we imported since we'll be importing everything // again using just the mailbox. IMPORT_LOG0( "*** Error importing mailbox using TOC: "); // DUMP_FILENAME(pMail, PR_TRUE); // Close the destination and truncate it. We don't need to bother // to reopen it because the nsIFileSpec implementation will open // before writing if necessary (and yes legacy importing code already // relies on this behavior). // pDst->CloseStream(); // pDst->Truncate(0); // Reset pBytes back to where it was before we imported this mailbox. // This will likely result in a funky progress bar which will move // backwards, but that's probably the best we can do to keep the // progress accurate since we'll be re-importing the same mailbox. if (pBytes) *pBytes = saveBytes; // Set the message count back to 0. if (pMsgCount) *pMsgCount = 0; } return rv; }