summaryrefslogtreecommitdiffstats
path: root/mailnews/import/oexpress/nsOE5File.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mailnews/import/oexpress/nsOE5File.cpp')
-rw-r--r--mailnews/import/oexpress/nsOE5File.cpp631
1 files changed, 0 insertions, 631 deletions
diff --git a/mailnews/import/oexpress/nsOE5File.cpp b/mailnews/import/oexpress/nsOE5File.cpp
deleted file mode 100644
index fd1fd0e15..000000000
--- a/mailnews/import/oexpress/nsOE5File.cpp
+++ /dev/null
@@ -1,631 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; 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 "nsOE5File.h"
-#include "OEDebugLog.h"
-#include "nsMsgUtils.h"
-#include "msgCore.h"
-#include "prprf.h"
-#include "nsMsgLocalFolderHdrs.h"
-#include "nsIOutputStream.h"
-#include "nsIInputStream.h"
-#include "nsIMsgPluggableStore.h"
-#include "nsIMsgHdr.h"
-#include "nsNetUtil.h"
-#include "nsISeekableStream.h"
-#include "nsMsgMessageFlags.h"
-#include <windows.h>
-
-#define kIndexGrowBy 100
-#define kSignatureSize 12
-#define kDontSeek 0xFFFFFFFF
-#define MARKED 0x20 // 4
-#define READ 0x80 // 1
-#define HASATTACHMENT 0x4000 // 268435456 10000000h
-#define ISANSWERED 0x80000 // 2
-#define ISFORWARDED 0x100000 // 4096
-#define ISWATCHED 0x400000 // 256
-#define ISIGNORED 0x800000 // 262144
-#define XLATFLAGS(s) (((MARKED & s) ? nsMsgMessageFlags::Marked : 0) | \
- ((READ & s) ? nsMsgMessageFlags::Read : 0) | \
- ((HASATTACHMENT & s) ? nsMsgMessageFlags::Attachment : 0) | \
- ((ISANSWERED & s) ? nsMsgMessageFlags::Replied : 0) | \
- ((ISFORWARDED & s) ? nsMsgMessageFlags::Forwarded : 0) | \
- ((ISWATCHED & s) ? nsMsgMessageFlags::Watched : 0) | \
- ((ISIGNORED & s) ? nsMsgMessageFlags::Ignored : 0))
-
-static char *gSig =
- "\xCF\xAD\x12\xFE\xC5\xFD\x74\x6F\x66\xE3\xD1\x11";
-
-// copied from nsprpub/pr/src/{io/prfile.c | md/windows/w95io.c} :
-// PR_FileTimeToPRTime and _PR_FileTimeToPRTime
-void nsOE5File::FileTimeToPRTime(const FILETIME *filetime, PRTime *prtm)
-{
-#ifdef __GNUC__
- const PRTime _pr_filetime_offset = 116444736000000000LL;
-#else
- const PRTime _pr_filetime_offset = 116444736000000000i64;
-#endif
-
- PR_ASSERT(sizeof(FILETIME) == sizeof(PRTime));
- ::CopyMemory(prtm, filetime, sizeof(PRTime));
-#ifdef __GNUC__
- *prtm = (*prtm - _pr_filetime_offset) / 10LL;
-#else
- *prtm = (*prtm - _pr_filetime_offset) / 10i64;
-#endif
-}
-
-bool nsOE5File::VerifyLocalMailFile(nsIFile *pFile)
-{
- char sig[kSignatureSize];
-
- nsCOMPtr <nsIInputStream> inputStream;
-
- if (NS_FAILED(NS_NewLocalFileInputStream(getter_AddRefs(inputStream), pFile)))
- return false;
-
- if (!ReadBytes(inputStream, sig, 0, kSignatureSize))
- return false;
-
- bool result = true;
-
- for (int i = 0; (i < kSignatureSize) && result; i++) {
- if (sig[i] != gSig[i])
- result = false;
- }
-
- char storeName[14];
- if (!ReadBytes(inputStream, storeName, 0x24C1, 12))
- result = false;
-
- storeName[12] = 0;
-
- if (PL_strcasecmp("LocalStore", storeName))
- result = false;
-
- return result;
-}
-
-bool nsOE5File::IsLocalMailFile(nsIFile *pFile)
-{
- nsresult rv;
- bool isFile = false;
-
- rv = pFile->IsFile(&isFile);
- if (NS_FAILED(rv) || !isFile)
- return false;
-
- bool result = VerifyLocalMailFile(pFile);
-
- return result;
-}
-
-bool nsOE5File::ReadIndex(nsIInputStream *pInputStream, uint32_t **ppIndex, uint32_t *pSize)
-{
- *ppIndex = nullptr;
- *pSize = 0;
-
- char signature[4];
- if (!ReadBytes(pInputStream, signature, 0, 4))
- return false;
-
- for (int i = 0; i < 4; i++) {
- if (signature[i] != gSig[i]) {
- IMPORT_LOG0("*** Outlook 5.0 dbx file signature doesn't match\n");
- return false;
- }
- }
-
- uint32_t offset = 0x00e4;
- uint32_t indexStart = 0;
- if (!ReadBytes(pInputStream, &indexStart, offset, 4)) {
- IMPORT_LOG0("*** Unable to read offset to index start\n");
- return false;
- }
-
- PRUint32Array array;
- array.count = 0;
- array.alloc = kIndexGrowBy;
- array.pIndex = new uint32_t[kIndexGrowBy];
-
- uint32_t next = ReadMsgIndex(pInputStream, indexStart, &array);
- while (next) {
- next = ReadMsgIndex(pInputStream, next, &array);
- }
-
- if (array.count) {
- *pSize = array.count;
- *ppIndex = array.pIndex;
- return true;
- }
-
- delete [] array.pIndex;
- return false;
-}
-
-
-uint32_t nsOE5File::ReadMsgIndex(nsIInputStream *pInputStream, uint32_t offset, PRUint32Array *pArray)
-{
- // Record is:
- // 4 byte marker
- // 4 byte unknown
- // 4 byte nextSubIndex
- // 4 byte (parentIndex?)
- // 2 bytes unknown
- // 1 byte length - # of entries in this record
- // 1 byte unknown
- // 4 byte unknown
- // length records consisting of 3 longs
- // 1 - pointer to record
- // 2 - child index pointer
- // 3 - number of records in child
-
- uint32_t marker;
-
- if (!ReadBytes(pInputStream, &marker, offset, 4))
- return 0;
-
- if (marker != offset)
- return 0;
-
-
- uint32_t vals[3];
-
- if (!ReadBytes(pInputStream, vals, offset + 4, 12))
- return 0;
-
-
- uint8_t len[4];
- if (!ReadBytes(pInputStream, len, offset + 16, 4))
- return 0;
-
-
-
- uint32_t cnt = (uint32_t) len[1];
- cnt *= 3;
- uint32_t *pData = new uint32_t[cnt];
-
- if (!ReadBytes(pInputStream, pData, offset + 24, cnt * 4)) {
- delete [] pData;
- return 0;
- }
-
- uint32_t next;
- uint32_t indexOffset;
- uint32_t * pRecord = pData;
- uint32_t * pNewIndex;
-
- for (uint8_t i = 0; i < (uint8_t)len[1]; i++, pRecord += 3) {
- indexOffset = pRecord[0];
-
- if (pArray->count >= pArray->alloc) {
- pNewIndex = new uint32_t[ pArray->alloc + kIndexGrowBy];
- memcpy(pNewIndex, pArray->pIndex, (pArray->alloc * 4));
- (pArray->alloc) += kIndexGrowBy;
- delete [] pArray->pIndex;
- pArray->pIndex = pNewIndex;
- }
-
- /*
- We could do some checking here if we wanted -
- make sure the index is within the file,
- make sure there isn't a duplicate index, etc.
- */
-
- pArray->pIndex[pArray->count] = indexOffset;
- (pArray->count)++;
-
-
-
- next = pRecord[1];
- if (next)
- while ((next = ReadMsgIndex(pInputStream, next, pArray)) != 0);
- }
- delete [] pData;
-
- // return the pointer to the next subIndex
- return vals[1];
-}
-
-bool nsOE5File::IsFromLine(char *pLine, uint32_t len)
-{
- return (len > 5 && (pLine[0] == 'F') && (pLine[1] == 'r') && (pLine[2] == 'o') && (pLine[3] == 'm') && (pLine[4] == ' '));
-}
-
-// Anything over 16K will be assumed BAD, BAD, BAD!
-#define kMailboxBufferSize 0x4000
-#define kMaxAttrCount 0x0030
-const char *nsOE5File::m_pFromLineSep = "From - Mon Jan 1 00:00:00 1965\x0D\x0A";
-
-nsresult nsOE5File::ImportMailbox(uint32_t *pBytesDone, bool *pAbort,
- nsString& name, nsIFile *inFile,
- nsIMsgFolder *dstFolder, uint32_t *pCount)
-{
- int32_t msgCount = 0;
- if (pCount)
- *pCount = 0;
-
- nsCOMPtr<nsIInputStream> inputStream;
- nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), inFile);
- NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsIMsgPluggableStore> msgStore;
- rv = dstFolder->GetMsgStore(getter_AddRefs(msgStore));
- NS_ENSURE_SUCCESS(rv, rv);
-
- uint32_t * pIndex;
- uint32_t indexSize;
- uint32_t * pFlags;
- uint64_t * pTime;
-
- if (!ReadIndex(inputStream, &pIndex, &indexSize)) {
- IMPORT_LOG1("No messages found in mailbox: %s\n", NS_LossyConvertUTF16toASCII(name.get()));
- return NS_OK;
- }
-
- pTime = new uint64_t[ indexSize];
- pFlags = new uint32_t[ indexSize];
- char * pBuffer = new char[kMailboxBufferSize];
- if (!(*pAbort))
- ConvertIndex(inputStream, pBuffer, pIndex, indexSize, pFlags, pTime);
-
- uint32_t block[4];
- int32_t sepLen = (int32_t) strlen(m_pFromLineSep);
- uint32_t 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.
- */
-
- uint32_t didBytes = 0;
- uint32_t next, size;
- char *pStart, *pEnd, *partialLineStart;
- nsAutoCString partialLine, tempLine;
- nsCOMPtr<nsIOutputStream> outputStream;
- rv = NS_OK;
-
- for (uint32_t i = 0; (i < indexSize) && !(*pAbort); i++)
- {
- if (! pIndex[i])
- continue;
-
- nsCOMPtr<nsIMsgDBHdr> msgHdr;
- bool reusable;
-
- rv = msgStore->GetNewMsgOutputStream(dstFolder, getter_AddRefs(msgHdr), &reusable,
- getter_AddRefs(outputStream));
- if (NS_FAILED(rv))
- {
- IMPORT_LOG1( "Mbx getting outputstream error: 0x%lx\n", rv);
- break;
- }
-
- 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.
- rv = NS_ERROR_FAILURE;
- 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);
- if (NS_SUCCEEDED(rv))
- // Now buffer starts from the 2nd line.
- pStart = pChar + 2;
- }
- }
- else if (pTime[i])
- {
- char result[156] = "";
- PRExplodedTime xpldTime;
- char buffer[128] = "";
- PRTime prt;
-
- nsOE5File::FileTimeToPRTime((FILETIME *)&pTime[i], &prt);
- // modeled after nsMsgSend.cpp
- PR_ExplodeTime(prt, PR_LocalTimeParameters, &xpldTime);
- PR_FormatTimeUSEnglish(buffer, sizeof(buffer),
- "%a %b %d %H:%M:%S %Y",
- &xpldTime);
- PL_strcpy(result, "From - ");
- PL_strcpy(result + 7, buffer);
- PL_strcpy(result + 7 + 24, CRLF);
-
- rv = outputStream->Write(result, (int32_t) strlen(result), &written);
- }
- if (NS_FAILED(rv))
- {
- // 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];
- uint32_t msgFlags = XLATFLAGS(pFlags[i]);
- 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", NS_LossyConvertUTF16toASCII(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: <someone@example.com>
- // 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)) {
- IMPORT_LOG0( "Error writing message during OE import\n");
- msgStore->DiscardNewMessage(outputStream, msgHdr);
- break;
- }
-
- msgStore->FinishNewMessage(outputStream, msgHdr);
-
- if (!reusable)
- outputStream->Close();
-
- 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", NS_LossyConvertUTF16toASCII(name.get()), pIndex[i]);
- *pAbort = true;
- }
- }
- if (outputStream)
- outputStream->Close();
- delete [] pBuffer;
- delete [] pFlags;
- delete [] pTime;
-
- if (NS_FAILED(rv))
- *pAbort = true;
-
- return rv;
-}
-
-
-/*
- A message index record consists of:
- 4 byte marker - matches record offset
- 4 bytes size - size of data after this header
- 2 bytes header length - not dependable
- 1 bytes - number of attributes
- 1 byte changes on this object
- Each attribute is a 4 byte value with the 1st byte being the tag
- and the remaing 3 bytes being data. The data is either a direct
- offset of an offset within the message index that points to the
- data for the tag.
- attr[0]:
- -hi bit== 1 means PRUint24 data = attr[1]
- -hi bit== 0 means (PRUint24) attr[1] = offset into data segment for data
- -attr[0] & 7f == tag index
- Header above is 0xC bytes, attr's are number * 4 bytes then follows data segment
- The data segment length is undefined. The index data is either part of the
- index structure or the index structure points to address in data that follows
- index structure table. Use that location to calculate file position of data.
- MSDN indicates 0x28 attributes possible.
-
- Current known tags are:
- 0x01 - flags addressed
- 0x81 - flags in attr's next 3 bytes
- 0x02 - a time value - addressed- 8 bytes
- 0x04 - text offset pointer, the data is the offset after the attribute
- of a 4 byte pointer to the message text <-- addr into data
- 0x05 - offset to truncated subject
- 0x08 - offste to subject
- 0x0D - offset to from
- 0x0E - offset to from addresses
- 0x13 - offset to to name
- 0x45 - offset to to address <----correct --> 0x14
- 0x80 - msgId <-correction-> 0x07 addr to msg id
- 0x84 - direct text offset, direct pointer to message text
-*/
-
-void nsOE5File::ConvertIndex(nsIInputStream *pFile, char *pBuffer,
- uint32_t *pIndex, uint32_t size,
- uint32_t *pFlags, uint64_t *pTime)
-{
- // for each index record, get the actual message offset! If there is a
- // problem just record the message offset as 0 and the message reading code
- // can log that error information.
- // XXXTODO- above error reporting is not done
-
- uint8_t recordHead[12];
- uint32_t marker;
- uint32_t recordSize;
- uint32_t numAttrs;
- uint32_t offset;
- uint32_t attrIndex;
- uint32_t attrOffset;
- uint8_t tag;
- uint32_t tagData;
- uint32_t flags;
- uint64_t time;
- uint32_t dataStart;
-
- for (uint32_t i = 0; i < size; i++) {
- offset = 0;
- flags = 0;
- time = 0;
- if (ReadBytes(pFile, recordHead, pIndex[i], 12)) {
- memcpy(&marker, recordHead, 4);
- memcpy(&recordSize, recordHead + 4, 4);
- numAttrs = (uint32_t) recordHead[10];
- if (marker == pIndex[i] && numAttrs <= kMaxAttrCount) {
- dataStart = pIndex[i] + 12 + (numAttrs * 4);
- if (ReadBytes(pFile, pBuffer, kDontSeek, numAttrs * 4)) {
- attrOffset = 0;
- for (attrIndex = 0; attrIndex < numAttrs; attrIndex++, attrOffset += 4) {
- tag = (uint8_t) pBuffer[attrOffset];
- if (tag == (uint8_t) 0x84) {
- tagData = 0;
- memcpy(&tagData, pBuffer + attrOffset + 1, 3);
- offset = tagData;
- }
- else if (tag == (uint8_t) 0x04) {
- tagData = 0;
- memcpy(&tagData, pBuffer + attrOffset + 1, 3);
- ReadBytes(pFile, &offset, dataStart + tagData, 4);
- }
- else if (tag == (uint8_t) 0x81) {
- tagData = 0;
- memcpy(&tagData, pBuffer + attrOffset +1, 3);
- flags = tagData;
- }
- else if (tag == (uint8_t) 0x01) {
- tagData = 0;
- memcpy(&tagData, pBuffer + attrOffset +1, 3);
- ReadBytes(pFile, &flags, dataStart + tagData, 4);
- }
- else if (tag == (uint8_t) 0x02) {
- tagData = 0;
- memcpy(&tagData, pBuffer + attrOffset +1, 3);
- ReadBytes(pFile, &time, dataStart + tagData, 4);
- }
- }
- }
- }
- }
- pIndex[i] = offset;
- pFlags[i] = flags;
- pTime[i] = time;
- }
-}
-
-
-bool nsOE5File::ReadBytes(nsIInputStream *stream, void *pBuffer, uint32_t offset, uint32_t bytes)
-{
- nsresult rv;
-
- nsCOMPtr <nsISeekableStream> seekableStream = do_QueryInterface(stream);
- if (offset != kDontSeek) {
- rv = seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, offset);
- if (NS_FAILED(rv))
- return false;
- }
-
- if (!bytes)
- return true;
-
- uint32_t cntRead;
- char * pReadTo = (char *)pBuffer;
- rv = stream->Read(pReadTo, bytes, &cntRead);
- return NS_SUCCEEDED(rv) && cntRead == bytes;
-
-}
-