nsresult nsOutlookMail::ImportMailbox(uint32_t *pDoneSoFar, bool *pAbort,
                                      int32_t index, const PRUnichar *pName,
                                      nsIMsgFolder *dstFolder,
                                      int32_t *pMsgCount)
{
  if ((index < 0) || (index >= m_folderList.GetSize())) {
    IMPORT_LOG0("*** Bad mailbox identifier, unable to import\n");
    *pAbort = true;
    return NS_ERROR_FAILURE;
  }

  int32_t    dummyMsgCount = 0;
  if (pMsgCount)
    *pMsgCount = 0;
  else
    pMsgCount = &dummyMsgCount;

  CMapiFolder *pFolder = m_folderList.GetItem(index);
  OpenMessageStore(pFolder);
  if (!m_lpMdb) {
    IMPORT_LOG1("*** Unable to obtain mapi message store for mailbox: %S\n", pName);
    return NS_ERROR_FAILURE;
  }

  if (pFolder->IsStore())
    return NS_OK;

  // now what?
  CMapiFolderContents    contents(m_lpMdb, pFolder->GetCBEntryID(), pFolder->GetEntryID());

  BOOL    done = FALSE;
  ULONG    cbEid;
  LPENTRYID  lpEid;
  ULONG    oType;
  LPMESSAGE  lpMsg = nullptr;
  ULONG    totalCount;
  double  doneCalc;

  nsCOMPtr<nsIOutputStream> outputStream;
  nsCOMPtr<nsIMsgPluggableStore> msgStore;
  nsresult rv = dstFolder->GetMsgStore(getter_AddRefs(msgStore));
  NS_ENSURE_SUCCESS(rv, rv);

  while (!done) {
    if (!contents.GetNext(&cbEid, &lpEid, &oType, &done)) {
      IMPORT_LOG1("*** Error iterating mailbox: %S\n", pName);
      return NS_ERROR_FAILURE;
    }

    nsCOMPtr<nsIMsgDBHdr> msgHdr;
    bool reusable;

    rv = msgStore->GetNewMsgOutputStream(dstFolder, getter_AddRefs(msgHdr), &reusable,
                                         getter_AddRefs(outputStream));
    totalCount = contents.GetCount();
    doneCalc = *pMsgCount;
    doneCalc /= totalCount;
    doneCalc *= 1000;
    if (pDoneSoFar) {
      *pDoneSoFar = (uint32_t) doneCalc;
      if (*pDoneSoFar > 1000)
        *pDoneSoFar = 1000;
    }

    if (!done && (oType == MAPI_MESSAGE)) {
      if (!m_mapi.OpenMdbEntry(m_lpMdb, cbEid, lpEid, (LPUNKNOWN *) &lpMsg)) {
        IMPORT_LOG1("*** Error opening messages in mailbox: %S\n", pName);
        return NS_ERROR_FAILURE;
      }

      // See if it's a drafts folder. Outlook doesn't allow drafts
      // folder to be configured so it's ok to hard code it here.
      nsAutoString folderName(pName);
      nsMsgDeliverMode mode = nsIMsgSend::nsMsgDeliverNow;
      mode = nsIMsgSend::nsMsgSaveAsDraft;
      if (folderName.LowerCaseEqualsLiteral("drafts"))
        mode = nsIMsgSend::nsMsgSaveAsDraft;

      rv = ImportMessage(lpMsg, outputStream, mode);
      if (NS_SUCCEEDED(rv)){ // No errors & really imported
         (*pMsgCount)++;
        msgStore->FinishNewMessage(outputStream, msgHdr);
      }
      else {
        IMPORT_LOG1( "*** Error reading message from mailbox: %S\n", pName);
        msgStore->DiscardNewMessage(outputStream, msgHdr);
      }
      if (!reusable)
        outputStream->Close();
    }
  }

  if (outputStream)
    outputStream->Close();
  return NS_OK;
}
nsresult nsEudoraMailbox::ImportMailboxUsingTOC(
  uint32_t *pBytes,
  bool *pAbort,
  nsIInputStream *pInputStream,
  nsIFile *tocFile,
  nsIMsgFolder *dstFolder,
  int32_t *pMsgCount)
{
  nsresult        rv = NS_OK;

  int64_t  mailSize = m_mailSize;
  int64_t  tocSize = 0;
  uint32_t  saveBytes = pBytes ? *pBytes : 0;
  nsCOMPtr <nsIInputStream> tocInputStream;

  rv = tocFile->GetFileSize(&tocSize);

  // if the index or the mail file is empty then just
  // use the original mail file.
  if (!mailSize || !tocSize)
    return NS_ERROR_FAILURE;
  rv = NS_NewLocalFileInputStream(getter_AddRefs(tocInputStream), tocFile);
  NS_ENSURE_SUCCESS(rv, rv);

  SimpleBufferTonyRCopiedOnce readBuffer;
  SimpleBufferTonyRCopiedOnce headers;
  SimpleBufferTonyRCopiedOnce body;
  SimpleBufferTonyRCopiedOnce copy;
  int32_t tocOffset = kMsgFirstOffset;
  EudoraTOCEntry tocEntry;

  copy.Allocate(kCopyBufferSize);
  readBuffer.Allocate(kMailReadBufferSize);

  IMPORT_LOG0("Importing mailbox using TOC: ");
  DUMP_FILENAME(tocFile, true);

  nsCOMPtr<nsISeekableStream> tocSeekableStream = do_QueryInterface(tocInputStream);
  nsCOMPtr<nsISeekableStream> mailboxSeekableStream = do_QueryInterface(pInputStream);
  nsCOMPtr<nsIOutputStream> outputStream;
  nsCOMPtr<nsIMsgPluggableStore> msgStore;

  rv = dstFolder->GetMsgStore(getter_AddRefs(msgStore));
  NS_ENSURE_SUCCESS(rv, rv);

  while (!*pAbort && (tocOffset < (int32_t)tocSize)) {
    if (NS_FAILED(rv = tocSeekableStream->Seek(nsISeekableStream::NS_SEEK_SET, tocOffset)))
      break;

    if (NS_FAILED(rv = ReadTOCEntry(tocInputStream, tocEntry)))
      break;

    nsCOMPtr<nsIMsgDBHdr> msgHdr;
    bool reusable;

    rv = msgStore->GetNewMsgOutputStream(dstFolder, getter_AddRefs(msgHdr), &reusable,
                                         getter_AddRefs(outputStream));
    if (NS_FAILED(rv))
      break;

    // Quick and dirty way to read in and parse the message the way the rest
    // of the code expects.
    nsCString              defaultDate;
    nsAutoCString            bodyType;
    ReadFileState            state;

    // Seek to the start of the email message.
    mailboxSeekableStream->Seek(nsISeekableStream::NS_SEEK_SET, tocEntry.m_Offset);

    // We're fudging the data to make ReadNextMessage happy. In particular
    // state.size is meant to be the size of the entire file, because it's
    // assumed that ReadNextMessage will actually have to parse. We know
    // exactly how big the message is, so we simply set the "size" to be
    // immediately where the message ends.
    state.offset = tocEntry.m_Offset;
    state.pInputStream = pInputStream;
    state.size = state.offset + tocEntry.m_Length;

    if (NS_SUCCEEDED(rv = ReadNextMessage(&state, readBuffer, headers, body, defaultDate, bodyType, &tocEntry)))
    {
      rv = ImportMessage(headers, body, defaultDate, bodyType, outputStream,
                         pMsgCount);

      if (pBytes)
        *pBytes += tocEntry.m_Length;
      if (NS_SUCCEEDED(rv))
        msgStore->FinishNewMessage(outputStream, msgHdr);
      else {
        msgStore->DiscardNewMessage(outputStream, msgHdr);
        IMPORT_LOG0( "*** Error importing message\n");
      }
    }

    // We currently don't consider an error from ReadNextMessage or ImportMessage to be fatal.
    // Reset the error back to no error in case this is the last time through the loop.
    rv = NS_OK;

    tocOffset += kMsgHeaderSize;

    if (!reusable)
      outputStream->Close();
  }
  if (outputStream)
    outputStream->Close();

  if (NS_SUCCEEDED(rv)) {
    IMPORT_LOG0(" finished\n");
  }
  else {
    // We failed somewhere important enough that we kept the error.
    // Bail on all that we imported since we'll be importing everything
    // again using just the mailbox.
    IMPORT_LOG0("*** Error importing mailbox using TOC: ");
//    DUMP_FILENAME(pMail, true);

    // Reset pBytes back to where it was before we imported this mailbox.
    // This will likely result in a funky progress bar which will move
    // backwards, but that's probably the best we can do to keep the
    // progress accurate since we'll be re-importing the same mailbox.
    if (pBytes)
      *pBytes = saveBytes;

    // Set the message count back to 0.
    if (pMsgCount)
      *pMsgCount = 0;
  }

  return rv;
}
示例#3
0
nsresult nsOutlookMail::ImportMailbox( PRUint32 *pDoneSoFar, bool *pAbort, PRInt32 index, const PRUnichar *pName, nsIFile *pDest, PRInt32 *pMsgCount)
{
    if ((index < 0) || (index >= m_folderList.GetSize())) {
        IMPORT_LOG0( "*** Bad mailbox identifier, unable to import\n");
        *pAbort = PR_TRUE;
        return( NS_ERROR_FAILURE);
    }

    PRInt32    dummyMsgCount = 0;
    if (pMsgCount)
        *pMsgCount = 0;
    else
        pMsgCount = &dummyMsgCount;

    CMapiFolder *pFolder = m_folderList.GetItem( index);
    OpenMessageStore( pFolder);
    if (!m_lpMdb) {
        IMPORT_LOG1( "*** Unable to obtain mapi message store for mailbox: %S\n", pName);
        return( NS_ERROR_FAILURE);
    }

    if (pFolder->IsStore())
        return( NS_OK);

    nsresult  rv;

    // now what?
    CMapiFolderContents    contents( m_lpMdb, pFolder->GetCBEntryID(), pFolder->GetEntryID());

    BOOL    done = FALSE;
    ULONG    cbEid;
    LPENTRYID  lpEid;
    ULONG    oType;
    LPMESSAGE  lpMsg = nsnull;
    ULONG    totalCount;
    PRFloat64  doneCalc;

    nsCOMPtr<nsIOutputStream> destOutputStream;
    rv = MsgNewBufferedFileOutputStream(getter_AddRefs(destOutputStream), pDest, -1, 0600);
    NS_ENSURE_SUCCESS(rv, rv);

    while (!done) {
        if (!contents.GetNext( &cbEid, &lpEid, &oType, &done)) {
            IMPORT_LOG1( "*** Error iterating mailbox: %S\n", pName);
            return( NS_ERROR_FAILURE);
        }

        totalCount = contents.GetCount();
        doneCalc = *pMsgCount;
        doneCalc /= totalCount;
        doneCalc *= 1000;
        if (pDoneSoFar) {
            *pDoneSoFar = (PRUint32) doneCalc;
            if (*pDoneSoFar > 1000)
                *pDoneSoFar = 1000;
        }

        if (!done && (oType == MAPI_MESSAGE)) {
            if (!m_mapi.OpenMdbEntry( m_lpMdb, cbEid, lpEid, (LPUNKNOWN *) &lpMsg)) {
                IMPORT_LOG1( "*** Error opening messages in mailbox: %S\n", pName);
                return( NS_ERROR_FAILURE);
            }

            // See if it's a drafts folder. Outlook doesn't allow drafts
            // folder to be configured so it's ok to hard code it here.
            nsAutoString folderName(pName);
            nsMsgDeliverMode mode = nsIMsgSend::nsMsgDeliverNow;
            mode = nsIMsgSend::nsMsgSaveAsDraft;
            if ( folderName.LowerCaseEqualsLiteral("drafts") )
                mode = nsIMsgSend::nsMsgSaveAsDraft;

            rv = ImportMessage(lpMsg, destOutputStream, mode);
            if (NS_SUCCEEDED( rv)) // No errors & really imported
                (*pMsgCount)++;
            else {
                IMPORT_LOG1( "*** Error reading message from mailbox: %S\n", pName);
            }
        }
    }

    return( NS_OK);
}
nsresult nsEudoraMailbox::ImportMailbox(uint32_t *pBytes, bool *pAbort,
                                        const PRUnichar *pName, nsIFile *pSrc,
                                        nsIMsgFolder *dstFolder,
                                        int32_t *pMsgCount)
{
  nsCOMPtr<nsIFile>   tocFile;
  nsCOMPtr<nsIInputStream> srcInputStream;
  nsCOMPtr<nsIInputStream> tocInputStream;
  nsCOMPtr<nsIOutputStream> mailOutputStream;
  bool                importWithoutToc = true;
  bool                deleteToc = false;
  nsCOMPtr<nsIFile>   mailFile;

  if (pMsgCount)
    *pMsgCount = 0;

  nsresult rv = pSrc->GetFileSize(&m_mailSize);

  rv = NS_NewLocalFileInputStream(getter_AddRefs(srcInputStream), pSrc);
  NS_ENSURE_SUCCESS(rv, rv);

  nsCOMPtr<nsIFile> srcFile(pSrc);

  // First, get the index file for this mailbox
  rv = FindTOCFile(pSrc, getter_AddRefs(tocFile), &deleteToc);
  if (NS_SUCCEEDED(rv) && tocFile)
  {
    IMPORT_LOG0("Reading euroda toc file: ");
    DUMP_FILENAME(tocFile, true);

    // Read the toc and import the messages
    rv = ImportMailboxUsingTOC(pBytes, pAbort, srcInputStream, tocFile,
                               dstFolder, pMsgCount);

    // clean up
    if (deleteToc)
      DeleteFile(tocFile);

    // If we were able to import with the TOC, then we don't need to bother
    // importing without the TOC.
    if (NS_SUCCEEDED(rv)) {
      importWithoutToc = false;
      IMPORT_LOG0("Imported mailbox: "); DUMP_FILENAME(pSrc, false);
      IMPORT_LOG0("  Using TOC: "); DUMP_FILENAME(tocFile, true);
    }
    else {
      IMPORT_LOG0("*** Error importing with TOC - will import without TOC.\n");
    }
  }

  // pSrc must be Released before returning

  if (importWithoutToc) {
    // The source file contains partially constructed mail messages,
    // and attachments.  We should first investigate if we can use the mailnews msgCompose
    // stuff to do the work for us.  If not we have to scan the mailboxes and do TONS
    // of work to properly reconstruct the message - Eudora is so nice that it strips things
    // like MIME headers, character encoding, and attachments - beautiful!

    rv = pSrc->GetFileSize(&m_mailSize);

    SimpleBufferTonyRCopiedOnce    readBuffer;
    SimpleBufferTonyRCopiedOnce    headers;
    SimpleBufferTonyRCopiedOnce    body;
    SimpleBufferTonyRCopiedOnce    copy;

    headers.m_convertCRs = true;
    body.m_convertCRs = true;

    copy.Allocate(kCopyBufferSize);
    readBuffer.Allocate(kMailReadBufferSize);
    ReadFileState      state;
    state.offset = 0;
    state.size = m_mailSize;
    state.pFile = pSrc;

    IMPORT_LOG0("Reading mailbox\n");

    if (NS_SUCCEEDED(rv))
    {
      nsCString defaultDate;
      nsAutoCString bodyType;

      IMPORT_LOG0("Reading first message\n");

      nsCOMPtr<nsIOutputStream> outputStream;
      nsCOMPtr<nsIMsgPluggableStore> msgStore;
      rv = dstFolder->GetMsgStore(getter_AddRefs(msgStore));
      NS_ENSURE_SUCCESS(rv, rv);

      while (!*pAbort && NS_SUCCEEDED(rv = ReadNextMessage( &state, readBuffer, headers, body, defaultDate, bodyType, NULL))) {

        if (pBytes)
          *pBytes += body.m_writeOffset - 1 + headers.m_writeOffset - 1;

        nsCOMPtr<nsIMsgDBHdr> msgHdr;
        bool reusable;

        rv = msgStore->GetNewMsgOutputStream(dstFolder, getter_AddRefs(msgHdr), &reusable,
                                             getter_AddRefs(outputStream));
        if (NS_FAILED(rv))
          break;

        rv = ImportMessage(headers, body, defaultDate, bodyType, outputStream, pMsgCount);

        if (NS_SUCCEEDED(rv))
          msgStore->FinishNewMessage(outputStream, msgHdr);
        else {
          msgStore->DiscardNewMessage(outputStream, msgHdr);
          IMPORT_LOG0( "*** Error importing message\n");
        }

        if (!reusable)
          outputStream->Close();

        if (!readBuffer.m_bytesInBuf && (state.offset >= state.size))
          break;
      }
      if (outputStream)
        outputStream->Close();
    }
    else {
      IMPORT_LOG0("*** Error creating file spec for composition\n");
    }
  }
  return rv;
}
nsresult nsEudoraMailbox::ImportMailboxUsingTOC(
  PRUint32 *pBytes,
  PRBool *pAbort,
  nsIInputStream *pInputStream,
  nsIFile *tocFile,
  nsIOutputStream *pDst,
  PRInt32 *pMsgCount)
{
  nsresult        rv = NS_OK;

  PRInt64  mailSize = m_mailSize;
  PRInt64  tocSize = 0;
  PRUint32  saveBytes = pBytes ? *pBytes : 0;
  nsCOMPtr <nsIInputStream> tocInputStream;

  rv = tocFile->GetFileSize( &tocSize);

  // if the index or the mail file is empty then just
  // use the original mail file.
  if (!mailSize || !tocSize)
    return NS_ERROR_FAILURE;
  rv = NS_NewLocalFileInputStream(getter_AddRefs(tocInputStream), tocFile);
  NS_ENSURE_SUCCESS(rv, rv);

  SimpleBufferTonyRCopiedOnce readBuffer;
  SimpleBufferTonyRCopiedOnce headers;
  SimpleBufferTonyRCopiedOnce body;
  SimpleBufferTonyRCopiedOnce copy;
  PRInt32 tocOffset = kMsgFirstOffset;
  EudoraTOCEntry tocEntry;

  copy.Allocate( kCopyBufferSize);
  readBuffer.Allocate(kMailReadBufferSize);

  IMPORT_LOG0( "Importing mailbox using TOC: ");
  DUMP_FILENAME( tocFile, PR_TRUE);

  nsCOMPtr <nsISeekableStream> tocSeekableStream = do_QueryInterface(tocInputStream);
  nsCOMPtr <nsISeekableStream> mailboxSeekableStream = do_QueryInterface(pInputStream);
  while (!*pAbort && (tocOffset < (PRInt32)tocSize)) {
    if ( NS_FAILED(rv = tocSeekableStream->Seek(nsISeekableStream::NS_SEEK_SET, tocOffset)) )
      break;

    if ( NS_FAILED(rv = ReadTOCEntry(tocInputStream, tocEntry)) )
      break;

    // Quick and dirty way to read in and parse the message the way the rest
    // of the code expects.
    nsCString              defaultDate;
    nsCAutoString            bodyType;
    ReadFileState            state;

    // Seek to the start of the email message.
    mailboxSeekableStream->Seek(nsISeekableStream::NS_SEEK_SET, tocEntry.m_Offset);

    // We're fudging the data to make ReadNextMessage happy. In particular
    // state.size is meant to be the size of the entire file, because it's
    // assumed that ReadNextMessage will actually have to parse. We know
    // exactly how big the message is, so we simply set the "size" to be
    // immediately where the message ends.
    state.offset = tocEntry.m_Offset;
    state.pInputStream = pInputStream;
    state.size = state.offset + tocEntry.m_Length;

    if ( NS_SUCCEEDED(rv = ReadNextMessage(&state, readBuffer, headers, body, defaultDate, bodyType, &tocEntry) ) )
    {
      rv = ImportMessage(headers, body, defaultDate, bodyType, pDst, pMsgCount);

      if (pBytes)
        *pBytes += tocEntry.m_Length;
    }

    // We currently don't consider an error from ReadNextMessage or ImportMessage to be fatal.
    // Reset the error back to no error in case this is the last time through the loop.
    rv = NS_OK;

    tocOffset += kMsgHeaderSize;
  }

  if ( NS_SUCCEEDED(rv) ) {
    IMPORT_LOG0( " finished\n");
  }
  else {
    // We failed somewhere important enough that we kept the error.
    // Bail on all that we imported since we'll be importing everything
    // again using just the mailbox.
    IMPORT_LOG0( "*** Error importing mailbox using TOC: ");
//    DUMP_FILENAME(pMail, PR_TRUE);

    // Close the destination and truncate it. We don't need to bother
    // to reopen it because the nsIFileSpec implementation will open
    // before writing if necessary (and yes legacy importing code already
    // relies on this behavior).
//    pDst->CloseStream();
//    pDst->Truncate(0);

    // Reset pBytes back to where it was before we imported this mailbox.
    // This will likely result in a funky progress bar which will move
    // backwards, but that's probably the best we can do to keep the
    // progress accurate since we'll be re-importing the same mailbox.
    if (pBytes)
      *pBytes = saveBytes;

    // Set the message count back to 0.
    if (pMsgCount)
      *pMsgCount = 0;
  }

  return rv;
}