Issue #1258 - Part 1: Import mailnews, ldap, and mork from comm-esr52.9.1

This commit is contained in:
Matt A. Tobin 2019-11-03 00:17:46 -04:00 • committed by Roy Tam
commit e400f4130a
1564 changed files with 510348 additions and 0 deletions

View file

@ -0,0 +1,20 @@
/* -*- 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/. */
#ifndef OEDebugLog_h___
#define OEDebugLog_h___
// Use MOZ_LOG for logging.
#include "mozilla/Logging.h"
extern PRLogModuleInfo *OELOGMODULE; // Logging module
#define IMPORT_LOG0(x) MOZ_LOG(OELOGMODULE, mozilla::LogLevel::Debug, (x))
#define IMPORT_LOG1(x, y) MOZ_LOG(OELOGMODULE, mozilla::LogLevel::Debug, (x, y))
#define IMPORT_LOG2(x, y, z) MOZ_LOG(OELOGMODULE, mozilla::LogLevel::Debug, (x, y, z))
#define IMPORT_LOG3(a, b, c, d) MOZ_LOG(OELOGMODULE, mozilla::LogLevel::Debug, (a, b, c, d))
#endif /* OEDebugLog_h___ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,64 @@
/* -*- 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/. */
#ifndef WabObject_h___
#define WabObject_h___
#include "nscore.h"
#include "nsStringGlue.h"
#include "nsIFile.h"
#include <windows.h>
#include <wab.h>
class CWabIterator {
public:
virtual nsresult EnumUser(const char16_t *pName, LPENTRYID pEid, ULONG cbEid) = 0;
virtual nsresult EnumList(const char16_t *pName, LPENTRYID pEid, ULONG cbEid, LPMAPITABLE lpTable) = 0;
};
class CWAB
{
public:
CWAB(nsIFile *fileName);
~CWAB();
bool Loaded(void) { return m_bInitialized;}
HRESULT IterateWABContents(CWabIterator *pIter, int *pDone);
// Methods for User entries
LPDISTLIST GetDistList(ULONG cbEid, LPENTRYID pEid);
void ReleaseDistList(LPDISTLIST pList) { if (pList) pList->Release();}
LPMAILUSER GetUser(ULONG cbEid, LPENTRYID pEid);
void ReleaseUser(LPMAILUSER pUser) { if (pUser) pUser->Release();}
LPSPropValue GetUserProperty(LPMAILUSER pUser, ULONG tag);
LPSPropValue GetListProperty(LPDISTLIST pList, ULONG tag);
void FreeProperty(LPSPropValue pVal) { if (pVal) m_lpWABObject->FreeBuffer(pVal);}
void GetValueString(LPSPropValue pVal, nsString& val);
void GetValueTime(LPSPropValue pVal, PRTime& val);
void CStrToUnicode(const char *pStr, nsString& result);
// Utility stuff used by iterate
void FreeProws(LPSRowSet prows);
bool IsAvailable();
private:
char16_t * m_pUniBuff;
int m_uniBuffLen;
bool m_bInitialized;
HINSTANCE m_hinstWAB;
LPWABOPEN m_lpfnWABOpen;
LPADRBOOK m_lpAdrBook;
LPWABOBJECT m_lpWABObject;
};
#endif // WABOBJECT_INCLUDED

View file

@ -0,0 +1,19 @@
# vim: set filetype=python:
# 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/.
SOURCES += [
'nsOE5File.cpp',
'nsOEAddressIterator.cpp',
'nsOEImport.cpp',
'nsOEMailbox.cpp',
'nsOERegUtil.cpp',
'nsOEScanBoxes.cpp',
'nsOESettings.cpp',
'nsOEStringBundle.cpp',
'WabObject.cpp',
]
FINAL_LIBRARY = 'import'

View file

@ -0,0 +1,631 @@
/* -*- 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;
}

View file

@ -0,0 +1,52 @@
/* -*- 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/. */
#ifndef nsOE5File_h___
#define nsOE5File_h___
#include "nsStringGlue.h"
#include "nsIFile.h"
#include "nsIMsgFolder.h"
#include <windows.h>
class nsIInputStream;
class nsOE5File
{
public:
/* pFile must already be open for reading. */
static bool VerifyLocalMailFile(nsIFile *pFile);
/* pFile must NOT be open for reading */
static bool IsLocalMailFile(nsIFile *pFile);
static bool ReadIndex(nsIInputStream *pFile, uint32_t **ppIndex, uint32_t *pSize);
static nsresult ImportMailbox(uint32_t *pBytesDone, bool *pAbort,
nsString& name, nsIFile *inFile,
nsIMsgFolder *pDstFolder, uint32_t *pCount);
static void FileTimeToPRTime(const FILETIME *filetime, PRTime *prtm);
private:
typedef struct {
uint32_t * pIndex;
uint32_t count;
uint32_t alloc;
} PRUint32Array;
static const char *m_pFromLineSep;
static bool ReadBytes(nsIInputStream *stream, void *pBuffer, uint32_t offset, uint32_t bytes);
static uint32_t ReadMsgIndex(nsIInputStream *file, uint32_t offset, PRUint32Array *pArray);
static void ConvertIndex(nsIInputStream *pFile, char *pBuffer, uint32_t *pIndex,
uint32_t size, uint32_t *pFlags, uint64_t *pTime);
static bool IsFromLine(char *pLine, uint32_t len);
};
#endif /* nsOE5File_h___ */

View file

@ -0,0 +1,396 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
/*
A sample of XPConnect. This file contains an implementation of
nsISample.
*/
#include "nscore.h"
#include "nsCOMPtr.h"
#include "nsStringGlue.h"
#include "nsMsgUtils.h"
#include "nsComponentManagerUtils.h"
#include "nsIServiceManager.h"
#include "nsIImportService.h"
#include "nsIImportFieldMap.h"
#include "nsABBaseCID.h"
#include "nsIAbCard.h"
#include "prprf.h"
#include "nsOEAddressIterator.h"
#include "OEDebugLog.h"
typedef struct {
int32_t mozField;
int32_t multiLine;
ULONG mapiTag;
} MAPIFields;
enum {
ieidPR_DISPLAY_NAME = 0,
ieidPR_ENTRYID,
ieidPR_OBJECT_TYPE,
ieidMax
};
/*
Fields in MAPI, not in Mozilla
PR_OFFICE_LOCATION
FIX - PR_BIRTHDAY - stored as PT_SYSTIME - FIX to extract for moz address book birthday
PR_DISPLAY_NAME_PREFIX - Mr., Mrs. Dr., etc.
PR_SPOUSE_NAME
PR_GENDER - integer, not text
FIX - PR_CONTACT_EMAIL_ADDRESSES - multiuline strings for email addresses, needs
parsing to get secondary email address for mozilla
*/
#define kIsMultiLine -2
#define kNoMultiLine -1
static MAPIFields gMapiFields[] = {
{ 35, kIsMultiLine, PR_COMMENT},
{ 6, kNoMultiLine, PR_BUSINESS_TELEPHONE_NUMBER},
{ 7, kNoMultiLine, PR_HOME_TELEPHONE_NUMBER},
{ 25, kNoMultiLine, PR_COMPANY_NAME},
{ 23, kNoMultiLine, PR_TITLE},
{ 10, kNoMultiLine, PR_CELLULAR_TELEPHONE_NUMBER},
{ 9, kNoMultiLine, PR_PAGER_TELEPHONE_NUMBER},
{ 8, kNoMultiLine, PR_BUSINESS_FAX_NUMBER},
{ 8, kNoMultiLine, PR_HOME_FAX_NUMBER},
{ 22, kNoMultiLine, PR_COUNTRY},
{ 19, kNoMultiLine, PR_LOCALITY},
{ 20, kNoMultiLine, PR_STATE_OR_PROVINCE},
{ 17, 18, PR_STREET_ADDRESS},
{ 21, kNoMultiLine, PR_POSTAL_CODE},
{ 27, kNoMultiLine, PR_PERSONAL_HOME_PAGE},
{ 26, kNoMultiLine, PR_BUSINESS_HOME_PAGE},
{ 13, kNoMultiLine, PR_HOME_ADDRESS_CITY},
{ 16, kNoMultiLine, PR_HOME_ADDRESS_COUNTRY},
{ 15, kNoMultiLine, PR_HOME_ADDRESS_POSTAL_CODE},
{ 14, kNoMultiLine, PR_HOME_ADDRESS_STATE_OR_PROVINCE},
{ 11, 12, PR_HOME_ADDRESS_STREET},
{ 24, kNoMultiLine, PR_DEPARTMENT_NAME}
};
nsOEAddressIterator::nsOEAddressIterator(CWAB *pWab, nsIAddrDatabase *database)
{
m_pWab = pWab;
m_database = database;
}
nsOEAddressIterator::~nsOEAddressIterator()
{
}
nsresult nsOEAddressIterator::EnumUser(const char16_t * pName, LPENTRYID pEid, ULONG cbEid)
{
IMPORT_LOG1("User: %S\n", pName);
nsresult rv = NS_OK;
if (m_database) {
LPMAILUSER pUser = m_pWab->GetUser(cbEid, pEid);
if (pUser) {
// Get a new row from the database!
nsCOMPtr <nsIMdbRow> newRow;
rv = m_database->GetNewRow(getter_AddRefs(newRow));
NS_ENSURE_SUCCESS(rv, rv);
if (newRow && BuildCard(pName, newRow, pUser))
{
rv = m_database->AddCardRowToDB(newRow);
NS_ENSURE_SUCCESS(rv, rv);
IMPORT_LOG0("* Added entry to address book database\n");
nsString eMail;
LPSPropValue pProp = m_pWab->GetUserProperty(pUser, PR_EMAIL_ADDRESS);
if (pProp)
{
m_pWab->GetValueString(pProp, eMail);
SanitizeValue(eMail);
m_pWab->FreeProperty(pProp);
m_listRows.Put(eMail, newRow);
}
}
m_pWab->ReleaseUser(pUser);
}
}
return rv;
}
void nsOEAddressIterator::FindListRow(nsString &eMail, nsIMdbRow **cardRow)
{
m_listRows.Get(eMail,cardRow);
}
nsresult nsOEAddressIterator::EnumList(const char16_t * pName, LPENTRYID pEid, ULONG cbEid, LPMAPITABLE lpTable)
{
// If no name provided then we're done.
if (!pName || !(*pName))
return NS_OK;
nsresult rv = NS_ERROR_FAILURE;
HRESULT hr = E_FAIL;
// Make sure we have db to work with.
if (!m_database)
return rv;
nsCOMPtr <nsIMdbRow> listRow;
rv = m_database->GetNewListRow(getter_AddRefs(listRow));
NS_ENSURE_SUCCESS(rv, rv);
rv = m_database->AddListName(listRow, NS_ConvertUTF16toUTF8(pName).get());
NS_ENSURE_SUCCESS(rv, rv);
rv = m_database->AddCardRowToDB(listRow);
NS_ENSURE_SUCCESS(rv, rv);
rv = m_database->AddListDirNode(listRow);
NS_ENSURE_SUCCESS(rv, rv);
LPSRowSet lpRowAB = NULL;
ULONG lpcbEID = 0;
LPENTRYID lpEID = NULL;
ULONG rowCount = 0;
int cNumRows = 0;
int numListElems = 0;
nsAutoString uniStr;
hr = lpTable->GetRowCount(0, &rowCount);
//
hr = lpTable->SeekRow(BOOKMARK_BEGINNING, 0, NULL);
if(HR_FAILED(hr))
return NS_ERROR_FAILURE;
// Read all the rows of the table one by one
do
{
hr = lpTable->QueryRows(1, 0, &lpRowAB);
if(HR_FAILED(hr))
break;
if(lpRowAB)
{
cNumRows = lpRowAB->cRows;
if (cNumRows)
{
LPTSTR lpsz = lpRowAB->aRow[0].lpProps[ieidPR_DISPLAY_NAME].Value.lpszA;
LPENTRYID lpEID = (LPENTRYID) lpRowAB->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.lpb;
ULONG cbEID = lpRowAB->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.cb;
// There are 2 kinds of objects - the MAPI_MAILUSER contact object
// and the MAPI_DISTLIST contact object
// For distribution lists, we will only consider MAILUSER
// objects since we can't nest lists yet.
if(lpRowAB->aRow[0].lpProps[ieidPR_OBJECT_TYPE].Value.l == MAPI_MAILUSER)
{
LPMAILUSER pUser = m_pWab->GetUser(cbEID, lpEID);
LPSPropValue pProp = m_pWab->GetUserProperty(pUser, PR_EMAIL_ADDRESS);
nsString eMail;
nsCOMPtr <nsIMdbRow> cardRow;
m_pWab->GetValueString(pProp, eMail);
SanitizeValue(eMail);
FindListRow(eMail, getter_AddRefs(cardRow));
if (cardRow)
{
nsCOMPtr <nsIAbCard> userCard;
nsCOMPtr <nsIAbCard> newCard;
userCard = do_CreateInstance(NS_ABMDBCARD_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
m_database->InitCardFromRow(userCard,cardRow);
m_database->AddListCardColumnsToRow(userCard, listRow, ++numListElems,
getter_AddRefs(newCard),
true, nullptr, nullptr);
}
m_pWab->FreeProperty(pProp);
m_pWab->ReleaseUser(pUser);
}
}
m_pWab->FreeProws(lpRowAB);
}
} while (SUCCEEDED(hr) && cNumRows && lpRowAB);
m_database->SetListAddressTotal(listRow, numListElems);
return rv;
}
void nsOEAddressIterator::SanitizeValue(nsString& val)
{
MsgReplaceSubstring(val, NS_LITERAL_STRING("\r\n"), NS_LITERAL_STRING(", "));
MsgReplaceChar(val, "\r\n", ',');
}
void nsOEAddressIterator::SplitString(nsString& val1, nsString& val2)
{
// Find the last line if there is more than one!
int32_t idx = val1.RFind("\x0D\x0A");
int32_t cnt = 2;
if (idx == -1) {
cnt = 1;
idx = val1.RFindChar(13);
}
if (idx == -1)
idx= val1.RFindChar(10);
if (idx != -1) {
val2 = Substring(val1, idx + cnt);
val1.SetLength(idx);
SanitizeValue(val1);
}
}
void nsOEAddressIterator::SetBirthDay(nsIMdbRow *newRow, PRTime& birthDay)
{
PRExplodedTime exploded;
PR_ExplodeTime(birthDay, PR_LocalTimeParameters, &exploded);
char stringValue[5];
PR_snprintf(stringValue, sizeof(stringValue), "%04d", exploded.tm_year);
m_database->AddBirthYear(newRow, stringValue);
PR_snprintf(stringValue, sizeof(stringValue), "%02d", exploded.tm_month + 1);
m_database->AddBirthMonth(newRow, stringValue);
PR_snprintf(stringValue, sizeof(stringValue), "%02d", exploded.tm_mday);
m_database->AddBirthDay(newRow, stringValue);
}
bool nsOEAddressIterator::BuildCard(const char16_t * pName, nsIMdbRow *newRow, LPMAILUSER pUser)
{
nsString lastName;
nsString firstName;
nsString eMail;
nsString nickName;
nsString middleName;
PRTime birthDay = 0;
LPSPropValue pProp = m_pWab->GetUserProperty(pUser, PR_EMAIL_ADDRESS);
if (pProp) {
m_pWab->GetValueString(pProp, eMail);
SanitizeValue(eMail);
m_pWab->FreeProperty(pProp);
}
pProp = m_pWab->GetUserProperty(pUser, PR_GIVEN_NAME);
if (pProp) {
m_pWab->GetValueString(pProp, firstName);
SanitizeValue(firstName);
m_pWab->FreeProperty(pProp);
}
pProp = m_pWab->GetUserProperty(pUser, PR_SURNAME);
if (pProp) {
m_pWab->GetValueString(pProp, lastName);
SanitizeValue(lastName);
m_pWab->FreeProperty(pProp);
}
pProp = m_pWab->GetUserProperty(pUser, PR_MIDDLE_NAME);
if (pProp) {
m_pWab->GetValueString(pProp, middleName);
SanitizeValue(middleName);
m_pWab->FreeProperty(pProp);
}
pProp = m_pWab->GetUserProperty(pUser, PR_NICKNAME);
if (pProp) {
m_pWab->GetValueString(pProp, nickName);
SanitizeValue(nickName);
m_pWab->FreeProperty(pProp);
}
// The idea here is that firstName and lastName cannot both be empty!
if (firstName.IsEmpty() && lastName.IsEmpty())
firstName = pName;
nsString displayName;
pProp = m_pWab->GetUserProperty(pUser, PR_DISPLAY_NAME);
if (pProp) {
m_pWab->GetValueString(pProp, displayName);
SanitizeValue(displayName);
m_pWab->FreeProperty(pProp);
}
if (displayName.IsEmpty()) {
if (firstName.IsEmpty())
displayName = pName;
else {
displayName = firstName;
if (!middleName.IsEmpty()) {
displayName.Append(char16_t(' '));
displayName.Append(middleName);
}
if (!lastName.IsEmpty()) {
displayName.Append(char16_t(' '));
displayName.Append(lastName);
}
}
}
pProp = m_pWab->GetUserProperty(pUser, PR_BIRTHDAY);
if (pProp) {
m_pWab->GetValueTime(pProp, birthDay);
m_pWab->FreeProperty(pProp);
}
// We now have the required fields
// write them out followed by any optional fields!
if (!displayName.IsEmpty())
m_database->AddDisplayName(newRow, NS_ConvertUTF16toUTF8(displayName).get());
if (!firstName.IsEmpty())
m_database->AddFirstName(newRow, NS_ConvertUTF16toUTF8(firstName).get());
if (!lastName.IsEmpty())
m_database->AddLastName(newRow, NS_ConvertUTF16toUTF8(lastName).get());
if (!nickName.IsEmpty())
m_database->AddNickName(newRow, NS_ConvertUTF16toUTF8(nickName).get());
if (!eMail.IsEmpty())
m_database->AddPrimaryEmail(newRow, NS_ConvertUTF16toUTF8(eMail).get());
if (birthDay)
SetBirthDay(newRow, birthDay);
// Do all of the extra fields!
nsString value;
nsString line2;
nsresult rv;
// Create a field map
nsCOMPtr<nsIImportService> impSvc(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv));
if (NS_SUCCEEDED(rv)) {
nsIImportFieldMap * pFieldMap = nullptr;
rv = impSvc->CreateNewFieldMap(&pFieldMap);
if (NS_SUCCEEDED(rv) && pFieldMap) {
int max = sizeof(gMapiFields) / sizeof(MAPIFields);
for (int i = 0; i < max; i++) {
pProp = m_pWab->GetUserProperty(pUser, gMapiFields[i].mapiTag);
if (pProp) {
m_pWab->GetValueString(pProp, value);
m_pWab->FreeProperty(pProp);
if (!value.IsEmpty()) {
if (gMapiFields[i].multiLine == kNoMultiLine) {
SanitizeValue(value);
pFieldMap->SetFieldValue(m_database, newRow, gMapiFields[i].mozField, value.get());
}
else if (gMapiFields[i].multiLine == kIsMultiLine) {
pFieldMap->SetFieldValue(m_database, newRow, gMapiFields[i].mozField, value.get());
}
else {
line2.Truncate();
SplitString(value, line2);
if (!value.IsEmpty())
pFieldMap->SetFieldValue(m_database, newRow, gMapiFields[i].mozField, value.get());
if (!line2.IsEmpty())
pFieldMap->SetFieldValue(m_database, newRow, gMapiFields[i].multiLine, line2.get());
}
}
}
}
// call fieldMap SetFieldValue based on the table of fields
NS_RELEASE(pFieldMap);
}
}
return true;
}

View file

@ -0,0 +1,36 @@
/* -*- 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/. */
#ifndef nsOEAddressIterator_h___
#define nsOEAddressIterator_h___
#include "mozilla/Attributes.h"
#include "WabObject.h"
#include "nsIAddrDatabase.h"
#include "mdb.h"
#include "nsStringGlue.h"
#include "nsInterfaceHashtable.h"
class nsOEAddressIterator : public CWabIterator {
public:
nsOEAddressIterator(CWAB *pWab, nsIAddrDatabase *database);
~nsOEAddressIterator();
virtual nsresult EnumUser(const char16_t * pName, LPENTRYID pEid, ULONG cbEid) override;
virtual nsresult EnumList(const char16_t * pName, LPENTRYID pEid, ULONG cbEid, LPMAPITABLE table) override;
void FindListRow(nsString &eMail, nsIMdbRow **cardRow);
private:
bool BuildCard(const char16_t * pName, nsIMdbRow *card, LPMAILUSER pUser);
void SanitizeValue(nsString& val);
void SplitString(nsString& val1, nsString& val2);
void SetBirthDay(nsIMdbRow *card, PRTime& birthDay);
CWAB * m_pWab;
nsCOMPtr<nsIAddrDatabase> m_database;
nsInterfaceHashtable <nsStringHashKey, nsIMdbRow> m_listRows;
};
#endif

View file

@ -0,0 +1,657 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
/*
Outlook Express (Win32) import mail and addressbook interfaces
*/
#include "nscore.h"
#include "nsMsgUtils.h"
#include "nsStringGlue.h"
#include "nsComponentManagerUtils.h"
#include "nsIImportService.h"
#include "nsOEImport.h"
#include "nsIMemory.h"
#include "nsOEScanBoxes.h"
#include "nsIImportService.h"
#include "nsIImportMail.h"
#include "nsIImportMailboxDescriptor.h"
#include "nsIImportGeneric.h"
#include "nsOEMailbox.h"
#include "nsIImportAddressBooks.h"
#include "nsIImportABDescriptor.h"
#include "nsIImportFieldMap.h"
#include "nsIMutableArray.h"
#include "nsXPCOM.h"
#include "nsISupportsPrimitives.h"
#include "WabObject.h"
#include "nsOEAddressIterator.h"
#include "nsIOutputStream.h"
#include "nsOE5File.h"
#include "nsIAddrDatabase.h"
#include "nsOESettings.h"
#include "nsTextFormatter.h"
#include "nsOEStringBundle.h"
#include "nsIStringBundle.h"
#include "nsUnicharUtils.h"
#include "nsDirectoryServiceUtils.h"
#include "nsDirectoryServiceDefs.h"
#include "OEDebugLog.h"
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
PRLogModuleInfo *OELOGMODULE = nullptr;
class ImportOEMailImpl : public nsIImportMail
{
public:
ImportOEMailImpl();
static nsresult Create(nsIImportMail** aImport);
// nsISupports interface
NS_DECL_THREADSAFE_ISUPPORTS
// nsIImportmail interface
/* void GetDefaultLocation (out nsIFile location, out boolean found, out boolean userVerify); */
NS_IMETHOD GetDefaultLocation(nsIFile **location, bool *found, bool *userVerify);
/* nsIArray FindMailboxes (in nsIFile location); */
NS_IMETHOD FindMailboxes(nsIFile *location, nsIArray **_retval);
NS_IMETHOD ImportMailbox(nsIImportMailboxDescriptor *source,
nsIMsgFolder *dstFolder,
char16_t **pErrorLog, char16_t **pSuccessLog,
bool *fatalError);
/* unsigned long GetImportProgress (); */
NS_IMETHOD GetImportProgress(uint32_t *_retval);
NS_IMETHOD TranslateFolderName(const nsAString & aFolderName, nsAString & _retval);
public:
static void ReportSuccess(nsString& name, int32_t count, nsString *pStream);
static void ReportError(int32_t errorNum, nsString& name, nsString *pStream);
static void AddLinebreak(nsString *pStream);
static void SetLogs(nsString& success, nsString& error, char16_t **pError, char16_t **pSuccess);
private:
virtual ~ImportOEMailImpl();
uint32_t m_bytesDone;
};
class ImportOEAddressImpl : public nsIImportAddressBooks
{
public:
ImportOEAddressImpl();
static nsresult Create(nsIImportAddressBooks** aImport);
// nsISupports interface
NS_DECL_THREADSAFE_ISUPPORTS
// nsIImportAddressBooks interface
NS_IMETHOD GetSupportsMultiple(bool *_retval) { *_retval = false; return NS_OK;}
NS_IMETHOD GetAutoFind(char16_t **description, bool *_retval);
NS_IMETHOD GetNeedsFieldMap(nsIFile *pLoc, bool *_retval) { *_retval = false; return NS_OK;}
NS_IMETHOD GetDefaultLocation(nsIFile **location, bool *found, bool *userVerify);
NS_IMETHOD FindAddressBooks(nsIFile *location, nsIArray **_retval);
NS_IMETHOD InitFieldMap(nsIImportFieldMap *fieldMap)
{ return NS_ERROR_FAILURE; }
NS_IMETHOD ImportAddressBook(nsIImportABDescriptor *source,
nsIAddrDatabase *destination,
nsIImportFieldMap *fieldMap,
nsISupports *aSupportService,
char16_t **errorLog,
char16_t **successLog,
bool *fatalError);
NS_IMETHOD GetImportProgress(uint32_t *_retval);
NS_IMETHOD GetSampleData(int32_t index, bool *pFound, char16_t **pStr)
{ return NS_ERROR_FAILURE;}
NS_IMETHOD SetSampleLocation(nsIFile *) { return NS_OK; }
private:
virtual ~ImportOEAddressImpl();
static void ReportSuccess(nsString& name, nsString *pStream);
private:
CWAB * m_pWab;
int m_doneSoFar;
};
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
nsOEImport::nsOEImport()
{
// Init logging module.
if (!OELOGMODULE)
OELOGMODULE = PR_NewLogModule("IMPORT");
IMPORT_LOG0("nsOEImport Module Created\n");
nsOEStringBundle::GetStringBundle();
}
nsOEImport::~nsOEImport()
{
IMPORT_LOG0("nsOEImport Module Deleted\n");
}
NS_IMPL_ISUPPORTS(nsOEImport, nsIImportModule)
NS_IMETHODIMP nsOEImport::GetName(char16_t **name)
{
NS_ENSURE_ARG_POINTER(name);
*name = nsOEStringBundle::GetStringByID(OEIMPORT_NAME);
return NS_OK;
}
NS_IMETHODIMP nsOEImport::GetDescription(char16_t **name)
{
NS_ENSURE_ARG_POINTER(name);
*name = nsOEStringBundle::GetStringByID(OEIMPORT_DESCRIPTION);
return NS_OK;
}
NS_IMETHODIMP nsOEImport::GetSupports(char **supports)
{
NS_PRECONDITION(supports != nullptr, "null ptr");
if (! supports)
return NS_ERROR_NULL_POINTER;
*supports = strdup(kOESupportsString);
return NS_OK;
}
NS_IMETHODIMP nsOEImport::GetSupportsUpgrade(bool *pUpgrade)
{
NS_PRECONDITION(pUpgrade != nullptr, "null ptr");
if (! pUpgrade)
return NS_ERROR_NULL_POINTER;
*pUpgrade = true;
return NS_OK;
}
NS_IMETHODIMP nsOEImport::GetImportInterface(const char *pImportType, nsISupports **ppInterface)
{
NS_ENSURE_ARG_POINTER(pImportType);
NS_ENSURE_ARG_POINTER(ppInterface);
*ppInterface = nullptr;
nsresult rv;
if (!strcmp(pImportType, "mail")) {
// create the nsIImportMail interface and return it!
nsIImportMail * pMail = nullptr;
nsIImportGeneric *pGeneric = nullptr;
rv = ImportOEMailImpl::Create(&pMail);
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIImportService> impSvc(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv));
if (NS_SUCCEEDED(rv)) {
rv = impSvc->CreateNewGenericMail(&pGeneric);
if (NS_SUCCEEDED(rv)) {
pGeneric->SetData("mailInterface", pMail);
nsString name;
nsOEStringBundle::GetStringByID(OEIMPORT_NAME, name);
nsCOMPtr<nsISupportsString> nameString (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv));
if (NS_SUCCEEDED(rv)) {
nameString->SetData(name);
pGeneric->SetData("name", nameString);
rv = pGeneric->QueryInterface(kISupportsIID, (void **)ppInterface);
}
}
}
}
NS_IF_RELEASE(pMail);
NS_IF_RELEASE(pGeneric);
return rv;
}
if (!strcmp(pImportType, "addressbook")) {
// create the nsIImportMail interface and return it!
nsIImportAddressBooks * pAddress = nullptr;
nsIImportGeneric * pGeneric = nullptr;
rv = ImportOEAddressImpl::Create(&pAddress);
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIImportService> impSvc(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv));
if (NS_SUCCEEDED(rv)) {
rv = impSvc->CreateNewGenericAddressBooks(&pGeneric);
if (NS_SUCCEEDED(rv)) {
pGeneric->SetData("addressInterface", pAddress);
rv = pGeneric->QueryInterface(kISupportsIID, (void **)ppInterface);
}
}
}
NS_IF_RELEASE(pAddress);
NS_IF_RELEASE(pGeneric);
return rv;
}
if (!strcmp(pImportType, "settings")) {
nsIImportSettings *pSettings = nullptr;
rv = nsOESettings::Create(&pSettings);
if (NS_SUCCEEDED(rv))
pSettings->QueryInterface(kISupportsIID, (void **)ppInterface);
NS_IF_RELEASE(pSettings);
return rv;
}
return NS_ERROR_NOT_AVAILABLE;
}
/////////////////////////////////////////////////////////////////////////////////
nsresult ImportOEMailImpl::Create(nsIImportMail** aImport)
{
NS_ENSURE_ARG_POINTER(aImport);
*aImport = new ImportOEMailImpl();
NS_ENSURE_TRUE(*aImport, NS_ERROR_OUT_OF_MEMORY);
NS_ADDREF(*aImport);
return NS_OK;
}
ImportOEMailImpl::ImportOEMailImpl()
{
}
ImportOEMailImpl::~ImportOEMailImpl()
{
}
NS_IMPL_ISUPPORTS(ImportOEMailImpl, nsIImportMail)
NS_IMETHODIMP ImportOEMailImpl::TranslateFolderName(const nsAString & aFolderName, nsAString & _retval)
{
if (aFolderName.LowerCaseEqualsLiteral("deleted items"))
_retval = NS_LITERAL_STRING(kDestTrashFolderName);
else if (aFolderName.LowerCaseEqualsLiteral("sent items"))
_retval = NS_LITERAL_STRING(kDestSentFolderName);
else if (aFolderName.LowerCaseEqualsLiteral("outbox"))
_retval = NS_LITERAL_STRING(kDestUnsentMessagesFolderName);
else
_retval = aFolderName;
return NS_OK;
}
NS_IMETHODIMP ImportOEMailImpl::GetDefaultLocation(nsIFile **ppLoc, bool *found, bool *userVerify)
{
NS_PRECONDITION(ppLoc != nullptr, "null ptr");
NS_PRECONDITION(found != nullptr, "null ptr");
NS_PRECONDITION(userVerify != nullptr, "null ptr");
if (!ppLoc || !found || !userVerify)
return NS_ERROR_NULL_POINTER;
// use scanboxes to find the location.
nsresult rv;
nsCOMPtr <nsIFile> file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
if (NS_FAILED(rv))
return rv;
if (nsOEScanBoxes::FindMail(file)) {
*found = true;
NS_IF_ADDREF(*ppLoc = file);
}
else {
*found = false;
*ppLoc = nullptr;
}
*userVerify = true;
return NS_OK;
}
NS_IMETHODIMP ImportOEMailImpl::FindMailboxes(nsIFile *pLoc, nsIArray **ppArray)
{
NS_PRECONDITION(pLoc != nullptr, "null ptr");
NS_PRECONDITION(ppArray != nullptr, "null ptr");
if (!pLoc || !ppArray)
return NS_ERROR_NULL_POINTER;
bool exists = false;
nsresult rv = pLoc->Exists(&exists);
if (NS_FAILED(rv) || !exists)
return NS_ERROR_FAILURE;
nsOEScanBoxes scan;
if (!scan.GetMailboxes(pLoc, ppArray))
*ppArray = nullptr;
return NS_OK;
}
void ImportOEMailImpl::AddLinebreak(nsString *pStream)
{
if (pStream)
pStream->Append(char16_t('\n'));
}
void ImportOEMailImpl::ReportSuccess(nsString& name, int32_t count, nsString *pStream)
{
if (!pStream)
return;
// load the success string
char16_t *pFmt = nsOEStringBundle::GetStringByID(OEIMPORT_MAILBOX_SUCCESS);
char16_t *pText = nsTextFormatter::smprintf(pFmt, name.get(), count);
pStream->Append(pText);
nsTextFormatter::smprintf_free(pText);
nsOEStringBundle::FreeString(pFmt);
AddLinebreak(pStream);
}
void ImportOEMailImpl::ReportError(int32_t errorNum, nsString& name, nsString *pStream)
{
if (!pStream)
return;
// load the error string
char16_t *pFmt = nsOEStringBundle::GetStringByID(errorNum);
char16_t *pText = nsTextFormatter::smprintf(pFmt, name.get());
pStream->Append(pText);
nsTextFormatter::smprintf_free(pText);
nsOEStringBundle::FreeString(pFmt);
AddLinebreak(pStream);
}
void ImportOEMailImpl::SetLogs(nsString& success, nsString& error, char16_t **pError, char16_t **pSuccess)
{
if (pError)
*pError = ToNewUnicode(error);
if (pSuccess)
*pSuccess = ToNewUnicode(success);
}
NS_IMETHODIMP ImportOEMailImpl::ImportMailbox(nsIImportMailboxDescriptor *pSource,
nsIMsgFolder *dstFolder,
char16_t **pErrorLog,
char16_t **pSuccessLog,
bool *fatalError)
{
NS_ENSURE_ARG_POINTER(pSource);
NS_ENSURE_ARG_POINTER(dstFolder);
NS_ENSURE_ARG_POINTER(fatalError);
nsString success;
nsString error;
bool abort = false;
nsString name;
nsString pName;
if (NS_SUCCEEDED(pSource->GetDisplayName(getter_Copies(pName))))
name = pName;
uint32_t mailSize = 0;
pSource->GetSize(&mailSize);
if (mailSize == 0) {
ReportSuccess(name, 0, &success);
SetLogs(success, error, pErrorLog, pSuccessLog);
return NS_OK;
}
nsCOMPtr <nsIFile> inFile;
if (NS_FAILED(pSource->GetFile(getter_AddRefs(inFile)))) {
ReportError(OEIMPORT_MAILBOX_BADSOURCEFILE, name, &error);
SetLogs(success, error, pErrorLog, pSuccessLog);
return NS_ERROR_FAILURE;
}
nsCString pPath;
inFile->GetNativePath(pPath);
IMPORT_LOG1("Importing Outlook Express mailbox: %s\n", pPath.get());
m_bytesDone = 0;
uint32_t msgCount = 0;
nsresult rv;
if (nsOE5File::IsLocalMailFile(inFile)) {
IMPORT_LOG1("Importing OE5 mailbox: %s!\n", NS_LossyConvertUTF16toASCII(name.get()));
rv = nsOE5File::ImportMailbox( &m_bytesDone, &abort, name, inFile, dstFolder, &msgCount);
}
else {
if (CImportMailbox::ImportMailbox( &m_bytesDone, &abort, name, inFile, dstFolder, &msgCount))
rv = NS_OK;
else
rv = NS_ERROR_FAILURE;
}
if (NS_SUCCEEDED(rv))
ReportSuccess(name, msgCount, &success);
else
ReportError(OEIMPORT_MAILBOX_CONVERTERROR, name, &error);
SetLogs(success, error, pErrorLog, pSuccessLog);
return rv;
}
NS_IMETHODIMP ImportOEMailImpl::GetImportProgress(uint32_t *pDoneSoFar)
{
NS_ENSURE_ARG_POINTER(pDoneSoFar);
*pDoneSoFar = m_bytesDone;
return NS_OK;
}
nsresult ImportOEAddressImpl::Create(nsIImportAddressBooks** aImport)
{
NS_ENSURE_ARG_POINTER(aImport);
*aImport = new ImportOEAddressImpl();
NS_ENSURE_TRUE(*aImport, NS_ERROR_OUT_OF_MEMORY);
NS_ADDREF(*aImport);
return NS_OK;
}
ImportOEAddressImpl::ImportOEAddressImpl()
{
m_pWab = nullptr;
}
ImportOEAddressImpl::~ImportOEAddressImpl()
{
if (m_pWab)
delete m_pWab;
}
NS_IMPL_ISUPPORTS(ImportOEAddressImpl, nsIImportAddressBooks)
NS_IMETHODIMP ImportOEAddressImpl::GetDefaultLocation(nsIFile **aLocation,
bool *aFound,
bool *aUserVerify)
{
NS_ENSURE_ARG_POINTER(aLocation);
NS_ENSURE_ARG_POINTER(aFound);
NS_ENSURE_ARG_POINTER(aUserVerify);
*aLocation = nullptr;
*aUserVerify = true;
CWAB *wab = new CWAB(nullptr);
*aFound = wab->IsAvailable();
delete wab;
if (*aFound) {
// Unfortunately WAB interface has no function to obtain address book location.
// So we set a fake location here.
if (NS_SUCCEEDED(NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR, aLocation)))
*aUserVerify = false;
}
return NS_OK;
}
NS_IMETHODIMP ImportOEAddressImpl::GetAutoFind(char16_t **description, bool *_retval)
{
NS_PRECONDITION(description != nullptr, "null ptr");
NS_PRECONDITION(_retval != nullptr, "null ptr");
if (! description || !_retval)
return NS_ERROR_NULL_POINTER;
*_retval = false;
nsString str;
str.Append(nsOEStringBundle::GetStringByID(OEIMPORT_AUTOFIND));
*description = ToNewUnicode(str);
return NS_OK;
}
NS_IMETHODIMP ImportOEAddressImpl::FindAddressBooks(nsIFile *location, nsIArray **_retval)
{
NS_PRECONDITION(_retval != nullptr, "null ptr");
if (!_retval)
return NS_ERROR_NULL_POINTER;
nsresult rv;
nsCOMPtr<nsIMutableArray> array(do_CreateInstance(NS_ARRAY_CONTRACTID, &rv));
if (NS_FAILED(rv))
return rv;
// Make sure we can load up the windows address book...
rv = NS_ERROR_FAILURE;
if (m_pWab)
delete m_pWab;
nsCOMPtr<nsIFile> currentProcessDir;
rv = NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR,
getter_AddRefs(currentProcessDir));
bool equals = false;
currentProcessDir->Equals(location, &equals);
// If the location is not a fake, use it.
if (location && !equals) {
nsCOMPtr<nsIFile> localFile = do_QueryInterface(location, &rv);
NS_ENSURE_SUCCESS(rv, rv);
m_pWab = new CWAB(localFile);
} else {
m_pWab = new CWAB(nullptr);
}
nsIImportABDescriptor * pID;
nsISupports * pInterface;
nsString str;
str.Append(nsOEStringBundle::GetStringByID(OEIMPORT_DEFAULT_NAME));
if (m_pWab->Loaded()) {
// create a new nsIImportABDescriptor and add it to the array
nsCOMPtr<nsIImportService> impSvc(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv));
if (NS_SUCCEEDED(rv)) {
rv = impSvc->CreateNewABDescriptor(&pID);
if (NS_SUCCEEDED(rv)) {
pID->SetIdentifier(0x4F453334);
pID->SetRef(1);
pID->SetSize(100);
pID->SetPreferredName(str);
rv = pID->QueryInterface(kISupportsIID, (void **) &pInterface);
array->AppendElement(pInterface, false);
pInterface->Release();
pID->Release();
}
}
}
if (NS_FAILED(rv)) {
delete m_pWab;
m_pWab = nullptr;
}
array.forget(_retval);
return NS_OK;
}
NS_IMETHODIMP ImportOEAddressImpl::ImportAddressBook(nsIImportABDescriptor *source,
nsIAddrDatabase *destination,
nsIImportFieldMap *fieldMap,
nsISupports *aSupportService,
char16_t **errorLog,
char16_t **successLog,
bool *fatalError)
{
NS_PRECONDITION(source != nullptr, "null ptr");
// NS_PRECONDITION(destination != nullptr, "null ptr");
// NS_PRECONDITION(fieldMap != nullptr, "null ptr");
NS_PRECONDITION(fatalError != nullptr, "null ptr");
if (!source || !fatalError)
return NS_ERROR_NULL_POINTER;
// we assume it is our one and only address book.
if (!m_pWab) {
IMPORT_LOG0("Wab not loaded in ImportAddressBook call\n");
return NS_ERROR_FAILURE;
}
IMPORT_LOG0("IMPORTING OUTLOOK EXPRESS ADDRESS BOOK\n");
nsString success;
nsString error;
if (!source || !destination || !fatalError)
{
nsOEStringBundle::GetStringByID(OEIMPORT_ADDRESS_BADPARAM, error);
if (fatalError)
*fatalError = true;
ImportOEMailImpl::SetLogs(success, error, errorLog, successLog);
return NS_ERROR_NULL_POINTER;
}
m_doneSoFar = 0;
nsOEAddressIterator * pIter = new nsOEAddressIterator(m_pWab, destination);
HRESULT hr = m_pWab->IterateWABContents(pIter, &m_doneSoFar);
delete pIter;
nsString name;
if (SUCCEEDED(hr) && NS_SUCCEEDED(source->GetPreferredName(name)))
ReportSuccess(name, &success);
else
ImportOEMailImpl::ReportError(OEIMPORT_ADDRESS_CONVERTERROR, name, &error);
ImportOEMailImpl::SetLogs(success, error, errorLog, successLog);
nsresult rv = destination->Commit(nsAddrDBCommitType::kLargeCommit);
return rv;
}
NS_IMETHODIMP ImportOEAddressImpl::GetImportProgress(uint32_t *_retval)
{
NS_PRECONDITION(_retval != nullptr, "null ptr");
if (! _retval)
return NS_ERROR_NULL_POINTER;
*_retval = (uint32_t) m_doneSoFar;
return NS_OK;
}
void ImportOEAddressImpl::ReportSuccess(nsString& name, nsString *pStream)
{
if (!pStream)
return;
// load the success string
char16_t *pFmt = nsOEStringBundle::GetStringByID(OEIMPORT_ADDRESS_SUCCESS);
char16_t *pText = nsTextFormatter::smprintf(pFmt, name.get());
pStream->Append(pText);
nsTextFormatter::smprintf_free(pText);
nsOEStringBundle::FreeString(pFmt);
ImportOEMailImpl::AddLinebreak(pStream);
}

View file

@ -0,0 +1,42 @@
/* -*- 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/. */
#ifndef nsOEImport_h___
#define nsOEImport_h___
#include "nsIImportModule.h"
#include "nsCOMPtr.h"
#define NS_OEIMPORT_CID \
{ /* be0bc880-1742-11d3-a206-00a0cc26da63 */ \
0xbe0bc880, 0x1742, 0x11d3, \
{0xa2, 0x06, 0x0, 0xa0, 0xcc, 0x26, 0xda, 0x63}}
#define kOESupportsString NS_IMPORT_MAIL_STR "," NS_IMPORT_ADDRESS_STR "," NS_IMPORT_SETTINGS_STR
class nsOEImport : public nsIImportModule
{
public:
nsOEImport();
NS_DECL_ISUPPORTS
////////////////////////////////////////////////////////////////////////////////////////
// we suppport the nsIImportModule interface
////////////////////////////////////////////////////////////////////////////////////////
NS_DECL_NSIIMPORTMODULE
protected:
virtual ~nsOEImport();
};
#endif /* nsOEImport_h___ */

View file

@ -0,0 +1,673 @@
/* -*- 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 "nsOEMailbox.h"
#include "OEDebugLog.h"
#include "msgCore.h"
#include "prprf.h"
#include "nsMsgLocalFolderHdrs.h"
#include "nsCRT.h"
#include "nsNetUtil.h"
#include "nsIInputStream.h"
#include "nsIOutputStream.h"
#include "nsIMsgFolder.h"
#include "nsIMsgHdr.h"
#include "nsIMsgPluggableStore.h"
#include "nsISeekableStream.h"
#include "nsMsgUtils.h"
class CMbxScanner {
public:
CMbxScanner(nsString& name, nsIFile * mbxFile, nsIMsgFolder *dstFolder);
~CMbxScanner();
virtual bool Initialize(void);
virtual bool DoWork(bool *pAbort, uint32_t *pDone, uint32_t *pCount);
bool WasErrorFatal(void) { return m_fatalError;}
uint32_t BytesProcessed(void) { return m_didBytes;}
protected:
bool WriteMailItem(uint32_t flags, uint32_t offset, uint32_t size, uint32_t *pTotalMsgSize = nullptr);
virtual void CleanUp(void);
private:
void ReportWriteError(nsIMsgFolder *folder, bool fatal = true);
void ReportReadError(nsIFile * file, bool fatal = true);
bool CopyMbxFileBytes(uint32_t flags, uint32_t numBytes);
bool IsFromLineKey(uint8_t *pBuf, uint32_t max);
public:
uint32_t m_msgCount;
protected:
uint32_t * m_pDone;
nsString m_name;
nsCOMPtr<nsIFile> m_mbxFile;
nsCOMPtr<nsIMsgFolder> m_dstFolder;
nsCOMPtr<nsIInputStream> m_mbxFileInputStream;
nsCOMPtr<nsIOutputStream> m_dstOutputStream;
nsCOMPtr<nsIMsgPluggableStore> m_msgStore;
uint8_t * m_pInBuffer;
uint8_t * m_pOutBuffer;
uint32_t m_bufSz;
uint32_t m_didBytes;
bool m_fatalError;
int64_t m_mbxFileSize;
uint32_t m_mbxOffset;
static const char * m_pFromLine;
};
class CIndexScanner : public CMbxScanner {
public:
CIndexScanner(nsString& name, nsIFile * idxFile, nsIFile * mbxFile, nsIMsgFolder *dstFolder);
~CIndexScanner();
virtual bool Initialize(void);
virtual bool DoWork(bool *pAbort, uint32_t *pDone, uint32_t *pCount);
protected:
virtual void CleanUp(void);
private:
bool ValidateIdxFile(void);
bool GetMailItem(uint32_t *pFlags, uint32_t *pOffset, uint32_t *pSize);
private:
nsCOMPtr <nsIFile> m_idxFile;
nsCOMPtr <nsIInputStream> m_idxFileInputStream;
uint32_t m_numMessages;
uint32_t m_idxOffset;
uint32_t m_curItemIndex;
};
bool CImportMailbox::ImportMailbox(uint32_t *pDone, bool *pAbort,
nsString& name, nsIFile * inFile,
nsIMsgFolder *outFolder, uint32_t *pCount)
{
bool done = false;
nsresult rv;
nsCOMPtr <nsIFile> idxFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv))
rv = idxFile->InitWithFile(inFile);
if (NS_FAILED(rv)) {
IMPORT_LOG0("New file spec failed!\n");
return false;
}
if (GetIndexFile(idxFile)) {
IMPORT_LOG1("Using index file for: %S\n", name.get());
CIndexScanner *pIdxScanner = new CIndexScanner(name, idxFile, inFile, outFolder);
if (pIdxScanner->Initialize()) {
if (pIdxScanner->DoWork(pAbort, pDone, pCount)) {
done = true;
}
else {
IMPORT_LOG0("CIndexScanner::DoWork() failed\n");
}
}
else {
IMPORT_LOG0("CIndexScanner::Initialize() failed\n");
}
delete pIdxScanner;
}
if (done)
return done;
/*
something went wrong with the index file, just scan the mailbox
file itself.
*/
CMbxScanner *pMbx = new CMbxScanner(name, inFile, outFolder);
if (pMbx->Initialize()) {
if (pMbx->DoWork(pAbort, pDone, pCount)) {
done = true;
}
else {
IMPORT_LOG0("CMbxScanner::DoWork() failed\n");
}
}
else {
IMPORT_LOG0("CMbxScanner::Initialize() failed\n");
}
delete pMbx;
return done;
}
bool CImportMailbox::GetIndexFile(nsIFile* file)
{
nsCString pLeaf;
if (NS_FAILED(file->GetNativeLeafName(pLeaf)))
return false;
int32_t len = pLeaf.Length();
if (len < 5)
return false;
pLeaf.Replace(len - 3, 3, NS_LITERAL_CSTRING("idx"));
IMPORT_LOG1("Looking for index leaf name: %s\n", pLeaf);
nsresult rv;
rv = file->SetNativeLeafName(pLeaf);
bool isFile = false;
bool exists = false;
if (NS_SUCCEEDED(rv)) rv = file->IsFile(&isFile);
if (NS_SUCCEEDED(rv)) rv = file->Exists(&exists);
return (isFile && exists);
}
const char *CMbxScanner::m_pFromLine = "From - Mon Jan 1 00:00:00 1965\x0D\x0A";
// let's try a 16K buffer and see how well that works?
#define kBufferKB 16
CMbxScanner::CMbxScanner(nsString& name, nsIFile* mbxFile,
nsIMsgFolder* dstFolder)
{
m_msgCount = 0;
m_name = name;
m_mbxFile = mbxFile;
m_dstFolder = dstFolder;
m_pInBuffer = nullptr;
m_pOutBuffer = nullptr;
m_bufSz = 0;
m_fatalError = false;
m_didBytes = 0;
m_mbxFileSize = 0;
m_mbxOffset = 0;
}
CMbxScanner::~CMbxScanner()
{
CleanUp();
}
void CMbxScanner::ReportWriteError(nsIMsgFolder * folder, bool fatal)
{
m_fatalError = fatal;
}
void CMbxScanner::ReportReadError(nsIFile * file, bool fatal)
{
m_fatalError = fatal;
}
bool CMbxScanner::Initialize(void)
{
m_bufSz = (kBufferKB * 1024);
m_pInBuffer = new uint8_t[m_bufSz];
m_pOutBuffer = new uint8_t[m_bufSz];
if (!m_pInBuffer || !m_pOutBuffer) {
return false;
}
m_mbxFile->GetFileSize(&m_mbxFileSize);
// open the mailbox file...
if (NS_FAILED(NS_NewLocalFileInputStream(getter_AddRefs(m_mbxFileInputStream), m_mbxFile))) {
CleanUp();
return false;
}
if (NS_FAILED(m_dstFolder->GetMsgStore(getter_AddRefs(m_msgStore)))) {
CleanUp();
return false;
}
return true;
}
#define kMbxHeaderSize 0x0054
#define kMbxMessageHeaderSz 16
bool CMbxScanner::DoWork(bool *pAbort, uint32_t *pDone, uint32_t *pCount)
{
m_mbxOffset = kMbxHeaderSize;
m_didBytes = kMbxHeaderSize;
while (!(*pAbort) && ((m_mbxOffset + kMbxMessageHeaderSz) < m_mbxFileSize)) {
uint32_t msgSz;
if (!WriteMailItem(0, m_mbxOffset, 0, &msgSz)) {
if (!WasErrorFatal())
ReportReadError(m_mbxFile);
return false;
}
m_mbxOffset += msgSz;
m_didBytes += msgSz;
m_msgCount++;
if (pDone)
*pDone = m_didBytes;
if (pCount)
*pCount = m_msgCount;
}
CleanUp();
return true;
}
void CMbxScanner::CleanUp(void)
{
if (m_mbxFileInputStream)
m_mbxFileInputStream->Close();
if (m_dstOutputStream)
m_dstOutputStream->Close();
delete [] m_pInBuffer;
m_pInBuffer = nullptr;
delete [] m_pOutBuffer;
m_pOutBuffer = nullptr;
}
#define kNumMbxLongsToRead 4
bool CMbxScanner::WriteMailItem(uint32_t flags, uint32_t offset, uint32_t size,
uint32_t *pTotalMsgSize)
{
uint32_t values[kNumMbxLongsToRead];
int32_t cnt = kNumMbxLongsToRead * sizeof(uint32_t);
nsresult rv;
uint32_t cntRead;
int8_t * pChar = (int8_t *) values;
nsCOMPtr <nsISeekableStream> seekableStream = do_QueryInterface(m_mbxFileInputStream);
rv = seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, offset);
if (NS_FAILED(rv)) {
IMPORT_LOG1("Mbx seek error: 0x%lx\n", offset);
return false;
}
rv = m_mbxFileInputStream->Read((char *) pChar, cnt, &cntRead);
if (NS_FAILED(rv) || (cntRead != cnt)) {
IMPORT_LOG1("Mbx read error at: 0x%lx\n", offset);
return false;
}
if (values[0] != 0x7F007F00) {
IMPORT_LOG2("Mbx tag field doesn't match: 0x%lx, at offset: 0x%lx\n", values[0], offset);
return false;
}
if (size && (values[2] != size)) {
IMPORT_LOG3("Mbx size doesn't match idx, mbx: %ld, idx: %ld, at offset: 0x%lx\n", values[2], size, offset);
return false;
}
if (pTotalMsgSize != nullptr)
*pTotalMsgSize = values[2];
nsCOMPtr<nsIMsgDBHdr> msgHdr;
bool reusable;
rv = m_msgStore->GetNewMsgOutputStream(m_dstFolder, getter_AddRefs(msgHdr), &reusable,
getter_AddRefs(m_dstOutputStream));
if (NS_FAILED(rv))
{
IMPORT_LOG1( "Mbx getting outputstream error: 0x%lx\n", rv);
return false;
}
// everything looks kosher...
// the actual message text follows and is values[3] bytes long...
bool copyOK = CopyMbxFileBytes(flags, values[3]);
if (copyOK)
m_msgStore->FinishNewMessage(m_dstOutputStream, msgHdr);
else {
m_msgStore->DiscardNewMessage(m_dstOutputStream, msgHdr);
IMPORT_LOG0( "Mbx CopyMbxFileBytes failed\n");
}
if (!reusable)
{
m_dstOutputStream->Close();
m_dstOutputStream = nullptr;
}
return copyOK;
}
bool CMbxScanner::IsFromLineKey(uint8_t * pBuf, uint32_t max)
{
return (max > 5 && (pBuf[0] == 'F') && (pBuf[1] == 'r') && (pBuf[2] == 'o') && (pBuf[3] == 'm') && (pBuf[4] == ' '));
}
#define IS_ANY_SPACE(_ch) ((_ch == ' ') || (_ch == '\t') || (_ch == 10) || (_ch == 13))
bool CMbxScanner::CopyMbxFileBytes(uint32_t flags, uint32_t numBytes)
{
if (!numBytes)
return true;
uint32_t cnt;
uint8_t last[2] = {0, 0};
uint32_t inIdx = 0;
bool first = true;
uint8_t * pIn;
uint8_t * pStart;
int32_t fromLen = strlen(m_pFromLine);
nsresult rv;
uint32_t cntRead;
uint8_t * pChar;
while (numBytes) {
if (numBytes > (m_bufSz - inIdx))
cnt = m_bufSz - inIdx;
else
cnt = numBytes;
// Read some of the message from the file...
pChar = m_pInBuffer + inIdx;
rv = m_mbxFileInputStream->Read((char *) pChar, (int32_t)cnt, &cntRead);
if (NS_FAILED(rv) || (cntRead != (int32_t)cnt)) {
ReportReadError(m_mbxFile);
return false;
}
// Keep track of the last 2 bytes of the message for terminating EOL logic
if (cnt < 2) {
last[0] = last[1];
last[1] = m_pInBuffer[cnt - 1];
}
else {
last[0] = m_pInBuffer[cnt - 2];
last[1] = m_pInBuffer[cnt - 1];
}
inIdx = 0;
// Handle the beginning line, don't duplicate an existing From separator
if (first) {
// check the first buffer to see if it already starts with a From line
// If it does, throw it away and use our own
if (IsFromLineKey(m_pInBuffer, cnt)) {
// skip past the first line
while ((inIdx < cnt) && (m_pInBuffer[inIdx] != nsCRT::CR))
inIdx++;
while ((inIdx < cnt) && (IS_ANY_SPACE(m_pInBuffer[inIdx])))
inIdx++;
if (inIdx >= cnt) {
// This should not occurr - it means the message starts
// with a From separator line that is longer than our
// file buffer! In this bizarre case, just skip this message
// since it is probably bogus anyway.
return true;
}
}
// Begin every message with a From separator
rv = m_dstOutputStream->Write(m_pFromLine, fromLen, &cntRead);
if (NS_FAILED(rv) || (cntRead != fromLen)) {
ReportWriteError(m_dstFolder);
return false;
}
char statusLine[50];
uint32_t msgFlags = flags; // need to convert from OE flags to mozilla flags
PR_snprintf(statusLine, sizeof(statusLine), X_MOZILLA_STATUS_FORMAT MSG_LINEBREAK, msgFlags & 0xFFFF);
rv = m_dstOutputStream->Write(statusLine, strlen(statusLine), &cntRead);
if (NS_SUCCEEDED(rv) && cntRead == fromLen)
{
PR_snprintf(statusLine, sizeof(statusLine), X_MOZILLA_STATUS2_FORMAT MSG_LINEBREAK, msgFlags & 0xFFFF0000);
rv = m_dstOutputStream->Write(statusLine, strlen(statusLine), &cntRead);
}
if (NS_FAILED(rv) || (cntRead != fromLen)) {
ReportWriteError(m_dstFolder);
return false;
}
first = false;
}
// Handle generic data, escape any lines that begin with "From "
pIn = m_pInBuffer + inIdx;
numBytes -= cnt;
m_didBytes += cnt;
pStart = pIn;
cnt -= inIdx;
inIdx = 0;
while (cnt) {
if (*pIn == nsCRT::CR) {
// need more in buffer?
if ((cnt < 7) && numBytes)
break;
if (cnt > 6) {
if ((pIn[1] == nsCRT::LF) && IsFromLineKey(pIn + 2, cnt)) {
inIdx += 2;
// Match, escape it
rv = m_dstOutputStream->Write((const char *)pStart, (int32_t)inIdx, &cntRead);
if (NS_SUCCEEDED(rv) && (cntRead == (int32_t)inIdx))
rv = m_dstOutputStream->Write(">", 1, &cntRead);
if (NS_FAILED(rv) || (cntRead != 1)) {
ReportWriteError(m_dstFolder);
return false;
}
cnt -= 2;
pIn += 2;
inIdx = 0;
pStart = pIn;
continue;
}
}
} // == nsCRT::CR
cnt--;
inIdx++;
pIn++;
}
rv = m_dstOutputStream->Write((const char *)pStart, (int32_t)inIdx, &cntRead);
if (NS_FAILED(rv) || (cntRead != (int32_t)inIdx)) {
ReportWriteError(m_dstFolder);
return false;
}
if (cnt) {
inIdx = cnt;
memcpy(m_pInBuffer, pIn, cnt);
}
else
inIdx = 0;
}
// I used to check for an eol before writing one but
// it turns out that adding a proper EOL before the next
// separator never really hurts so better to be safe
// and always do it.
// if ((last[0] != nsCRT::CR) || (last[1] != nsCRT::LF)) {
rv = m_dstOutputStream->Write("\x0D\x0A", 2, &cntRead);
if (NS_FAILED(rv) || (cntRead != 2)) {
ReportWriteError(m_dstFolder);
return false;
}
// } // != nsCRT::CR || != nsCRT::LF
return true;
}
CIndexScanner::CIndexScanner(nsString& name, nsIFile * idxFile,
nsIFile * mbxFile, nsIMsgFolder * dstFolder)
: CMbxScanner( name, mbxFile, dstFolder)
{
m_idxFile = idxFile;
m_curItemIndex = 0;
m_idxOffset = 0;
}
CIndexScanner::~CIndexScanner()
{
CleanUp();
}
bool CIndexScanner::Initialize(void)
{
if (!CMbxScanner::Initialize())
return false;
nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(m_idxFileInputStream), m_idxFile);
if (NS_FAILED(rv)) {
CleanUp();
return false;
}
return true;
}
bool CIndexScanner::ValidateIdxFile(void)
{
int8_t id[4];
int32_t cnt = 4;
nsresult rv;
uint32_t cntRead;
int8_t * pReadTo;
pReadTo = id;
rv = m_idxFileInputStream->Read((char *) pReadTo, cnt, &cntRead);
if (NS_FAILED(rv) || (cntRead != cnt))
return false;
if ((id[0] != 'J') || (id[1] != 'M') || (id[2] != 'F') || (id[3] != '9'))
return false;
cnt = 4;
uint32_t subId;
pReadTo = (int8_t *) &subId;
rv = m_idxFileInputStream->Read((char *) pReadTo, cnt, &cntRead);
if (NS_FAILED(rv) || (cntRead != cnt))
return false;
if (subId != 0x00010004) {
IMPORT_LOG1("Idx file subid doesn't match: 0x%lx\n", subId);
return false;
}
pReadTo = (int8_t *) &m_numMessages;
rv = m_idxFileInputStream->Read((char *) pReadTo, cnt, &cntRead);
if (NS_FAILED(rv) || (cntRead != cnt))
return false;
IMPORT_LOG1("Idx file num messages: %ld\n", m_numMessages);
m_didBytes += 80;
m_idxOffset = 80;
return true;
}
/*
Idx file...
Header is 80 bytes, JMF9, subId? 0x00010004, numMessages, fileSize, 1, 0x00010010
Entries start at byte 80
4 byte numbers
Flags? maybe
?? who knows
index
start of this entry in the file
length of this record
msg offset in mbx
msg length in mbx
*/
// #define DEBUG_SUBJECT_AND_FLAGS 1
#define kNumIdxLongsToRead 7
bool CIndexScanner::GetMailItem(uint32_t *pFlags, uint32_t *pOffset, uint32_t *pSize)
{
uint32_t values[kNumIdxLongsToRead];
int32_t cnt = kNumIdxLongsToRead * sizeof(uint32_t);
int8_t * pReadTo = (int8_t *) values;
uint32_t cntRead;
nsresult rv;
nsCOMPtr <nsISeekableStream> seekableStream = do_QueryInterface(m_idxFileInputStream);
rv = seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, m_idxOffset);
if (NS_FAILED(rv))
return false;
rv = m_idxFileInputStream->Read((char *) pReadTo, cnt, &cntRead);
if (NS_FAILED(rv) || (cntRead != cnt))
return false;
if (values[3] != m_idxOffset) {
IMPORT_LOG2("Self pointer invalid: m_idxOffset=0x%lx, self=0x%lx\n", m_idxOffset, values[3]);
return false;
}
// So... what do we have here???
#ifdef DEBUG_SUBJECT_AND_FLAGS
IMPORT_LOG2("Number: %ld, msg offset: 0x%lx, ", values[2], values[5]);
IMPORT_LOG2("msg length: %ld, Flags: 0x%lx\n", values[6], values[0]);
seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, m_idxOffset + 212);
uint32_t subSz = 0;
cnt = 4;
pReadTo = (int8_t *) &subSz;
m_idxFileInputStream->Read((char *) pReadTo, cnt, &cntRead);
if ((subSz >= 0) && (subSz < 1024)) {
char *pSub = new char[subSz + 1];
m_idxFileInputStream->Read(pSub, subSz, &cntRead);
pSub[subSz] = 0;
IMPORT_LOG1(" Subject: %s\n", pSub);
delete [] pSub;
}
#endif
m_idxOffset += values[4];
m_didBytes += values[4];
*pFlags = values[0];
*pOffset = values[5];
*pSize = values[6];
return true;
}
#define kOEDeletedFlag 0x0001
bool CIndexScanner::DoWork(bool *pAbort, uint32_t *pDone, uint32_t *pCount)
{
m_didBytes = 0;
if (!ValidateIdxFile())
return false;
bool failed = false;
while ((m_curItemIndex < m_numMessages) && !failed && !(*pAbort)) {
uint32_t flags, offset, size;
if (!GetMailItem(&flags, &offset, &size)) {
CleanUp();
return false;
}
m_curItemIndex++;
if (!(flags & kOEDeletedFlag)) {
if (!WriteMailItem(flags, offset, size))
failed = true;
else {
m_msgCount++;
}
}
m_didBytes += size;
if (pDone)
*pDone = m_didBytes;
if (pCount)
*pCount = m_msgCount;
}
CleanUp();
return !failed;
}
void CIndexScanner::CleanUp(void)
{
CMbxScanner::CleanUp();
m_idxFileInputStream->Close();
}

View file

@ -0,0 +1,27 @@
/* -*- 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/. */
#ifndef nsOEMailbox_h___
#define nsOEMailbox_h___
#include "nscore.h"
#include "nsStringGlue.h"
#include "nsIFile.h"
class nsIMsgFolder;
class CImportMailbox {
public:
static bool ImportMailbox(uint32_t *pDone, bool *pAbort, nsString& name,
nsIFile * inFile, nsIMsgFolder * outFolder,
uint32_t *pCount);
private:
static bool GetIndexFile(nsIFile* mbxFile);
};
#endif // nsOEMailbox_h__

View file

@ -0,0 +1,27 @@
/* -*- 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 "nsOERegUtil.h"
#include "OEDebugLog.h"
#include <windows.h>
#include "nsIWindowsRegKey.h"
#include "nsComponentManagerUtils.h"
nsresult nsOERegUtil::GetDefaultUserId(nsAString &aUserId)
{
nsresult rv;
nsCOMPtr<nsIWindowsRegKey> key =
do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = key->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
NS_LITERAL_STRING("Identities"),
nsIWindowsRegKey::ACCESS_QUERY_VALUE);
if (NS_FAILED(rv))
return rv;
return key->ReadStringValue(NS_LITERAL_STRING("Default User ID"), aUserId);
}

View file

@ -0,0 +1,20 @@
/* -*- 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/. */
#ifndef nsOERegUtil_h___
#define nsOERegUtil_h___
#include <windows.h>
#include "nsStringGlue.h"
class nsOERegUtil
{
public:
static nsresult GetDefaultUserId(nsAString &aUserId);
};
#endif /* nsOERegUtil_h___ */

View file

@ -0,0 +1,859 @@
/* -*- 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 "nsOEScanBoxes.h"
#include "nsMsgUtils.h"
#include "nsIComponentManager.h"
#include "nsIServiceManager.h"
#include "nsIImportService.h"
#include "nsIFile.h"
#include "nsIImportMailboxDescriptor.h"
#include "nsOERegUtil.h"
#include "nsOE5File.h"
#include "nsNetUtil.h"
#include "OEDebugLog.h"
#include "nsIInputStream.h"
#include "nsISeekableStream.h"
#include "plstr.h"
#include <windows.h>
#include "nsIWindowsRegKey.h"
#ifdef MOZILLA_INTERNAL_API
#include "nsNativeCharsetUtils.h"
#else
#include "nsMsgI18N.h"
#define NS_CopyNativeToUnicode(source, dest) \
nsMsgI18NConvertToUnicode(nsMsgI18NFileSystemCharset(), source, dest)
#define NS_CopyUnicodeToNative(source, dest) \
nsMsgI18NConvertFromUnicode(nsMsgI18NFileSystemCharset(), source, dest)
#endif
/*
.nch file format???
offset 20 - long = offset to first record
*/
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
nsOEScanBoxes::nsOEScanBoxes()
{
m_pFirst = nullptr;
}
nsOEScanBoxes::~nsOEScanBoxes()
{
int i, max;
MailboxEntry *pEntry;
for (i = 0, max = m_entryArray.Length(); i < max; i++) {
pEntry = m_entryArray.ElementAt(i);
delete pEntry;
}
// Now free the unprocessed child entries (ie, those without parents for some reason).
for (i = 0, max = m_pendingChildArray.Length(); i < max; i++)
{
pEntry = m_pendingChildArray.ElementAt(i);
if (!pEntry->processed)
delete pEntry;
}
}
/*
3.x & 4.x registry
Software/Microsoft/Outlook Express/
5.0 registry
Identies - value of "Default User ID" is {GUID}
Identities/{GUID}/Software/Microsoft/Outlook Express/5.0/
*/
bool nsOEScanBoxes::Find50Mail(nsIFile *pWhere)
{
nsAutoString userId;
nsresult rv = nsOERegUtil::GetDefaultUserId(userId);
NS_ENSURE_SUCCESS(rv, false);
nsAutoString path(NS_LITERAL_STRING("Identities\\"));
path.Append(userId);
path.AppendLiteral("\\Software\\Microsoft\\Outlook Express\\5.0");
nsCOMPtr<nsIWindowsRegKey> key =
do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
NS_ENSURE_SUCCESS(rv, false);
rv = key->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
path,
nsIWindowsRegKey::ACCESS_QUERY_VALUE);
NS_ENSURE_SUCCESS(rv, false);
nsAutoString storeRoot;
key->ReadStringValue(NS_LITERAL_STRING("Store Root"), storeRoot);
NS_ENSURE_SUCCESS(rv, false);
nsCOMPtr<nsIFile> localWhere = do_QueryInterface(pWhere);
localWhere->InitWithPath(storeRoot);
nsAutoCString nativeStoreRoot;
NS_CopyUnicodeToNative(storeRoot, nativeStoreRoot);
IMPORT_LOG1("Setting native path: %s\n", nativeStoreRoot.get());
bool isDir = false;
rv = localWhere->IsDirectory(&isDir);
return isDir;
}
bool nsOEScanBoxes::FindMail(nsIFile *pWhere)
{
if (Find50Mail(pWhere))
return true;
nsresult rv;
nsCOMPtr<nsIWindowsRegKey> key =
do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
NS_ENSURE_SUCCESS(rv, false);
rv = key->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
NS_LITERAL_STRING("Software\\Microsoft\\Outlook Express"),
nsIWindowsRegKey::ACCESS_QUERY_VALUE);
NS_ENSURE_SUCCESS(rv, false);
nsAutoString storeRoot;
key->ReadStringValue(NS_LITERAL_STRING("Store Root"), storeRoot);
NS_ENSURE_SUCCESS(rv, false);
nsCOMPtr<nsIFile> localWhere = do_QueryInterface(pWhere);
localWhere->InitWithPath(storeRoot);
localWhere->AppendNative(NS_LITERAL_CSTRING("Mail"));
bool isDir = false;
localWhere->IsDirectory(&isDir);
return isDir;
}
bool nsOEScanBoxes::GetMailboxes(nsIFile *pWhere, nsIArray **pArray)
{
nsCString path;
pWhere->GetNativePath(path);
if (!path.IsEmpty()) {
IMPORT_LOG1("Looking for mail in: %s\n", path.get());
}
else {
pWhere->GetNativeLeafName(path);
if (!path.IsEmpty())
IMPORT_LOG1("Looking for mail in: %s\n", path.get());
else
IMPORT_LOG0("Unable to get info about where to look for mail\n");
}
nsCOMPtr <nsIFile> location;
pWhere->Clone(getter_AddRefs(location));
// 1. Look for 5.0 folders.dbx
// 2. Look for 3.x & 4.x folders.nch
// 3. Look for 5.0 *.dbx mailboxes
// 4. Look for 3.x & 4.x *.mbx mailboxes
bool result;
location->AppendNative(NS_LITERAL_CSTRING("folders.dbx"));
if (Find50MailBoxes(location)) {
result = GetMailboxList(pWhere, pArray);
}
else {
// 2. Look for 4.x mailboxes
pWhere->Clone(getter_AddRefs(location));
location->AppendNative(NS_LITERAL_CSTRING("folders.nch"));
if (FindMailBoxes(location)) {
result = GetMailboxList(pWhere, pArray);
}
else {
// 3 & 4, look for the specific mailbox files.
pWhere->Clone(getter_AddRefs(location));
ScanMailboxDir(location);
result = GetMailboxList(pWhere, pArray);
}
}
return result;
}
void nsOEScanBoxes::Reset(void)
{
int max = m_entryArray.Length();
for (int i = 0; i < max; i++) {
MailboxEntry *pEntry = m_entryArray.ElementAt(i);
delete pEntry;
}
m_entryArray.Clear();
m_pFirst = nullptr;
}
bool nsOEScanBoxes::FindMailBoxes(nsIFile* descFile)
{
Reset();
nsresult rv;
bool isFile = false;
rv = descFile->IsFile(&isFile);
if (NS_FAILED(rv) || !isFile)
return false;
nsCOMPtr <nsIInputStream> descInputStream;
rv = NS_NewLocalFileInputStream(getter_AddRefs(descInputStream), descFile);
NS_ENSURE_SUCCESS(rv, false);
IMPORT_LOG0("Reading the folders.nch file\n");
uint32_t curRec;
if (!ReadLong(descInputStream, curRec, 20)) {
return false;
}
// Now for each record
bool done = false;
uint32_t equal;
uint32_t size;
uint32_t previous;
uint32_t next;
MailboxEntry * pEntry;
bool failed;
while (!done) {
if (!ReadLong(descInputStream, equal, curRec)) return false;
if (curRec != equal) {
IMPORT_LOG1("Record start invalid: %ld\n", curRec);
break;
}
if (!ReadLong(descInputStream, size, curRec + 4)) return false;
if (!ReadLong(descInputStream, previous, curRec + 8)) return false;
if (!ReadLong(descInputStream, next, curRec + 12)) return false;
failed = false;
pEntry = new MailboxEntry;
if (!ReadLong(descInputStream, pEntry->index, curRec + 16)) failed = true;
if (!ReadString(descInputStream, pEntry->mailName, curRec + 20)) failed = true;
if (!ReadString(descInputStream, pEntry->fileName, curRec + 279)) failed = true;
if (!ReadLong(descInputStream, pEntry->parent, curRec + 539)) failed = true;
if (!ReadLong(descInputStream, pEntry->child, curRec + 543)) failed = true;
if (!ReadLong(descInputStream, pEntry->sibling, curRec + 547)) failed = true;
if (!ReadLong(descInputStream, pEntry->type, curRec + 551)) failed = true;
if (failed) {
delete pEntry;
return false;
}
#ifdef _TRACE_MAILBOX_ENTRIES
IMPORT_LOG0("------------\n");
IMPORT_LOG2(" Offset: %lx, index: %ld\n", curRec, pEntry->index);
IMPORT_LOG2(" previous: %lx, next: %lx\n", previous, next);
IMPORT_LOG2(" Name: %S, File: %s\n", (char16_t *) pEntry->mailName, (const char *) pEntry->fileName);
IMPORT_LOG3(" Parent: %ld, Child: %ld, Sibling: %ld\n", pEntry->parent, pEntry->child, pEntry->sibling);
#endif
if (!StringEndsWith(pEntry->fileName, NS_LITERAL_CSTRING(".mbx")))
pEntry->fileName.Append(".mbx");
m_entryArray.AppendElement(pEntry);
curRec = next;
if (!next)
done = true;
}
MailboxEntry *pZero = GetIndexEntry(0);
if (pZero)
m_pFirst = GetIndexEntry(pZero->child);
IMPORT_LOG1("Read the folders.nch file, found %ld mailboxes\n", (long) m_entryArray.Length());
return true;
}
bool nsOEScanBoxes::Find50MailBoxes(nsIFile* descFile)
{
Reset();
nsresult rv;
bool isFile = false;
rv = descFile->IsFile(&isFile);
if (NS_FAILED(rv) || !isFile)
return false;
nsCOMPtr <nsIInputStream> descInputStream;
rv = NS_NewLocalFileInputStream(getter_AddRefs(descInputStream), descFile);
NS_ENSURE_SUCCESS(rv, false);
IMPORT_LOG0("Reading the folders.dbx file\n");
uint32_t *pIndex;
uint32_t indexSize = 0;
if (!nsOE5File::ReadIndex(descInputStream, &pIndex, &indexSize)) {
IMPORT_LOG0("*** NOT USING FOLDERS.DBX!!!\n");
return false;
}
uint32_t marker;
uint32_t size;
char *pBytes;
uint32_t cntRead;
int32_t recordId;
int32_t strOffset;
uint8_t tag;
uint32_t data;
int32_t dataOffset;
uint32_t id;
uint32_t parent;
uint32_t numMessages;
char * pFileName;
char * pDataSource;
MailboxEntry * pEntry;
MailboxEntry * pLastEntry = nullptr;
uint32_t localStoreId = 0;
for (uint32_t i = 0; i < indexSize; i++) {
if (!ReadLong(descInputStream, marker, pIndex[i])) continue;
if (marker != pIndex[i]) continue;
if (!ReadLong(descInputStream, size, pIndex[i] + 4)) continue;
size += 4;
pBytes = new char[size];
rv = descInputStream->Read(pBytes, size, &cntRead);
if (NS_FAILED(rv) || ((uint32_t)cntRead != size)) {
delete [] pBytes;
continue;
}
recordId = pBytes[2];
strOffset = (recordId * 4) + 4;
if (recordId == 4)
strOffset += 4;
id = 0;
parent = 0;
numMessages = 0;
pFileName = nullptr;
pDataSource = nullptr;
dataOffset = 4;
while (dataOffset < strOffset) {
tag = (uint8_t) pBytes[dataOffset];
data = 0; // make sure all bytes are 0 before copying 3 bytes over.
memcpy(&data, &(pBytes[dataOffset + 1]), 3);
switch(tag) {
case 0x80: // id record
id = data;
break;
case 0x81: // parent id
parent = data;
break;
case 0x87: // number of messages in this mailbox
numMessages = data;
break;
case 0x03: // file name for this mailbox
if (((uint32_t)strOffset + data) < size)
pFileName = (char *)(pBytes + strOffset + data);
break;
case 0x05: // data source for this record (this is not a mailbox!)
if (((uint32_t)strOffset + data) < size)
pDataSource = (char *) (pBytes + strOffset + data);
break;
}
dataOffset += 4;
}
// now build an entry if necessary!
if (pDataSource) {
if (!PL_strcasecmp(pDataSource, "LocalStore"))
{
localStoreId = id;
// See if we have any child folders that need to be added/processed for this top level parent.
ProcessPendingChildEntries(localStoreId, localStoreId, m_pendingChildArray);
// Clean up the pending list.
RemoveProcessedChildEntries();
}
}
else if (id && localStoreId && parent) {
// veryify that this mailbox is in the local store
data = parent;
while (data && (data != localStoreId)) {
pEntry = GetIndexEntry(data);
if (pEntry)
data = pEntry->parent;
else
data = 0;
}
if (data == localStoreId) {
// Create an entry for this bugger
pEntry = NewMailboxEntry(id, parent, (const char *) (pBytes + strOffset), pFileName);
if (pEntry)
{
AddChildEntry(pEntry, localStoreId);
pEntry->processed = true;
// See if we have any child folders that need to be added/processed.
ProcessPendingChildEntries(id, localStoreId, m_pendingChildArray);
// Clean up the pending list.
RemoveProcessedChildEntries();
}
}
else
{
// Put this folder into child array and process it when its parent shows up.
pEntry = NewMailboxEntry(id, parent, (const char *) (pBytes + strOffset), pFileName);
if (pEntry)
m_pendingChildArray.AppendElement(pEntry);
}
}
else if (pFileName)
{
// Put this folder into child array and process it when its parent shows up.
// For some reason, it's likely that child folders come before their parents.
pEntry = NewMailboxEntry(id, parent, (const char *) (pBytes + strOffset), pFileName);
if (pEntry)
m_pendingChildArray.AppendElement(pEntry);
}
delete [] pBytes;
}
delete [] pIndex;
return m_entryArray.Length();
}
nsOEScanBoxes::MailboxEntry *nsOEScanBoxes::NewMailboxEntry(uint32_t id, uint32_t parent, const char *prettyName, char *pFileName)
{
MailboxEntry *pEntry = new MailboxEntry();
if (!pEntry)
return nullptr;
pEntry->index = id;
pEntry->parent = parent;
pEntry->child = 0;
pEntry->type = 0;
pEntry->sibling = -1;
pEntry->processed = false;
NS_CopyNativeToUnicode(nsDependentCString(prettyName), pEntry->mailName);
if (pFileName)
pEntry->fileName = pFileName;
return pEntry;
}
void nsOEScanBoxes::ProcessPendingChildEntries(uint32_t parent, uint32_t rootIndex, nsTArray<MailboxEntry*> &childArray)
{
int32_t i, max;
MailboxEntry *pEntry;
for (i = 0, max = childArray.Length(); i < max; i++)
{
pEntry = childArray.ElementAt(i);
if ((!pEntry->processed) && (pEntry->parent == parent))
{
AddChildEntry(pEntry, rootIndex);
pEntry->processed = true; // indicate it's been processed.
// See if there are unprocessed child folders for this child in the
// array as well (ie, both child and grand-child are on the list).
ProcessPendingChildEntries(pEntry->index, rootIndex, childArray);
}
}
}
void nsOEScanBoxes::RemoveProcessedChildEntries()
{
// Remove already processed entries from the pending list. Note that these entries are also
// on 'm_entryArray' list so we don't want to deallocate the space for the entries now.
MailboxEntry * pEntry;
int32_t i;
for (i = m_pendingChildArray.Length()-1; i >= 0; i--)
{
pEntry = m_pendingChildArray.ElementAt(i);
if (pEntry->processed)
m_pendingChildArray.RemoveElementAt(i);
}
}
void nsOEScanBoxes::AddChildEntry(MailboxEntry *pEntry, uint32_t rootIndex)
{
if (!m_pFirst) {
if (pEntry->parent == rootIndex) {
m_pFirst = pEntry;
m_entryArray.AppendElement(pEntry);
}
else {
delete pEntry;
}
return;
}
MailboxEntry * pParent = nullptr;
MailboxEntry * pSibling = nullptr;
if (pEntry->parent == rootIndex) {
pSibling = m_pFirst;
}
else {
pParent = GetIndexEntry(pEntry->parent);
}
if (!pParent && !pSibling) {
delete pEntry;
return;
}
if (pParent && (pParent->child == 0)) {
pParent->child = pEntry->index;
m_entryArray.AppendElement(pEntry);
return;
}
if (!pSibling)
pSibling = GetIndexEntry(pParent->child);
while (pSibling && (pSibling->sibling != -1)) {
pSibling = GetIndexEntry(pSibling->sibling);
}
if (!pSibling) {
delete pEntry;
return;
}
pSibling->sibling = pEntry->index;
m_entryArray.AppendElement(pEntry);
}
bool nsOEScanBoxes::Scan50MailboxDir(nsIFile * srcDir)
{
Reset();
MailboxEntry *pEntry;
int32_t index = 1;
char *pLeaf;
bool hasMore;
nsCOMPtr<nsISimpleEnumerator> directoryEnumerator;
nsresult rv = srcDir->GetDirectoryEntries(getter_AddRefs(directoryEnumerator));
NS_ENSURE_SUCCESS(rv, false);
directoryEnumerator->HasMoreElements(&hasMore);
bool isFile;
nsCOMPtr<nsIFile> entry;
nsCString fName;
while (hasMore && NS_SUCCEEDED(rv))
{
nsCOMPtr<nsISupports> aSupport;
rv = directoryEnumerator->GetNext(getter_AddRefs(aSupport));
nsCOMPtr<nsIFile> entry(do_QueryInterface(aSupport, &rv));
directoryEnumerator->HasMoreElements(&hasMore);
isFile = false;
rv = entry->IsFile(&isFile);
if (NS_SUCCEEDED(rv) && isFile) {
pLeaf = nullptr;
rv = entry->GetNativeLeafName(fName);
if (NS_SUCCEEDED(rv) &&
(StringEndsWith(fName, NS_LITERAL_CSTRING(".dbx")))) {
// This is a *.dbx file in the mail directory
if (nsOE5File::IsLocalMailFile(entry)) {
pEntry = new MailboxEntry;
pEntry->index = index;
index++;
pEntry->parent = 0;
pEntry->child = 0;
pEntry->sibling = index;
pEntry->type = -1;
fName.SetLength(fName.Length() - 4);
pEntry->fileName = fName.get();
NS_CopyNativeToUnicode(fName, pEntry->mailName);
m_entryArray.AppendElement(pEntry);
}
}
}
}
if (m_entryArray.Length() > 0) {
pEntry = m_entryArray.ElementAt(m_entryArray.Length() - 1);
pEntry->sibling = -1;
return true;
}
return false;
}
void nsOEScanBoxes::ScanMailboxDir(nsIFile * srcDir)
{
if (Scan50MailboxDir(srcDir))
return;
Reset();
MailboxEntry * pEntry;
int32_t index = 1;
nsAutoCString pLeaf;
uint32_t sLen;
bool hasMore;
nsCOMPtr<nsISimpleEnumerator> directoryEnumerator;
nsresult rv = srcDir->GetDirectoryEntries(getter_AddRefs(directoryEnumerator));
NS_ENSURE_SUCCESS_VOID(rv);
directoryEnumerator->HasMoreElements(&hasMore);
bool isFile;
nsCOMPtr<nsIFile> entry;
nsCString fName;
nsCString ext;
nsCString name;
while (hasMore && NS_SUCCEEDED(rv))
{
nsCOMPtr<nsISupports> aSupport;
rv = directoryEnumerator->GetNext(getter_AddRefs(aSupport));
nsCOMPtr<nsIFile> entry(do_QueryInterface(aSupport, &rv));
directoryEnumerator->HasMoreElements(&hasMore);
isFile = false;
rv = entry->IsFile(&isFile);
if (NS_SUCCEEDED(rv) && isFile)
{
rv = entry->GetNativeLeafName(pLeaf);
if (NS_SUCCEEDED(rv) && !pLeaf.IsEmpty() &&
((sLen = pLeaf.Length()) > 4) &&
(!PL_strcasecmp(pLeaf.get() + sLen - 3, "mbx")))
{
// This is a *.mbx file in the mail directory
pEntry = new MailboxEntry;
pEntry->index = index;
index++;
pEntry->parent = 0;
pEntry->child = 0;
pEntry->sibling = index;
pEntry->type = -1;
pEntry->fileName = pLeaf;
pLeaf.SetLength(sLen - 4);
NS_CopyNativeToUnicode(pLeaf, pEntry->mailName);
m_entryArray.AppendElement(pEntry);
}
}
}
if (m_entryArray.Length() > 0) {
pEntry = m_entryArray.ElementAt(m_entryArray.Length() - 1);
pEntry->sibling = -1;
}
}
uint32_t nsOEScanBoxes::CountMailboxes(MailboxEntry *pBox)
{
if (pBox == nullptr) {
if (m_pFirst != nullptr)
pBox = m_pFirst;
else {
if (m_entryArray.Length() > 0)
pBox = m_entryArray.ElementAt(0);
}
}
uint32_t count = 0;
MailboxEntry * pChild;
while (pBox) {
count++;
if (pBox->child) {
pChild = GetIndexEntry(pBox->child);
if (pChild != nullptr)
count += CountMailboxes(pChild);
}
if (pBox->sibling != -1) {
pBox = GetIndexEntry(pBox->sibling);
}
else
pBox = nullptr;
}
return count;
}
bool nsOEScanBoxes::GetMailboxList(nsIFile * root, nsIArray **pArray)
{
nsresult rv;
nsCOMPtr<nsIMutableArray> array(do_CreateInstance(NS_ARRAY_CONTRACTID, &rv));
if (NS_FAILED(rv)) {
IMPORT_LOG0("FAILED to allocate the nsIArray\n");
return false;
}
BuildMailboxList(nullptr, root, 1, array);
array.forget(pArray);
return true;
}
void nsOEScanBoxes::BuildMailboxList(MailboxEntry *pBox, nsIFile * root, int32_t depth, nsIMutableArray *pArray)
{
if (pBox == nullptr) {
if (m_pFirst != nullptr) {
pBox = m_pFirst;
IMPORT_LOG0("Assigning start of mailbox list to m_pFirst\n");
}
else {
if (m_entryArray.Length() > 0) {
pBox = m_entryArray.ElementAt(0);
IMPORT_LOG0("Assigning start of mailbox list to entry at index 0\n");
}
}
if (pBox == nullptr) {
IMPORT_LOG0("ERROR ASSIGNING STARTING MAILBOX\n");
}
}
nsresult rv;
nsCOMPtr<nsIFile> file;
MailboxEntry *pChild;
nsIImportMailboxDescriptor *pID;
nsISupports *pInterface;
int64_t size;
nsCOMPtr<nsIImportService> impSvc(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv));
NS_ENSURE_SUCCESS_VOID(rv);
while (pBox) {
rv = impSvc->CreateNewMailboxDescriptor(&pID);
if (NS_SUCCEEDED(rv)) {
pID->SetDepth(depth);
pID->SetIdentifier(pBox->index);
pID->SetDisplayName((char16_t *)pBox->mailName.get());
if (!pBox->fileName.IsEmpty()) {
pID->GetFile(getter_AddRefs(file));
file->InitWithFile(root);
file->AppendNative(pBox->fileName);
size = 0;
file->GetFileSize(&size);
pID->SetSize(size);
}
rv = pID->QueryInterface(kISupportsIID, (void **) &pInterface);
pArray->AppendElement(pInterface, false);
pInterface->Release();
pID->Release();
}
if (pBox->child) {
pChild = GetIndexEntry(pBox->child);
if (pChild != nullptr)
BuildMailboxList(pChild, root, depth + 1, pArray);
}
if (pBox->sibling != -1) {
pBox = GetIndexEntry(pBox->sibling);
}
else
pBox = nullptr;
}
}
nsOEScanBoxes::MailboxEntry * nsOEScanBoxes::GetIndexEntry(uint32_t index)
{
int32_t max = m_entryArray.Length();
for (int32_t i = 0; i < max; i++) {
MailboxEntry *pEntry = m_entryArray.ElementAt(i);
if (pEntry->index == index)
return pEntry;
}
return nullptr;
}
// -------------------------------------------------------
// File utility routines
// -------------------------------------------------------
bool nsOEScanBoxes::ReadLong(nsIInputStream * stream, int32_t& val, uint32_t offset)
{
nsresult rv;
nsCOMPtr <nsISeekableStream> seekStream = do_QueryInterface(stream, &rv);
NS_ENSURE_SUCCESS(rv, false);
rv = seekStream->Seek(nsISeekableStream::NS_SEEK_SET, offset);
NS_ENSURE_SUCCESS(rv, false);
uint32_t cntRead;
char * pReadTo = (char *)&val;
rv = stream->Read(pReadTo, sizeof(val), &cntRead);
return NS_SUCCEEDED(rv) && cntRead == sizeof(val);
}
bool nsOEScanBoxes::ReadLong(nsIInputStream * stream, uint32_t& val, uint32_t offset)
{
nsresult rv;
nsCOMPtr <nsISeekableStream> seekStream = do_QueryInterface(stream, &rv);
NS_ENSURE_SUCCESS(rv, false);
rv = seekStream->Seek(nsISeekableStream::NS_SEEK_SET, offset);
NS_ENSURE_SUCCESS(rv, false);
uint32_t cntRead;
char * pReadTo = (char *)&val;
rv = stream->Read(pReadTo, sizeof(val), &cntRead);
if (NS_FAILED(rv) || (cntRead != sizeof(val)))
return false;
return true;
}
// It appears as though the strings for file name and mailbox
// name are at least 254 chars - verified - they are probably 255
// but why bother going that far! If a file name is that long then
// the heck with it.
#define kOutlookExpressStringLength 252
bool nsOEScanBoxes::ReadString(nsIInputStream * stream, nsString& str, uint32_t offset)
{
nsresult rv;
nsCOMPtr<nsISeekableStream> seekStream = do_QueryInterface(stream, &rv);
NS_ENSURE_SUCCESS(rv, false);
rv = seekStream->Seek(nsISeekableStream::NS_SEEK_SET, offset);
NS_ENSURE_SUCCESS(rv, false);
uint32_t cntRead;
char buffer[kOutlookExpressStringLength];
char *pReadTo = buffer;
rv = stream->Read(pReadTo, kOutlookExpressStringLength, &cntRead);
if (NS_FAILED(rv) || (cntRead != kOutlookExpressStringLength))
return false;
buffer[kOutlookExpressStringLength - 1] = 0;
str.AssignASCII(buffer);
return true;
}
bool nsOEScanBoxes::ReadString(nsIInputStream * stream, nsCString& str, uint32_t offset)
{
nsresult rv;
nsCOMPtr<nsISeekableStream> seekStream = do_QueryInterface(stream, &rv);
NS_ENSURE_SUCCESS(rv, false);
rv = seekStream->Seek(nsISeekableStream::NS_SEEK_SET, offset);
NS_ENSURE_SUCCESS(rv, false);
uint32_t cntRead;
char buffer[kOutlookExpressStringLength];
char *pReadTo = buffer;
rv = stream->Read(pReadTo, kOutlookExpressStringLength, &cntRead);
if (NS_FAILED(rv) || (cntRead != kOutlookExpressStringLength))
return false;
buffer[kOutlookExpressStringLength - 1] = 0;
str = buffer;
return true;
}

View file

@ -0,0 +1,76 @@
/* -*- 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/. */
#ifndef nsOEScanBoxes_h___
#define nsOEScanBoxes_h___
#include "nsStringGlue.h"
#include "nsIImportModule.h"
#include "nsTArray.h"
#include "nsCOMPtr.h"
#include "nsIArray.h"
#include "nsIMutableArray.h"
#include "nsIFile.h"
#include "nsIImportService.h"
class nsIInputStream;
class nsOEScanBoxes {
public:
nsOEScanBoxes();
~nsOEScanBoxes();
static bool FindMail(nsIFile *pWhere);
bool GetMailboxes(nsIFile *pWhere, nsIArray **pArray);
private:
typedef struct {
uint32_t index;
uint32_t parent;
int32_t child;
int32_t sibling;
int32_t type;
nsString mailName;
nsCString fileName;
bool processed; // used by entries on m_pendingChildArray list
} MailboxEntry;
static bool Find50Mail(nsIFile *pWhere);
void Reset(void);
bool FindMailBoxes(nsIFile * descFile);
bool Find50MailBoxes(nsIFile * descFile);
// If find mailboxes fails you can use this routine to get the raw mailbox file names
void ScanMailboxDir(nsIFile * srcDir);
bool Scan50MailboxDir(nsIFile * srcDir);
MailboxEntry * GetIndexEntry(uint32_t index);
void AddChildEntry(MailboxEntry *pEntry, uint32_t rootIndex);
MailboxEntry * NewMailboxEntry(uint32_t id, uint32_t parent, const char *prettyName, char *pFileName);
void ProcessPendingChildEntries(uint32_t parent, uint32_t rootIndex, nsTArray<MailboxEntry*> &childArray);
void RemoveProcessedChildEntries();
bool ReadLong(nsIInputStream * stream, int32_t& val, uint32_t offset);
bool ReadLong(nsIInputStream * stream, uint32_t& val, uint32_t offset);
bool ReadString(nsIInputStream * stream, nsString& str, uint32_t offset);
bool ReadString(nsIInputStream * stream, nsCString& str, uint32_t offset);
uint32_t CountMailboxes(MailboxEntry *pBox);
void BuildMailboxList(MailboxEntry *pBox, nsIFile * root, int32_t depth, nsIMutableArray *pArray);
bool GetMailboxList(nsIFile * root, nsIArray **pArray);
private:
MailboxEntry * m_pFirst;
nsTArray<MailboxEntry*> m_entryArray;
nsTArray<MailboxEntry*> m_pendingChildArray; // contains child folders whose parent folders have not showed up.
nsCOMPtr<nsIImportService> mService;
};
#endif // nsOEScanBoxes_h__

View file

@ -0,0 +1,921 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
/*
Outlook Express (Win32) settings
*/
#include "nsOESettings.h"
#include "mozilla/WindowsVersion.h"
#include "nsCOMPtr.h"
#include "nscore.h"
#include "nsMsgUtils.h"
#include "nsOEImport.h"
#include "nsIComponentManager.h"
#include "nsIServiceManager.h"
#include "nsOERegUtil.h"
#include "nsIMsgAccountManager.h"
#include "nsIMsgAccount.h"
#include "nsIImportSettings.h"
#include "nsMsgBaseCID.h"
#include "nsMsgCompCID.h"
#include "nsMsgI18N.h"
#include "nsISmtpService.h"
#include "nsISmtpServer.h"
#include "nsOEStringBundle.h"
#include "OEDebugLog.h"
#include "nsIPop3IncomingServer.h"
#include "nsIImapIncomingServer.h"
#include "nsINntpIncomingServer.h"
#include "stdlib.h"
#include <windows.h>
#include "nsIWindowsRegKey.h"
#include "nsComponentManagerUtils.h"
#ifdef MOZILLA_INTERNAL_API
#include "nsNativeCharsetUtils.h"
#else
#include "nsMsgI18N.h"
#define NS_CopyNativeToUnicode(source, dest) \
nsMsgI18NConvertToUnicode(nsMsgI18NFileSystemCharset(), source, dest)
#define NS_CopyUnicodeToNative(source, dest) \
nsMsgI18NConvertFromUnicode(nsMsgI18NFileSystemCharset(), source, dest)
#endif
class OESettings {
public:
static nsresult GetDefaultMailAccount(nsAString &aMailAccount);
static nsresult GetCheckMailInterval(uint32_t *aInterval);
static nsresult Find50Key(nsIWindowsRegKey **aKey);
static nsresult Find40Key(nsIWindowsRegKey **aKey);
static nsresult FindAccountsKey(nsIWindowsRegKey **aKey);
static bool DoImport(nsIMsgAccount **ppAccount);
static bool DoIMAPServer(nsIMsgAccountManager *aMgr,
nsIWindowsRegKey *aKey,
const nsString &aServerName,
nsIMsgAccount **ppAccount);
static bool DoPOP3Server(nsIMsgAccountManager *aMgr,
nsIWindowsRegKey *aKey,
const nsString &aServerName,
nsIMsgAccount **ppAccount);
static bool DoNNTPServer(nsIMsgAccountManager *aMgr,
nsIWindowsRegKey *aKey,
const nsString &aServerName,
nsIMsgAccount **ppAccount);
static void SetIncomingServerProperties(nsIMsgIncomingServer *aServer,
nsIWindowsRegKey *aKey,
const nsString &aKeyNamePrefix);
static void SetIdentities(nsIMsgAccountManager *aMgr,
nsIMsgAccount *aAccount,
nsIWindowsRegKey *aKey,
const nsString &aIncomgUserName,
int32_t authMethodIncoming, bool isNNTP);
static void SetSmtpServer(const nsString &aSmtpServer,
nsIWindowsRegKey *aKey,
nsIMsgIdentity *aId,
const nsString &aIncomgUserName,
int32_t authMethodIncoming);
static nsresult GetAccountName(nsIWindowsRegKey *aKey,
const nsString &aDefaultName,
nsAString &aAccountName);
static bool IsKB933612Applied();
};
static uint32_t checkNewMailTime;// OE global setting, let's default to 30
static bool checkNewMail; // OE global setting, let's default to false
// This won't cause unwanted autodownloads-
// user can set prefs after import
////////////////////////////////////////////////////////////////////////
nsresult nsOESettings::Create(nsIImportSettings** aImport)
{
NS_PRECONDITION(aImport != nullptr, "null ptr");
if (! aImport)
return NS_ERROR_NULL_POINTER;
*aImport = new nsOESettings();
if (! *aImport)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aImport);
return NS_OK;
}
nsOESettings::nsOESettings()
{
}
nsOESettings::~nsOESettings()
{
}
NS_IMPL_ISUPPORTS(nsOESettings, nsIImportSettings)
NS_IMETHODIMP nsOESettings::AutoLocate(char16_t **description, nsIFile **location, bool *_retval)
{
NS_PRECONDITION(description != nullptr, "null ptr");
NS_PRECONDITION(_retval != nullptr, "null ptr");
if (!description || !_retval)
return NS_ERROR_NULL_POINTER;
*description = nsOEStringBundle::GetStringByID(OEIMPORT_NAME);
if (location)
*location = nullptr;
*_retval = false;
nsCOMPtr<nsIWindowsRegKey> key;
if (NS_FAILED(OESettings::Find50Key(getter_AddRefs(key))) &&
NS_FAILED(OESettings::Find40Key(getter_AddRefs(key))))
return NS_OK;
if (NS_SUCCEEDED(OESettings::FindAccountsKey(getter_AddRefs(key))))
*_retval = true;
return NS_OK;
}
NS_IMETHODIMP nsOESettings::SetLocation(nsIFile *location)
{
return NS_OK;
}
NS_IMETHODIMP nsOESettings::Import(nsIMsgAccount **localMailAccount, bool *_retval)
{
NS_PRECONDITION(_retval != nullptr, "null ptr");
if (OESettings::DoImport(localMailAccount)) {
*_retval = true;
IMPORT_LOG0("Settings import appears successful\n");
}
else {
*_retval = false;
IMPORT_LOG0("Settings import returned FALSE\n");
}
return NS_OK;
}
nsresult OESettings::GetDefaultMailAccount(nsAString &aMailAccount)
{
nsresult rv;
nsCOMPtr<nsIWindowsRegKey> key =
do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString userId;
rv = nsOERegUtil::GetDefaultUserId(userId);
// OE has default mail account here when it has been
// set up by transfer or has multiple identities
// look below for orig code that looked in new OE installs
if (NS_SUCCEEDED(rv)) {
nsAutoString path(NS_LITERAL_STRING("Identities\\"));
path.Append(userId);
path.AppendLiteral("\\Software\\Microsoft\\Internet Account Manager");
rv = key->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
path,
nsIWindowsRegKey::ACCESS_QUERY_VALUE);
if (NS_SUCCEEDED(rv))
key->ReadStringValue(NS_LITERAL_STRING("Default Mail Account"), aMailAccount);
}
if (!aMailAccount.IsEmpty())
return NS_OK;
// else it must be here in original install location from orig code
rv = key->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
NS_LITERAL_STRING("Software\\Microsoft\\Outlook Express"),
nsIWindowsRegKey::ACCESS_QUERY_VALUE);
if (NS_FAILED(rv))
return rv;
return key->ReadStringValue(NS_LITERAL_STRING("Default Mail Account"), aMailAccount);
}
nsresult OESettings::GetCheckMailInterval(uint32_t *aInterval)
{
nsCOMPtr<nsIWindowsRegKey> key;
// 'poll for messages' setting in OE is a global setting
// in OE options general tab and in following global OE
// registry location.
// for all accounts poll interval is a 32 bit value, 0 for
// "don't poll", else milliseconds
nsresult rv = Find50Key(getter_AddRefs(key));
if (NS_FAILED(rv))
rv = Find40Key(getter_AddRefs(key));
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIWindowsRegKey> subKey;
rv = key->OpenChild(NS_LITERAL_STRING("Mail"),
nsIWindowsRegKey::ACCESS_QUERY_VALUE,
getter_AddRefs(subKey));
if (NS_FAILED(rv))
return rv;
uint32_t intValue;
rv = subKey->ReadIntValue(NS_LITERAL_STRING("Poll For Mail"), &intValue);
if (NS_SUCCEEDED(rv) && intValue != PR_UINT32_MAX)
*aInterval = intValue / 60000;
return rv;
}
nsresult OESettings::FindAccountsKey(nsIWindowsRegKey **aKey)
{
nsAutoString userId;
nsresult rv = nsOERegUtil::GetDefaultUserId(userId);
if (NS_FAILED(rv))
return rv;
nsAutoString path(NS_LITERAL_STRING("Identities\\"));
path.Append(userId);
path.AppendLiteral("\\Software\\Microsoft\\Internet Account Manager\\Accounts");
nsCOMPtr<nsIWindowsRegKey> key =
do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = key->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
path,
nsIWindowsRegKey::ACCESS_QUERY_VALUE |
nsIWindowsRegKey::ACCESS_ENUMERATE_SUB_KEYS);
if (NS_SUCCEEDED(rv)) {
NS_ADDREF(*aKey = key);
return rv;
}
rv = key->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
NS_LITERAL_STRING("Software\\Microsoft\\Internet Account Manager\\Accounts"),
nsIWindowsRegKey::ACCESS_QUERY_VALUE |
nsIWindowsRegKey::ACCESS_ENUMERATE_SUB_KEYS);
NS_IF_ADDREF(*aKey = key);
return rv;
}
nsresult OESettings::Find50Key(nsIWindowsRegKey **aKey)
{
nsresult rv;
nsCOMPtr<nsIWindowsRegKey> key =
do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString userId;
rv = nsOERegUtil::GetDefaultUserId(userId);
if (NS_FAILED(rv))
return rv;
nsAutoString path(NS_LITERAL_STRING("Identities\\"));
path.Append(userId);
path.AppendLiteral("\\Software\\Microsoft\\Outlook Express\\5.0");
rv = key->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
path,
nsIWindowsRegKey::ACCESS_QUERY_VALUE);
NS_IF_ADDREF(*aKey = key);
return rv;
}
nsresult OESettings::Find40Key(nsIWindowsRegKey **aKey)
{
nsresult rv;
nsCOMPtr<nsIWindowsRegKey> key =
do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = key->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
NS_LITERAL_STRING("Software\\Microsoft\\Outlook Express"),
nsIWindowsRegKey::ACCESS_QUERY_VALUE);
NS_IF_ADDREF(*aKey = key);
return rv;
}
bool OESettings::DoImport(nsIMsgAccount **aAccount)
{
nsCOMPtr<nsIWindowsRegKey> key;
nsresult rv = FindAccountsKey(getter_AddRefs(key));
if (NS_FAILED(rv)) {
IMPORT_LOG0( "*** Error finding Outlook Express registry account keys\n");
return false;
}
nsCOMPtr<nsIMsgAccountManager> accMgr =
do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
if (NS_FAILED(rv)) {
IMPORT_LOG0("*** Failed to create a account manager!\n");
return false;
}
nsAutoString defMailName;
rv = GetDefaultMailAccount(defMailName);
checkNewMail = false;
checkNewMailTime = 30;
rv = GetCheckMailInterval(&checkNewMailTime);
if (NS_SUCCEEDED(rv))
checkNewMail = true;
// Iterate the accounts looking for POP3 & IMAP accounts...
// Ignore LDAP for now!
uint32_t accounts = 0;
nsAutoString keyComp;
uint32_t childCount = 0;
key->GetChildCount(&childCount);
for (uint32_t i = 0; i < childCount; i++) {
nsAutoString keyName;
key->GetChildName(i, keyName);
nsCOMPtr<nsIWindowsRegKey> subKey;
rv = key->OpenChild(keyName,
nsIWindowsRegKey::ACCESS_QUERY_VALUE,
getter_AddRefs(subKey));
if (NS_FAILED(rv))
continue;
nsAutoCString nativeKeyName;
NS_CopyUnicodeToNative(keyName, nativeKeyName);
IMPORT_LOG1("Opened Outlook Express account: %s\n",
nativeKeyName.get());
nsIMsgAccount *anAccount = nullptr;
nsAutoString value;
rv = subKey->ReadStringValue(NS_LITERAL_STRING("IMAP Server"), value);
if (NS_SUCCEEDED(rv) && DoIMAPServer(accMgr, subKey, value, &anAccount))
accounts++;
rv = subKey->ReadStringValue(NS_LITERAL_STRING("NNTP Server"), value);
if (NS_SUCCEEDED(rv) && DoNNTPServer(accMgr, subKey, value, &anAccount))
accounts++;
rv = subKey->ReadStringValue(NS_LITERAL_STRING("POP3 Server"), value);
if (NS_SUCCEEDED(rv) && DoPOP3Server(accMgr, subKey, value, &anAccount))
accounts++;
if (anAccount) {
// Is this the default account?
keyComp = keyName;
if (keyComp.Equals(defMailName))
accMgr->SetDefaultAccount(anAccount);
NS_RELEASE(anAccount);
}
}
// Now save the new acct info to pref file.
rv = accMgr->SaveAccountInfo();
NS_ASSERTION(NS_SUCCEEDED(rv), "Can't save account info to pref file");
return accounts != 0;
}
nsresult OESettings::GetAccountName(nsIWindowsRegKey *aKey,
const nsString &aDefaultName,
nsAString &aAccountName)
{
nsresult rv;
rv = aKey->ReadStringValue(NS_LITERAL_STRING("Account Name"), aAccountName);
if (NS_FAILED(rv))
aAccountName.Assign(aDefaultName);
return NS_OK;
}
bool OESettings::DoIMAPServer(nsIMsgAccountManager *aMgr,
nsIWindowsRegKey *aKey,
const nsString &aServerName,
nsIMsgAccount **ppAccount)
{
if (ppAccount)
*ppAccount = nullptr;
nsAutoString userName;
nsresult rv;
rv = aKey->ReadStringValue(NS_LITERAL_STRING("IMAP User Name"), userName);
if (NS_FAILED(rv))
return false;
nsAutoCString nativeUserName;
NS_CopyUnicodeToNative(userName, nativeUserName);
nsAutoCString nativeServerName;
NS_CopyUnicodeToNative(aServerName, nativeServerName);
// I now have a user name/server name pair, find out if it already exists?
nsCOMPtr<nsIMsgIncomingServer> in;
rv = aMgr->FindServer(nativeUserName,
nativeServerName,
NS_LITERAL_CSTRING("imap"),
getter_AddRefs(in));
if (NS_SUCCEEDED(rv)) {
// for an existing server we create another identity,
// TB lists under 'manage identities'
nsCOMPtr<nsIMsgAccount> account;
rv = aMgr->FindAccountForServer(in, getter_AddRefs(account));
if (NS_FAILED(rv))
return false;
IMPORT_LOG0("Created an identity and added to existing IMAP incoming server\n");
// Fiddle with the identities
int32_t authMethod;
in->GetAuthMethod(&authMethod);
SetIdentities(aMgr, account, aKey, userName, authMethod, false);
if (ppAccount)
account->QueryInterface(NS_GET_IID(nsIMsgAccount),
(void **)ppAccount);
return true;
}
// Create the incoming server and an account for it?
rv = aMgr->CreateIncomingServer(nativeUserName,
nativeServerName,
NS_LITERAL_CSTRING("imap"),
getter_AddRefs(in));
NS_ENSURE_SUCCESS(rv, false);
nsAutoString rootFolder;
rv = aKey->ReadStringValue(NS_LITERAL_STRING("IMAP Root Folder"), rootFolder);
if (NS_SUCCEEDED(rv) && !rootFolder.IsEmpty()) {
nsCOMPtr<nsIImapIncomingServer> imapServer = do_QueryInterface(in);
nsAutoCString nativeRootFolder;
NS_CopyUnicodeToNative(rootFolder, nativeRootFolder);
imapServer->SetServerDirectory(nativeRootFolder);
}
SetIncomingServerProperties(in, aKey, NS_LITERAL_STRING("IMAP "));
IMPORT_LOG2("Created IMAP server named: %s, userName: %s\n",
nativeServerName.get(), nativeUserName.get());
nsAutoString prettyName;
if (NS_SUCCEEDED(GetAccountName(aKey, aServerName, prettyName)))
rv = in->SetPrettyName(prettyName);
// We have a server, create an account.
nsCOMPtr<nsIMsgAccount> account;
rv = aMgr->CreateAccount(getter_AddRefs(account));
if (NS_SUCCEEDED(rv) && account) {
rv = account->SetIncomingServer(in);
IMPORT_LOG0("Created an account and set the IMAP server as the incoming server\n");
// Fiddle with the identities
int32_t authMethod;
in->GetAuthMethod(&authMethod);
SetIdentities(aMgr, account, aKey, userName, authMethod, false);
if (ppAccount)
account->QueryInterface(NS_GET_IID(nsIMsgAccount), (void **)ppAccount);
return true;
}
return false;
}
bool OESettings::DoPOP3Server(nsIMsgAccountManager *aMgr,
nsIWindowsRegKey *aKey,
const nsString &aServerName,
nsIMsgAccount **ppAccount)
{
if (ppAccount)
*ppAccount = nullptr;
nsAutoString userName;
nsresult rv;
rv = aKey->ReadStringValue(NS_LITERAL_STRING("POP3 User Name"), userName);
if (NS_FAILED(rv))
return false;
nsAutoCString nativeUserName;
NS_CopyUnicodeToNative(userName, nativeUserName);
nsAutoCString nativeServerName;
NS_CopyUnicodeToNative(aServerName, nativeServerName);
// I now have a user name/server name pair, find out if it already exists?
nsCOMPtr<nsIMsgIncomingServer> in;
rv = aMgr->FindServer(nativeUserName,
nativeServerName,
NS_LITERAL_CSTRING("pop3"),
getter_AddRefs(in));
if (NS_SUCCEEDED(rv)) {
IMPORT_LOG2("Existing POP3 server named: %s, userName: %s\n",
nativeUserName.get(), nativeServerName.get());
// for an existing server we create another identity,
// TB listed under 'manage identities'
nsCOMPtr<nsIMsgAccount> account;
rv = aMgr->FindAccountForServer(in, getter_AddRefs(account));
if (NS_SUCCEEDED(rv) && account) {
IMPORT_LOG0("Created identity and added to existing POP3 incoming server.\n");
// Fiddle with the identities
int32_t authMethod;
in->GetAuthMethod(&authMethod);
SetIdentities(aMgr, account, aKey, userName, authMethod, false);
if (ppAccount)
account->QueryInterface(NS_GET_IID(nsIMsgAccount), (void **)ppAccount);
return true;
}
return false;
}
// Create the incoming server and an account for it?
rv = aMgr->CreateIncomingServer(nativeUserName,
nativeServerName,
NS_LITERAL_CSTRING("pop3"),
getter_AddRefs( in));
if (NS_FAILED(rv))
return false;
SetIncomingServerProperties(in, aKey, NS_LITERAL_STRING("POP3 "));
nsCOMPtr<nsIPop3IncomingServer> pop3Server = do_QueryInterface(in);
if (pop3Server) {
// set local folders as the Inbox to use for this POP3 server
nsCOMPtr<nsIMsgIncomingServer> localFoldersServer;
aMgr->GetLocalFoldersServer(getter_AddRefs(localFoldersServer));
if (!localFoldersServer)
{
// If Local Folders does not exist already, create it
if (NS_FAILED(aMgr->CreateLocalMailAccount())) {
IMPORT_LOG0("*** Failed to create Local Folders!\n");
return false;
}
aMgr->GetLocalFoldersServer(getter_AddRefs(localFoldersServer));
}
// now get the account for this server
nsCOMPtr<nsIMsgAccount> localFoldersAccount;
aMgr->FindAccountForServer(localFoldersServer, getter_AddRefs(localFoldersAccount));
if (localFoldersAccount)
{
nsCString localFoldersAcctKey;
localFoldersAccount->GetKey(localFoldersAcctKey);
pop3Server->SetDeferredToAccount(localFoldersAcctKey);
}
uint32_t intValue;
rv = aKey->ReadIntValue(NS_LITERAL_STRING("POP3 Skip Account"), &intValue);
// OE:0=='Include this account when receiving mail or synchronizing'==
// TB:1==AM:Server:advanced:Include this server when getting new mail
pop3Server->SetDeferGetNewMail(NS_SUCCEEDED(rv) && intValue == 0);
rv = aKey->ReadIntValue(NS_LITERAL_STRING("Leave Mail On Server"),
&intValue);
pop3Server->SetLeaveMessagesOnServer(NS_SUCCEEDED(rv) && intValue == 1);
rv = aKey->ReadIntValue(NS_LITERAL_STRING("Remove When Deleted"),
&intValue);
pop3Server->SetDeleteMailLeftOnServer(NS_SUCCEEDED(rv) && intValue == 1);
rv = aKey->ReadIntValue(NS_LITERAL_STRING("Remove When Expired"),
&intValue);
pop3Server->SetDeleteByAgeFromServer(NS_SUCCEEDED(rv) && intValue == 1);
rv = aKey->ReadIntValue(NS_LITERAL_STRING("Expire Days"),
&intValue);
if (NS_SUCCEEDED(rv))
pop3Server->SetNumDaysToLeaveOnServer(static_cast<int32_t>(intValue));
}
IMPORT_LOG2("Created POP3 server named: %s, userName: %s\n",
nativeServerName.get(), nativeUserName.get());
nsString prettyName;
if (NS_SUCCEEDED(GetAccountName(aKey, aServerName, prettyName)))
rv = in->SetPrettyName(prettyName);
// We have a server, create an account.
nsCOMPtr<nsIMsgAccount> account;
rv = aMgr->CreateAccount(getter_AddRefs( account));
if (NS_SUCCEEDED( rv) && account) {
rv = account->SetIncomingServer(in);
IMPORT_LOG0("Created a new account and set the incoming server to the POP3 server.\n");
int32_t authMethod;
in->GetAuthMethod(&authMethod);
// Fiddle with the identities
SetIdentities(aMgr, account, aKey, userName, authMethod, false);
if (ppAccount)
account->QueryInterface(NS_GET_IID(nsIMsgAccount),
(void **)ppAccount);
return true;
}
return false;
}
bool OESettings::DoNNTPServer(nsIMsgAccountManager *aMgr,
nsIWindowsRegKey *aKey,
const nsString &aServerName,
nsIMsgAccount **ppAccount)
{
if (ppAccount)
*ppAccount = nullptr;
nsAutoString userName;
nsresult rv;
// this only exists if NNTP server requires it or not anon login
rv = aKey->ReadStringValue(NS_LITERAL_STRING("NNTP User Name"), userName);
bool result = false;
nsAutoCString nativeServerName;
NS_CopyUnicodeToNative(aServerName, nativeServerName);
// I now have a user name/server name pair, find out if it already exists?
// NNTP can have empty user name. This is wild card in findserver
nsCOMPtr<nsIMsgIncomingServer> in;
rv = aMgr->FindServer(EmptyCString(),
nativeServerName,
NS_LITERAL_CSTRING("nntp"),
getter_AddRefs(in));
if (NS_FAILED(rv) || (in == nullptr)) {
// Create the incoming server and an account for it?
rv = aMgr->CreateIncomingServer(EmptyCString(),
nativeServerName,
NS_LITERAL_CSTRING("nntp"),
getter_AddRefs(in));
if (NS_SUCCEEDED(rv) && in) {
uint32_t port = 0;
rv = aKey->ReadIntValue(NS_LITERAL_STRING("NNTP Port"),
&port);
if (NS_SUCCEEDED(rv) && port && port != 119)
in->SetPort(static_cast<int32_t>(port));
nsAutoCString nativeUserName;
NS_CopyUnicodeToNative(userName, nativeUserName);
// do nntpincomingserver stuff
nsCOMPtr<nsINntpIncomingServer> nntpServer = do_QueryInterface(in);
if (nntpServer && !userName.IsEmpty()) {
nntpServer->SetPushAuth(true);
in->SetUsername(nativeUserName);
}
IMPORT_LOG2("Created NNTP server named: %s, userName: %s\n",
nativeServerName.get(), nativeUserName.get());
nsString prettyName;
if (NS_SUCCEEDED(GetAccountName(aKey, aServerName, prettyName)))
rv = in->SetPrettyName(prettyName);
// We have a server, create an account.
nsCOMPtr<nsIMsgAccount> account;
rv = aMgr->CreateAccount(getter_AddRefs(account));
if (NS_SUCCEEDED(rv) && account) {
rv = account->SetIncomingServer(in);
IMPORT_LOG0("Created an account and set the NNTP server as the incoming server\n");
// Fiddle with the identities
SetIdentities(aMgr, account, aKey, userName, 0, true);
result = true;
if (ppAccount)
account->QueryInterface(NS_GET_IID(nsIMsgAccount), (void **)ppAccount);
}
}
}
else if (NS_SUCCEEDED(rv) && in) {
// for the existing server...
nsCOMPtr<nsIMsgAccount> account;
rv = aMgr->FindAccountForServer(in, getter_AddRefs(account));
if (NS_SUCCEEDED(rv) && account) {
IMPORT_LOG0("Using existing account and set the NNTP server as the incoming server\n");
// Fiddle with the identities
SetIdentities(aMgr, account, aKey, userName, 0, true);
if (ppAccount)
account->QueryInterface(NS_GET_IID(nsIMsgAccount),
(void **)ppAccount);
return true;
}
}
else
result = true;
return result;
}
void OESettings::SetIncomingServerProperties(nsIMsgIncomingServer *aServer,
nsIWindowsRegKey *aKey,
const nsString &aKeyNamePrefix)
{
nsresult rv;
uint32_t secureConnection = 0;
nsString keyName(aKeyNamePrefix);
keyName.AppendLiteral("Secure Connection");
rv = aKey->ReadIntValue(keyName, &secureConnection);
if (NS_SUCCEEDED(rv) && secureConnection == 1)
aServer->SetSocketType(nsMsgSocketType::SSL);
uint32_t port = 0;
keyName.SetLength(aKeyNamePrefix.Length());
keyName.AppendLiteral("Port");
rv = aKey->ReadIntValue(keyName, &port);
if (NS_SUCCEEDED(rv) && port)
aServer->SetPort(static_cast<int32_t>(port));
int32_t authMethod;
uint32_t useSicily = 0;
keyName.SetLength(aKeyNamePrefix.Length());
keyName.AppendLiteral("Use Sicily");
rv = aKey->ReadIntValue(keyName, &useSicily);
if (NS_SUCCEEDED(rv) && useSicily)
authMethod = nsMsgAuthMethod::secure;
else
authMethod = nsMsgAuthMethod::passwordCleartext;
aServer->SetAuthMethod(authMethod);
aServer->SetDoBiff(checkNewMail);
aServer->SetBiffMinutes(checkNewMailTime);
}
void OESettings::SetIdentities(nsIMsgAccountManager *aMgr,
nsIMsgAccount *pAcc,
nsIWindowsRegKey *aKey,
const nsString &aIncomgUserName,
int32_t authMethodIncoming,
bool isNNTP)
{
// Get the relevant information for an identity
nsresult rv;
nsAutoString name;
rv = aKey->ReadStringValue(isNNTP ?
NS_LITERAL_STRING("NNTP Display Name") :
NS_LITERAL_STRING("SMTP Display Name"),
name);
nsAutoString email;
rv = aKey->ReadStringValue(isNNTP ?
NS_LITERAL_STRING("NNTP Email Address") :
NS_LITERAL_STRING("SMTP Email Address"),
email);
nsAutoString reply;
rv = aKey->ReadStringValue(isNNTP ?
NS_LITERAL_STRING("NNTP Reply To Email Address") :
NS_LITERAL_STRING("SMTP Reply To Email Address"),
reply);
nsAutoString orgName;
rv = aKey->ReadStringValue(isNNTP ?
NS_LITERAL_STRING("NNTP Organization Name") :
NS_LITERAL_STRING("SMTP Organization Name"),
orgName);
nsCOMPtr<nsIMsgIdentity> id;
rv = aMgr->CreateIdentity(getter_AddRefs(id));
if (NS_FAILED(rv))
return;
id->SetFullName(name);
id->SetOrganization(orgName);
nsAutoCString nativeEmail;
NS_CopyUnicodeToNative(email, nativeEmail);
id->SetEmail(nativeEmail);
if (!reply.IsEmpty()) {
nsAutoCString nativeReply;
NS_CopyUnicodeToNative(reply, nativeReply);
id->SetReplyTo(nativeReply);
}
// Outlook Express users are used to top style quoting.
id->SetReplyOnTop(isNNTP ? 0 : 1);
pAcc->AddIdentity(id);
nsAutoCString nativeName;
NS_CopyUnicodeToNative(name, nativeName);
IMPORT_LOG0("Created identity and added to the account\n");
IMPORT_LOG1("\tname: %s\n", nativeName.get());
IMPORT_LOG1("\temail: %s\n", nativeEmail.get());
if (isNNTP) // NNTP does not use SMTP in OE or TB
return;
nsAutoString smtpServer;
rv = aKey->ReadStringValue(NS_LITERAL_STRING("SMTP Server"), smtpServer);
SetSmtpServer(smtpServer, aKey, id, aIncomgUserName, authMethodIncoming);
}
void OESettings::SetSmtpServer(const nsString &aSmtpServer,
nsIWindowsRegKey *aKey,
nsIMsgIdentity *aId,
const nsString &aIncomgUserName,
int32_t authMethodIncoming)
{
// set the id.smtpserver accordingly
// first we have to calculate the smtp user name which is based on sicily
if (!aKey || !aId || aIncomgUserName.IsEmpty() || aSmtpServer.IsEmpty())
return;
nsCString smtpServerKey;
// smtp user name depends on sicily which may or not exist
uint32_t useSicily = 0;
nsresult rv = aKey->ReadIntValue(NS_LITERAL_STRING("SMTP Use Sicily"),
&useSicily);
nsAutoString userName;
switch (useSicily) {
case 1:
case 3:
// has to go in whether empty or no
// shouldn't be empty but better safe than sorry
aKey->ReadStringValue(NS_LITERAL_STRING("SMTP User Name"), userName);
break;
case 2:
userName = aIncomgUserName;
break;
default:
break; // initial userName == ""
}
nsCOMPtr<nsISmtpService> smtpService(do_GetService(NS_SMTPSERVICE_CONTRACTID, &rv));
if (NS_SUCCEEDED(rv) && smtpService) {
nsCOMPtr<nsISmtpServer> foundServer;
// don't try to make another server
// regardless if username doesn't match
nsAutoCString nativeUserName;
NS_CopyUnicodeToNative(userName, nativeUserName);
nsAutoCString nativeSmtpServer;
NS_CopyUnicodeToNative(aSmtpServer, nativeSmtpServer);
rv = smtpService->FindServer(nativeUserName.get(),
nativeSmtpServer.get(),
getter_AddRefs(foundServer));
if (NS_SUCCEEDED(rv) && foundServer) {
// set our account keyed to this smptserver key
foundServer->GetKey(getter_Copies(smtpServerKey));
aId->SetSmtpServerKey(smtpServerKey);
IMPORT_LOG1("SMTP server already exists: %s\n",
nativeSmtpServer.get());
}
else {
nsCOMPtr<nsISmtpServer> smtpServer;
rv = smtpService->CreateServer(getter_AddRefs(smtpServer));
if (NS_SUCCEEDED(rv) && smtpServer) {
uint32_t port = 0;
rv = aKey->ReadIntValue(NS_LITERAL_STRING("SMTP Port"),
&port);
if (NS_SUCCEEDED(rv) && port)
smtpServer->SetPort(static_cast<int32_t>(port));
int32_t socketType = nsMsgSocketType::plain;
uint32_t secureConnection = 0;
rv = aKey->ReadIntValue(NS_LITERAL_STRING("SMTP Secure Connection"),
&secureConnection);
if (NS_SUCCEEDED(rv) && secureConnection == 1) {
// Outlook Express does not support STARTTLS without KB933612 fix.
if (IsKB933612Applied() && port != 465)
socketType = nsMsgSocketType::alwaysSTARTTLS;
else
socketType = nsMsgSocketType::SSL;
}
smtpServer->SetSocketType(socketType);
smtpServer->SetUsername(nativeUserName);
switch (useSicily) {
case 1 :
smtpServer->SetAuthMethod(nsMsgAuthMethod::secure);
break;
case 2 : // requires SMTP authentication to use the incoming server settings
smtpServer->SetAuthMethod(authMethodIncoming);
break;
case 3 :
smtpServer->SetAuthMethod(nsMsgAuthMethod::passwordCleartext);
break;
default:
smtpServer->SetAuthMethod(nsMsgAuthMethod::none);
}
smtpServer->SetHostname(nativeSmtpServer);
smtpServer->GetKey(getter_Copies(smtpServerKey));
aId->SetSmtpServerKey(smtpServerKey);
IMPORT_LOG1("Created new SMTP server: %s\n",
nativeSmtpServer.get());
}
}
}
}
bool OESettings::IsKB933612Applied()
{
// The following versions of Windows include KB933612 fix:
// - Windows 7 and future versions of Windows
// - Windows Vista, SP1 or later
// - Windows Server 2003, SP2 or later
// - Windows XP, SP3 or later
//
// The following versions do not:
// - Windows Vista SP0
// - Windows Server 2003, SP1 or earlier
// - Windows XP, SP2 or earlier
//
// See http://support.microsoft.com/kb/929123 and
// http://support.microsoft.com/kb/933612
//
// Note that mozilla::IsWin2003SP2OrLater() will return true for
// Windows Vista and mozilla::IsXPSP3OrLater() will return true
// for Windows Server 2003.
return mozilla::IsVistaSP1OrLater() ||
!mozilla::IsWin2003OrLater() && mozilla::IsXPSP3OrLater() ||
!mozilla::IsVistaOrLater() && mozilla::IsWin2003SP2OrLater();
}

View file

@ -0,0 +1,22 @@
/* -*- 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/. */
#ifndef nsOESettings_h___
#define nsOESettings_h___
#include "nsIImportSettings.h"
class nsOESettings : public nsIImportSettings {
public:
nsOESettings();
static nsresult Create(nsIImportSettings** aImport);
NS_DECL_ISUPPORTS
NS_DECL_NSIIMPORTSETTINGS
private:
virtual ~nsOESettings();
};
#endif /* nsOESettings_h___ */

View file

@ -0,0 +1,71 @@
/* -*- Mode: C++; tab-width: 2; 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 "prprf.h"
#include "prmem.h"
#include "nsCOMPtr.h"
#include "nsMsgUtils.h"
#include "nsIStringBundle.h"
#include "nsOEStringBundle.h"
#include "nsIServiceManager.h"
#include "nsIURI.h"
#include "mozilla/Services.h"
#define OE_MSGS_URL "chrome://messenger/locale/oeImportMsgs.properties"
nsIStringBundle * nsOEStringBundle::m_pBundle = nullptr;
nsIStringBundle *nsOEStringBundle::GetStringBundle(void)
{
if (m_pBundle)
return m_pBundle;
char* propertyURL = OE_MSGS_URL;
nsIStringBundle* sBundle = nullptr;
nsCOMPtr<nsIStringBundleService> sBundleService =
mozilla::services::GetStringBundleService();
if (sBundleService) {
sBundleService->CreateBundle(propertyURL, &sBundle);
}
m_pBundle = sBundle;
return sBundle;
}
void nsOEStringBundle::GetStringByID(int32_t stringID, nsString& result)
{
char16_t *ptrv = GetStringByID(stringID);
result.Adopt(ptrv);
}
char16_t *nsOEStringBundle::GetStringByID(int32_t stringID)
{
if (!m_pBundle)
m_pBundle = GetStringBundle();
if (m_pBundle) {
char16_t *ptrv = nullptr;
nsresult rv = m_pBundle->GetStringFromID(stringID, &ptrv);
if (NS_SUCCEEDED(rv) && ptrv)
return ptrv;
}
nsString resultString;
resultString.AppendLiteral("[StringID ");
resultString.AppendInt(stringID);
resultString.AppendLiteral("?]");
return ToNewUnicode(resultString);
}
void nsOEStringBundle::Cleanup(void)
{
if (m_pBundle)
m_pBundle->Release();
m_pBundle = nullptr;
}

View file

@ -0,0 +1,38 @@
/* 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/. */
#ifndef _nsOEStringBundle_H__
#define _nsOEStringBundle_H__
#include "nsStringGlue.h"
class nsIStringBundle;
class nsOEStringBundle {
public:
static char16_t * GetStringByID(int32_t stringID);
static void GetStringByID(int32_t stringID, nsString& result);
static nsIStringBundle * GetStringBundle(void); // don't release
static void FreeString(char16_t *pStr) { NS_Free(pStr);}
static void Cleanup(void);
private:
static nsIStringBundle * m_pBundle;
};
#define OEIMPORT_NAME 2000
#define OEIMPORT_DESCRIPTION 2011
#define OEIMPORT_MAILBOX_SUCCESS 2002
#define OEIMPORT_MAILBOX_BADPARAM 2003
#define OEIMPORT_MAILBOX_BADSOURCEFILE 2004
#define OEIMPORT_MAILBOX_CONVERTERROR 2005
#define OEIMPORT_DEFAULT_NAME 2006
#define OEIMPORT_AUTOFIND 2007
#define OEIMPORT_ADDRESS_SUCCESS 2008
#define OEIMPORT_ADDRESS_CONVERTERROR 2009
#define OEIMPORT_ADDRESS_BADPARAM 2010
#endif /* _nsOEStringBundle_H__ */