nsresult nsEudoraCompose::CopyComposedMessage( nsCString& fromLine, nsIFile *pSrc, nsIOutputStream *pDst, SimpleBufferTonyRCopiedOnce& copy) { copy.m_bytesInBuf = 0; copy.m_writeOffset = 0; ReadFileState state; state.pFile = pSrc; state.offset = 0; state.size = 0; pSrc->GetFileSize( &state.size); if (!state.size) { IMPORT_LOG0( "*** Error, unexpected zero file size for composed message\n"); return( NS_ERROR_FAILURE); } nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(state.pInputStream), pSrc); if (NS_FAILED( rv)) { IMPORT_LOG0( "*** Error, unable to open composed message file\n"); return( NS_ERROR_FAILURE); } PRUint32 written; rv = pDst->Write( fromLine.get(), fromLine.Length(), &written); // well, isn't this a hoot! // Read the headers from the new message, get the ones we like // and write out only the headers we want from the new message, // along with all of the other headers from the "old" message! if (NS_SUCCEEDED( rv)) rv = FillMailBuffer( &state, copy); if (NS_SUCCEEDED( rv)) rv = ReadHeaders( &state, copy, m_readHeaders); if (NS_SUCCEEDED( rv)) { rv = WriteHeaders( pDst, m_readHeaders); } // We need to go ahead and write out the rest of the copy buffer // so that the following will properly copy the rest of the body char lastChar = 0; rv = EscapeFromSpaceLine(pDst, copy.m_pBuffer + copy.m_writeOffset, copy.m_pBuffer+copy.m_bytesInBuf); if (copy.m_bytesInBuf) lastChar = copy.m_pBuffer[copy.m_bytesInBuf - 1]; if (NS_SUCCEEDED(rv)) copy.m_writeOffset = copy.m_bytesInBuf; while ((state.offset < state.size) && NS_SUCCEEDED( rv)) { rv = FillMailBuffer( &state, copy); if (NS_SUCCEEDED( rv)) { rv = EscapeFromSpaceLine(pDst, copy.m_pBuffer + copy.m_writeOffset, copy.m_pBuffer+copy.m_bytesInBuf); lastChar = copy.m_pBuffer[copy.m_bytesInBuf - 1]; if (NS_SUCCEEDED( rv)) copy.m_writeOffset = copy.m_bytesInBuf; else IMPORT_LOG0( "*** Error writing to destination mailbox\n"); } } state.pInputStream->Close(); if ((lastChar != 0x0A) && NS_SUCCEEDED( rv)) { rv = pDst->Write( "\x0D\x0A", 2, &written); if (written != 2) rv = NS_ERROR_FAILURE; } return( rv); }
nsresult nsOE5File::ImportMailbox( PRUint32 *pBytesDone, PRBool *pAbort, nsString& name, nsIFile *inFile, nsIFile *pDestination, PRUint32 *pCount) { nsresult rv; PRInt32 msgCount = 0; if (pCount) *pCount = 0; nsCOMPtr <nsIInputStream> inputStream; rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), inFile); if (NS_FAILED( rv)) return( rv); nsCOMPtr <nsIOutputStream> outputStream; rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), pDestination, -1, 0600); if (NS_FAILED( rv)) return( rv); PRUint32 * pIndex; PRUint32 indexSize; if (!ReadIndex( inputStream, &pIndex, &indexSize)) { IMPORT_LOG1( "No messages found in mailbox: %S\n", name.get()); return( NS_OK); } char * pBuffer = new char[kMailboxBufferSize]; if (!(*pAbort)) ConvertIndex( inputStream, pBuffer, pIndex, indexSize); PRUint32 block[4]; PRInt32 sepLen = (PRInt32) strlen( m_pFromLineSep); PRUint32 written; /* Each block is: marker - matches file offset block length text length in block pointer to next block. (0 if end) Each message is made up of a linked list of block data. So what we do for each message is: 1. Read the first block data. 2. Write out the From message separator if the message doesn't already start with one. 3. If the block of data doesn't end with CRLF then a line is broken into two blocks, so save the incomplete line for later process when we read the next block. Then write out the block excluding the partial line at the end of the block (if exists). 4. If there's next block of data then read next data block. Otherwise we're done. If we found a partial line in step #3 then find the rest of the line from the current block and write out this line separately. 5. Reset some of the control variables and repeat step #3. */ PRUint32 didBytes = 0; PRUint32 next, size; char *pStart, *pEnd, *partialLineStart; nsCAutoString partialLine, tempLine; rv = NS_OK; for (PRUint32 i = 0; (i < indexSize) && !(*pAbort); i++) { if (! pIndex[i]) continue; if (ReadBytes( inputStream, block, pIndex[i], 16) && (block[0] == pIndex[i]) && (block[2] < kMailboxBufferSize) && (ReadBytes( inputStream, pBuffer, kDontSeek, block[2]))) { // block[2] contains the chars in the buffer (ie, buf content size). // block[3] contains offset to the next block of data (0 means no more data). size = block[2]; pStart = pBuffer; pEnd = pStart + size; // write out the from separator. if (IsFromLine( pBuffer, size)) { char *pChar = pStart; while ((pChar < pEnd) && (*pChar != '\r') && (*(pChar+1) != '\n')) pChar++; if (pChar < pEnd) { // Get the "From " line so write it out. rv = outputStream->Write(pStart, pChar-pStart+2, &written); NS_ENSURE_SUCCESS(rv,rv); // Now buffer starts from the 2nd line. pStart = pChar + 2; } } else { // Write out the default from line since there is none in the msg. rv = outputStream->Write( m_pFromLineSep, sepLen, &written); // FIXME: Do I need to check the return value of written??? if (NS_FAILED( rv)) break; } char statusLine[50]; PRUint32 msgFlags = 0; // need to convert from OE flags to mozilla flags PR_snprintf(statusLine, sizeof(statusLine), X_MOZILLA_STATUS_FORMAT MSG_LINEBREAK, msgFlags & 0xFFFF); rv = outputStream->Write(statusLine, strlen(statusLine), &written); NS_ENSURE_SUCCESS(rv,rv); PR_snprintf(statusLine, sizeof(statusLine), X_MOZILLA_STATUS2_FORMAT MSG_LINEBREAK, msgFlags & 0xFFFF0000); rv = outputStream->Write(statusLine, strlen(statusLine), &written); NS_ENSURE_SUCCESS(rv,rv); do { partialLine.Truncate(); partialLineStart = pEnd; // If the buffer doesn't end with CRLF then a line is broken into two blocks, // so save the incomplete line for later process when we read the next block. if ( (size > 1) && !(*(pEnd - 2) == '\r' && *(pEnd - 1) == '\n') ) { partialLineStart -= 2; while ((partialLineStart >= pStart) && (*partialLineStart != '\r') && (*(partialLineStart+1) != '\n')) partialLineStart--; if (partialLineStart != (pEnd - 2)) partialLineStart += 2; // skip over CRLF if we find them. partialLine.Assign(partialLineStart, pEnd - partialLineStart); } // Now process the block of data which ends with CRLF. rv = EscapeFromSpaceLine(outputStream, pStart, partialLineStart); if (NS_FAILED(rv)) break; didBytes += block[2]; next = block[3]; if (! next) { // OK, we're done so flush out the partial line if it's not empty. if (partialLine.Length()) rv = EscapeFromSpaceLine(outputStream, (char *)partialLine.get(), (partialLine.get()+partialLine.Length())); } else if (ReadBytes(inputStream, block, next, 16) && (block[0] == next) && (block[2] < kMailboxBufferSize) && (ReadBytes(inputStream, pBuffer, kDontSeek, block[2]))) { // See if we have a partial line from previous block. If so then build a complete // line (ie, take the remaining chars from this block) and process this line. Need // to adjust where data start and size in this case. size = block[2]; pStart = pBuffer; pEnd = pStart + size; if (partialLine.Length()) { while ((pStart < pEnd) && (*pStart != '\r') && (*(pStart+1) != '\n')) pStart++; if (pStart < pEnd) // if we found a CRLF .. pStart += 2; // .. then copy that too. tempLine.Assign(pBuffer, pStart - pBuffer); partialLine.Append(tempLine); rv = EscapeFromSpaceLine(outputStream, (char *)partialLine.get(), (partialLine.get()+partialLine.Length())); if (NS_FAILED(rv)) break; // Adjust where data start and size (since some of the data has been processed). size -= (pStart - pBuffer); } } else { IMPORT_LOG2( "Error reading message from %S at 0x%lx\n", name.get(), pIndex[i]); rv = outputStream->Write( "\x0D\x0A", 2, &written); next = 0; } } while (next); // Always end a msg with CRLF. This will make sure that OE msgs without body is // correctly recognized as msgs. Otherwise, we'll end up with the following in // the msg folder where the 2nd msg starts right after the headers of the 1st msg: // // From - Jan 1965 00:00:00 <<<--- 1st msg starts here // Subject: Test msg // . . . (more headers) // To: <*****@*****.**> // From - Jan 1965 00:00:00 <<<--- 2nd msg starts here // Subject: How are you // . . .(more headers) // // In this case, the 1st msg is not recognized as a msg (it's skipped) // when you open the folder. rv = outputStream->Write( "\x0D\x0A", 2, &written); if (NS_FAILED(rv)) break; msgCount++; if (pCount) *pCount = msgCount; if (pBytesDone) *pBytesDone = didBytes; } else { // Error reading message, should this be logged??? IMPORT_LOG2( "Error reading message from %S at 0x%lx\n", name.get(), pIndex[i]); *pAbort = PR_TRUE; } } delete [] pBuffer; if (NS_FAILED(rv)) *pAbort = PR_TRUE; return( rv); }
BOOL nsOutlookMail::WriteMessage( nsIOutputStream *pDest, CMapiMessage *pMsg, int& attachCount, BOOL *pTerminate) { BOOL bResult = TRUE; const char *pData; int len; BOOL checkStart = FALSE; *pTerminate = FALSE; pData = pMsg->GetFromLine( len); if (pData) { bResult = WriteData( pDest, pData, len); checkStart = TRUE; } nsCOMPtr<nsIOutputStream> outStream = pDest; pData = pMsg->GetHeaders( len); if (pData && len) { if (checkStart) bResult = (EscapeFromSpaceLine(outStream, (char *)pData, pData+len) == NS_OK); else bResult = (EscapeFromSpaceLine(outStream, (char *)(pData+1), pData+len-1) == NS_OK); } // Do we need to add any mime headers??? // Is the message multipart? // If so, then we are OK, but need to make sure we add mime // header info to the body of the message // If not AND we have attachments, then we need to add mime headers. BOOL needsMimeHeaders = pMsg->IsMultipart(); if (!needsMimeHeaders && attachCount) { // if the message already has mime headers // that aren't multipart then we are in trouble! // in that case, ditch the attachments... alternatively, we could // massage the headers and replace the existing mime headers // with our own but I think this case is likely not to occur. if (pMsg->HasContentHeader()) attachCount = 0; else { if (bResult) bResult = WriteMimeMsgHeader( pDest, pMsg); needsMimeHeaders = TRUE; } } if (bResult) bResult = WriteStr( pDest, "\x0D\x0A"); if (needsMimeHeaders) { if (bResult) bResult = WriteStr( pDest, "This is a MIME formatted message.\x0D\x0A"); if (bResult) bResult = WriteStr( pDest, "\x0D\x0A"); if (bResult) bResult = WriteMimeBoundary( pDest, pMsg, FALSE); if (pMsg->BodyIsHtml()) { if (bResult) bResult = WriteStr( pDest, "Content-type: text/html\x0D\x0A"); } else { if (bResult) bResult = WriteStr( pDest, "Content-type: text/plain\x0D\x0A"); } if (bResult) bResult = WriteStr( pDest, "\x0D\x0A"); } pData = pMsg->GetBody( len); if (pData && len) { if (bResult) bResult = (EscapeFromSpaceLine(outStream, (char *)pData, pData+len) == NS_OK); if ((len < 2) || (pData[len - 1] != 0x0A) || (pData[len - 2] != 0x0D)) bResult = WriteStr( pDest, "\x0D\x0A"); } *pTerminate = needsMimeHeaders; return( bResult); }