Back to index

lightning-sunbird  0.9+nobinonly
nsImportMail.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 /*
00040 */
00041 
00042 #ifdef MOZ_LOGGING
00043 // sorry, this has to be before the pre-compiled header
00044 #define FORCE_PR_LOG /* Allow logging in the release build */
00045 #endif
00046 
00047 #include "prthread.h"
00048 #include "prprf.h"
00049 #include "nscore.h"
00050 #include "nsCOMPtr.h"
00051 #include "nsISupportsArray.h"
00052 
00053 #include "nsIImportMail.h"
00054 #include "nsIImportGeneric.h"
00055 #include "nsXPCOM.h"
00056 #include "nsISupportsPrimitives.h"
00057 #include "nsIImportMailboxDescriptor.h"
00058 #include "nsCRT.h"
00059 #include "nsString.h"
00060 #include "nsUnicharUtils.h"
00061 #include "nsIProxyObjectManager.h"
00062 #include "nsXPIDLString.h"
00063 
00064 #include "nsIFileSpec.h"
00065 
00066 #include "nsIMsgAccountManager.h"
00067 #include "nsIMessengerMigrator.h"
00068 #include "nsIMsgMailSession.h"
00069 #include "nsMsgBaseCID.h"
00070 #include "nsIMsgFolder.h"
00071 #include "nsImportStringBundle.h"
00072 #include "nsIStringBundle.h"
00073 #include "nsTextFormatter.h"
00074 
00075 #include "nsIImportService.h"
00076 
00077 #include "ImportDebug.h"
00078 
00079 #define IMPORT_MSGS_URL       "chrome://messenger/locale/importMsgs.properties"
00080 
00081 static NS_DEFINE_CID(kProxyObjectManagerCID, NS_PROXYEVENT_MANAGER_CID);
00082 static NS_DEFINE_CID(kSupportsWStringCID, NS_SUPPORTS_STRING_CID);
00083 
00085 
00086 PR_STATIC_CALLBACK( void) ImportMailThread( void *stuff);
00087 
00088 static nsCOMPtr<nsIImportService>  gService;
00089 
00090 class ImportThreadData;
00091 
00092 class nsImportGenericMail : public nsIImportGeneric
00093 {
00094 public:
00095 
00096        nsImportGenericMail();
00097        virtual ~nsImportGenericMail();
00098        
00099        NS_DECL_ISUPPORTS
00100 
00101        /* nsISupports GetData (in string dataId); */
00102        NS_IMETHOD GetData(const char *dataId, nsISupports **_retval);
00103 
00104        NS_IMETHOD SetData(const char *dataId, nsISupports *pData);
00105 
00106        NS_IMETHOD GetStatus( const char *statusKind, PRInt32 *_retval);
00107 
00108        /* boolean WantsProgress (); */
00109        NS_IMETHOD WantsProgress(PRBool *_retval);
00110 
00111     /* boolean BeginImport (in nsISupportsString successLog, in nsISupportsString errorLog, in boolean isAddrLocHome); */
00112     NS_IMETHODIMP BeginImport(nsISupportsString *successLog, nsISupportsString *errorLog, PRBool isAddrLocHome, PRBool *_retval) ;
00113 
00114        /* boolean ContinueImport (); */
00115        NS_IMETHOD ContinueImport(PRBool *_retval);
00116 
00117        /* long GetProgress (); */
00118        NS_IMETHOD GetProgress(PRInt32 *_retval);
00119 
00120        /* void CancelImport (); */
00121        NS_IMETHOD CancelImport(void);
00122 
00123 private:
00124        PRBool CreateFolder( nsIMsgFolder **ppFolder);
00125        void   GetDefaultMailboxes( void);
00126        void   GetDefaultLocation( void);
00127        void   GetDefaultDestination( void);
00128        void   GetMailboxName( PRUint32 index, nsISupportsString *pStr);
00129 
00130 public:
00131        static void   SetLogs( nsString& success, nsString& error, nsISupportsString *pSuccess, nsISupportsString *pError);
00132        static void ReportError( PRInt32 id, const PRUnichar *pName, nsString *pStream);
00133 
00134 private:
00135        nsString                    m_pName;      // module name that created this interface
00136        nsIMsgFolder *              m_pDestFolder;
00137        PRBool                      m_deleteDestFolder;
00138        PRBool                      m_createdFolder;
00139        nsCOMPtr <nsIFileSpec> m_pSrcLocation;
00140        PRBool                      m_gotLocation;
00141        PRBool                      m_found;
00142        PRBool                      m_userVerify;
00143        nsIImportMail *             m_pInterface;
00144        nsISupportsArray *   m_pMailboxes;
00145        nsISupportsString *m_pSuccessLog;
00146        nsISupportsString *m_pErrorLog;
00147        PRUint32                    m_totalSize;
00148        PRBool                      m_doImport;
00149        ImportThreadData *   m_pThreadData;
00150     PRBool        m_performingMigration;
00151 };
00152 
00153 class ImportThreadData {
00154 public:
00155        PRBool                             driverAlive;
00156        PRBool                             threadAlive;
00157        PRBool                             abort;
00158        PRBool                             fatalError;
00159        PRUint32                           currentTotal;
00160        PRUint32                           currentSize;
00161        nsIMsgFolder *                     destRoot;
00162        PRBool                             ownsDestRoot;
00163        nsISupportsArray *          boxes;
00164        nsIImportMail *                    mailImport;
00165        nsISupportsString *  successLog;
00166        nsISupportsString *  errorLog;
00167        PRUint32                           currentMailbox;
00168     PRBool          performingMigration;
00169 
00170        ImportThreadData();
00171        ~ImportThreadData();
00172        void DriverDelete();
00173        void ThreadDelete();
00174        void DriverAbort();
00175 };
00176 
00177 
00178 nsresult NS_NewGenericMail(nsIImportGeneric** aImportGeneric)
00179 {
00180     NS_PRECONDITION(aImportGeneric != nsnull, "null ptr");
00181     if (! aImportGeneric)
00182         return NS_ERROR_NULL_POINTER;
00183        
00184        nsImportGenericMail *pGen = new nsImportGenericMail();
00185 
00186        if (pGen == nsnull)
00187               return NS_ERROR_OUT_OF_MEMORY;
00188 
00189        NS_ADDREF( pGen);
00190        nsresult rv = pGen->QueryInterface( NS_GET_IID(nsIImportGeneric), (void **)aImportGeneric);
00191        NS_RELEASE( pGen);
00192     
00193     return( rv);
00194 }
00195 
00196 nsImportGenericMail::nsImportGenericMail()
00197 {
00198        m_found = PR_FALSE;
00199        m_userVerify = PR_FALSE;
00200        m_gotLocation = PR_FALSE;
00201        m_pInterface = nsnull;
00202        m_pMailboxes = nsnull;
00203        m_pSuccessLog = nsnull;
00204        m_pErrorLog = nsnull;
00205        m_totalSize = 0;
00206        m_doImport = PR_FALSE;
00207        m_pThreadData = nsnull;
00208 
00209        m_pDestFolder = nsnull;
00210        m_deleteDestFolder = PR_FALSE;
00211        m_createdFolder = PR_FALSE;
00212     m_performingMigration = PR_FALSE;
00213 
00214   // Init logging module.
00215   if (!IMPORTLOGMODULE)
00216     IMPORTLOGMODULE = PR_NewLogModule("IMPORT");
00217 }
00218 
00219 
00220 nsImportGenericMail::~nsImportGenericMail()
00221 {
00222        if (m_pThreadData) {
00223               m_pThreadData->DriverAbort();
00224               m_pThreadData = nsnull;
00225        }
00226        
00227        NS_IF_RELEASE( m_pDestFolder);
00228        NS_IF_RELEASE( m_pInterface);
00229        NS_IF_RELEASE( m_pMailboxes);
00230        NS_IF_RELEASE( m_pSuccessLog);
00231        NS_IF_RELEASE( m_pErrorLog);
00232 }
00233 
00234 
00235 
00236 NS_IMPL_THREADSAFE_ISUPPORTS1(nsImportGenericMail, nsIImportGeneric)
00237 
00238 
00239 NS_IMETHODIMP nsImportGenericMail::GetData(const char *dataId, nsISupports **_retval)
00240 {
00241        nsresult rv = NS_OK;
00242 
00243     NS_PRECONDITION(_retval != nsnull, "null ptr");
00244        if (!_retval)
00245               return NS_ERROR_NULL_POINTER;
00246        
00247        *_retval = nsnull;
00248        if (!nsCRT::strcasecmp( dataId, "mailInterface")) {
00249               *_retval = m_pInterface;
00250               NS_IF_ADDREF( m_pInterface);
00251        }
00252        
00253        if (!nsCRT::strcasecmp( dataId, "mailBoxes")) {
00254               if (!m_pMailboxes)
00255                      GetDefaultMailboxes();
00256               *_retval = m_pMailboxes;
00257               NS_IF_ADDREF( m_pMailboxes);
00258        }
00259 
00260        if (!nsCRT::strcasecmp( dataId, "mailLocation")) {
00261               if (!m_pSrcLocation)
00262                      GetDefaultLocation();
00263               NS_IF_ADDREF(*_retval = m_pSrcLocation);
00264        }
00265        
00266        if (!nsCRT::strcasecmp( dataId, "mailDestination")) {
00267               if (!m_pDestFolder)
00268                      GetDefaultDestination();
00269               *_retval = m_pDestFolder;
00270               NS_IF_ADDREF( m_pDestFolder);
00271        }
00272        
00273        if (!nsCRT::strcasecmp( dataId, "migration")) {
00274         nsCOMPtr<nsISupportsPRBool> migrationString = do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID, &rv);
00275         NS_ENSURE_SUCCESS(rv, rv);
00276         migrationString->SetData(m_performingMigration);
00277         NS_IF_ADDREF( *_retval = migrationString);
00278        }
00279        
00280        if (!nsCRT::strcasecmp( dataId, "currentMailbox")) {
00281               // create an nsISupportsString, get the current mailbox
00282               // name being imported and put it in the string
00283               nsCOMPtr<nsISupportsString> data = do_CreateInstance( kSupportsWStringCID, &rv);
00284               if (NS_FAILED( rv))
00285                      return( rv);
00286               if (m_pThreadData) {
00287                      GetMailboxName( m_pThreadData->currentMailbox, data);
00288               }
00289               *_retval = data;
00290               NS_ADDREF( *_retval);
00291        }
00292 
00293        return( rv);
00294 }
00295 
00296 NS_IMETHODIMP nsImportGenericMail::SetData( const char *dataId, nsISupports *item)
00297 {
00298     nsresult rv = NS_OK;
00299        NS_PRECONDITION(dataId != nsnull, "null ptr");
00300     if (!dataId)
00301         return NS_ERROR_NULL_POINTER;
00302 
00303        if (!nsCRT::strcasecmp( dataId, "mailInterface")) {
00304               NS_IF_RELEASE( m_pInterface);
00305               if (item)
00306                      item->QueryInterface( NS_GET_IID(nsIImportMail), (void **) &m_pInterface);
00307        }
00308        if (!nsCRT::strcasecmp( dataId, "mailBoxes")) {
00309               NS_IF_RELEASE( m_pMailboxes);
00310               if (item)
00311                      item->QueryInterface( NS_GET_IID(nsISupportsArray), (void **) &m_pMailboxes);
00312        }
00313        
00314        if (!nsCRT::strcasecmp( dataId, "mailLocation")) {
00315               NS_IF_RELEASE( m_pMailboxes);
00316     m_pSrcLocation = nsnull;
00317     if (item) {
00318       nsresult rv;
00319       nsCOMPtr <nsILocalFile> location = do_QueryInterface(item, &rv);
00320       NS_ENSURE_SUCCESS(rv,rv);
00321       
00322       rv = NS_NewFileSpecFromIFile(location, getter_AddRefs(m_pSrcLocation));
00323       NS_ENSURE_SUCCESS(rv,rv);
00324     }
00325        }
00326        
00327        if (!nsCRT::strcasecmp( dataId, "mailDestination")) {
00328               NS_IF_RELEASE( m_pDestFolder);
00329               if (item)
00330                      item->QueryInterface( NS_GET_IID(nsIMsgFolder), (void **) &m_pDestFolder);
00331               m_deleteDestFolder = PR_FALSE;
00332        }
00333        
00334        if (!nsCRT::strcasecmp( dataId, "name")) {
00335               nsCOMPtr<nsISupportsString> nameString;
00336               if (item) {
00337                      item->QueryInterface( NS_GET_IID(nsISupportsString), getter_AddRefs(nameString));
00338                      rv = nameString->GetData(m_pName);
00339               }
00340        }
00341 
00342   if (!nsCRT::strcasecmp( dataId, "migration")) {
00343               nsCOMPtr<nsISupportsPRBool> migrationString;
00344               if (item) {
00345                      item->QueryInterface( NS_GET_IID(nsISupportsPRBool), getter_AddRefs(migrationString));
00346                      rv = migrationString->GetData(&m_performingMigration);
00347               }
00348        }
00349 
00350        return rv;
00351 }
00352 
00353 NS_IMETHODIMP nsImportGenericMail::GetStatus( const char *statusKind, PRInt32 *_retval)
00354 {
00355        NS_PRECONDITION(statusKind != nsnull, "null ptr");
00356        NS_PRECONDITION(_retval != nsnull, "null ptr");
00357        if (!statusKind || !_retval)
00358               return( NS_ERROR_NULL_POINTER);
00359        
00360        *_retval = 0;
00361 
00362        if (!nsCRT::strcasecmp( statusKind, "isInstalled")) {
00363               GetDefaultLocation();
00364               *_retval = (PRInt32) m_found;
00365        }
00366 
00367        if (!nsCRT::strcasecmp( statusKind, "canUserSetLocation")) {
00368               GetDefaultLocation();
00369               *_retval = (PRInt32) m_userVerify;
00370        }
00371 
00372        return( NS_OK);
00373 }
00374 
00375 
00376 void nsImportGenericMail::GetDefaultLocation( void)
00377 {
00378        if (!m_pInterface)
00379               return;
00380        
00381        if (m_pSrcLocation && m_gotLocation)
00382               return;
00383 
00384        m_gotLocation = PR_TRUE;
00385 
00386        nsIFileSpec * pLoc = nsnull;
00387        m_pInterface->GetDefaultLocation( &pLoc, &m_found, &m_userVerify);
00388        if (!m_pSrcLocation)
00389               m_pSrcLocation = pLoc;
00390        else {
00391               NS_IF_RELEASE( pLoc);
00392        }
00393 }
00394 
00395 void nsImportGenericMail::GetDefaultMailboxes( void)
00396 {
00397        if (!m_pInterface || m_pMailboxes || !m_pSrcLocation)
00398               return;
00399        
00400        m_pInterface->FindMailboxes( m_pSrcLocation, &m_pMailboxes);
00401 }
00402 
00403 void nsImportGenericMail::GetDefaultDestination( void)
00404 {
00405        if (m_pDestFolder)
00406               return;
00407        if (!m_pInterface)
00408               return;
00409 
00410        nsIMsgFolder *       rootFolder;
00411        m_deleteDestFolder = PR_FALSE;
00412        m_createdFolder = PR_FALSE;
00413        if (CreateFolder( &rootFolder)) {
00414               m_pDestFolder = rootFolder;
00415               m_deleteDestFolder = PR_TRUE;
00416               m_createdFolder = PR_TRUE;
00417               return;
00418        }
00419   IMPORT_LOG0("*** GetDefaultDestination: Failed to create a default import destination folder.");
00420 }
00421 
00422 NS_IMETHODIMP nsImportGenericMail::WantsProgress(PRBool *_retval)
00423 {
00424        NS_PRECONDITION(_retval != nsnull, "null ptr");
00425     if (!_retval)
00426         return NS_ERROR_NULL_POINTER;
00427        
00428        if (m_pThreadData) {
00429               m_pThreadData->DriverAbort();
00430               m_pThreadData = nsnull;
00431        }
00432 
00433        if (!m_pMailboxes) {
00434               GetDefaultLocation();
00435               GetDefaultMailboxes();
00436        }
00437 
00438        if (!m_pDestFolder) {
00439               GetDefaultDestination();
00440        }
00441 
00442        PRUint32             totalSize = 0;
00443        PRBool               result = PR_FALSE;
00444 
00445        if (m_pMailboxes) {
00446               PRUint32             i;
00447               PRBool               import;
00448               PRUint32             count = 0;
00449               nsresult             rv;
00450               PRUint32             size;
00451 
00452               rv = m_pMailboxes->Count( &count);
00453               
00454               for (i = 0; i < count; i++) {
00455                      nsCOMPtr<nsIImportMailboxDescriptor> box =
00456                             do_QueryElementAt(m_pMailboxes, i);
00457                      if (box) {
00458                             import = PR_FALSE;
00459                             size = 0;
00460                             rv = box->GetImport( &import);
00461                             if (import) {
00462                                    rv = box->GetSize( &size);
00463                                    result = PR_TRUE;
00464                             }
00465                             totalSize += size;
00466                      }
00467               }
00468 
00469               m_totalSize = totalSize;
00470        }
00471        
00472        m_doImport = result;
00473 
00474        *_retval = result;   
00475 
00476        return( NS_OK);
00477 }
00478 
00479 void nsImportGenericMail::GetMailboxName( PRUint32 index, nsISupportsString *pStr)
00480 {
00481        if (m_pMailboxes) {
00482               nsCOMPtr<nsIImportMailboxDescriptor> box(do_QueryElementAt(m_pMailboxes, index));
00483               if (box) {
00484                      nsXPIDLString name;
00485                      box->GetDisplayName(getter_Copies(name));
00486                      if (!name.IsEmpty()) {
00487                             pStr->SetData(name);
00488                      }
00489               }
00490        }
00491 }
00492 
00493 NS_IMETHODIMP nsImportGenericMail::BeginImport(nsISupportsString *successLog, nsISupportsString *errorLog, PRBool isAddrLocHome, PRBool *_retval)
00494 {
00495        NS_PRECONDITION(_retval != nsnull, "null ptr");
00496     if (!_retval)
00497         return NS_ERROR_NULL_POINTER;
00498 
00499        nsString      success;
00500        nsString      error;
00501 
00502        if (!m_doImport) {
00503               nsImportStringBundle::GetStringByID( IMPORT_NO_MAILBOXES, success);
00504               SetLogs( success, error, successLog, errorLog);                
00505               *_retval = PR_TRUE;
00506               return( NS_OK);             
00507        }
00508        
00509        if (!m_pInterface || !m_pMailboxes) {
00510     IMPORT_LOG0( "*** BeginImport: Either the interface or source mailbox is not set properly.");
00511               nsImportStringBundle::GetStringByID( IMPORT_ERROR_MB_NOTINITIALIZED, error);
00512               SetLogs( success, error, successLog, errorLog);
00513               *_retval = PR_FALSE;
00514               return( NS_OK);
00515        }
00516        
00517        if (!m_pDestFolder) {
00518     IMPORT_LOG0( "*** BeginImport: The destination mailbox is not set properly.");
00519               nsImportStringBundle::GetStringByID( IMPORT_ERROR_MB_NODESTFOLDER, error);
00520               SetLogs( success, error, successLog, errorLog);
00521               *_retval = PR_FALSE;
00522               return( NS_OK);
00523        }
00524 
00525        if (m_pThreadData) {
00526               m_pThreadData->DriverAbort();
00527               m_pThreadData = nsnull;
00528        }
00529 
00530        NS_IF_RELEASE( m_pSuccessLog);
00531        NS_IF_RELEASE( m_pErrorLog);
00532        m_pSuccessLog = successLog;
00533        m_pErrorLog = errorLog;
00534        NS_IF_ADDREF( m_pSuccessLog);
00535        NS_IF_ADDREF( m_pErrorLog);
00536        
00537        
00538        // kick off the thread to do the import!!!!
00539        m_pThreadData = new ImportThreadData();
00540        m_pThreadData->boxes = m_pMailboxes;
00541        NS_ADDREF( m_pMailboxes);
00542        m_pThreadData->mailImport = m_pInterface;
00543        NS_ADDREF( m_pInterface);
00544        m_pThreadData->errorLog = m_pErrorLog;
00545        NS_IF_ADDREF( m_pErrorLog);
00546        m_pThreadData->successLog = m_pSuccessLog;
00547        NS_IF_ADDREF( m_pSuccessLog);
00548        
00549        m_pThreadData->ownsDestRoot = m_deleteDestFolder;
00550        m_pThreadData->destRoot = m_pDestFolder;
00551     m_pThreadData->performingMigration = m_performingMigration;
00552        NS_IF_ADDREF( m_pDestFolder);
00553 
00554 
00555        PRThread *pThread = PR_CreateThread( PR_USER_THREAD, &ImportMailThread, m_pThreadData, 
00556                                                                PR_PRIORITY_NORMAL, 
00557                                                                PR_LOCAL_THREAD, 
00558                                                                PR_UNJOINABLE_THREAD,
00559                                                                0);
00560        if (!pThread) {
00561               m_pThreadData->ThreadDelete();
00562               m_pThreadData->abort = PR_TRUE;
00563               m_pThreadData->DriverAbort();
00564               m_pThreadData = nsnull;
00565               *_retval = PR_FALSE;
00566               nsImportStringBundle::GetStringByID( IMPORT_ERROR_MB_NOTHREAD, error);
00567               SetLogs( success, error, successLog, errorLog);
00568        }
00569        else
00570               *_retval = PR_TRUE;
00571                                    
00572        return( NS_OK);
00573 
00574 }
00575 
00576 
00577 NS_IMETHODIMP nsImportGenericMail::ContinueImport(PRBool *_retval)
00578 {
00579     NS_PRECONDITION(_retval != nsnull, "null ptr");
00580     if (!_retval)
00581         return NS_ERROR_NULL_POINTER;
00582        
00583        *_retval = PR_TRUE;
00584        if (m_pThreadData) {
00585               if (m_pThreadData->fatalError)
00586                      *_retval = PR_FALSE;
00587        }
00588 
00589        return( NS_OK);
00590 }
00591 
00592 
00593 NS_IMETHODIMP nsImportGenericMail::GetProgress(PRInt32 *_retval)
00594 {
00595        // This returns the progress from the the currently
00596        // running import mail or import address book thread.
00597     NS_PRECONDITION(_retval != nsnull, "null ptr");
00598     if (!_retval)
00599         return NS_ERROR_NULL_POINTER;
00600 
00601        if (!m_pThreadData || !(m_pThreadData->threadAlive)) {
00602               *_retval = 100;                           
00603               return( NS_OK);      
00604        }
00605        
00606        PRUint32 sz = 0;
00607        if (m_pThreadData->currentSize && m_pInterface) {
00608               if (NS_FAILED( m_pInterface->GetImportProgress( &sz)))
00609                      sz = 0;
00610        }
00611        
00612 
00613        // *_retval = (PRInt32) (((PRUint32)(m_pThreadData->currentTotal + sz) * (PRUint32)100) / m_totalSize);
00614 
00615        if (m_totalSize) {
00616               PRFloat64     perc;
00617               perc = (PRFloat64) m_pThreadData->currentTotal;
00618               perc += sz;
00619               perc *= 100;
00620               perc /= m_totalSize;
00621               *_retval = (PRInt32) perc;
00622               if (*_retval > 100)
00623                      *_retval = 100;
00624        }
00625        else
00626               *_retval = 0;
00627        
00628        // never return 100% while the thread is still alive
00629        if (*_retval > 99)
00630               *_retval = 99;
00631 
00632        return( NS_OK);
00633 }
00634 
00635 void nsImportGenericMail::ReportError( PRInt32 id, const PRUnichar *pName, nsString *pStream)
00636 {
00637        if (!pStream)
00638               return;
00639        // load the error string
00640        nsIStringBundle *pBundle = nsImportStringBundle::GetStringBundleProxy();
00641        PRUnichar *pFmt = nsImportStringBundle::GetStringByID( id, pBundle);
00642        PRUnichar *pText = nsTextFormatter::smprintf( pFmt, pName);
00643        pStream->Append( pText);
00644        nsTextFormatter::smprintf_free( pText);
00645        nsImportStringBundle::FreeString( pFmt);
00646        pStream->AppendWithConversion( NS_LINEBREAK);
00647        NS_IF_RELEASE( pBundle);
00648 }
00649 
00650 
00651 void nsImportGenericMail::SetLogs( nsString& success, nsString& error, nsISupportsString *pSuccess, nsISupportsString *pError)
00652 {
00653     nsAutoString str;
00654     if (pSuccess) {
00655         pSuccess->GetData(str);
00656         str.Append(success);
00657         pSuccess->SetData(str);
00658     }
00659     if (pError) {
00660         pError->GetData(str);
00661         str.Append(error);
00662         pError->SetData(str);
00663     }
00664 }
00665 
00666 NS_IMETHODIMP nsImportGenericMail::CancelImport(void)
00667 {
00668        if (m_pThreadData) {
00669               m_pThreadData->abort = PR_TRUE;
00670               m_pThreadData->DriverAbort();
00671               m_pThreadData = nsnull;
00672        }
00673 
00674        return( NS_OK);
00675 }
00676 
00677 
00678 ImportThreadData::ImportThreadData()
00679 {
00680        fatalError = PR_FALSE;
00681        driverAlive = PR_TRUE;
00682        threadAlive = PR_TRUE;
00683        abort = PR_FALSE;
00684        currentTotal = 0;
00685        currentSize = 0;
00686        destRoot = nsnull;
00687        ownsDestRoot = PR_FALSE;
00688        boxes = nsnull;
00689        mailImport = nsnull;
00690        successLog = nsnull;
00691        errorLog = nsnull;
00692 }
00693 
00694 ImportThreadData::~ImportThreadData()
00695 {
00696        NS_IF_RELEASE( destRoot);
00697        NS_IF_RELEASE( boxes);
00698        NS_IF_RELEASE( mailImport);
00699        NS_IF_RELEASE( errorLog);
00700        NS_IF_RELEASE( successLog);
00701 }
00702 
00703 void ImportThreadData::DriverDelete( void)
00704 {
00705        driverAlive = PR_FALSE;
00706        if (!driverAlive && !threadAlive)
00707               delete this;
00708 }
00709 
00710 void ImportThreadData::ThreadDelete()
00711 {
00712        threadAlive = PR_FALSE;
00713        if (!driverAlive && !threadAlive)
00714               delete this;
00715 }
00716 
00717 void ImportThreadData::DriverAbort()
00718 {
00719        if (abort && !threadAlive && destRoot) {
00720               if (ownsDestRoot) {
00721                      destRoot->RecursiveDelete(PR_TRUE, nsnull);
00722               }
00723               else {
00724                      // FIXME: just delete the stuff we created?
00725               }
00726        }
00727        else
00728               abort = PR_TRUE;
00729        DriverDelete();
00730 }
00731 
00732 
00733 
00734 PR_STATIC_CALLBACK( void)
00735 ImportMailThread( void *stuff)
00736 {
00737        ImportThreadData *pData = (ImportThreadData *)stuff;
00738        
00739   IMPORT_LOG0("ImportMailThread: Starting...");
00740               
00741        nsresult rv = NS_OK;
00742 
00743        nsCOMPtr<nsIMsgFolder>      destRoot( pData->destRoot);        
00744                             
00745        PRUint32      count = 0;
00746        rv = pData->boxes->Count( &count);
00747        
00748        PRUint32             i;
00749        PRBool               import;
00750        PRUint32             size;  
00751        PRUint32             depth = 1;
00752        PRUint32             newDepth;
00753        nsString             lastName;
00754        PRUnichar *          pName;
00755        
00756        nsCOMPtr<nsIMsgFolder>      curFolder( destRoot);
00757        nsCOMPtr<nsIMsgFolder>             curProxy;
00758 
00759        nsCOMPtr<nsIMsgFolder>             newFolder;
00760        nsCOMPtr<nsIFileSpec>              outBox;
00761        nsCOMPtr<nsISupports>              subFolder;
00762        nsCOMPtr<nsIEnumerator>     enumerator;
00763 
00764        PRBool                                    exists;
00765        
00766        nsString      success;
00767        nsString      error;
00768 
00769        nsCOMPtr<nsIStringBundle>   bundle( dont_AddRef( nsImportStringBundle::GetStringBundleProxy()));
00770 
00771        // Initialize the curFolder proxy object
00772        nsCOMPtr<nsIProxyObjectManager> proxyMgr = 
00773                 do_GetService(kProxyObjectManagerCID, &rv);
00774        if (NS_SUCCEEDED(rv)) {
00775               rv = proxyMgr->GetProxyForObject( NS_UI_THREAD_EVENTQ, NS_GET_IID(nsIMsgFolder),
00776                                                                       curFolder, PROXY_SYNC | PROXY_ALWAYS, getter_AddRefs( curProxy));
00777 
00778               if (NS_SUCCEEDED(rv))
00779                      // GetSubfolders() will initialize folders if they are not already initialized.
00780                      curProxy->GetSubFolders(getter_AddRefs(enumerator));
00781     else
00782       IMPORT_LOG1( "*** ImportMailThread: Can't get the destination root folder proxy. rv=(0x%lx)", (long) rv);
00783        }
00784        else {
00785     IMPORT_LOG0("*** ImportMailThread: Unable to obtain proxy service to do the import.");
00786               nsImportStringBundle::GetStringByID( IMPORT_ERROR_MB_NOPROXY, error, bundle);
00787               pData->abort = PR_TRUE;
00788        }
00789 
00790 
00791   IMPORT_LOG1("ImportMailThread: Total number of folders to import = %d.", count);
00792 
00793   // Note that the front-end js script only displays one import result string so 
00794   // we combine both good and bad import status into one string (in var 'success').
00795 
00796        for (i = 0; (i < count) && !(pData->abort); i++) {
00797               nsCOMPtr<nsIImportMailboxDescriptor> box =
00798                      do_QueryElementAt(pData->boxes, i);
00799               if (box) {
00800                      pData->currentMailbox = i;
00801 
00802                      import = PR_FALSE;
00803                      size = 0;
00804                      rv = box->GetImport( &import);
00805                      if (import)
00806                             rv = box->GetSize( &size);
00807                      rv = box->GetDepth( &newDepth);
00808                      if (newDepth > depth) {
00809           // OK, we are going to add a subfolder under the last/previous folder we processed, so
00810           // find this folder (stored in 'lastName') who is going to be the new parent folder.
00811         IMPORT_LOG1("ImportMailThread: Processing child folder '%s'.", NS_ConvertUCS2toUTF8(lastName).get());
00812                             rv = curProxy->GetChildNamed( lastName.get(), getter_AddRefs( subFolder));
00813                             if (NS_FAILED( rv)) {
00814           IMPORT_LOG1("*** ImportMailThread: Failed to get the interface for child folder '%s'.", NS_ConvertUCS2toUTF8(lastName).get());
00815                                    nsImportGenericMail::ReportError( IMPORT_ERROR_MB_FINDCHILD, lastName.get(), &error);
00816                                    pData->fatalError = PR_TRUE;
00817                                    break;
00818                             }
00819 
00820                             rv = proxyMgr->GetProxyForObject( NS_UI_THREAD_EVENTQ, NS_GET_IID(nsIMsgFolder), 
00821                                                                                     subFolder, PROXY_SYNC | PROXY_ALWAYS, getter_AddRefs( curProxy));
00822                             if (NS_FAILED( rv)) {
00823           IMPORT_LOG1("*** ImportMailThread: Failed to get the proxy interface for child folder '%s'.", NS_ConvertUCS2toUTF8(lastName).get());
00824                                    nsImportStringBundle::GetStringByID( IMPORT_ERROR_MB_NOPROXY, error, bundle);
00825                                    pData->fatalError = PR_TRUE;
00826                                    break;
00827                             }
00828 
00829                             // Make sure this new parent folder obj has the correct subfolder list so far.
00830                             rv = curProxy->GetSubFolders(getter_AddRefs(enumerator));
00831                      }
00832                      else if (newDepth < depth) {
00833                             rv = NS_OK;
00834                             while ((newDepth < depth) && NS_SUCCEEDED( rv)) {
00835                                    nsCOMPtr<nsIMsgFolder> parFolder;
00836                                    rv = curProxy->GetParent( getter_AddRefs( parFolder));
00837           if (NS_FAILED( rv)) {
00838             IMPORT_LOG1("*** ImportMailThread: Failed to get the interface for parent folder '%s'.", lastName.get());
00839                                      nsImportGenericMail::ReportError( IMPORT_ERROR_MB_FINDCHILD, lastName.get(), &error);
00840                                      pData->fatalError = PR_TRUE;
00841                                      break;
00842                               }
00843 
00844                                    rv = proxyMgr->GetProxyForObject( NS_UI_THREAD_EVENTQ, NS_GET_IID(nsIMsgFolder),
00845                                                                                            parFolder, PROXY_SYNC | PROXY_ALWAYS, getter_AddRefs( curProxy));
00846                                    depth--;
00847                             }
00848                             if (NS_FAILED( rv)) {
00849           IMPORT_LOG1("*** ImportMailThread: Failed to get the proxy interface for parent folder '%s'.", lastName.get());
00850                                    nsImportStringBundle::GetStringByID( IMPORT_ERROR_MB_NOPROXY, error, bundle);
00851                                    pData->fatalError = PR_TRUE;
00852                                    break;
00853                             }
00854                      }
00855                      depth = newDepth;
00856                      pName = nsnull;
00857                      box->GetDisplayName( &pName);
00858                      if (pName) {
00859                             lastName = pName;
00860                             nsCRT::free( pName);
00861                      }
00862                      else
00863                             lastName.AssignLiteral("Unknown!");
00864                             
00865             // translate the folder name if we are doing migration
00866             if (pData->performingMigration)
00867                 pData->mailImport->TranslateFolderName(lastName, lastName); 
00868                             
00869                      exists = PR_FALSE;
00870                      rv = curProxy->ContainsChildNamed( lastName.get(), &exists);
00871       
00872             // If we are performing profile migration (as opposed to importing) then we are starting
00873             // with empty local folders. In that case, always choose to over-write the existing local folder
00874             // with this name. Don't create a unique subfolder name. Otherwise you end up with "Inbox, Inbox0" 
00875             // or "Unsent Folders, UnsentFolders0"
00876             if (exists && !pData->performingMigration) {
00877                             nsXPIDLString subName;
00878                             curProxy->GenerateUniqueSubfolderName( lastName.get(), nsnull, getter_Copies(subName));
00879                             if (!subName.IsEmpty()) 
00880                                    lastName.Assign(subName);
00881                      }
00882                             
00883       IMPORT_LOG1("ImportMailThread: Creating new import folder '%s'.", NS_ConvertUCS2toUTF8(lastName).get());
00884             curProxy->CreateSubfolder( lastName.get(),nsnull); // this may fail if the folder already exists..that's ok
00885 
00886                             rv = curProxy->GetChildNamed( lastName.get(), getter_AddRefs( subFolder));
00887                             if (NS_SUCCEEDED( rv)) {
00888                                    newFolder = do_QueryInterface( subFolder);
00889                                    if (newFolder) {
00890                                           newFolder->GetPath( getter_AddRefs( outBox));
00891                                    }
00892                                    else {
00893             IMPORT_LOG1("*** ImportMailThread: Failed to locate subfolder interface '%s'.", lastName.get());
00894                                    }
00895                             }
00896         else
00897           IMPORT_LOG1("*** ImportMailThread: Failed to locate subfolder '%s' after it's been created.", lastName.get());
00898                             
00899                      if (NS_FAILED( rv)) {
00900                             nsImportGenericMail::ReportError( IMPORT_ERROR_MB_CREATE, lastName.get(), &error);
00901                      }
00902 
00903                      if (size && import && newFolder && outBox && NS_SUCCEEDED( rv)) {
00904                             PRBool fatalError = PR_FALSE;
00905                             pData->currentSize = size;
00906                             PRUnichar *pSuccess = nsnull;
00907                             PRUnichar *pError = nsnull;
00908                             rv = pData->mailImport->ImportMailbox( box, outBox, &pError, &pSuccess, &fatalError);
00909                             if (pError) {
00910                                    error.Append( pError);
00911                                    nsCRT::free( pError);
00912                             }
00913                             if (pSuccess) {
00914                                    success.Append( pSuccess);
00915                                    nsCRT::free( pSuccess);
00916                             }
00917 
00918                             pData->currentSize = 0;
00919                             pData->currentTotal += size;
00920                                    
00921                             outBox->CloseStream();
00922 
00923           // OK, we've copied the actual folder/file over if the folder size is not 0
00924           // (ie, the msg summary is no longer valid) so close the msg database so that
00925           // when the folder is reopened the folder db can be reconstructed (which
00926           // validates msg summary and forces folder to be reparsed).
00927                             newFolder->ForceDBClosed();
00928 
00929                             if (fatalError) {
00930                                    IMPORT_LOG1( "*** ImportMailThread: ImportMailbox returned fatalError, mailbox #%d\n", (int) i);
00931                                    pData->fatalError = PR_TRUE;
00932                                    break;
00933                             }
00934                      }
00935               }
00936        }
00937 
00938        // Now save the new acct info to pref file.
00939        nsCOMPtr <nsIMsgAccountManager> accMgr = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
00940         if (NS_SUCCEEDED(rv) && accMgr) {
00941          rv = accMgr->SaveAccountInfo();
00942          NS_ASSERTION(NS_SUCCEEDED(rv), "Can't save account info to pref file");
00943        }
00944        
00945        nsImportGenericMail::SetLogs( success, error, pData->successLog, pData->errorLog);
00946 
00947        if (pData->abort || pData->fatalError) {
00948               IMPORT_LOG0( "*** ImportMailThread: Abort or fatalError flag was set\n");
00949               if (pData->ownsDestRoot) {
00950                      IMPORT_LOG0( "Calling destRoot->RecursiveDelete\n");
00951                      destRoot->RecursiveDelete( PR_TRUE, nsnull);
00952               }
00953               else {
00954                      // FIXME: just delete the stuff we created?
00955               }
00956        }
00957 
00958        IMPORT_LOG1( "Import mailbox thread done: %d\n", (int) pData->currentTotal);
00959 
00960        pData->ThreadDelete();      
00961 
00962 }
00963 
00964 // Creates a folder in Local Folders with the module name + mail
00965 // for e.g: Outlook Mail
00966 PRBool nsImportGenericMail::CreateFolder( nsIMsgFolder **ppFolder)
00967 {
00968   nsresult rv;
00969   *ppFolder = nsnull;
00970 
00971   nsCOMPtr<nsIStringBundle> bundle;
00972   nsCOMPtr<nsIStringBundleService> bundleService(do_GetService(
00973                                      NS_STRINGBUNDLE_CONTRACTID, &rv));
00974   if (NS_FAILED(rv) || !bundleService) 
00975       return PR_FALSE;
00976   rv = bundleService->CreateBundle(IMPORT_MSGS_URL, getter_AddRefs(bundle));
00977   if (NS_FAILED(rv)) 
00978       return PR_FALSE;
00979   nsXPIDLString folderName;
00980   if (!m_pName.IsEmpty()) {
00981     const PRUnichar *moduleName[] = { m_pName.get() };
00982     rv = bundle->FormatStringFromName(NS_LITERAL_STRING("ModuleFolderName").get(),
00983                                       moduleName, 1,
00984                                       getter_Copies(folderName));
00985   }
00986   else {
00987     rv = bundle->GetStringFromName(NS_LITERAL_STRING("DefaultFolderName").get(),
00988                                    getter_Copies(folderName));
00989   }
00990   if (NS_FAILED(rv)) {
00991       IMPORT_LOG0( "*** Failed to get Folder Name!\n");
00992       return PR_FALSE;
00993   }
00994   nsCOMPtr <nsIMsgAccountManager> accMgr = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
00995   if (NS_FAILED(rv)) {
00996     IMPORT_LOG0( "*** Failed to create account manager!\n");
00997     return PR_FALSE;
00998   }
00999 
01000   nsCOMPtr <nsIMsgIncomingServer> server;
01001   rv = accMgr->GetLocalFoldersServer(getter_AddRefs(server)); 
01002   // if Local Folders does not exist already, create it
01003   if (NS_FAILED(rv) || !server)
01004   {
01005     nsCOMPtr <nsIMessengerMigrator> messengerMigrator = do_GetService(NS_MESSENGERMIGRATOR_CONTRACTID, &rv);
01006     if (NS_FAILED(rv)) {
01007       IMPORT_LOG0( "*** Failed to create messenger migrator!\n");
01008       return PR_FALSE;
01009     }
01010     rv = messengerMigrator->CreateLocalMailAccount(PR_FALSE);
01011     if (NS_FAILED(rv)) {
01012       IMPORT_LOG0( "*** Failed to create Local Folders!\n");
01013       return PR_FALSE;
01014     }
01015     
01016     rv = accMgr->GetLocalFoldersServer(getter_AddRefs(server)); 
01017   }
01018 
01019   if (NS_SUCCEEDED(rv) && server) {
01020     nsCOMPtr <nsIMsgFolder> localRootFolder;
01021     rv = server->GetRootMsgFolder(getter_AddRefs(localRootFolder)); 
01022     if (localRootFolder) {
01023       // we need to call GetSubFolders() so that the folders get initialized 
01024       // if they are not initialized yet. 
01025       nsCOMPtr <nsIEnumerator> aEnumerator;
01026       rv = localRootFolder->GetSubFolders(getter_AddRefs(aEnumerator));
01027       if (NS_SUCCEEDED(rv)) {
01028         // check if the folder name we picked already exists.
01029         PRBool exists = PR_FALSE;
01030         rv = localRootFolder->ContainsChildNamed(folderName.get(), &exists);
01031         if (exists) {
01032           nsXPIDLString name;
01033           localRootFolder->GenerateUniqueSubfolderName(folderName.get(), nsnull, getter_Copies(name));
01034           if (!name.IsEmpty())
01035             folderName.Assign(name);
01036           else {
01037             IMPORT_LOG0( "*** Failed to find a unique folder name!\n");
01038             return PR_FALSE;
01039           }
01040         }
01041         IMPORT_LOG1( "Creating folder for importing mail: '%s'\n", NS_ConvertUCS2toUTF8(folderName).get());
01042 
01043         // if we are doing migration, don't bother putting the local folders we are importing as a 
01044         // sub folder of local folders.
01045         if (m_performingMigration)       
01046         {
01047           NS_IF_ADDREF(*ppFolder = localRootFolder);
01048           return PR_TRUE;
01049         }
01050         else
01051         {
01052         rv = localRootFolder->CreateSubfolder(folderName.get(), nsnull);
01053         if (NS_SUCCEEDED(rv)) {
01054           nsCOMPtr<nsISupports> subFolder;
01055           rv = localRootFolder->GetChildNamed(folderName.get(), getter_AddRefs(subFolder));
01056           if (subFolder) {
01057             subFolder->QueryInterface(NS_GET_IID(nsIMsgFolder), (void **) ppFolder);
01058             if (*ppFolder) {
01059               IMPORT_LOG1("Folder '%s' created successfully\n", NS_ConvertUCS2toUTF8(folderName).get());
01060               return PR_TRUE;
01061             }
01062           } // if subFolder
01063         }
01064         } // if not performing migration
01065       }
01066     } // if localRootFolder
01067   } // if server
01068   IMPORT_LOG0("****** FAILED TO CREATE FOLDER FOR IMPORT\n");
01069   return PR_FALSE;
01070 }