From fe336622c8bcbdd38fcf38b9b5a97d3fcb6d7b94 Mon Sep 17 00:00:00 2001 From: "bienvenu%nventure.com" Date: Tue, 8 May 2007 23:07:19 +0000 Subject: [PATCH] fix eudora import to maintain status flags, patch by gwenger@qualcomm.com, r=mscott, sr=bienvenu 368347 git-svn-id: svn://10.0.0.236/trunk@226146 18797224-902f-48f8-a5cc-f745e15eee43 --- .../mailnews/import/eudora/src/Makefile.in | 1 + .../import/eudora/src/nsEudoraImport.cpp | 56 + .../import/eudora/src/nsEudoraMailbox.cpp | 653 ++-- .../import/eudora/src/nsEudoraMailbox.h | 120 +- .../import/eudora/src/nsEudoraWin32.cpp | 2842 ++++++++--------- 5 files changed, 2014 insertions(+), 1658 deletions(-) diff --git a/mozilla/mailnews/import/eudora/src/Makefile.in b/mozilla/mailnews/import/eudora/src/Makefile.in index 8c6a4a463b4..2634aa830d5 100644 --- a/mozilla/mailnews/import/eudora/src/Makefile.in +++ b/mozilla/mailnews/import/eudora/src/Makefile.in @@ -63,6 +63,7 @@ REQUIRES = xpcom \ msgdb \ msgbaseutil \ msglocal \ + mime \ mimetype \ unicharutil \ $(NULL) diff --git a/mozilla/mailnews/import/eudora/src/nsEudoraImport.cpp b/mozilla/mailnews/import/eudora/src/nsEudoraImport.cpp index efbbacddab8..d789e4d5ea6 100644 --- a/mozilla/mailnews/import/eudora/src/nsEudoraImport.cpp +++ b/mozilla/mailnews/import/eudora/src/nsEudoraImport.cpp @@ -75,6 +75,9 @@ #include "nsEudoraSettings.h" #include "nsReadableUtils.h" #include "nsUnicharUtils.h" +#include "nsIMsgTagService.h" +#include "nsMsgBaseCID.h" + #if defined(XP_WIN) || defined(XP_OS2) #include "nsEudoraWin32.h" @@ -360,6 +363,59 @@ nsresult ImportEudoraMailImpl::Create(nsIImportMail** aImport) ImportEudoraMailImpl::ImportEudoraMailImpl() { + // Create keys to support the default Eudora label colors. + // Ideally importing the settings will have already created these, + // in which case we won't bother (we'll detect that each key already + // exists). But to be sure we need to create the keys here, at + // least until the infrastructure is improved in some fashion so + // that we can rely on settings *always* being imported before mail. + nsresult rv; + nsCOMPtr pTagService = do_GetService(NS_MSGTAGSERVICE_CONTRACTID, &rv); + + if ( NS_SUCCEEDED(rv) ) { + struct EudoraDefaultLabels + { + char * key; + nsString tag; + char * color; + }; + +#if defined(XP_MAC) || defined(XP_MACOSX) + // For now default to no labels on Mac + #define kNumEudoraLabels 0 + + // Use one dummy entry for now as a placeholder to keep the Mac code valid, + // until we enter actual reasonable defaults for Mac builds. + EudoraDefaultLabels defaultEudoraLabels[1] = + { "eudoralabel1", NS_LITERAL_STRING("Label 1"), "#FF6600" }; +#else + // These aren't the actual default Windows Eudora colors. Rather they're the closest + // equivalents that I could find that Thunderbird supports. When importing actual + // label settings, we'll need to map Eudora colors to ones that are supported. + #define kNumEudoraLabels 7 + EudoraDefaultLabels defaultEudoraLabels[kNumEudoraLabels] = + { "eudoralabel1", NS_LITERAL_STRING("Label 1"), "#FF6600", + "eudoralabel2", NS_LITERAL_STRING("Label 2"), "#FF0000", + "eudoralabel3", NS_LITERAL_STRING("Label 3"), "#CC66CC", + "eudoralabel4", NS_LITERAL_STRING("Label 4"), "#3366FF", + "eudoralabel5", NS_LITERAL_STRING("Label 5"), "#000099", + "eudoralabel6", NS_LITERAL_STRING("Label 6"), "#009900", + "eudoralabel7", NS_LITERAL_STRING("Label 7"), "#663333" }; +#endif + + nsCString eudoraKey; + nsString eudoraTag; + nsCString eudoraColor; + + for (PRInt16 i = 0; i < kNumEudoraLabels; i++) { + eudoraKey = defaultEudoraLabels[i].key; + rv = pTagService->GetTagForKey(eudoraKey, eudoraTag); + if ( NS_FAILED(rv) || eudoraTag.IsEmpty() ) { + eudoraColor = defaultEudoraLabels[i].color; + rv = pTagService->AddTagForKey( eudoraKey, defaultEudoraLabels[i].tag, eudoraColor, EmptyCString() ); + } + } + } } diff --git a/mozilla/mailnews/import/eudora/src/nsEudoraMailbox.cpp b/mozilla/mailnews/import/eudora/src/nsEudoraMailbox.cpp index c7110563a41..8b01dcc0782 100644 --- a/mozilla/mailnews/import/eudora/src/nsEudoraMailbox.cpp +++ b/mozilla/mailnews/import/eudora/src/nsEudoraMailbox.cpp @@ -37,12 +37,17 @@ * * ***** END LICENSE BLOCK ***** */ +#include "msgCore.h" #include "nsCOMPtr.h" #include "nsReadableUtils.h" #include "nsEudoraMailbox.h" #include "nsDirectoryServiceDefs.h" #include "nsEudoraCompose.h" #include "nspr.h" +#include "nsMsgMessageFlags.h" +#include "nsMailHeaders.h" +#include "nsMsgLocalFolderHdrs.h" + #include "nsMsgUtils.h" #include "nsNetUtil.h" #include "EudoraDebugLog.h" @@ -107,6 +112,89 @@ static char *eudoraMonths[12] = { }; +PRUint16 EudoraTOCEntry::GetMozillaStatusFlags() +{ + // Return the mozilla equivalent of flags that Eudora supports. + PRUint16 flags = 0; + +#if defined(XP_MAC) || defined(XP_MACOSX) + +#else + switch (m_State) + { + case MS_UNREAD: + flags = 0; + break; + + case MS_READ: + flags = MSG_FLAG_READ; + break; + + case MS_REPLIED: + flags = MSG_FLAG_READ | MSG_FLAG_REPLIED; + break; + + case MS_FORWARDED: + flags = MSG_FLAG_READ | MSG_FLAG_FORWARDED; + break; + + case MS_REDIRECT: + // Redirect doesn't really mean forwarded, but forwarded + // seems to be the closest equivalent for now. + flags = MSG_FLAG_READ | MSG_FLAG_FORWARDED; + break; + + case MS_UNSENDABLE: + case MS_SENDABLE: + case MS_QUEUED: + case MS_SENT: + case MS_UNSENT: + case MS_TIME_QUEUED: + case MS_SPOOLED: + // To do: Add more sent message flag handling. + flags = 0; + break; + + case MS_RECOVERED: + flags = MSG_FLAG_READ; + break; + } + + // Range check priority just to be sure + if (m_Priority < MSP_HIGHEST) + m_Priority = MSP_HIGHEST; + if (m_Priority > MSP_LOWEST) + m_Priority = MSP_LOWEST; + + // Translate priority into format used in mozilla status flags + // (which is reversed for some reason) + flags |= (7-m_Priority) << 13; +#endif + + return flags; +} + + +PRUint32 EudoraTOCEntry::GetMozillaStatus2Flags() +{ +#if defined(XP_MAC) || defined(XP_MACOSX) + return 0; +#else + + // Return the mozilla equivalent of flags that Eudora supports. + PRUint32 flags = 0; + + if (m_Imflags & IMFLAGS_DELETED) + flags |= MSG_FLAG_IMAP_DELETED; + + if (m_Flags & MSF_READ_RECEIPT) + flags |= MSG_FLAG_MDN_REPORT_NEEDED; + + return flags; +#endif +} + + nsEudoraMailbox::nsEudoraMailbox() { m_fromLen = 0; @@ -154,13 +242,12 @@ nsresult nsEudoraMailbox::ImportMailbox( PRUint32 *pBytes, PRBool *pAbort, const { nsCOMPtr tocFile; nsCOMPtr srcInputStream; + nsCOMPtr tocInputStream; nsCOMPtr mailOutputStream; + PRBool importWithoutToc = PR_TRUE; PRBool deleteToc = PR_FALSE; nsresult rv; nsCOMPtr mailFile; - PRBool deleteMailFile = PR_FALSE; - PRUint32 div = 1; - PRUint32 mul = 1; if (pMsgCount) *pMsgCount = 0; @@ -175,186 +262,93 @@ nsresult nsEudoraMailbox::ImportMailbox( PRUint32 *pBytes, PRBool *pAbort, const // First, get the index file for this mailbox rv = FindTOCFile( pSrc, getter_AddRefs( tocFile), &deleteToc); - if (NS_SUCCEEDED( rv) && tocFile) { + if (NS_SUCCEEDED( rv) && tocFile) + { IMPORT_LOG0( "Reading euroda toc file: "); DUMP_FILENAME( tocFile, PR_TRUE); - rv = CreateTempFile(getter_AddRefs( mailFile)); - deleteMailFile = PR_TRUE; - if (NS_SUCCEEDED( rv)) { - // Read the TOC and compact the mailbox file into a temp file - if (NS_SUCCEEDED( rv)) { - rv = NS_NewLocalFileOutputStream(getter_AddRefs(mailOutputStream), - mailFile, - PR_CREATE_FILE | PR_WRONLY | PR_TRUNCATE, - 0644); - if (NS_SUCCEEDED( rv)) { - // Read the toc and compact the mailbox into mailFile - rv = CompactMailbox( pBytes, pAbort, pSrc, tocFile, mailOutputStream); - div = 4; - mul = 3; - } - } - } - + rv = NS_NewLocalFileOutputStream(getter_AddRefs(mailOutputStream), pDst); + NS_ENSURE_SUCCESS(rv, rv); + // Read the toc and import the messages + rv = ImportMailboxUsingTOC( pBytes, pAbort, srcInputStream, tocFile, mailOutputStream, pMsgCount); + // clean up if (deleteToc) - DeleteFile( tocFile); - if (NS_FAILED( rv)) { - DeleteFile( mailFile); - mailFile = pSrc; - deleteMailFile = PR_FALSE; - IMPORT_LOG0( "*** Error compacting mailbox.\n"); - } - - IMPORT_LOG0( "Compacted mailbox: "); DUMP_FILENAME( mailFile, PR_TRUE); + DeleteFile( tocFile); - if (NS_SUCCEEDED( rv)) { - mailFile = pSrc; - - IMPORT_LOG0( "Compacting mailbox was successful\n"); + // If we were able to import with the TOC, then we don't need to bother + // importing without the TOC. + if ( NS_SUCCEEDED(rv) ) { + importWithoutToc = PR_FALSE; + IMPORT_LOG0( "Imported mailbox: "); DUMP_FILENAME( pSrc, PR_FALSE); + IMPORT_LOG0( " Using TOC: "); DUMP_FILENAME(tocFile, PR_TRUE); } else { - DeleteFile( mailFile); - deleteMailFile = PR_FALSE; - IMPORT_LOG0( "*** Error accessing compacted mailbox\n"); + IMPORT_LOG0( "*** Error importing with TOC - will import without TOC.\n"); } } - - // So, where we are now, is we have the mail file to import in pSrc - // It may need deleting if deleteMailFile is PR_TRUE. + // pSrc must be Released before returning - - // The source file contains partially constructed mail messages, - // and attachments. We should first investigate if we can use the mailnews msgCompose - // stuff to do the work for us. If not we have to scan the mailboxes and do TONS - // of work to properly reconstruct the message - Eudora is so nice that it strips things - // like MIME headers, character encoding, and attachments - beautiful! - - rv = pSrc->GetFileSize( &m_mailSize); - NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr compositionFile; - SimpleBufferTonyRCopiedOnce readBuffer; - SimpleBufferTonyRCopiedOnce headers; - SimpleBufferTonyRCopiedOnce body; - SimpleBufferTonyRCopiedOnce copy; - PRUint32 written; - nsCString fromLine(eudoraFromLine); - - headers.m_convertCRs = PR_TRUE; - body.m_convertCRs = PR_TRUE; - - copy.Allocate( kCopyBufferSize); - readBuffer.Allocate( kMailReadBufferSize); - ReadFileState state; - state.offset = 0; - state.size = m_mailSize; - state.pFile = pSrc; - rv = NS_NewLocalFileInputStream(getter_AddRefs(state.pInputStream), pSrc); + if (importWithoutToc) { + // The source file contains partially constructed mail messages, + // and attachments. We should first investigate if we can use the mailnews msgCompose + // stuff to do the work for us. If not we have to scan the mailboxes and do TONS + // of work to properly reconstruct the message - Eudora is so nice that it strips things + // like MIME headers, character encoding, and attachments - beautiful! - IMPORT_LOG0( "Reading mailbox\n"); + rv = pSrc->GetFileSize( &m_mailSize); + + SimpleBufferTonyRCopiedOnce readBuffer; + SimpleBufferTonyRCopiedOnce headers; + SimpleBufferTonyRCopiedOnce body; + SimpleBufferTonyRCopiedOnce copy; + nsCString fromLine(eudoraFromLine); + + headers.m_convertCRs = PR_TRUE; + body.m_convertCRs = PR_TRUE; + + copy.Allocate( kCopyBufferSize); + readBuffer.Allocate( kMailReadBufferSize); + ReadFileState state; + state.offset = 0; + state.size = m_mailSize; + state.pFile = pSrc; + + IMPORT_LOG0( "Reading mailbox\n"); + + if (NS_SUCCEEDED( rv )) + { + nsEudoraCompose compose; + nsCString defaultDate; + nsCAutoString bodyType; + + IMPORT_LOG0( "Reading first message\n"); + + while (!*pAbort && NS_SUCCEEDED( rv = ReadNextMessage( &state, readBuffer, headers, body, defaultDate, bodyType, NULL))) { + + if (pBytes) { + *pBytes += body.m_writeOffset - 1 + headers.m_writeOffset - 1; + } + + rv = ImportMessage(headers, body, defaultDate, bodyType, mailOutputStream, pMsgCount); + + if (!readBuffer.m_bytesInBuf && (state.offset >= state.size)) + break; + } - if (NS_SUCCEEDED(rv)) - { - nsEudoraCompose compose; - nsCString defaultDate; - nsCAutoString bodyType; - - /* - IMPORT_LOG0( "Calling compose.SendMessage\n"); - rv = compose.SendMessage( compositionFile); - if (NS_SUCCEEDED( rv)) { - IMPORT_LOG0( "Composed message in file: "); DUMP_FILENAME( compositionFile, PR_TRUE); } else { - IMPORT_LOG0( "*** Error composing message\n"); + IMPORT_LOG0( "*** Error creating file spec for composition\n"); } - */ - - IMPORT_LOG0( "Reading first message\n"); - - - nsCOMPtr dstOutputStream; - rv = NS_NewLocalFileOutputStream(getter_AddRefs(dstOutputStream), - pDst, - PR_CREATE_FILE | PR_WRONLY | PR_TRUNCATE, - 0644); - NS_ENSURE_SUCCESS(rv, rv); - while (!*pAbort && NS_SUCCEEDED( rv = ReadNextMessage( &state, readBuffer, headers, body, defaultDate, bodyType))) { - - if (pBytes) { - *pBytes += (((body.m_writeOffset - 1 + headers.m_writeOffset - 1) / div) * mul); - } - - // Unfortunately Eudora stores HTML messages in the sent folder - // without any content type header at all. If the first line of the message body is - // then mark the message as html internally...See Bug #258489 - if (body.m_pBuffer && (body.m_writeOffset > strlen(kHTMLTag)) && (strncmp(body.m_pBuffer, kHTMLTag, strlen(kHTMLTag)) == 0 )) - bodyType = "text/html"; // ignore whatever body type we were given...force html - - compose.SetBody( body.m_pBuffer, body.m_writeOffset - 1, bodyType); - compose.SetHeaders( headers.m_pBuffer, headers.m_writeOffset - 1); - compose.SetAttachments( &m_attachments); - compose.SetDefaultDate(defaultDate); - - rv = compose.SendTheMessage( getter_AddRefs(compositionFile)); - if (NS_SUCCEEDED( rv)) { - /* IMPORT_LOG0( "Composed message in file: "); DUMP_FILENAME( compositionFile, PR_TRUE); */ - // copy the resulting file into the destination file! - rv = compose.CopyComposedMessage( fromLine, compositionFile, dstOutputStream, copy); - DeleteFile( compositionFile); - if (NS_FAILED( rv)) { - IMPORT_LOG0( "*** Error copying composed message to destination mailbox\n"); - break; - } - if (pMsgCount) - (*pMsgCount)++; - } - else { - IMPORT_LOG0( "*** Error composing message, writing raw message\n"); - rv = WriteFromSep( dstOutputStream); - - rv = dstOutputStream->Write( kComposeErrorStr, - strlen( kComposeErrorStr), - &written ); - - if (NS_SUCCEEDED( rv)) - rv = dstOutputStream->Write( headers.m_pBuffer, headers.m_writeOffset - 1, &written); - if (NS_SUCCEEDED( rv) && (written == (headers.m_writeOffset - 1))) - rv = dstOutputStream->Write( "\x0D\x0A" "\x0D\x0A", 4, &written); - if (NS_SUCCEEDED( rv) && (written == 4)) - rv = dstOutputStream->Write( body.m_pBuffer, body.m_writeOffset - 1, &written); - if (NS_SUCCEEDED( rv) && (written == (body.m_writeOffset - 1))) { - rv = dstOutputStream->Write( "\x0D\x0A", 2, &written); - if (written != 2) - rv = NS_ERROR_FAILURE; - } - - if (NS_FAILED( rv)) { - IMPORT_LOG0( "*** Error writing to destination mailbox\n"); - break; - } - } - - if (!readBuffer.m_bytesInBuf && (state.offset >= state.size)) - break; - } - - } - else { - IMPORT_LOG0( "*** Error creating file spec for composition\n"); } - if (deleteMailFile) - DeleteFile( pSrc); - pSrc->Release(); return( rv); } -#ifdef XP_MACOSX +#if defined(XP_MAC) || defined(XP_MACOSX) #define kMsgHeaderSize 220 #define kMsgFirstOffset 278 #else @@ -362,99 +356,266 @@ nsresult nsEudoraMailbox::ImportMailbox( PRUint32 *pBytes, PRBool *pAbort, const #define kMsgFirstOffset 104 #endif -nsresult nsEudoraMailbox::CompactMailbox( PRUint32 *pBytes, PRBool *pAbort, nsIFile *pMail, nsIFile *pToc, nsIOutputStream *pDstOutputStream) + +nsresult nsEudoraMailbox::ImportMailboxUsingTOC( + PRUint32 *pBytes, + PRBool *pAbort, + nsIInputStream *pInputStream, + nsIFile *tocFile, + nsIOutputStream *pDst, + PRInt32 *pMsgCount) { - PRInt64 mailSize = m_mailSize; - PRInt64 tocSize = 0; - PRUint32 msgCount = 0; - nsresult rv; + nsresult rv = NS_OK; - rv = pToc->GetFileSize( &tocSize); + PRInt64 mailSize = m_mailSize; + PRInt64 tocSize = 0; + PRUint32 saveBytes = pBytes ? *pBytes : 0; + nsCOMPtr tocInputStream; - // if the index or the mail file is empty then just - // use the original mail file. - if (!mailSize || !tocSize) - return( NS_ERROR_FAILURE); + rv = tocFile->GetFileSize( &tocSize); - SimpleBufferTonyRCopiedOnce copy; - PRBool done = PR_FALSE; - PRInt32 tocOffset = kMsgFirstOffset; - PRInt32 data[2]; - PRInt32 count; - PRUint32 read; - PRUint32 written; - char * pBuffer; - char lastChar; + // if the index or the mail file is empty then just + // use the original mail file. + if (!mailSize || !tocSize) + return NS_ERROR_FAILURE; + rv = NS_NewLocalFileInputStream(getter_AddRefs(tocInputStream), tocFile); + NS_ENSURE_SUCCESS(rv, rv); - copy.Allocate( kCopyBufferSize); + SimpleBufferTonyRCopiedOnce readBuffer; + SimpleBufferTonyRCopiedOnce headers; + SimpleBufferTonyRCopiedOnce body; + SimpleBufferTonyRCopiedOnce copy; + PRInt32 tocOffset = kMsgFirstOffset; + EudoraTOCEntry tocEntry; - IMPORT_LOG0( "Compacting mailbox: "); - nsCOMPtr tocStream; - rv = NS_NewLocalFileInputStream(getter_AddRefs(tocStream), pToc); + copy.Allocate( kCopyBufferSize); + readBuffer.Allocate(kMailReadBufferSize); - nsCOMPtr seekTOCStream = do_QueryInterface(tocStream, &rv); - NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr mailInputStream; - rv = NS_NewLocalFileInputStream(getter_AddRefs(mailInputStream), pMail); - nsCOMPtr seekMailStream = do_QueryInterface(mailInputStream, &rv); - NS_ENSURE_SUCCESS(rv, rv); + IMPORT_LOG0( "Importing mailbox using TOC: "); + DUMP_FILENAME( tocFile, PR_TRUE); - while (!*pAbort && (tocOffset < (PRInt32)tocSize)) { - if (NS_FAILED( rv = seekTOCStream->Seek(nsISeekableStream::NS_SEEK_SET, tocOffset))) return( rv); - pBuffer = (char *)data; - if (NS_FAILED( rv = tocStream->Read( pBuffer, 8, &read)) || (read != 8)) - return( NS_ERROR_FAILURE); - // data[0] is the message offset, data[1] is the message size - if (NS_FAILED( rv = seekMailStream->Seek(nsISeekableStream::NS_SEEK_SET, data[0]))) return( rv); - count = kCopyBufferSize; - if (count > data[1]) - count = data[1]; - pBuffer = copy.m_pBuffer; - if (NS_FAILED( rv = mailInputStream->Read( pBuffer, count, &read)) || (read != count)) - return( NS_ERROR_FAILURE); - if (count < 6) - return( NS_ERROR_FAILURE); - if ((copy.m_pBuffer[0] != 'F') || (copy.m_pBuffer[1] != 'r') || - (copy.m_pBuffer[2] != 'o') || (copy.m_pBuffer[3] != 'm') || - (copy.m_pBuffer[4] != ' ')) - return( NS_ERROR_FAILURE); - - if (pBytes) - *pBytes += (data[1] / 4); - // Looks like everything is cool, we have a message that appears to start with a separator - while (data[1]) { - lastChar = copy.m_pBuffer[count - 1]; - if (NS_FAILED( rv = pDstOutputStream->Write( copy.m_pBuffer, count, &written)) || (written != count)) - return( NS_ERROR_FAILURE); - data[1] -= count; - if (data[1]) { - pBuffer = copy.m_pBuffer; - count = kCopyBufferSize; - if (count > data[1]) - count = data[1]; - if (NS_FAILED( rv = mailInputStream->Read( pBuffer, count, &read)) || (read != count)) - return( NS_ERROR_FAILURE); - } + nsCOMPtr seekableStream = do_QueryInterface(tocInputStream); + while (!*pAbort && (tocOffset < (PRInt32)tocSize)) { + if ( NS_FAILED(rv = seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, tocOffset)) ) + break; + + if ( NS_FAILED(rv = ReadTOCEntry(tocInputStream, tocEntry)) ) + break; + + // Quick and dirty way to read in and parse the message the way the rest + // of the code expects. + nsCString defaultDate; + nsCAutoString bodyType; + ReadFileState state; + + // We're fudging the data to make ReadNextMessage happy. In particular + // state.size is meant to be the size of the entire file, because it's + // assumed that ReadNextMessage will actually have to parse. We know + // exactly how big the message is, so we simply set the "size" to be + // immediately where the message ends. + state.offset = tocEntry.m_Offset; + state.pInputStream = pInputStream; + state.size = state.offset + tocEntry.m_Length; + + if ( NS_SUCCEEDED(rv = ReadNextMessage(&state, readBuffer, headers, body, defaultDate, bodyType, &tocEntry) ) ) + { + rv = ImportMessage(headers, body, defaultDate, bodyType, pDst, pMsgCount); + + if (pBytes) + *pBytes += tocEntry.m_Length; + } + + // We currently don't consider an error from ReadNextMessage or ImportMessage to be fatal. + // Reset the error back to no error in case this is the last time through the loop. + rv = NS_OK; + + tocOffset += kMsgHeaderSize; + } + + if ( NS_SUCCEEDED(rv) ) { + IMPORT_LOG0( " finished\n"); + } + else { + // We failed somewhere important enough that we kept the error. + // Bail on all that we imported since we'll be importing everything + // again using just the mailbox. + IMPORT_LOG0( "*** Error importing mailbox using TOC: "); +// DUMP_FILENAME(pMail, PR_TRUE); + + // Close the destination and truncate it. We don't need to bother + // to reopen it because the nsIFileSpec implementation will open + // before writing if necessary (and yes legacy importing code already + // relies on this behavior). +// pDst->CloseStream(); +// pDst->Truncate(0); + + // Reset pBytes back to where it was before we imported this mailbox. + // This will likely result in a funky progress bar which will move + // backwards, but that's probably the best we can do to keep the + // progress accurate since we'll be re-importing the same mailbox. + if (pBytes) + *pBytes = saveBytes; + + // Set the message count back to 0. + if (pMsgCount) + *pMsgCount = 0; + } + + return rv; +} + +nsresult nsEudoraMailbox::ReadTOCEntry(nsIInputStream *pToc, EudoraTOCEntry& tocEntry) +{ +#define READ_TOC_FIELD(entry) pBuffer = (char *)&entry;\ + if ( NS_FAILED(pToc->Read(pBuffer, sizeof(entry), &bytesRead)) || (bytesRead != sizeof(entry)) )\ + return NS_ERROR_FAILURE + + PRUint32 bytesRead = 0; + char * pBuffer; + + // Here we'll read any initial data that's in the same format on both Mac and Windows + READ_TOC_FIELD(tocEntry.m_Offset); + READ_TOC_FIELD(tocEntry.m_Length); + +#if defined(XP_MAC) || defined(XP_MACOSX) + // Read Mac specific data + +#else + // Read Windows specific data + PRInt16 x1 = 0, y1 = 0, x2 = 400, y2 = 300, tzm = 0; + PRInt8 nIgnoreChar; + PRUint8 cJunkInfo = 0; + PRUint32 ulJunkPluginID; + + READ_TOC_FIELD(tocEntry.m_Seconds); + READ_TOC_FIELD(tocEntry.m_State); + READ_TOC_FIELD(tocEntry.m_Flags); + READ_TOC_FIELD(tocEntry.m_Priority); + READ_TOC_FIELD(nIgnoreChar); + READ_TOC_FIELD(tocEntry.m_Date); + READ_TOC_FIELD(tocEntry.m_lArrivalSeconds); + READ_TOC_FIELD(tocEntry.m_From); + READ_TOC_FIELD(tocEntry.m_Subject); + + // We'll read but ignore window position + READ_TOC_FIELD(x1); + READ_TOC_FIELD(y1); + READ_TOC_FIELD(x2); + READ_TOC_FIELD(y2); + + READ_TOC_FIELD(tocEntry.m_Label); + READ_TOC_FIELD(tocEntry.m_Hash); + READ_TOC_FIELD(tocEntry.m_UniqueMessageId); + READ_TOC_FIELD(tocEntry.m_FlagsEx); + READ_TOC_FIELD(tocEntry.m_PersonaHash); + + READ_TOC_FIELD(tzm); + tocEntry.m_TimeZoneMinutes = tzm; + + // IMAP specific info (present, but not useful when POP mailbox) + READ_TOC_FIELD(tocEntry.m_Imflags); + READ_TOC_FIELD(tocEntry.m_MsgSize); + + // Moodwatch info - may never be worth importing + READ_TOC_FIELD(tocEntry.m_nMood); + + // Get the junk score byte + READ_TOC_FIELD(cJunkInfo); + if (cJunkInfo & 0x80) + { + // If the high bit is set note that this message was manually junked + // and unset the high bit. + tocEntry.m_bManuallyJunked = PR_TRUE; + cJunkInfo &= 0x7F; + } + else + { + tocEntry.m_bManuallyJunked = PR_FALSE; + } + tocEntry.m_ucJunkScore = cJunkInfo; + + READ_TOC_FIELD(ulJunkPluginID); +#endif + + return NS_OK; +} + + +nsresult nsEudoraMailbox::ImportMessage( + SimpleBufferTonyRCopiedOnce &headers, + SimpleBufferTonyRCopiedOnce &body, + nsCString& defaultDate, + nsCAutoString& bodyType, + nsIOutputStream *pDst, + PRInt32 *pMsgCount) +{ + nsresult rv = NS_OK; + PRUint32 written = 0; + nsEudoraCompose compose; + + // Unfortunately Eudora stores HTML messages in the sent folder + // without any content type header at all. If the first line of the message body is + // then mark the message as html internally...See Bug #258489 + if (body.m_pBuffer && (body.m_writeOffset > (PRInt32)strlen(kHTMLTag)) && (strncmp(body.m_pBuffer, kHTMLTag, strlen(kHTMLTag)) == 0 )) + bodyType = "text/html"; // ignore whatever body type we were given...force html + + compose.SetBody( body.m_pBuffer, body.m_writeOffset - 1, bodyType); + compose.SetHeaders( headers.m_pBuffer, headers.m_writeOffset - 1); + compose.SetAttachments( &m_attachments); + compose.SetDefaultDate(defaultDate); + + nsCOMPtr compositionFile; + rv = compose.SendTheMessage(getter_AddRefs(compositionFile)); + if (NS_SUCCEEDED( rv)) { + nsCString fromLine(eudoraFromLine); + SimpleBufferTonyRCopiedOnce copy; + + copy.Allocate( kCopyBufferSize); + + /* IMPORT_LOG0( "Composed message in file: "); DUMP_FILENAME( compositionFile, PR_TRUE); */ + // copy the resulting file into the destination file! + rv = compose.CopyComposedMessage( fromLine, compositionFile, pDst, copy); + DeleteFile(compositionFile); + if (NS_FAILED( rv)) { + IMPORT_LOG0( "*** Error copying composed message to destination mailbox\n"); } - if ((lastChar != 0x0D) && (lastChar != 0x0A)) { - if (NS_FAILED( rv = pDstOutputStream->Write( "\x0D\x0A", 2, &written)) || (written != 2)) - return( rv); - } - - IMPORT_LOG1( " Message #%d processed.", ++msgCount); + if (pMsgCount) + (*pMsgCount)++; + } + else { + IMPORT_LOG0( "*** Error composing message, writing raw message\n"); + rv = WriteFromSep( pDst); - tocOffset += kMsgHeaderSize; + rv = pDst->Write( kComposeErrorStr, + strlen( kComposeErrorStr), + &written ); + + if (NS_SUCCEEDED( rv)) + rv = pDst->Write( headers.m_pBuffer, headers.m_writeOffset - 1, &written); + if (NS_SUCCEEDED( rv) && (written == (headers.m_writeOffset - 1))) + rv = pDst->Write( "\x0D\x0A" "\x0D\x0A", 4, &written); + if (NS_SUCCEEDED( rv) && (written == 4)) + rv = pDst->Write( body.m_pBuffer, body.m_writeOffset - 1, &written); + if (NS_SUCCEEDED( rv) && (written == (body.m_writeOffset - 1))) { + rv = pDst->Write( "\x0D\x0A", 2, &written); + if (written != 2) + rv = NS_ERROR_FAILURE; + } + + if (NS_FAILED( rv)) { + IMPORT_LOG0( "*** Error writing to destination mailbox\n"); + } } - IMPORT_LOG0( " finished\n"); - - return( NS_OK); + return rv; } -nsresult nsEudoraMailbox::ReadNextMessage( ReadFileState *pState, SimpleBufferTonyRCopiedOnce& copy, SimpleBufferTonyRCopiedOnce& header, SimpleBufferTonyRCopiedOnce& body, nsCString& defaultDate, nsCString& bodyType) +nsresult nsEudoraMailbox::ReadNextMessage( ReadFileState *pState, SimpleBufferTonyRCopiedOnce& copy, + SimpleBufferTonyRCopiedOnce& header, SimpleBufferTonyRCopiedOnce& body, + nsCString& defaultDate, nsCString& bodyType, EudoraTOCEntry *pTocEntry) { header.m_writeOffset = 0; body.m_writeOffset = 0; @@ -543,6 +704,28 @@ nsresult nsEudoraMailbox::ReadNextMessage( ReadFileState *pState, SimpleBufferTo IMPORT_LOG0( "*** Error writing final headers\n"); return( NS_ERROR_FAILURE); } + + if (pTocEntry) { + // This is not the prettiest spot to stick this code, but it works and it was convenient. + char header_str[128]; + + // Write X-Mozilla-Status header + PR_snprintf( header_str, 128, MSG_LINEBREAK X_MOZILLA_STATUS_FORMAT MSG_LINEBREAK, pTocEntry->GetMozillaStatusFlags() ); + header.Write( header_str, strlen(header_str) ); + + // Write X-Mozilla-Status2 header + PR_snprintf( header_str, 128, X_MOZILLA_STATUS2_FORMAT MSG_LINEBREAK, pTocEntry->GetMozillaStatus2Flags() ); + header.Write( header_str, strlen(header_str) ); + + // Format and write X-Mozilla-Keys header + nsCString keywordHdr(X_MOZILLA_KEYWORDS); + if ( pTocEntry->HasEudoraLabel() ) { + PR_snprintf( header_str, 128, "eudoralabel%d", pTocEntry->GetLabelNumber() ); + keywordHdr.Replace(sizeof(HEADER_X_MOZILLA_KEYWORDS) + 1, strlen(header_str), header_str); + } + header.Write( keywordHdr.get(), keywordHdr.Length() ); + } + if (!header.Write( &endBuffer, 1)) { IMPORT_LOG0( "*** Error writing header trailing null\n"); return( NS_ERROR_FAILURE); diff --git a/mozilla/mailnews/import/eudora/src/nsEudoraMailbox.h b/mozilla/mailnews/import/eudora/src/nsEudoraMailbox.h index 26898856db6..f16a20d6b8f 100644 --- a/mozilla/mailnews/import/eudora/src/nsEudoraMailbox.h +++ b/mozilla/mailnews/import/eudora/src/nsEudoraMailbox.h @@ -52,6 +52,118 @@ class nsIOutputStream; ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// +class EudoraTOCEntry { +public: + PRUint16 GetMozillaStatusFlags(); + PRUint32 GetMozillaStatus2Flags(); + + PRInt32 m_Offset; + PRInt32 m_Length; +#if defined(XP_MAC) || defined(XP_MACOSX) + // Mac specific flags and fields for reading message summaries + PRBool HasEudoraLabel() { return PR_FALSE; } + PRInt16 GetLabelNumber() { return 0; } + +#else + // Windows specific flags and fields for reading message summaries + PRBool HasEudoraLabel() { return (m_Label > 0) && (m_Label <= 7); } + PRInt16 GetLabelNumber() { return HasEudoraLabel() ? m_Label : 0; } + + // MesSummary flags (used with m_Flags) + static const PRUint16 MSF_ALT_SIGNATURE = 0x0001; + static const PRUint16 MSF_USE_SIGNATURE = 0x0002; + static const PRUint16 MSF_WORD_WRAP = 0x0004; + static const PRUint16 MSF_TABS_IN_BODY = 0x0008; + static const PRUint16 MSF_KEEP_COPIES = 0x0010; + static const PRUint16 MSF_TEXT_AS_DOC = 0x0020; + static const PRUint16 MSF_RETURN_RECEIPT = 0x0040; + static const PRUint16 MSF_QUOTED_PRINTABLE = 0x0080; + static const PRUint16 MSF_ENCODE0 = 0x0100; + static const PRUint16 MSF_ENCODE1 = 0x0200; + static const PRUint16 MSF_SHOW_ALL_HEADERS = 0x0400; + static const PRUint16 MSF_SUB_PART = 0x0800; + static const PRUint16 MSF_MAPI_MESSAGE = 0x1000; + static const PRUint16 MSF_XRICH = 0x2000; + static const PRUint16 MSF_READ_RECEIPT = 0x4000; + static const PRUint16 MSF_HAS_ATTACHMENT = 0x8000; + static const PRUint16 MSF_COMP_MOD_FLAGS = 0x8FFF; + static const PRUint16 MSF_BINHEX = 0; + static const PRUint16 MSF_MIME = MSF_ENCODE0; + static const PRUint16 MSF_UUENCODE = MSF_ENCODE1; + + // MesSummary extended flags (used with m_FlagsEx) + static const PRUint16 MSFEX_AUTO_ATTACHED = 0x0001; + static const PRUint16 MSFEX_HTML = 0x0002; + static const PRUint16 MSFEX_MDN = 0x0004; + static const PRUint16 MSFEX_MIME_ATTACHED = 0x0008; + static const PRUint16 MSFEX_SEND_PLAIN = 0x0010; + static const PRUint16 MSFEX_SEND_STYLED = 0x0020; + static const PRUint16 MSFEX_FLOWED = 0x0040; + static const PRUint16 MSFEX_INL_SIGNATURE = 0x0080; + static const PRUint16 MSFEX_EMPTY_BODY = 0x0100; + + // MesSummary states + static const PRInt8 MS_UNREAD = 0; + static const PRInt8 MS_READ = 1; + static const PRInt8 MS_REPLIED = 2; + static const PRInt8 MS_FORWARDED = 3; + static const PRInt8 MS_REDIRECT = 4; + static const PRInt8 MS_UNSENDABLE = 5; + static const PRInt8 MS_SENDABLE = 6; + static const PRInt8 MS_QUEUED = 7; + static const PRInt8 MS_SENT = 8; + static const PRInt8 MS_UNSENT = 9; + static const PRInt8 MS_TIME_QUEUED =10; + static const PRInt8 MS_SPOOLED =11; + static const PRInt8 MS_RECOVERED =12; + + // MesSummary priorites + static const PRInt16 MSP_HIGHEST = 1; + static const PRInt16 MSP_HIGH = 2; + static const PRInt16 MSP_NORMAL = 3; + static const PRInt16 MSP_LOW = 4; + static const PRInt16 MSP_LOWEST = 5; + + // MesSummary Mood + static const PRInt8 MSM_MOOD_UNKNOWN = 0; + static const PRInt8 MSM_MOOD_CLEAN = 1; + static const PRInt8 MSM_MOOD_LOW = 2; + static const PRInt8 MSM_MOOD_MEDIUM = 3; + static const PRInt8 MSM_MOOD_HIGH = 4; + + // Imap message flags : + static const PRUint32 IMFLAGS_SEEN = 0x00000001; + static const PRUint32 IMFLAGS_ANSWERED = 0x00000002; + static const PRUint32 IMFLAGS_FLAGGED = 0x00000004; + static const PRUint32 IMFLAGS_DELETED = 0x00000008; + static const PRUint32 IMFLAGS_DRAFT = 0x00000010; + static const PRUint32 IMFLAGS_RECENT = 0x00000020; + + PRUint16 m_Flags; + PRUint16 m_FlagsEx; + PRUint32 m_Hash; + PRUint32 m_UniqueMessageId; + PRUint32 m_PersonaHash; + PRInt16 m_State; + PRUint8 m_ucJunkScore; + PRBool m_bManuallyJunked; + PRInt8 m_Priority; + PRInt8 m_nMood; + PRInt16 m_Label; + PRInt32 m_Seconds; + PRInt32 m_lArrivalSeconds; + PRInt32 m_TimeZoneMinutes; + char m_Date[28]; + char m_From[64]; + char m_Subject[64]; + + // IMAP specific attributes + PRUint32 m_Imflags; // IMAP message flags - 4 bytes. + PRUint16 m_MsgSize; + PRInt32 m_nUndownloadedAttachments; // Number of undownloaded attachments. +#endif +}; + class nsEudoraMailbox { public: nsEudoraMailbox(); @@ -80,8 +192,12 @@ protected: private: - nsresult CompactMailbox( PRUint32 *pBytes, PRBool *pAbort, nsIFile *pMail, nsIFile *pToc, nsIOutputStream *pDstOutputStream); - nsresult ReadNextMessage( ReadFileState *pState, SimpleBufferTonyRCopiedOnce& copy, SimpleBufferTonyRCopiedOnce& header, SimpleBufferTonyRCopiedOnce& body, nsCString& defaultDate, nsCString &defBodyType); + nsresult ImportMailboxUsingTOC( PRUint32 *pBytes, PRBool *pAbort, nsIInputStream *pInputStream, nsIFile *tocFile, nsIOutputStream *pDst, PRInt32 *pMsgCount); + nsresult ReadTOCEntry(nsIInputStream *pToc, EudoraTOCEntry& tocEntry); + nsresult ImportMessage(SimpleBufferTonyRCopiedOnce& headers, SimpleBufferTonyRCopiedOnce& body, nsCString& defaultDate, nsCAutoString& bodyType, nsIOutputStream *pDst, PRInt32 *pMsgCount); + nsresult ReadNextMessage( ReadFileState *pState, SimpleBufferTonyRCopiedOnce& copy, SimpleBufferTonyRCopiedOnce& header, + SimpleBufferTonyRCopiedOnce& body, nsCString& defaultDate, + nsCString &defBodyType, EudoraTOCEntry *pTocEntry); PRInt32 FindStartLine( SimpleBufferTonyRCopiedOnce& data); PRInt32 FindNextEndLine( SimpleBufferTonyRCopiedOnce& data); PRInt32 IsEndHeaders( SimpleBufferTonyRCopiedOnce& data); diff --git a/mozilla/mailnews/import/eudora/src/nsEudoraWin32.cpp b/mozilla/mailnews/import/eudora/src/nsEudoraWin32.cpp index a132f18ce9e..8862256a88d 100644 --- a/mozilla/mailnews/import/eudora/src/nsEudoraWin32.cpp +++ b/mozilla/mailnews/import/eudora/src/nsEudoraWin32.cpp @@ -1,917 +1,917 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org Code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Pierre Phaneuf - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "nsCOMPtr.h" -#include "nsReadableUtils.h" -#include "nsIComponentManager.h" -#include "nsIServiceManager.h" -#include "nsIMsgAccountManager.h" -#include "nsIMsgAccount.h" -#include "nsIPop3IncomingServer.h" -#include "nsMsgBaseCID.h" -#include "nsMsgCompCID.h" -#include "nsISmtpService.h" -#include "nsISmtpServer.h" -#include "nsEudoraWin32.h" -#include "nsIImportService.h" -#include "nsIImportMailboxDescriptor.h" -#include "nsIImportABDescriptor.h" -#include "nsEudoraStringBundle.h" -#include "nsEudoraImport.h" -#include "nsUnicharUtils.h" -#include "nsNetUtil.h" -#include "EudoraDebugLog.h" - -static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); - -static const char * kWhitespace = "\b\t\r\n "; - -// ::RegOpenKeyEx( HKEY_CURRENT_USER, "Software\\Accounts", 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &sKey) == ERROR_SUCCESS) - -BYTE * nsEudoraWin32::GetValueBytes( HKEY hKey, const char *pValueName) -{ - LONG err; - DWORD bufSz; - LPBYTE pBytes = NULL; - - err = ::RegQueryValueEx( hKey, pValueName, NULL, NULL, NULL, &bufSz); - if (err == ERROR_SUCCESS) { - pBytes = new BYTE[bufSz]; - err = ::RegQueryValueEx( hKey, pValueName, NULL, NULL, pBytes, &bufSz); - if (err != ERROR_SUCCESS) { - delete [] pBytes; - pBytes = NULL; - } - } - - return( pBytes); -} - - -nsEudoraWin32::nsEudoraWin32() -{ - m_pMimeSection = nsnull; -} - -nsEudoraWin32::~nsEudoraWin32() -{ - delete [] m_pMimeSection; -} - -PRBool nsEudoraWin32::FindMailFolder( nsIFile **pFolder) -{ - return( FindEudoraLocation( pFolder)); -} - -PRBool nsEudoraWin32::FindEudoraLocation( nsIFile **pFolder, PRBool findIni) -{ - PRBool result = PR_FALSE; - PRBool exists = PR_FALSE; - nsCOMPtr eudoraPath = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID); - // look in the registry to see where eudora is installed? - HKEY sKey; - if (::RegOpenKeyEx( HKEY_CURRENT_USER, "Software\\Qualcomm\\Eudora\\CommandLine", 0, KEY_QUERY_VALUE, &sKey) == ERROR_SUCCESS) { - // get the value of "Current" - BYTE *pBytes = GetValueBytes( sKey, "Current"); - if (pBytes) { - nsCString str((const char *)pBytes); - delete [] pBytes; - - str.CompressWhitespace(); - - // Command line is Eudora mailfolder eudora.ini - if (findIni) { - // find the string coming after the last space - PRInt32 index = str.RFind(" "); - if (index != -1) { - index++; // skip the space - nsCString path; - str.Mid( path, index, str.Length() - index); - - eudoraPath->InitWithNativePath(path); - eudoraPath->IsFile( &exists); - if (exists) - result = exists; - else // it may just be the mailbox location....guess that there will be a eudora.ini file there - { - eudoraPath->AppendNative(NS_LITERAL_CSTRING("eudora.ini")); - eudoraPath->IsFile( &exists); - result = exists; - } - } - } // if findIni - else { - int idx = -1; - if (str.CharAt( 0) == '"') { - idx = str.FindChar( '"', 1); - if (idx != -1) - idx++; - } - else { - idx = str.FindChar( ' '); - } - - if (idx != -1) { - idx++; - while (str.CharAt( idx) == ' ') idx++; - int endIdx = -1; - if (str.CharAt( idx) == '"') { - endIdx = str.FindChar( '"', idx); - } - else { - endIdx = str.FindChar( ' ', idx); - } - if (endIdx != -1) { - nsCString path; - str.Mid( path, idx, endIdx - idx); - - eudoraPath->InitWithNativePath(path); - - if (NS_SUCCEEDED( eudoraPath->IsDirectory( &exists))) - result = exists; - } - } - } - } // if pBytes - ::RegCloseKey( sKey); - } - - NS_IF_ADDREF(*pFolder = eudoraPath); - return( result); -} - -nsresult nsEudoraWin32::FindMailboxes( nsIFile *pRoot, nsISupportsArray **ppArray) -{ - nsresult rv = NS_NewISupportsArray( ppArray); - if (NS_FAILED( rv)) { - IMPORT_LOG0( "FAILED to allocate the nsISupportsArray\n"); - return( rv); - } - - nsCOMPtr impSvc(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv)); - if (NS_FAILED( rv)) - return( rv); - - m_depth = 0; - m_mailImportLocation = do_QueryInterface(pRoot); - return( ScanMailDir( pRoot, *ppArray, impSvc)); -} - - -nsresult nsEudoraWin32::ScanMailDir( nsIFile *pFolder, nsISupportsArray *pArray, nsIImportService *pImport) -{ - PRBool exists = PR_FALSE; - PRBool isFile = PR_FALSE; - char * pContents = nsnull; - PRInt32 len = 0; - nsCOMPtr descMap; - nsresult rv; - - if (NS_FAILED( rv = pFolder->Clone(getter_AddRefs(descMap)))) - return( rv); - - m_depth++; - - rv = descMap->AppendNative(NS_LITERAL_CSTRING("descmap.pce")); - if (NS_SUCCEEDED( rv)) - rv = descMap->IsFile( &isFile); - if (NS_SUCCEEDED( rv)) - rv = descMap->Exists( &exists); - if (NS_SUCCEEDED( rv) && exists && isFile) { - nsCOMPtr inputStream; - nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), descMap); - if (NS_FAILED(rv)) - return rv; - - PRUint32 bytesLeft = 0; - - rv = inputStream->Available(&bytesLeft); - if (NS_FAILED(rv)) { - IMPORT_LOG0( "*** Error checking address file for eof\n"); - inputStream->Close(); - return rv; - } - pContents = (char *) PR_Malloc(bytesLeft + 1); - if (!pContents) - return NS_ERROR_OUT_OF_MEMORY; - PRUint32 bytesRead; - rv = inputStream->Read(pContents, bytesLeft, &bytesRead); - if (bytesRead != bytesLeft) - return NS_ERROR_FAILURE; - pContents[bytesRead] = '\0'; - if (NS_SUCCEEDED( rv) && pContents) { - len = bytesRead; - if (NS_SUCCEEDED( rv)) - rv = ScanDescmap( pFolder, pArray, pImport, pContents, len); - PR_Free( pContents); - } - else - rv = NS_ERROR_FAILURE; - } - - if (NS_FAILED( rv) || !isFile || !exists) - rv = IterateMailDir( pFolder, pArray, pImport); - - m_depth--; - - return( rv); -} - -nsresult nsEudoraWin32::IterateMailDir( nsIFile *pFolder, nsISupportsArray *pArray, nsIImportService *pImport) -{ - PRBool hasMore; - nsCOMPtr directoryEnumerator; - nsresult rv = pFolder->GetDirectoryEntries(getter_AddRefs(directoryEnumerator)); - NS_ENSURE_SUCCESS(rv, rv); - - directoryEnumerator->HasMoreElements(&hasMore); - PRBool isFolder; - PRBool isFile; - nsCOMPtr entry; - nsCString fName; - nsCString ext; - nsCString name; - - while (hasMore && NS_SUCCEEDED(rv)) - { - nsCOMPtr aSupport; - rv = directoryEnumerator->GetNext(getter_AddRefs(aSupport)); - nsCOMPtr entry(do_QueryInterface(aSupport, &rv)); - directoryEnumerator->HasMoreElements(&hasMore); - - if (NS_SUCCEEDED( rv)) { - rv = entry->GetNativeLeafName(fName); - if (NS_SUCCEEDED( rv) && !fName.IsEmpty()) { - if (fName.Length() > 4) { - fName.Right( ext, 4); - fName.Left( name, fName.Length() - 4); - } - else { - ext.Truncate(); - name = fName; - } - ToLowerCase(ext); - if (ext.EqualsLiteral(".fol")) { - isFolder = PR_FALSE; - entry->IsDirectory( &isFolder); - if (isFolder) { - // add the folder - rv = FoundMailFolder( entry, name.get(), pArray, pImport); - if (NS_SUCCEEDED( rv)) { - rv = ScanMailDir( entry, pArray, pImport); - if (NS_FAILED( rv)) { - IMPORT_LOG0( "*** Error scanning mail directory\n"); - } - } - } - } - else if (ext.EqualsLiteral(".mbx")) { - isFile = PR_FALSE; - entry->IsFile( &isFile); - if (isFile) { - rv = FoundMailbox( entry, name.get(), pArray, pImport); - } - } - } - } - } - return( rv); -} - -nsresult nsEudoraWin32::ScanDescmap( nsIFile *pFolder, nsISupportsArray *pArray, nsIImportService *pImport, const char *pData, PRInt32 len) -{ - // use this to find stuff in the directory. - - nsCOMPtr entry; - nsresult rv; - - if (NS_FAILED( rv = pFolder->Clone(getter_AddRefs(entry)))) - return( rv); - entry->AppendNative(NS_LITERAL_CSTRING("dummy")); - // format is Name,FileName,Type,Flag? - // Type = M or S for mailbox - // = F for folder - - PRInt32 fieldLen; - PRInt32 pos = 0; - const char * pStart; - nsCString name; - nsCString fName; - nsCString type; - nsCString flag; - PRBool isFile; - PRBool isFolder; - while (pos < len) { - pStart = pData; - fieldLen = 0; - while ((pos < len) && (*pData != ',')) { - pos++; - pData++; - fieldLen++; - } - name.Truncate(); - if (fieldLen) - name.Append( pStart, fieldLen); - name.Trim( kWhitespace); - pos++; - pData++; - pStart = pData; - fieldLen = 0; - while ((pos < len) && (*pData != ',')) { - pos++; - pData++; - fieldLen++; - } - fName.Truncate(); - if (fieldLen) - fName.Append( pStart, fieldLen); - fName.Trim( kWhitespace); - pos++; - pData++; - pStart = pData; - fieldLen = 0; - while ((pos < len) && (*pData != ',')) { - pos++; - pData++; - fieldLen++; - } - type.Truncate(); - if (fieldLen) - type.Append( pStart, fieldLen); - type.Trim( kWhitespace); - pos++; - pData++; - pStart = pData; - fieldLen = 0; - while ((pos < len) && (*pData != 0x0D) && (*pData != 0x0A) && (*pData != ',')) { - pos++; - pData++; - fieldLen++; - } - flag.Truncate(); - if (fieldLen) - flag.Append( pStart, fieldLen); - flag.Trim( kWhitespace); - while ((pos < len) && ((*pData == 0x0D) || (*pData == 0x0A))) { - pos++; - pData++; - } - - IMPORT_LOG2( "name: %s, fName: %s\n", name.get(), fName.get()); - - if (!fName.IsEmpty() && !name.IsEmpty() && (type.Length() == 1)) { - rv = entry->SetNativeLeafName(fName); - if (NS_SUCCEEDED( rv)) { - if (type.CharAt( 0) == 'F') { - isFolder = PR_FALSE; - entry->IsDirectory( &isFolder); - if (isFolder) { - rv = FoundMailFolder( entry, name.get(), pArray, pImport); - if (NS_SUCCEEDED( rv)) { - rv = ScanMailDir( entry, pArray, pImport); - if (NS_FAILED( rv)) { - IMPORT_LOG0( "*** Error scanning mail directory\n"); - } - } - } - } - else if ((type.CharAt( 0) == 'M') || (type.CharAt( 0) == 'S')) { - isFile = PR_FALSE; - entry->IsFile( &isFile); - if (isFile) { - FoundMailbox( entry, name.get(), pArray, pImport); - } - } - } - } - } - - return( NS_OK); -} - - -nsresult nsEudoraWin32::FoundMailbox( nsIFile *mailFile, const char *pName, nsISupportsArray *pArray, nsIImportService *pImport) -{ - nsString displayName; - nsCOMPtr desc; - nsISupports * pInterface; - - NS_CopyNativeToUnicode(nsDependentCString(pName), displayName); - -#ifdef IMPORT_DEBUG - nsCAutoString path; - mailFile->GetNativePath(path); - if (!path.IsEmpty()) - IMPORT_LOG2( "Found eudora mailbox, %s: %s\n", path.get(), pName); - else - IMPORT_LOG1( "Found eudora mailbox, %s\n", pName); - IMPORT_LOG1( "\tm_depth = %d\n", (int)m_depth); -#endif - - nsresult rv = pImport->CreateNewMailboxDescriptor( getter_AddRefs( desc)); - if (NS_SUCCEEDED( rv)) { - PRInt64 sz = 0; - mailFile->GetFileSize( &sz); - desc->SetDisplayName( displayName.get()); - desc->SetDepth( m_depth); - desc->SetSize( sz); - nsCOMPtr pFile = nsnull; - desc->GetFile(getter_AddRefs(pFile)); - if (pFile) { - nsCOMPtr localMailFile = do_QueryInterface(mailFile); - pFile->InitWithFile( localMailFile); - } - rv = desc->QueryInterface( kISupportsIID, (void **) &pInterface); - pArray->AppendElement( pInterface); - pInterface->Release(); - } - - return( NS_OK); -} - - -nsresult nsEudoraWin32::FoundMailFolder( nsIFile *mailFolder, const char *pName, nsISupportsArray *pArray, nsIImportService *pImport) -{ - nsString displayName; - nsCOMPtr desc; - nsISupports * pInterface; - - NS_CopyNativeToUnicode(nsDependentCString(pName), displayName); - -#ifdef IMPORT_DEBUG - nsCAutoString path; - mailFolder->GetNativePath(path); - if (!path.IsEmpty()) { - IMPORT_LOG2( "Found eudora folder, %s: %s\n", path.get(), pName); - } - else { - IMPORT_LOG1( "Found eudora folder, %s\n", pName); - } - IMPORT_LOG1( "\tm_depth = %d\n", (int)m_depth); -#endif - - nsresult rv = pImport->CreateNewMailboxDescriptor( getter_AddRefs( desc)); - if (NS_SUCCEEDED( rv)) { - PRUint32 sz = 0; - desc->SetDisplayName( displayName.get()); - desc->SetDepth( m_depth); - desc->SetSize( sz); - nsCOMPtr pFile = nsnull; - desc->GetFile(getter_AddRefs(pFile)); - if (pFile) { - nsCOMPtr localMailFile = do_QueryInterface(mailFolder); - pFile->InitWithFile( localMailFile); - } - rv = desc->QueryInterface( kISupportsIID, (void **) &pInterface); - pArray->AppendElement( pInterface); - pInterface->Release(); - } - - return( NS_OK); -} - - -nsresult nsEudoraWin32::FindTOCFile( nsIFile *pMailFile, nsIFile **ppTOCFile, PRBool *pDeleteToc) -{ - nsresult rv; - nsCAutoString leaf; - - *pDeleteToc = PR_FALSE; - *ppTOCFile = nsnull; - rv = pMailFile->GetNativeLeafName(leaf); - if (NS_FAILED( rv)) - return( rv); - rv = pMailFile->GetParent( ppTOCFile); - if (NS_FAILED( rv)) - return( rv); - - nsCString name; - if ((leaf.Length() > 4) && (leaf.CharAt( leaf.Length() - 4) == '.')) - leaf.Left( name, leaf.Length() - 4); - else - name = leaf; - name.Append( ".toc"); - rv = (*ppTOCFile)->AppendNative(name); - if (NS_FAILED( rv)) - return( rv); - - PRBool exists = PR_FALSE; - rv = (*ppTOCFile)->Exists( &exists); - if (NS_FAILED( rv)) - return( rv); - PRBool isFile = PR_FALSE; - rv = (*ppTOCFile)->IsFile( &isFile); - if (NS_FAILED( rv)) - return( rv); - if (exists && isFile) - return( NS_OK); - - return( NS_ERROR_FAILURE); -} - - -PRBool nsEudoraWin32::ImportSettings( nsIFile *pIniFile, nsIMsgAccount **localMailAccount) -{ - PRBool result = PR_FALSE; - nsresult rv; - - nsCOMPtr accMgr = - do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv); - if (NS_FAILED(rv)) { - IMPORT_LOG0( "*** Failed to create a account manager!\n"); - return( PR_FALSE); - } - - // Eudora info is arranged by key, 1 for the default, then persona's for additional - // accounts. - // Start with the first one, then do each persona - nsCString iniPath; - pIniFile->GetNativePath(iniPath); - if (iniPath.IsEmpty()) - return( PR_FALSE); - UINT valInt; - SimpleBufferTonyRCopiedOnce section; - DWORD sSize; - DWORD sOffset = 0; - DWORD start; - nsCString sectionName("Settings"); - int popCount = 0; - int accounts = 0; - - DWORD allocSize = 0; - do { - allocSize += 2048; - section.Allocate( allocSize); - sSize = ::GetPrivateProfileSection( "Personalities", section.m_pBuffer, allocSize, iniPath.get()); - } while (sSize == (allocSize - 2)); - - nsIMsgAccount * pAccount; - - do { - if (!sectionName.IsEmpty()) { - pAccount = nsnull; - valInt = ::GetPrivateProfileInt( sectionName.get(), "UsesPOP", 1, iniPath.get()); - if (valInt) { - // This is a POP account - if (BuildPOPAccount( accMgr, sectionName.get(), iniPath.get(), &pAccount)) { - accounts++; - popCount++; - if (popCount > 1) { - if (localMailAccount && *localMailAccount) { - NS_RELEASE( *localMailAccount); - *localMailAccount = nsnull; - } - } - else { - if (localMailAccount) { - *localMailAccount = pAccount; - NS_IF_ADDREF( pAccount); - } - } - } - } - else { - valInt = ::GetPrivateProfileInt( sectionName.get(), "UsesIMAP", 0, iniPath.get()); - if (valInt) { - // This is an IMAP account - if (BuildIMAPAccount( accMgr, sectionName.get(), iniPath.get(), &pAccount)) { - accounts++; - } - } - } - if (pAccount && (sOffset == 0)) { - accMgr->SetDefaultAccount( pAccount); - } - - NS_IF_RELEASE( pAccount); - } - - sectionName.Truncate(); - while ((sOffset < sSize) && (section.m_pBuffer[sOffset] != '=')) - sOffset++; - sOffset++; - start = sOffset; - while ((sOffset < sSize) && (section.m_pBuffer[sOffset] != 0)) - sOffset++; - if (sOffset > start) { - sectionName.Append( section.m_pBuffer + start, sOffset - start); - sectionName.Trim( kWhitespace); - } - - } while (sOffset < sSize); - - // 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); -} - -// maximium size of settings strings -#define kIniValueSize 384 - - -void nsEudoraWin32::GetServerAndUserName( const char *pSection, const char *pIni, nsCString& serverName, nsCString& userName, char *pBuff) -{ - DWORD valSize; - int idx; - nsCString tStr; - - serverName.Truncate(); - userName.Truncate(); - - valSize = ::GetPrivateProfileString( pSection, "PopServer", "", pBuff, kIniValueSize, pIni); - if (valSize) - serverName = pBuff; - else { - valSize = ::GetPrivateProfileString( pSection, "POPAccount", "", pBuff, kIniValueSize, pIni); - if (valSize) { - serverName = pBuff; - idx = serverName.FindChar( '@'); - if (idx != -1) { - serverName.Right( tStr, serverName.Length() - idx - 1); - serverName = tStr; - } - } - } - valSize = ::GetPrivateProfileString( pSection, "LoginName", "", pBuff, kIniValueSize, pIni); - if (valSize) - userName = pBuff; - else { - valSize = ::GetPrivateProfileString( pSection, "POPAccount", "", pBuff, kIniValueSize, pIni); - if (valSize) { - userName = pBuff; - idx = userName.FindChar( '@'); - if (idx != -1) { - userName.Left( tStr, idx); - userName = tStr; - } - } - } -} - -void nsEudoraWin32::GetAccountName( const char *pSection, nsString& str) -{ - str.Truncate(); - - nsCString s(pSection); - - if (s.Equals(NS_LITERAL_CSTRING("Settings"), nsCaseInsensitiveCStringComparator())) { - str.AssignLiteral("Eudora "); - str.AppendWithConversion( pSection); - } - else { - nsCString tStr; - str.AssignWithConversion(pSection); - if (s.Length() > 8) { - s.Left( tStr, 8); - if (tStr.Equals(NS_LITERAL_CSTRING("Persona-"), nsCaseInsensitiveCStringComparator())) { - s.Right( tStr, s.Length() - 8); - str.AssignWithConversion(tStr.get()); - } - } - } -} - - -PRBool nsEudoraWin32::BuildPOPAccount( nsIMsgAccountManager *accMgr, const char *pSection, const char *pIni, nsIMsgAccount **ppAccount) -{ - if (ppAccount) - *ppAccount = nsnull; - - char valBuff[kIniValueSize]; - nsCString serverName; - nsCString userName; - - GetServerAndUserName( pSection, pIni, serverName, userName, valBuff); - - if (serverName.IsEmpty() || userName.IsEmpty()) - return( PR_FALSE); - - PRBool result = PR_FALSE; - - // I now have a user name/server name pair, find out if it already exists? - nsCOMPtr in; - nsresult rv = accMgr->FindServer( userName, serverName, NS_LITERAL_CSTRING("pop3"), getter_AddRefs(in)); - if (NS_FAILED(rv) || !in) { - // Create the incoming server and an account for it? - rv = accMgr->CreateIncomingServer( userName, serverName, NS_LITERAL_CSTRING("pop3"), getter_AddRefs(in)); - if (NS_SUCCEEDED( rv) && in) { - rv = in->SetType( "pop3"); - // rv = in->SetHostName( serverName); - // rv = in->SetUsername( userName); - - IMPORT_LOG2( "Created POP3 server named: %s, userName: %s\n", serverName.get(), userName.get()); - - nsString prettyName; - GetAccountName( pSection, prettyName); - - PRUnichar *pretty = ToNewUnicode(prettyName); - IMPORT_LOG1( "\tSet pretty name to: %S\n", pretty); - rv = in->SetPrettyName( pretty); - nsCRT::free( pretty); - - // We have a server, create an account. - nsCOMPtr account; - rv = accMgr->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"); - - nsCOMPtr pop3Server = do_QueryInterface(in, &rv); - NS_ENSURE_SUCCESS(rv,rv); - UINT valInt = ::GetPrivateProfileInt(pSection, "LeaveMailOnServer", 0, pIni); - pop3Server->SetLeaveMessagesOnServer(valInt ? PR_TRUE : PR_FALSE); - - // Fiddle with the identities - SetIdentities(accMgr, account, pSection, pIni, userName.get(), serverName.get(), valBuff); - result = PR_TRUE; - if (ppAccount) - account->QueryInterface( NS_GET_IID(nsIMsgAccount), (void **)ppAccount); - } - } - } - else - result = PR_TRUE; - - return( result); -} - -PRBool nsEudoraWin32::BuildIMAPAccount( nsIMsgAccountManager *accMgr, const char *pSection, const char *pIni, nsIMsgAccount **ppAccount) -{ - char valBuff[kIniValueSize]; - nsCString serverName; - nsCString userName; - - GetServerAndUserName( pSection, pIni, serverName, userName, valBuff); - - if (serverName.IsEmpty() || userName.IsEmpty()) - return( PR_FALSE); - - PRBool result = PR_FALSE; - - nsCOMPtr in; - nsresult rv = accMgr->FindServer( userName, serverName, NS_LITERAL_CSTRING("imap"), getter_AddRefs(in)); - if (NS_FAILED( rv) || (in == nsnull)) { - // Create the incoming server and an account for it? - rv = accMgr->CreateIncomingServer( userName, serverName, NS_LITERAL_CSTRING("imap"), getter_AddRefs(in)); - if (NS_SUCCEEDED( rv) && in) { - rv = in->SetType( "imap"); - // rv = in->SetHostName( serverName); - // rv = in->SetUsername( userName); - - IMPORT_LOG2( "Created IMAP server named: %s, userName: %s\n", serverName.get(), userName.get()); - - nsString prettyName; - GetAccountName( pSection, prettyName); - - PRUnichar *pretty = ToNewUnicode(prettyName); - - IMPORT_LOG1( "\tSet pretty name to: %S\n", pretty); - - rv = in->SetPrettyName( pretty); - nsCRT::free( pretty); - - // We have a server, create an account. - nsCOMPtr account; - rv = accMgr->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 - SetIdentities(accMgr, account, pSection, pIni, userName.get(), serverName.get(), valBuff); - result = PR_TRUE; - if (ppAccount) - account->QueryInterface( NS_GET_IID(nsIMsgAccount), (void **)ppAccount); - } - } - } - else - result = PR_TRUE; - - return( result); -} - -void nsEudoraWin32::SetIdentities(nsIMsgAccountManager *accMgr, nsIMsgAccount *acc, const char *pSection, const char *pIniFile, const char *userName, const char *serverName, char *pBuff) -{ - nsCAutoString realName; - nsCAutoString email; - nsCAutoString server; - DWORD valSize; - nsresult rv; - - valSize = ::GetPrivateProfileString( pSection, "RealName", "", pBuff, kIniValueSize, pIniFile); - if (valSize) - realName = pBuff; - valSize = ::GetPrivateProfileString( pSection, "SMTPServer", "", pBuff, kIniValueSize, pIniFile); - if (valSize) - server = pBuff; - valSize = ::GetPrivateProfileString( pSection, "ReturnAddress", "", pBuff, kIniValueSize, pIniFile); - if (valSize) - email = pBuff; - - nsCOMPtr id; - rv = accMgr->CreateIdentity( getter_AddRefs( id)); - if (id) { - nsAutoString fullName; - fullName.Assign(NS_ConvertASCIItoUTF16(realName)); - id->SetFullName(fullName); - id->SetIdentityName(fullName); - if (email.IsEmpty()) { - email = userName; - email += "@"; - email += serverName; - } - id->SetEmail(email); - acc->AddIdentity( id); - - IMPORT_LOG0( "Created identity and added to the account\n"); - IMPORT_LOG1( "\tname: %s\n", realName.get()); - IMPORT_LOG1( "\temail: %s\n", email.get()); - } - SetSmtpServer( accMgr, acc, server.get(), userName); -} - - -void nsEudoraWin32::SetSmtpServer( nsIMsgAccountManager *pMgr, nsIMsgAccount *pAcc, const char *pServer, const char *pUser) -{ - nsresult rv; - - nsCOMPtr smtpService(do_GetService(NS_SMTPSERVICE_CONTRACTID, &rv)); - if (NS_SUCCEEDED(rv) && smtpService) { - nsCOMPtr foundServer; - - rv = smtpService->FindServer( pUser, pServer, getter_AddRefs( foundServer)); - if (NS_SUCCEEDED( rv) && foundServer) { - IMPORT_LOG1( "SMTP server already exists: %s\n", pServer); - return; - } - nsCOMPtr smtpServer; - - rv = smtpService->CreateSmtpServer( getter_AddRefs( smtpServer)); - if (NS_SUCCEEDED( rv) && smtpServer) { - smtpServer->SetHostname( pServer); - if (pUser) - smtpServer->SetUsername( pUser); - - IMPORT_LOG1( "Created new SMTP server: %s\n", pServer); - } - } -} - -nsresult nsEudoraWin32::GetAttachmentInfo( const char *pFileName, nsIFile *pFile, nsCString& mimeType, nsCString& aAttachmentName) -{ - nsresult rv; - mimeType.Truncate(); - nsCOMPtr pLocalFile = do_QueryInterface(pFile, &rv); - NS_ENSURE_SUCCESS(rv, rv); - pLocalFile->InitWithNativePath(nsDependentCString(pFileName)); - PRBool isFile = PR_FALSE; - PRBool exists = PR_FALSE; - if (NS_FAILED( rv = pFile->Exists( &exists))) - return( rv); - if (NS_FAILED( rv = pFile->IsFile( &isFile))) - return( rv); +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org Code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsCOMPtr.h" +#include "nsReadableUtils.h" +#include "nsIComponentManager.h" +#include "nsIServiceManager.h" +#include "nsIMsgAccountManager.h" +#include "nsIMsgAccount.h" +#include "nsIPop3IncomingServer.h" +#include "nsMsgBaseCID.h" +#include "nsMsgCompCID.h" +#include "nsISmtpService.h" +#include "nsISmtpServer.h" +#include "nsEudoraWin32.h" +#include "nsIImportService.h" +#include "nsIImportMailboxDescriptor.h" +#include "nsIImportABDescriptor.h" +#include "nsEudoraStringBundle.h" +#include "nsEudoraImport.h" +#include "nsUnicharUtils.h" +#include "nsNetUtil.h" +#include "EudoraDebugLog.h" + +static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); + +static const char * kWhitespace = "\b\t\r\n "; + +// ::RegOpenKeyEx( HKEY_CURRENT_USER, "Software\\Accounts", 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &sKey) == ERROR_SUCCESS) + +BYTE * nsEudoraWin32::GetValueBytes( HKEY hKey, const char *pValueName) +{ + LONG err; + DWORD bufSz; + LPBYTE pBytes = NULL; + + err = ::RegQueryValueEx( hKey, pValueName, NULL, NULL, NULL, &bufSz); + if (err == ERROR_SUCCESS) { + pBytes = new BYTE[bufSz]; + err = ::RegQueryValueEx( hKey, pValueName, NULL, NULL, pBytes, &bufSz); + if (err != ERROR_SUCCESS) { + delete [] pBytes; + pBytes = NULL; + } + } + + return( pBytes); +} + + +nsEudoraWin32::nsEudoraWin32() +{ + m_pMimeSection = nsnull; +} + +nsEudoraWin32::~nsEudoraWin32() +{ + delete [] m_pMimeSection; +} + +PRBool nsEudoraWin32::FindMailFolder( nsIFile **pFolder) +{ + return( FindEudoraLocation( pFolder)); +} + +PRBool nsEudoraWin32::FindEudoraLocation( nsIFile **pFolder, PRBool findIni) +{ + PRBool result = PR_FALSE; + PRBool exists = PR_FALSE; + nsCOMPtr eudoraPath = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID); + // look in the registry to see where eudora is installed? + HKEY sKey; + if (::RegOpenKeyEx( HKEY_CURRENT_USER, "Software\\Qualcomm\\Eudora\\CommandLine", 0, KEY_QUERY_VALUE, &sKey) == ERROR_SUCCESS) { + // get the value of "Current" + BYTE *pBytes = GetValueBytes( sKey, "Current"); + if (pBytes) { + nsCString str((const char *)pBytes); + delete [] pBytes; + + str.CompressWhitespace(); + + // Command line is Eudora mailfolder eudora.ini + if (findIni) { + // find the string coming after the last space + PRInt32 index = str.RFind(" "); + if (index != -1) { + index++; // skip the space + nsCString path; + str.Mid( path, index, str.Length() - index); + + eudoraPath->InitWithNativePath(path); + eudoraPath->IsFile( &exists); + if (exists) + result = exists; + else // it may just be the mailbox location....guess that there will be a eudora.ini file there + { + eudoraPath->AppendNative(NS_LITERAL_CSTRING("eudora.ini")); + eudoraPath->IsFile( &exists); + result = exists; + } + } + } // if findIni + else { + int idx = -1; + if (str.CharAt( 0) == '"') { + idx = str.FindChar( '"', 1); + if (idx != -1) + idx++; + } + else { + idx = str.FindChar( ' '); + } + + if (idx != -1) { + idx++; + while (str.CharAt( idx) == ' ') idx++; + int endIdx = -1; + if (str.CharAt( idx) == '"') { + endIdx = str.FindChar( '"', idx); + } + else { + endIdx = str.FindChar( ' ', idx); + } + if (endIdx != -1) { + nsCString path; + str.Mid( path, idx, endIdx - idx); + + eudoraPath->InitWithNativePath(path); + + if (NS_SUCCEEDED( eudoraPath->IsDirectory( &exists))) + result = exists; + } + } + } + } // if pBytes + ::RegCloseKey( sKey); + } + + NS_IF_ADDREF(*pFolder = eudoraPath); + return( result); +} + +nsresult nsEudoraWin32::FindMailboxes( nsIFile *pRoot, nsISupportsArray **ppArray) +{ + nsresult rv = NS_NewISupportsArray( ppArray); + if (NS_FAILED( rv)) { + IMPORT_LOG0( "FAILED to allocate the nsISupportsArray\n"); + return( rv); + } + + nsCOMPtr impSvc(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv)); + if (NS_FAILED( rv)) + return( rv); + + m_depth = 0; + m_mailImportLocation = do_QueryInterface(pRoot); + return( ScanMailDir( pRoot, *ppArray, impSvc)); +} + + +nsresult nsEudoraWin32::ScanMailDir( nsIFile *pFolder, nsISupportsArray *pArray, nsIImportService *pImport) +{ + PRBool exists = PR_FALSE; + PRBool isFile = PR_FALSE; + char * pContents = nsnull; + PRInt32 len = 0; + nsCOMPtr descMap; + nsresult rv; + + if (NS_FAILED( rv = pFolder->Clone(getter_AddRefs(descMap)))) + return( rv); + + m_depth++; + + rv = descMap->AppendNative(NS_LITERAL_CSTRING("descmap.pce")); + if (NS_SUCCEEDED( rv)) + rv = descMap->IsFile( &isFile); + if (NS_SUCCEEDED( rv)) + rv = descMap->Exists( &exists); + if (NS_SUCCEEDED( rv) && exists && isFile) { + nsCOMPtr inputStream; + nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), descMap); + if (NS_FAILED(rv)) + return rv; + + PRUint32 bytesLeft = 0; + + rv = inputStream->Available(&bytesLeft); + if (NS_FAILED(rv)) { + IMPORT_LOG0( "*** Error checking address file for eof\n"); + inputStream->Close(); + return rv; + } + pContents = (char *) PR_Malloc(bytesLeft + 1); + if (!pContents) + return NS_ERROR_OUT_OF_MEMORY; + PRUint32 bytesRead; + rv = inputStream->Read(pContents, bytesLeft, &bytesRead); + if (bytesRead != bytesLeft) + return NS_ERROR_FAILURE; + pContents[bytesRead] = '\0'; + if (NS_SUCCEEDED( rv) && pContents) { + len = bytesRead; + if (NS_SUCCEEDED( rv)) + rv = ScanDescmap( pFolder, pArray, pImport, pContents, len); + PR_Free( pContents); + } + else + rv = NS_ERROR_FAILURE; + } + + if (NS_FAILED( rv) || !isFile || !exists) + rv = IterateMailDir( pFolder, pArray, pImport); + + m_depth--; + + return( rv); +} + +nsresult nsEudoraWin32::IterateMailDir( nsIFile *pFolder, nsISupportsArray *pArray, nsIImportService *pImport) +{ + PRBool hasMore; + nsCOMPtr directoryEnumerator; + nsresult rv = pFolder->GetDirectoryEntries(getter_AddRefs(directoryEnumerator)); + NS_ENSURE_SUCCESS(rv, rv); + + directoryEnumerator->HasMoreElements(&hasMore); + PRBool isFolder; + PRBool isFile; + nsCOMPtr entry; + nsCString fName; + nsCString ext; + nsCString name; + + while (hasMore && NS_SUCCEEDED(rv)) + { + nsCOMPtr aSupport; + rv = directoryEnumerator->GetNext(getter_AddRefs(aSupport)); + nsCOMPtr entry(do_QueryInterface(aSupport, &rv)); + directoryEnumerator->HasMoreElements(&hasMore); + + if (NS_SUCCEEDED( rv)) { + rv = entry->GetNativeLeafName(fName); + if (NS_SUCCEEDED( rv) && !fName.IsEmpty()) { + if (fName.Length() > 4) { + fName.Right( ext, 4); + fName.Left( name, fName.Length() - 4); + } + else { + ext.Truncate(); + name = fName; + } + ToLowerCase(ext); + if (ext.EqualsLiteral(".fol")) { + isFolder = PR_FALSE; + entry->IsDirectory( &isFolder); + if (isFolder) { + // add the folder + rv = FoundMailFolder( entry, name.get(), pArray, pImport); + if (NS_SUCCEEDED( rv)) { + rv = ScanMailDir( entry, pArray, pImport); + if (NS_FAILED( rv)) { + IMPORT_LOG0( "*** Error scanning mail directory\n"); + } + } + } + } + else if (ext.EqualsLiteral(".mbx")) { + isFile = PR_FALSE; + entry->IsFile( &isFile); + if (isFile) { + rv = FoundMailbox( entry, name.get(), pArray, pImport); + } + } + } + } + } + return( rv); +} + +nsresult nsEudoraWin32::ScanDescmap( nsIFile *pFolder, nsISupportsArray *pArray, nsIImportService *pImport, const char *pData, PRInt32 len) +{ + // use this to find stuff in the directory. + + nsCOMPtr entry; + nsresult rv; + + if (NS_FAILED( rv = pFolder->Clone(getter_AddRefs(entry)))) + return( rv); + entry->AppendNative(NS_LITERAL_CSTRING("dummy")); + // format is Name,FileName,Type,Flag? + // Type = M or S for mailbox + // = F for folder + + PRInt32 fieldLen; + PRInt32 pos = 0; + const char * pStart; + nsCString name; + nsCString fName; + nsCString type; + nsCString flag; + PRBool isFile; + PRBool isFolder; + while (pos < len) { + pStart = pData; + fieldLen = 0; + while ((pos < len) && (*pData != ',')) { + pos++; + pData++; + fieldLen++; + } + name.Truncate(); + if (fieldLen) + name.Append( pStart, fieldLen); + name.Trim( kWhitespace); + pos++; + pData++; + pStart = pData; + fieldLen = 0; + while ((pos < len) && (*pData != ',')) { + pos++; + pData++; + fieldLen++; + } + fName.Truncate(); + if (fieldLen) + fName.Append( pStart, fieldLen); + fName.Trim( kWhitespace); + pos++; + pData++; + pStart = pData; + fieldLen = 0; + while ((pos < len) && (*pData != ',')) { + pos++; + pData++; + fieldLen++; + } + type.Truncate(); + if (fieldLen) + type.Append( pStart, fieldLen); + type.Trim( kWhitespace); + pos++; + pData++; + pStart = pData; + fieldLen = 0; + while ((pos < len) && (*pData != 0x0D) && (*pData != 0x0A) && (*pData != ',')) { + pos++; + pData++; + fieldLen++; + } + flag.Truncate(); + if (fieldLen) + flag.Append( pStart, fieldLen); + flag.Trim( kWhitespace); + while ((pos < len) && ((*pData == 0x0D) || (*pData == 0x0A))) { + pos++; + pData++; + } + + IMPORT_LOG2( "name: %s, fName: %s\n", name.get(), fName.get()); + + if (!fName.IsEmpty() && !name.IsEmpty() && (type.Length() == 1)) { + rv = entry->SetNativeLeafName(fName); + if (NS_SUCCEEDED( rv)) { + if (type.CharAt( 0) == 'F') { + isFolder = PR_FALSE; + entry->IsDirectory( &isFolder); + if (isFolder) { + rv = FoundMailFolder( entry, name.get(), pArray, pImport); + if (NS_SUCCEEDED( rv)) { + rv = ScanMailDir( entry, pArray, pImport); + if (NS_FAILED( rv)) { + IMPORT_LOG0( "*** Error scanning mail directory\n"); + } + } + } + } + else if ((type.CharAt( 0) == 'M') || (type.CharAt( 0) == 'S')) { + isFile = PR_FALSE; + entry->IsFile( &isFile); + if (isFile) { + FoundMailbox( entry, name.get(), pArray, pImport); + } + } + } + } + } + + return( NS_OK); +} + + +nsresult nsEudoraWin32::FoundMailbox( nsIFile *mailFile, const char *pName, nsISupportsArray *pArray, nsIImportService *pImport) +{ + nsString displayName; + nsCOMPtr desc; + nsISupports * pInterface; + + NS_CopyNativeToUnicode(nsDependentCString(pName), displayName); + +#ifdef IMPORT_DEBUG + nsCAutoString path; + mailFile->GetNativePath(path); + if (!path.IsEmpty()) + IMPORT_LOG2( "Found eudora mailbox, %s: %s\n", path.get(), pName); + else + IMPORT_LOG1( "Found eudora mailbox, %s\n", pName); + IMPORT_LOG1( "\tm_depth = %d\n", (int)m_depth); +#endif + + nsresult rv = pImport->CreateNewMailboxDescriptor( getter_AddRefs( desc)); + if (NS_SUCCEEDED( rv)) { + PRInt64 sz = 0; + mailFile->GetFileSize( &sz); + desc->SetDisplayName( displayName.get()); + desc->SetDepth( m_depth); + desc->SetSize( sz); + nsCOMPtr pFile = nsnull; + desc->GetFile(getter_AddRefs(pFile)); + if (pFile) { + nsCOMPtr localMailFile = do_QueryInterface(mailFile); + pFile->InitWithFile( localMailFile); + } + rv = desc->QueryInterface( kISupportsIID, (void **) &pInterface); + pArray->AppendElement( pInterface); + pInterface->Release(); + } + + return( NS_OK); +} + + +nsresult nsEudoraWin32::FoundMailFolder( nsIFile *mailFolder, const char *pName, nsISupportsArray *pArray, nsIImportService *pImport) +{ + nsString displayName; + nsCOMPtr desc; + nsISupports * pInterface; + + NS_CopyNativeToUnicode(nsDependentCString(pName), displayName); + +#ifdef IMPORT_DEBUG + nsCAutoString path; + mailFolder->GetNativePath(path); + if (!path.IsEmpty()) { + IMPORT_LOG2( "Found eudora folder, %s: %s\n", path.get(), pName); + } + else { + IMPORT_LOG1( "Found eudora folder, %s\n", pName); + } + IMPORT_LOG1( "\tm_depth = %d\n", (int)m_depth); +#endif + + nsresult rv = pImport->CreateNewMailboxDescriptor( getter_AddRefs( desc)); + if (NS_SUCCEEDED( rv)) { + PRUint32 sz = 0; + desc->SetDisplayName( displayName.get()); + desc->SetDepth( m_depth); + desc->SetSize( sz); + nsCOMPtr pFile = nsnull; + desc->GetFile(getter_AddRefs(pFile)); + if (pFile) { + nsCOMPtr localMailFile = do_QueryInterface(mailFolder); + pFile->InitWithFile( localMailFile); + } + rv = desc->QueryInterface( kISupportsIID, (void **) &pInterface); + pArray->AppendElement( pInterface); + pInterface->Release(); + } + + return( NS_OK); +} + + +nsresult nsEudoraWin32::FindTOCFile( nsIFile *pMailFile, nsIFile **ppTOCFile, PRBool *pDeleteToc) +{ + nsresult rv; + nsCAutoString leaf; + + *pDeleteToc = PR_FALSE; + *ppTOCFile = nsnull; + rv = pMailFile->GetNativeLeafName(leaf); + if (NS_FAILED( rv)) + return( rv); + rv = pMailFile->GetParent( ppTOCFile); + if (NS_FAILED( rv)) + return( rv); + + nsCString name; + if ((leaf.Length() > 4) && (leaf.CharAt( leaf.Length() - 4) == '.')) + leaf.Left( name, leaf.Length() - 4); + else + name = leaf; + name.Append( ".toc"); + rv = (*ppTOCFile)->AppendNative(name); + if (NS_FAILED( rv)) + return( rv); + + PRBool exists = PR_FALSE; + rv = (*ppTOCFile)->Exists( &exists); + if (NS_FAILED( rv)) + return( rv); + PRBool isFile = PR_FALSE; + rv = (*ppTOCFile)->IsFile( &isFile); + if (NS_FAILED( rv)) + return( rv); + if (exists && isFile) + return( NS_OK); + + return( NS_ERROR_FAILURE); +} + + +PRBool nsEudoraWin32::ImportSettings( nsIFile *pIniFile, nsIMsgAccount **localMailAccount) +{ + PRBool result = PR_FALSE; + nsresult rv; + + nsCOMPtr accMgr = + do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv); + if (NS_FAILED(rv)) { + IMPORT_LOG0( "*** Failed to create a account manager!\n"); + return( PR_FALSE); + } + + // Eudora info is arranged by key, 1 for the default, then persona's for additional + // accounts. + // Start with the first one, then do each persona + nsCString iniPath; + pIniFile->GetNativePath(iniPath); + if (iniPath.IsEmpty()) + return( PR_FALSE); + UINT valInt; + SimpleBufferTonyRCopiedOnce section; + DWORD sSize; + DWORD sOffset = 0; + DWORD start; + nsCString sectionName("Settings"); + int popCount = 0; + int accounts = 0; + + DWORD allocSize = 0; + do { + allocSize += 2048; + section.Allocate( allocSize); + sSize = ::GetPrivateProfileSection( "Personalities", section.m_pBuffer, allocSize, iniPath.get()); + } while (sSize == (allocSize - 2)); + + nsIMsgAccount * pAccount; + + do { + if (!sectionName.IsEmpty()) { + pAccount = nsnull; + valInt = ::GetPrivateProfileInt( sectionName.get(), "UsesPOP", 1, iniPath.get()); + if (valInt) { + // This is a POP account + if (BuildPOPAccount( accMgr, sectionName.get(), iniPath.get(), &pAccount)) { + accounts++; + popCount++; + if (popCount > 1) { + if (localMailAccount && *localMailAccount) { + NS_RELEASE( *localMailAccount); + *localMailAccount = nsnull; + } + } + else { + if (localMailAccount) { + *localMailAccount = pAccount; + NS_IF_ADDREF( pAccount); + } + } + } + } + else { + valInt = ::GetPrivateProfileInt( sectionName.get(), "UsesIMAP", 0, iniPath.get()); + if (valInt) { + // This is an IMAP account + if (BuildIMAPAccount( accMgr, sectionName.get(), iniPath.get(), &pAccount)) { + accounts++; + } + } + } + if (pAccount && (sOffset == 0)) { + accMgr->SetDefaultAccount( pAccount); + } + + NS_IF_RELEASE( pAccount); + } + + sectionName.Truncate(); + while ((sOffset < sSize) && (section.m_pBuffer[sOffset] != '=')) + sOffset++; + sOffset++; + start = sOffset; + while ((sOffset < sSize) && (section.m_pBuffer[sOffset] != 0)) + sOffset++; + if (sOffset > start) { + sectionName.Append( section.m_pBuffer + start, sOffset - start); + sectionName.Trim( kWhitespace); + } + + } while (sOffset < sSize); + + // 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); +} + +// maximium size of settings strings +#define kIniValueSize 384 + + +void nsEudoraWin32::GetServerAndUserName( const char *pSection, const char *pIni, nsCString& serverName, nsCString& userName, char *pBuff) +{ + DWORD valSize; + int idx; + nsCString tStr; + + serverName.Truncate(); + userName.Truncate(); + + valSize = ::GetPrivateProfileString( pSection, "PopServer", "", pBuff, kIniValueSize, pIni); + if (valSize) + serverName = pBuff; + else { + valSize = ::GetPrivateProfileString( pSection, "POPAccount", "", pBuff, kIniValueSize, pIni); + if (valSize) { + serverName = pBuff; + idx = serverName.FindChar( '@'); + if (idx != -1) { + serverName.Right( tStr, serverName.Length() - idx - 1); + serverName = tStr; + } + } + } + valSize = ::GetPrivateProfileString( pSection, "LoginName", "", pBuff, kIniValueSize, pIni); + if (valSize) + userName = pBuff; + else { + valSize = ::GetPrivateProfileString( pSection, "POPAccount", "", pBuff, kIniValueSize, pIni); + if (valSize) { + userName = pBuff; + idx = userName.FindChar( '@'); + if (idx != -1) { + userName.Left( tStr, idx); + userName = tStr; + } + } + } +} + +void nsEudoraWin32::GetAccountName( const char *pSection, nsString& str) +{ + str.Truncate(); + + nsCString s(pSection); + + if (s.Equals(NS_LITERAL_CSTRING("Settings"), nsCaseInsensitiveCStringComparator())) { + str.AssignLiteral("Eudora "); + str.AppendWithConversion( pSection); + } + else { + nsCString tStr; + str.AssignWithConversion(pSection); + if (s.Length() > 8) { + s.Left( tStr, 8); + if (tStr.Equals(NS_LITERAL_CSTRING("Persona-"), nsCaseInsensitiveCStringComparator())) { + s.Right( tStr, s.Length() - 8); + str.AssignWithConversion(tStr.get()); + } + } + } +} + + +PRBool nsEudoraWin32::BuildPOPAccount( nsIMsgAccountManager *accMgr, const char *pSection, const char *pIni, nsIMsgAccount **ppAccount) +{ + if (ppAccount) + *ppAccount = nsnull; + + char valBuff[kIniValueSize]; + nsCString serverName; + nsCString userName; + + GetServerAndUserName( pSection, pIni, serverName, userName, valBuff); + + if (serverName.IsEmpty() || userName.IsEmpty()) + return( PR_FALSE); + + PRBool result = PR_FALSE; + + // I now have a user name/server name pair, find out if it already exists? + nsCOMPtr in; + nsresult rv = accMgr->FindServer( userName, serverName, NS_LITERAL_CSTRING("pop3"), getter_AddRefs(in)); + if (NS_FAILED(rv) || !in) { + // Create the incoming server and an account for it? + rv = accMgr->CreateIncomingServer( userName, serverName, NS_LITERAL_CSTRING("pop3"), getter_AddRefs(in)); + if (NS_SUCCEEDED( rv) && in) { + rv = in->SetType( "pop3"); + // rv = in->SetHostName( serverName); + // rv = in->SetUsername( userName); + + IMPORT_LOG2( "Created POP3 server named: %s, userName: %s\n", serverName.get(), userName.get()); + + nsString prettyName; + GetAccountName( pSection, prettyName); + + PRUnichar *pretty = ToNewUnicode(prettyName); + IMPORT_LOG1( "\tSet pretty name to: %S\n", pretty); + rv = in->SetPrettyName( pretty); + nsCRT::free( pretty); + + // We have a server, create an account. + nsCOMPtr account; + rv = accMgr->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"); + + nsCOMPtr pop3Server = do_QueryInterface(in, &rv); + NS_ENSURE_SUCCESS(rv,rv); + UINT valInt = ::GetPrivateProfileInt(pSection, "LeaveMailOnServer", 0, pIni); + pop3Server->SetLeaveMessagesOnServer(valInt ? PR_TRUE : PR_FALSE); + + // Fiddle with the identities + SetIdentities(accMgr, account, pSection, pIni, userName.get(), serverName.get(), valBuff); + result = PR_TRUE; + if (ppAccount) + account->QueryInterface( NS_GET_IID(nsIMsgAccount), (void **)ppAccount); + } + } + } + else + result = PR_TRUE; + + return( result); +} + +PRBool nsEudoraWin32::BuildIMAPAccount( nsIMsgAccountManager *accMgr, const char *pSection, const char *pIni, nsIMsgAccount **ppAccount) +{ + char valBuff[kIniValueSize]; + nsCString serverName; + nsCString userName; + + GetServerAndUserName( pSection, pIni, serverName, userName, valBuff); + + if (serverName.IsEmpty() || userName.IsEmpty()) + return( PR_FALSE); + + PRBool result = PR_FALSE; + + nsCOMPtr in; + nsresult rv = accMgr->FindServer( userName, serverName, NS_LITERAL_CSTRING("imap"), getter_AddRefs(in)); + if (NS_FAILED( rv) || (in == nsnull)) { + // Create the incoming server and an account for it? + rv = accMgr->CreateIncomingServer( userName, serverName, NS_LITERAL_CSTRING("imap"), getter_AddRefs(in)); + if (NS_SUCCEEDED( rv) && in) { + rv = in->SetType( "imap"); + // rv = in->SetHostName( serverName); + // rv = in->SetUsername( userName); + + IMPORT_LOG2( "Created IMAP server named: %s, userName: %s\n", serverName.get(), userName.get()); + + nsString prettyName; + GetAccountName( pSection, prettyName); + + PRUnichar *pretty = ToNewUnicode(prettyName); + + IMPORT_LOG1( "\tSet pretty name to: %S\n", pretty); + + rv = in->SetPrettyName( pretty); + nsCRT::free( pretty); + + // We have a server, create an account. + nsCOMPtr account; + rv = accMgr->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 + SetIdentities(accMgr, account, pSection, pIni, userName.get(), serverName.get(), valBuff); + result = PR_TRUE; + if (ppAccount) + account->QueryInterface( NS_GET_IID(nsIMsgAccount), (void **)ppAccount); + } + } + } + else + result = PR_TRUE; + + return( result); +} + +void nsEudoraWin32::SetIdentities(nsIMsgAccountManager *accMgr, nsIMsgAccount *acc, const char *pSection, const char *pIniFile, const char *userName, const char *serverName, char *pBuff) +{ + nsCAutoString realName; + nsCAutoString email; + nsCAutoString server; + DWORD valSize; + nsresult rv; + + valSize = ::GetPrivateProfileString( pSection, "RealName", "", pBuff, kIniValueSize, pIniFile); + if (valSize) + realName = pBuff; + valSize = ::GetPrivateProfileString( pSection, "SMTPServer", "", pBuff, kIniValueSize, pIniFile); + if (valSize) + server = pBuff; + valSize = ::GetPrivateProfileString( pSection, "ReturnAddress", "", pBuff, kIniValueSize, pIniFile); + if (valSize) + email = pBuff; + + nsCOMPtr id; + rv = accMgr->CreateIdentity( getter_AddRefs( id)); + if (id) { + nsAutoString fullName; + fullName.Assign(NS_ConvertASCIItoUTF16(realName)); + id->SetFullName(fullName); + id->SetIdentityName(fullName); + if (email.IsEmpty()) { + email = userName; + email += "@"; + email += serverName; + } + id->SetEmail(email); + acc->AddIdentity( id); + + IMPORT_LOG0( "Created identity and added to the account\n"); + IMPORT_LOG1( "\tname: %s\n", realName.get()); + IMPORT_LOG1( "\temail: %s\n", email.get()); + } + SetSmtpServer( accMgr, acc, server.get(), userName); +} + + +void nsEudoraWin32::SetSmtpServer( nsIMsgAccountManager *pMgr, nsIMsgAccount *pAcc, const char *pServer, const char *pUser) +{ + nsresult rv; + + nsCOMPtr smtpService(do_GetService(NS_SMTPSERVICE_CONTRACTID, &rv)); + if (NS_SUCCEEDED(rv) && smtpService) { + nsCOMPtr foundServer; + + rv = smtpService->FindServer( pUser, pServer, getter_AddRefs( foundServer)); + if (NS_SUCCEEDED( rv) && foundServer) { + IMPORT_LOG1( "SMTP server already exists: %s\n", pServer); + return; + } + nsCOMPtr smtpServer; + + rv = smtpService->CreateSmtpServer( getter_AddRefs( smtpServer)); + if (NS_SUCCEEDED( rv) && smtpServer) { + smtpServer->SetHostname( pServer); + if (pUser) + smtpServer->SetUsername( pUser); + + IMPORT_LOG1( "Created new SMTP server: %s\n", pServer); + } + } +} + +nsresult nsEudoraWin32::GetAttachmentInfo( const char *pFileName, nsIFile *pFile, nsCString& mimeType, nsCString& aAttachmentName) +{ + nsresult rv; + mimeType.Truncate(); + nsCOMPtr pLocalFile = do_QueryInterface(pFile, &rv); + NS_ENSURE_SUCCESS(rv, rv); + pLocalFile->InitWithNativePath(nsDependentCString(pFileName)); + PRBool isFile = PR_FALSE; + PRBool exists = PR_FALSE; + if (NS_FAILED( rv = pFile->Exists( &exists))) + return( rv); + if (NS_FAILED( rv = pFile->IsFile( &isFile))) + return( rv); if (!exists || !isFile) { // Windows Eudora writes the full path to the attachment when the message @@ -923,10 +923,10 @@ nsresult nsEudoraWin32::GetAttachmentInfo( const char *pFileName, nsIFile *pFile // // Check to see if we have any better luck looking for the attachment // in the current attachment directory. - nsCAutoString name; - pFile->GetNativeLeafName(name); - if (name.IsEmpty()) - return( NS_ERROR_FAILURE); + nsCAutoString name; + pFile->GetNativeLeafName(name); + if (name.IsEmpty()) + return( NS_ERROR_FAILURE); nsCOMPtr altFile; rv = m_mailImportLocation->Clone(getter_AddRefs(altFile)); @@ -956,265 +956,265 @@ nsresult nsEudoraWin32::GetAttachmentInfo( const char *pFileName, nsIFile *pFile } } - if (exists && isFile) { - nsCAutoString name; - pFile->GetNativeLeafName(name); - if (name.IsEmpty()) - return( NS_ERROR_FAILURE); - if (name.Length() > 4) { - nsCString ext; - PRInt32 idx = name.RFindChar( '.'); - if (idx != -1) { - name.Right( ext, name.Length() - idx); - GetMimeTypeFromExtension( ext, mimeType); - } - } - if (mimeType.IsEmpty()) - mimeType = "application/octet-stream"; - - aAttachmentName = name; // use the leaf name of the attachment file url as the attachment name - - return( NS_OK); - } - - return( NS_ERROR_FAILURE); -} - -PRBool nsEudoraWin32::FindMimeIniFile( nsIFile *pFile) -{ - PRBool hasMore; - nsCOMPtr directoryEnumerator; - nsresult rv = pFile->GetDirectoryEntries(getter_AddRefs(directoryEnumerator)); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr pLocalFile = do_QueryInterface(pFile, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - directoryEnumerator->HasMoreElements(&hasMore); - PRBool isFile; - nsCOMPtr entry; - nsCString fName; - nsCString ext; - nsCString name; - - PRBool found = PR_FALSE; - - while (hasMore && NS_SUCCEEDED(rv)) - { - nsCOMPtr aSupport; - rv = directoryEnumerator->GetNext(getter_AddRefs(aSupport)); - nsCOMPtr entry(do_QueryInterface(aSupport, &rv)); - directoryEnumerator->HasMoreElements(&hasMore); - - - if (NS_SUCCEEDED( rv)) { - rv = entry->GetNativeLeafName(fName); - if (NS_SUCCEEDED( rv) && !fName.IsEmpty()) { - if (fName.Length() > 4) { - fName.Right( ext, 4); - fName.Left( name, fName.Length() - 4); - } - else { - ext.Truncate(); - name = fName; - } - ToLowerCase(ext); - if (ext.EqualsLiteral(".ini")) { - isFile = PR_FALSE; - entry->IsFile( &isFile); - if (isFile) { - if (found) { - // which one of these files is newer? - PRInt64 modDate1, modDate2; - entry->GetLastModifiedTime( &modDate2); - pFile->GetLastModifiedTime( &modDate1); - if (modDate2 > modDate1) - pLocalFile->InitWithFile( entry); - } - else { - pLocalFile->InitWithFile( entry); - found = PR_TRUE; - } - } - } - } - } - } - return found; -} - - -void nsEudoraWin32::GetMimeTypeFromExtension( nsCString& ext, nsCString& mimeType) -{ - HKEY sKey; - if (::RegOpenKeyEx( HKEY_CLASSES_ROOT, ext.get(), 0, KEY_QUERY_VALUE, &sKey) == ERROR_SUCCESS) { - // get the value of "Current" - BYTE *pBytes = GetValueBytes( sKey, "Content Type"); - if (pBytes) { - mimeType = (const char *)pBytes; - delete [] pBytes; - } - ::RegCloseKey( sKey); - } - - if (!mimeType.IsEmpty() || !m_mailImportLocation || (ext.Length() > 10)) - return; - - // TLR: FIXME: We should/could cache the extension to mime type maps we find - // and check the cache first before scanning all of eudora's mappings? - - // It's not in the registry, try and find the .ini file for Eudora's private - // mime type list - if (!m_pMimeSection) { - nsCOMPtr pFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID); - if (!pFile) - return; - - pFile->InitWithFile( m_mailImportLocation); - - pFile->AppendNative(NS_LITERAL_CSTRING("eudora.ini")); - PRBool exists = PR_FALSE; - PRBool isFile = PR_FALSE; - nsresult rv = pFile->Exists( &exists); - if (NS_SUCCEEDED( rv)) - rv = pFile->IsFile( &isFile); - if (!isFile || !exists) { - rv = pFile->InitWithFile( m_mailImportLocation); - if (NS_FAILED( rv)) - return; - if (!FindMimeIniFile( pFile)) - return; - } - - nsCAutoString fileName; - pFile->GetNativePath(fileName); - if (fileName.IsEmpty()) - return; - // Read the mime map section - DWORD size = 1024; - DWORD dSize = size - 2; - while (dSize == (size - 2)) { - if (m_pMimeSection) - delete [] m_pMimeSection; - size += 1024; - m_pMimeSection = new char[size]; - dSize = ::GetPrivateProfileSection( "Mappings", m_pMimeSection, size, fileName.get()); - } - } - - if (!m_pMimeSection) - return; - - IMPORT_LOG1( "Looking for mime type for extension: %s\n", ext.get()); - - // out/in/both=extension,mac creator,mac type,mime type1,mime type2 - const char *pExt = ext.get(); - pExt++; - - char * pChar = m_pMimeSection; - char * pStart; - int len; - nsCString tStr; - for(;;) { - while (*pChar != '=') { - if (!(*pChar) && !(*(pChar + 1))) - return; - pChar++; - } - if (*pChar) - pChar++; - pStart = pChar; - len = 0; - while (*pChar && (*pChar != ',')) { - pChar++; - len++; - } - if (!*pChar) return; - tStr.Truncate(); - tStr.Append( pStart, len); - tStr.Trim( kWhitespace); - if (!nsCRT::strcasecmp( tStr.get(), pExt)) { - // skip the mac creator and type - pChar++; - while (*pChar && (*pChar != ',')) - pChar++; - if (!*pChar) return; - pChar++; - while (*pChar && (*pChar != ',')) - pChar++; - if (!*pChar) return; - pChar++; - // Get the first mime type - len = 0; - pStart = pChar; - while (*pChar && (*pChar != ',')) { - pChar++; - len++; - } - if (!*pChar) return; - pChar++; - if (!len) continue; - tStr.Truncate(); - tStr.Append( pStart, len); - tStr.Trim( kWhitespace); - if (tStr.IsEmpty()) continue; - mimeType.Truncate(); - mimeType.Append( tStr.get()); - mimeType.Append( "/"); - pStart = pChar; - len = 0; - while (*pChar && (*pChar != 0x0D) && (*pChar != 0x0A)) { - pChar++; - len++; - } - if (!len) continue; - tStr.Truncate(); - tStr.Append( pStart, len); - tStr.Trim( kWhitespace); - if (tStr.IsEmpty()) continue; - mimeType.Append( tStr.get()); - - IMPORT_LOG1( "Found Mime Type: %s\n", mimeType.get()); - - return; - } - } -} - -PRBool nsEudoraWin32::FindAddressFolder( nsIFile **pFolder) -{ - IMPORT_LOG0( "*** Looking for Eudora address folder\n"); - - return( FindEudoraLocation( pFolder)); -} - -nsresult nsEudoraWin32::FindAddressBooks( nsIFile *pRoot, nsISupportsArray **ppArray) -{ - - nsCOMPtr file; - nsCOMPtr localRoot = do_QueryInterface(pRoot); - nsresult rv = file->InitWithFile( localRoot); - if (NS_FAILED( rv)) - return( rv); - - rv = NS_NewISupportsArray( ppArray); - if (NS_FAILED( rv)) { - IMPORT_LOG0( "FAILED to allocate the nsISupportsArray\n"); - return( rv); - } - - nsCOMPtr impSvc(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv)); - if (NS_FAILED( rv)) - return( rv); - m_addressImportFolder = pRoot; - nsString displayName; - nsEudoraStringBundle::GetStringByID( EUDORAIMPORT_NICKNAMES_NAME, displayName); - - // First off, get the default nndbase.txt, then scan the default nicknames subdir, - // then look in the .ini file for additional directories to scan for address books! - PRBool exists = PR_FALSE; - PRBool isFile = PR_FALSE; - + if (exists && isFile) { + nsCAutoString name; + pFile->GetNativeLeafName(name); + if (name.IsEmpty()) + return( NS_ERROR_FAILURE); + if (name.Length() > 4) { + nsCString ext; + PRInt32 idx = name.RFindChar( '.'); + if (idx != -1) { + name.Right( ext, name.Length() - idx); + GetMimeTypeFromExtension( ext, mimeType); + } + } + if (mimeType.IsEmpty()) + mimeType = "application/octet-stream"; + + aAttachmentName = name; // use the leaf name of the attachment file url as the attachment name + + return( NS_OK); + } + + return( NS_ERROR_FAILURE); +} + +PRBool nsEudoraWin32::FindMimeIniFile( nsIFile *pFile) +{ + PRBool hasMore; + nsCOMPtr directoryEnumerator; + nsresult rv = pFile->GetDirectoryEntries(getter_AddRefs(directoryEnumerator)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr pLocalFile = do_QueryInterface(pFile, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + directoryEnumerator->HasMoreElements(&hasMore); + PRBool isFile; + nsCOMPtr entry; + nsCString fName; + nsCString ext; + nsCString name; + + PRBool found = PR_FALSE; + + while (hasMore && NS_SUCCEEDED(rv)) + { + nsCOMPtr aSupport; + rv = directoryEnumerator->GetNext(getter_AddRefs(aSupport)); + nsCOMPtr entry(do_QueryInterface(aSupport, &rv)); + directoryEnumerator->HasMoreElements(&hasMore); + + + if (NS_SUCCEEDED( rv)) { + rv = entry->GetNativeLeafName(fName); + if (NS_SUCCEEDED( rv) && !fName.IsEmpty()) { + if (fName.Length() > 4) { + fName.Right( ext, 4); + fName.Left( name, fName.Length() - 4); + } + else { + ext.Truncate(); + name = fName; + } + ToLowerCase(ext); + if (ext.EqualsLiteral(".ini")) { + isFile = PR_FALSE; + entry->IsFile( &isFile); + if (isFile) { + if (found) { + // which one of these files is newer? + PRInt64 modDate1, modDate2; + entry->GetLastModifiedTime( &modDate2); + pFile->GetLastModifiedTime( &modDate1); + if (modDate2 > modDate1) + pLocalFile->InitWithFile( entry); + } + else { + pLocalFile->InitWithFile( entry); + found = PR_TRUE; + } + } + } + } + } + } + return found; +} + + +void nsEudoraWin32::GetMimeTypeFromExtension( nsCString& ext, nsCString& mimeType) +{ + HKEY sKey; + if (::RegOpenKeyEx( HKEY_CLASSES_ROOT, ext.get(), 0, KEY_QUERY_VALUE, &sKey) == ERROR_SUCCESS) { + // get the value of "Current" + BYTE *pBytes = GetValueBytes( sKey, "Content Type"); + if (pBytes) { + mimeType = (const char *)pBytes; + delete [] pBytes; + } + ::RegCloseKey( sKey); + } + + if (!mimeType.IsEmpty() || !m_mailImportLocation || (ext.Length() > 10)) + return; + + // TLR: FIXME: We should/could cache the extension to mime type maps we find + // and check the cache first before scanning all of eudora's mappings? + + // It's not in the registry, try and find the .ini file for Eudora's private + // mime type list + if (!m_pMimeSection) { + nsCOMPtr pFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID); + if (!pFile) + return; + + pFile->InitWithFile( m_mailImportLocation); + + pFile->AppendNative(NS_LITERAL_CSTRING("eudora.ini")); + PRBool exists = PR_FALSE; + PRBool isFile = PR_FALSE; + nsresult rv = pFile->Exists( &exists); + if (NS_SUCCEEDED( rv)) + rv = pFile->IsFile( &isFile); + if (!isFile || !exists) { + rv = pFile->InitWithFile( m_mailImportLocation); + if (NS_FAILED( rv)) + return; + if (!FindMimeIniFile( pFile)) + return; + } + + nsCAutoString fileName; + pFile->GetNativePath(fileName); + if (fileName.IsEmpty()) + return; + // Read the mime map section + DWORD size = 1024; + DWORD dSize = size - 2; + while (dSize == (size - 2)) { + if (m_pMimeSection) + delete [] m_pMimeSection; + size += 1024; + m_pMimeSection = new char[size]; + dSize = ::GetPrivateProfileSection( "Mappings", m_pMimeSection, size, fileName.get()); + } + } + + if (!m_pMimeSection) + return; + + IMPORT_LOG1( "Looking for mime type for extension: %s\n", ext.get()); + + // out/in/both=extension,mac creator,mac type,mime type1,mime type2 + const char *pExt = ext.get(); + pExt++; + + char * pChar = m_pMimeSection; + char * pStart; + int len; + nsCString tStr; + for(;;) { + while (*pChar != '=') { + if (!(*pChar) && !(*(pChar + 1))) + return; + pChar++; + } + if (*pChar) + pChar++; + pStart = pChar; + len = 0; + while (*pChar && (*pChar != ',')) { + pChar++; + len++; + } + if (!*pChar) return; + tStr.Truncate(); + tStr.Append( pStart, len); + tStr.Trim( kWhitespace); + if (!nsCRT::strcasecmp( tStr.get(), pExt)) { + // skip the mac creator and type + pChar++; + while (*pChar && (*pChar != ',')) + pChar++; + if (!*pChar) return; + pChar++; + while (*pChar && (*pChar != ',')) + pChar++; + if (!*pChar) return; + pChar++; + // Get the first mime type + len = 0; + pStart = pChar; + while (*pChar && (*pChar != ',')) { + pChar++; + len++; + } + if (!*pChar) return; + pChar++; + if (!len) continue; + tStr.Truncate(); + tStr.Append( pStart, len); + tStr.Trim( kWhitespace); + if (tStr.IsEmpty()) continue; + mimeType.Truncate(); + mimeType.Append( tStr.get()); + mimeType.Append( "/"); + pStart = pChar; + len = 0; + while (*pChar && (*pChar != 0x0D) && (*pChar != 0x0A)) { + pChar++; + len++; + } + if (!len) continue; + tStr.Truncate(); + tStr.Append( pStart, len); + tStr.Trim( kWhitespace); + if (tStr.IsEmpty()) continue; + mimeType.Append( tStr.get()); + + IMPORT_LOG1( "Found Mime Type: %s\n", mimeType.get()); + + return; + } + } +} + +PRBool nsEudoraWin32::FindAddressFolder( nsIFile **pFolder) +{ + IMPORT_LOG0( "*** Looking for Eudora address folder\n"); + + return( FindEudoraLocation( pFolder)); +} + +nsresult nsEudoraWin32::FindAddressBooks( nsIFile *pRoot, nsISupportsArray **ppArray) +{ + + nsCOMPtr file; + nsCOMPtr localRoot = do_QueryInterface(pRoot); + nsresult rv = file->InitWithFile( localRoot); + if (NS_FAILED( rv)) + return( rv); + + rv = NS_NewISupportsArray( ppArray); + if (NS_FAILED( rv)) { + IMPORT_LOG0( "FAILED to allocate the nsISupportsArray\n"); + return( rv); + } + + nsCOMPtr impSvc(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv)); + if (NS_FAILED( rv)) + return( rv); + m_addressImportFolder = pRoot; + nsString displayName; + nsEudoraStringBundle::GetStringByID( EUDORAIMPORT_NICKNAMES_NAME, displayName); + + // First off, get the default nndbase.txt, then scan the default nicknames subdir, + // then look in the .ini file for additional directories to scan for address books! + PRBool exists = PR_FALSE; + PRBool isFile = PR_FALSE; + rv = file->AppendNative(NS_LITERAL_CSTRING("nndbase.txt")); PRBool checkedBoth = PR_FALSE; do @@ -1234,247 +1234,247 @@ nsresult nsEudoraWin32::FindAddressBooks( nsIFile *pRoot, nsISupportsArray **ppA rv = file->SetNativeLeafName(NS_LITERAL_CSTRING("nndbase.nnt")); checkedBoth = PR_TRUE; } while (NS_SUCCEEDED(rv)); - - if (exists && isFile) { - if (NS_FAILED( rv = FoundAddressBook( file, displayName.get(), *ppArray, impSvc))) - return( rv); - } - - // Try the default directory - rv = rv = file->InitWithFile( localRoot); - if (NS_FAILED( rv)) - return( rv); - rv = file->AppendNative(NS_LITERAL_CSTRING("Nickname")); - PRBool isDir = PR_FALSE; - exists = PR_FALSE; - if (NS_SUCCEEDED( rv)) - rv = file->Exists( &exists); - if (NS_SUCCEEDED( rv) && exists) - rv = file->IsDirectory( &isDir); - if (exists && isDir) { - if (NS_FAILED( rv = ScanAddressDir(file, *ppArray, impSvc))) - return( rv); - } - - // Try the ini file to find other directories! - rv = rv = file->InitWithFile( localRoot); - if (NS_FAILED( rv)) - return( rv); - rv = file->AppendNative(NS_LITERAL_CSTRING("eudora.ini")); - exists = PR_FALSE; - isFile = PR_FALSE; - if (NS_SUCCEEDED( rv)) - rv = file->Exists( &exists); - if (NS_SUCCEEDED( rv) && exists) - rv = file->IsFile( &isFile); - - if (!isFile || !exists) { - rv = file->InitWithFile( localRoot); - if (NS_FAILED( rv)) - return( NS_OK); - if (!FindMimeIniFile(file)) - return( NS_OK); - } - - nsCString fileName; - file->GetNativePath(fileName); - // This is the supposed ini file name! - // Get the extra directories for nicknames and parse it for valid nickname directories - // to look into... - char *pBuffer = new char[2048]; - DWORD len = ::GetPrivateProfileString( "Settings", "ExtraNicknameDirs", "", pBuffer, 2048, fileName.get()); - if (len == 2047) { - // If the value is really that large then don't bother! - delete [] pBuffer; - return( NS_OK); - } - nsCString dirs(pBuffer); - delete [] pBuffer; - dirs.Trim( kWhitespace); - PRInt32 idx = 0; - nsCString currentDir; - while ((idx = dirs.FindChar( ';')) != -1) { - dirs.Left( currentDir, idx); - currentDir.Trim( kWhitespace); - if (!currentDir.IsEmpty()) { - rv = file->InitWithNativePath(currentDir); - exists = PR_FALSE; - isDir = PR_FALSE; - if (NS_SUCCEEDED( rv)) - rv = file->Exists( &exists); - if (NS_SUCCEEDED( rv) && exists) - rv = file->IsDirectory( &isDir); - if (exists && isDir) { - if (NS_FAILED( rv = ScanAddressDir(file, *ppArray, impSvc))) - return( rv); - } - } - dirs.Right( currentDir, dirs.Length() - idx - 1); - dirs = currentDir; - dirs.Trim( kWhitespace); - } - if (!dirs.IsEmpty()) { - rv = file->InitWithNativePath(dirs); - exists = PR_FALSE; - isDir = PR_FALSE; - if (NS_SUCCEEDED( rv)) - rv = file->Exists( &exists); - if (NS_SUCCEEDED( rv) && exists) - rv = file->IsDirectory( &isDir); - if (exists && isDir) { - if (NS_FAILED( rv = ScanAddressDir(file, *ppArray, impSvc))) - return( rv); - } - } - - return( NS_OK); -} - - -nsresult nsEudoraWin32::ScanAddressDir( nsIFile *pDir, nsISupportsArray *pArray, nsIImportService *impSvc) -{ - PRBool hasMore; - nsCOMPtr directoryEnumerator; - nsresult rv = pDir->GetDirectoryEntries(getter_AddRefs(directoryEnumerator)); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr pLocalFile = do_QueryInterface(pDir, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - directoryEnumerator->HasMoreElements(&hasMore); - PRBool isFile; - nsCOMPtr entry; - nsCString fName; - nsCString ext; - nsCString name; - - PRBool found = PR_FALSE; - - while (hasMore && NS_SUCCEEDED(rv)) - { - nsCOMPtr aSupport; - rv = directoryEnumerator->GetNext(getter_AddRefs(aSupport)); - nsCOMPtr entry(do_QueryInterface(aSupport, &rv)); - directoryEnumerator->HasMoreElements(&hasMore); - - if (NS_SUCCEEDED( rv)) { - rv = entry->GetNativeLeafName(fName); - if (NS_SUCCEEDED( rv) && !fName.IsEmpty()) { - if (fName.Length() > 4) { - fName.Right( ext, 4); - fName.Left( name, fName.Length() - 4); - } - else { - ext.Truncate(); - name = fName; - } - ToLowerCase(ext); - if (ext.EqualsLiteral(".txt")) { - isFile = PR_FALSE; - entry->IsFile( &isFile); - if (isFile) { - rv = FoundAddressBook( entry, nsnull, pArray, impSvc); - if (NS_FAILED( rv)) - return( rv); - } - } - } - } - } - - return( rv); -} - - -nsresult nsEudoraWin32::FoundAddressBook( nsIFile *file, const PRUnichar *pName, nsISupportsArray *pArray, nsIImportService *impSvc) -{ - nsCOMPtr desc; - nsISupports * pInterface; - nsString name; - nsresult rv; - - if (pName) - name = pName; - else { - nsAutoString leaf; - rv = file->GetLeafName(leaf); - if (NS_FAILED( rv)) - return( rv); - if (leaf.IsEmpty()) - return( NS_ERROR_FAILURE); - nsString tStr; - leaf.Right( tStr, 4); - if (tStr.LowerCaseEqualsLiteral(".txt") || tStr.LowerCaseEqualsLiteral(".nnt")) { - leaf.Left( tStr, leaf.Length() - 4); - leaf = tStr; - } - } - - nsCOMPtr fileLoc = do_QueryInterface(file, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - rv = impSvc->CreateNewABDescriptor( getter_AddRefs( desc)); - if (NS_SUCCEEDED( rv)) { - PRInt64 sz = 0; - file->GetFileSize( &sz); - desc->SetPreferredName(name); - desc->SetSize((PRUint32) sz); - desc->SetAbFile(fileLoc); - rv = desc->QueryInterface( kISupportsIID, (void **) &pInterface); - pArray->AppendElement( pInterface); - pInterface->Release(); - } - if (NS_FAILED( rv)) { - IMPORT_LOG0( "*** Error creating address book descriptor for eudora\n"); - return( rv); - } - - return( NS_OK); -} - - -void nsEudoraWin32::ConvertPath( nsCString& str) -{ - nsCString temp; - nsCString path; - PRInt32 idx = 0; - PRInt32 start = 0; - nsCString search; - - idx = str.FindChar( '\\', idx); - if ((idx == 2) && (str.CharAt( 1) == ':')) { - str.Left( path, 3); - idx++; - idx = str.FindChar( '\\', idx); - start = 3; - if ((idx == -1) && (str.Length() > 3)) { - str.Right( temp, str.Length() - start); - path.Append( temp); - } - } - - WIN32_FIND_DATA findFileData; - while (idx != -1) { - str.Mid( temp, start, idx - start); - search = path; - search.Append( temp); - HANDLE h = FindFirstFile( search.get(), &findFileData); - if (h == INVALID_HANDLE_VALUE) - return; - path.Append( findFileData.cFileName); - idx++; - start = idx; - idx = str.FindChar( '\\', idx); - FindClose( h); - if (idx != -1) - path.Append( '\\'); - else { - str.Right( temp, str.Length() - start); - path.Append( '\\'); - path.Append( temp); - } - } - - str = path; -} - + + if (exists && isFile) { + if (NS_FAILED( rv = FoundAddressBook( file, displayName.get(), *ppArray, impSvc))) + return( rv); + } + + // Try the default directory + rv = rv = file->InitWithFile( localRoot); + if (NS_FAILED( rv)) + return( rv); + rv = file->AppendNative(NS_LITERAL_CSTRING("Nickname")); + PRBool isDir = PR_FALSE; + exists = PR_FALSE; + if (NS_SUCCEEDED( rv)) + rv = file->Exists( &exists); + if (NS_SUCCEEDED( rv) && exists) + rv = file->IsDirectory( &isDir); + if (exists && isDir) { + if (NS_FAILED( rv = ScanAddressDir(file, *ppArray, impSvc))) + return( rv); + } + + // Try the ini file to find other directories! + rv = rv = file->InitWithFile( localRoot); + if (NS_FAILED( rv)) + return( rv); + rv = file->AppendNative(NS_LITERAL_CSTRING("eudora.ini")); + exists = PR_FALSE; + isFile = PR_FALSE; + if (NS_SUCCEEDED( rv)) + rv = file->Exists( &exists); + if (NS_SUCCEEDED( rv) && exists) + rv = file->IsFile( &isFile); + + if (!isFile || !exists) { + rv = file->InitWithFile( localRoot); + if (NS_FAILED( rv)) + return( NS_OK); + if (!FindMimeIniFile(file)) + return( NS_OK); + } + + nsCString fileName; + file->GetNativePath(fileName); + // This is the supposed ini file name! + // Get the extra directories for nicknames and parse it for valid nickname directories + // to look into... + char *pBuffer = new char[2048]; + DWORD len = ::GetPrivateProfileString( "Settings", "ExtraNicknameDirs", "", pBuffer, 2048, fileName.get()); + if (len == 2047) { + // If the value is really that large then don't bother! + delete [] pBuffer; + return( NS_OK); + } + nsCString dirs(pBuffer); + delete [] pBuffer; + dirs.Trim( kWhitespace); + PRInt32 idx = 0; + nsCString currentDir; + while ((idx = dirs.FindChar( ';')) != -1) { + dirs.Left( currentDir, idx); + currentDir.Trim( kWhitespace); + if (!currentDir.IsEmpty()) { + rv = file->InitWithNativePath(currentDir); + exists = PR_FALSE; + isDir = PR_FALSE; + if (NS_SUCCEEDED( rv)) + rv = file->Exists( &exists); + if (NS_SUCCEEDED( rv) && exists) + rv = file->IsDirectory( &isDir); + if (exists && isDir) { + if (NS_FAILED( rv = ScanAddressDir(file, *ppArray, impSvc))) + return( rv); + } + } + dirs.Right( currentDir, dirs.Length() - idx - 1); + dirs = currentDir; + dirs.Trim( kWhitespace); + } + if (!dirs.IsEmpty()) { + rv = file->InitWithNativePath(dirs); + exists = PR_FALSE; + isDir = PR_FALSE; + if (NS_SUCCEEDED( rv)) + rv = file->Exists( &exists); + if (NS_SUCCEEDED( rv) && exists) + rv = file->IsDirectory( &isDir); + if (exists && isDir) { + if (NS_FAILED( rv = ScanAddressDir(file, *ppArray, impSvc))) + return( rv); + } + } + + return( NS_OK); +} + + +nsresult nsEudoraWin32::ScanAddressDir( nsIFile *pDir, nsISupportsArray *pArray, nsIImportService *impSvc) +{ + PRBool hasMore; + nsCOMPtr directoryEnumerator; + nsresult rv = pDir->GetDirectoryEntries(getter_AddRefs(directoryEnumerator)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr pLocalFile = do_QueryInterface(pDir, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + directoryEnumerator->HasMoreElements(&hasMore); + PRBool isFile; + nsCOMPtr entry; + nsCString fName; + nsCString ext; + nsCString name; + + PRBool found = PR_FALSE; + + while (hasMore && NS_SUCCEEDED(rv)) + { + nsCOMPtr aSupport; + rv = directoryEnumerator->GetNext(getter_AddRefs(aSupport)); + nsCOMPtr entry(do_QueryInterface(aSupport, &rv)); + directoryEnumerator->HasMoreElements(&hasMore); + + if (NS_SUCCEEDED( rv)) { + rv = entry->GetNativeLeafName(fName); + if (NS_SUCCEEDED( rv) && !fName.IsEmpty()) { + if (fName.Length() > 4) { + fName.Right( ext, 4); + fName.Left( name, fName.Length() - 4); + } + else { + ext.Truncate(); + name = fName; + } + ToLowerCase(ext); + if (ext.EqualsLiteral(".txt")) { + isFile = PR_FALSE; + entry->IsFile( &isFile); + if (isFile) { + rv = FoundAddressBook( entry, nsnull, pArray, impSvc); + if (NS_FAILED( rv)) + return( rv); + } + } + } + } + } + + return( rv); +} + + +nsresult nsEudoraWin32::FoundAddressBook( nsIFile *file, const PRUnichar *pName, nsISupportsArray *pArray, nsIImportService *impSvc) +{ + nsCOMPtr desc; + nsISupports * pInterface; + nsString name; + nsresult rv; + + if (pName) + name = pName; + else { + nsAutoString leaf; + rv = file->GetLeafName(leaf); + if (NS_FAILED( rv)) + return( rv); + if (leaf.IsEmpty()) + return( NS_ERROR_FAILURE); + nsString tStr; + leaf.Right( tStr, 4); + if (tStr.LowerCaseEqualsLiteral(".txt") || tStr.LowerCaseEqualsLiteral(".nnt")) { + leaf.Left( tStr, leaf.Length() - 4); + leaf = tStr; + } + } + + nsCOMPtr fileLoc = do_QueryInterface(file, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = impSvc->CreateNewABDescriptor( getter_AddRefs( desc)); + if (NS_SUCCEEDED( rv)) { + PRInt64 sz = 0; + file->GetFileSize( &sz); + desc->SetPreferredName(name); + desc->SetSize((PRUint32) sz); + desc->SetAbFile(fileLoc); + rv = desc->QueryInterface( kISupportsIID, (void **) &pInterface); + pArray->AppendElement( pInterface); + pInterface->Release(); + } + if (NS_FAILED( rv)) { + IMPORT_LOG0( "*** Error creating address book descriptor for eudora\n"); + return( rv); + } + + return( NS_OK); +} + + +void nsEudoraWin32::ConvertPath( nsCString& str) +{ + nsCString temp; + nsCString path; + PRInt32 idx = 0; + PRInt32 start = 0; + nsCString search; + + idx = str.FindChar( '\\', idx); + if ((idx == 2) && (str.CharAt( 1) == ':')) { + str.Left( path, 3); + idx++; + idx = str.FindChar( '\\', idx); + start = 3; + if ((idx == -1) && (str.Length() > 3)) { + str.Right( temp, str.Length() - start); + path.Append( temp); + } + } + + WIN32_FIND_DATA findFileData; + while (idx != -1) { + str.Mid( temp, start, idx - start); + search = path; + search.Append( temp); + HANDLE h = FindFirstFile( search.get(), &findFileData); + if (h == INVALID_HANDLE_VALUE) + return; + path.Append( findFileData.cFileName); + idx++; + start = idx; + idx = str.FindChar( '\\', idx); + FindClose( h); + if (idx != -1) + path.Append( '\\'); + else { + str.Right( temp, str.Length() - start); + path.Append( '\\'); + path.Append( temp); + } + } + + str = path; +} +