Back to index

lightning-sunbird  0.9+nobinonly
nsImportAddressBooks.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 #include "prthread.h"
00040 #include "prprf.h"
00041 #include "nscore.h"
00042 #include "nsCOMPtr.h"
00043 #include "nsIImportService.h"
00044 #include "nsISupportsArray.h"
00045 #include "nsIImportAddressBooks.h"
00046 #include "nsIImportGeneric.h"
00047 #include "nsXPCOM.h"
00048 #include "nsISupportsPrimitives.h"
00049 #include "nsIImportABDescriptor.h"
00050 #include "nsIImportFieldMap.h"
00051 #include "nsCRT.h"
00052 #include "nsString.h"
00053 #include "nsIURL.h"
00054 #include "nsNetCID.h"
00055 
00056 #include "nsIFileSpec.h"
00057 #include "nsILocalFile.h"
00058 
00059 #include "nsIAddrDatabase.h"
00060 #include "nsIAddrBookSession.h"
00061 #include "nsIRDFService.h"
00062 #include "nsRDFCID.h"
00063 #include "nsAbBaseCID.h"
00064 #include "nsIAbDirectory.h"
00065 #include "nsIAddressBook.h"
00066 #include "nsImportStringBundle.h"
00067 #include "nsTextFormatter.h"
00068 #include "nsIProxyObjectManager.h"
00069 #include "nsProxiedService.h"
00070 
00071 #include "ImportDebug.h"
00072 
00073 static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
00074 static NS_DEFINE_CID(kSupportsWStringCID, NS_SUPPORTS_STRING_CID);
00075 static NS_DEFINE_CID(kProxyObjectManagerCID, NS_PROXYEVENT_MANAGER_CID);
00076 
00077 
00079 
00080 PR_STATIC_CALLBACK( void) ImportAddressThread( void *stuff);
00081 
00082 
00083 class AddressThreadData;
00084 
00085 class nsImportGenericAddressBooks : public nsIImportGeneric
00086 {
00087 public:
00088 
00089        nsImportGenericAddressBooks();
00090        virtual ~nsImportGenericAddressBooks();
00091        
00092        NS_DECL_ISUPPORTS
00093 
00094        /* nsISupports GetData (in string dataId); */
00095        NS_IMETHOD GetData(const char *dataId, nsISupports **_retval);
00096 
00097        NS_IMETHOD SetData(const char *dataId, nsISupports *pData);
00098 
00099        NS_IMETHOD GetStatus( const char *statusKind, PRInt32 *_retval);
00100 
00101        /* boolean WantsProgress (); */
00102        NS_IMETHOD WantsProgress(PRBool *_retval);
00103 
00104     /* boolean BeginImport (in nsISupportsString successLog, in nsISupportsString errorLog, in boolean isAddrLocHome); */
00105     NS_IMETHOD BeginImport(nsISupportsString *successLog, nsISupportsString *errorLog, PRBool isAddrLocHome, PRBool *_retval) ;
00106 
00107        /* boolean ContinueImport (); */
00108        NS_IMETHOD ContinueImport(PRBool *_retval);
00109 
00110        /* long GetProgress (); */
00111        NS_IMETHOD GetProgress(PRInt32 *_retval);
00112 
00113        /* void CancelImport (); */
00114        NS_IMETHOD CancelImport(void);
00115 
00116 private:
00117        void   GetDefaultLocation( void);
00118        void   GetDefaultBooks( void);
00119        void   GetDefaultFieldMap( void);
00120 
00121 public:
00122        static void   SetLogs( nsString& success, nsString& error, nsISupportsString *pSuccess, nsISupportsString *pError);
00123        static void ReportError( PRUnichar *pName, nsString *pStream);
00124 
00125 private:
00126        nsIImportAddressBooks *            m_pInterface;
00127        nsISupportsArray *                 m_pBooks;
00128        nsCOMPtr <nsIFileSpec> m_pLocation;
00129        nsIImportFieldMap *                m_pFieldMap;
00130        PRBool                                    m_autoFind;
00131        PRUnichar *                               m_description;
00132        PRBool                                    m_gotLocation;
00133        PRBool                                    m_found;
00134        PRBool                                    m_userVerify;
00135        nsISupportsString *         m_pSuccessLog;
00136        nsISupportsString *         m_pErrorLog;
00137        PRUint32                                  m_totalSize;
00138        PRBool                                    m_doImport;
00139        AddressThreadData *                m_pThreadData;
00140        char *                                    m_pDestinationUri;
00141 };
00142 
00143 class AddressThreadData {
00144 public:
00145        PRBool                                    driverAlive;
00146        PRBool                                    threadAlive;
00147        PRBool                                    abort;
00148        PRBool                                    fatalError;
00149        PRUint32                                  currentTotal;
00150        PRUint32                                  currentSize;
00151        nsISupportsArray *                 books;
00152        nsIImportAddressBooks *            addressImport;
00153        nsIImportFieldMap *                fieldMap;
00154        nsISupportsString *         successLog;
00155        nsISupportsString *         errorLog;
00156        char *                                    pDestinationUri;
00157        PRBool                      bAddrLocInput ;
00158 
00159        AddressThreadData();
00160        ~AddressThreadData();
00161        void DriverDelete();
00162        void ThreadDelete();
00163        void DriverAbort();
00164 };
00165 
00166 
00167 nsresult NS_NewGenericAddressBooks(nsIImportGeneric** aImportGeneric)
00168 {
00169     NS_PRECONDITION(aImportGeneric != nsnull, "null ptr");
00170     if (! aImportGeneric)
00171         return NS_ERROR_NULL_POINTER;
00172        
00173        nsImportGenericAddressBooks *pGen = new nsImportGenericAddressBooks();
00174 
00175        if (pGen == nsnull)
00176               return NS_ERROR_OUT_OF_MEMORY;
00177 
00178        NS_ADDREF( pGen);
00179        nsresult rv = pGen->QueryInterface( NS_GET_IID(nsIImportGeneric), (void **)aImportGeneric);
00180        NS_RELEASE( pGen);
00181     
00182     return( rv);
00183 }
00184 
00185 nsImportGenericAddressBooks::nsImportGenericAddressBooks()
00186 {
00187        m_pInterface = nsnull;
00188        m_pBooks = nsnull;
00189        m_pSuccessLog = nsnull;
00190        m_pErrorLog = nsnull;
00191        m_totalSize = 0;
00192        m_doImport = PR_FALSE;
00193        m_pThreadData = nsnull;
00194        m_pDestinationUri = nsnull;
00195        m_pFieldMap = nsnull;
00196 
00197        m_autoFind = PR_FALSE;
00198        m_description = nsnull;
00199        m_gotLocation = PR_FALSE;
00200        m_found = PR_FALSE;
00201        m_userVerify = PR_FALSE;
00202 }
00203 
00204 
00205 nsImportGenericAddressBooks::~nsImportGenericAddressBooks()
00206 {
00207        if (m_pThreadData) {
00208               m_pThreadData->DriverAbort();
00209               m_pThreadData = nsnull;
00210        }
00211        
00212        if (m_pDestinationUri)
00213               nsCRT::free( m_pDestinationUri);
00214        
00215        if (m_description)
00216               nsCRT::free( m_description);
00217 
00218        NS_IF_RELEASE( m_pFieldMap);
00219        NS_IF_RELEASE( m_pInterface);
00220        NS_IF_RELEASE( m_pBooks);
00221        NS_IF_RELEASE( m_pSuccessLog);
00222        NS_IF_RELEASE( m_pErrorLog);
00223 }
00224 
00225 
00226 
00227 NS_IMPL_THREADSAFE_ISUPPORTS1(nsImportGenericAddressBooks, nsIImportGeneric)
00228 
00229 
00230 NS_IMETHODIMP nsImportGenericAddressBooks::GetData(const char *dataId, nsISupports **_retval)
00231 {
00232     NS_PRECONDITION(_retval != nsnull, "null ptr");
00233        if (!_retval)
00234               return NS_ERROR_NULL_POINTER;
00235        
00236        nsresult      rv;
00237        *_retval = nsnull;
00238        if (!nsCRT::strcasecmp( dataId, "addressInterface")) {
00239               *_retval = m_pInterface;
00240               NS_IF_ADDREF( m_pInterface);
00241        }
00242        
00243        if (!nsCRT::strcasecmp( dataId, "addressLocation")) {
00244               if (!m_pLocation)
00245                      GetDefaultLocation();
00246               NS_IF_ADDREF(*_retval = m_pLocation);
00247        }
00248        
00249        if (!nsCRT::strcasecmp( dataId, "addressBooks")) {
00250               if (!m_pLocation)
00251                      GetDefaultLocation();
00252               if (!m_pBooks)
00253                      GetDefaultBooks();
00254               *_retval = m_pBooks;
00255               NS_IF_ADDREF( m_pBooks);
00256        }
00257        
00258        if (!nsCRT::strcasecmp( dataId, "addressDestination")) {
00259               if (m_pDestinationUri) {
00260             nsCOMPtr<nsISupportsCString> abString = do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID, &rv);
00261             NS_ENSURE_SUCCESS(rv, rv);
00262             abString->SetData(nsDependentCString(m_pDestinationUri));
00263             NS_IF_ADDREF( *_retval = abString);
00264               }
00265        }
00266 
00267        if (!nsCRT::strcasecmp( dataId, "fieldMap")) {
00268               if (m_pFieldMap) {
00269                      *_retval = m_pFieldMap;
00270                      m_pFieldMap->AddRef();
00271               }
00272               else {
00273                      if (m_pInterface && m_pLocation) {
00274                             PRBool needsIt = PR_FALSE;
00275                             m_pInterface->GetNeedsFieldMap( m_pLocation, &needsIt);
00276                             if (needsIt) {
00277                                    GetDefaultFieldMap();
00278                                    if (m_pFieldMap) {
00279                                           *_retval = m_pFieldMap;
00280                                           m_pFieldMap->AddRef();
00281                                    }
00282                             }
00283                      }
00284               }
00285        }
00286 
00287        if (!nsCRT::strncasecmp( dataId, "sampleData-", 11)) {
00288               // extra the record number
00289               const char *pNum = dataId + 11;
00290               PRInt32       rNum = 0;
00291               while (*pNum) {
00292                      rNum *= 10;
00293                      rNum += (*pNum - '0');
00294                      pNum++;
00295               }
00296               IMPORT_LOG1( "Requesting sample data #: %ld\n", (long)rNum);
00297               if (m_pInterface) {
00298                      nsCOMPtr<nsISupportsString> data = do_CreateInstance( kSupportsWStringCID, &rv);
00299                      if (NS_FAILED( rv))
00300                             return( rv);
00301                      PRUnichar *   pData = nsnull;
00302                      PRBool        found = PR_FALSE;
00303                      rv = m_pInterface->GetSampleData( rNum, &found, &pData);
00304                      if (NS_FAILED( rv))
00305                             return( rv);
00306                      if (found) {
00307                             data->SetData(nsDependentString(pData));
00308                             *_retval = data;
00309                             NS_ADDREF( *_retval);
00310                      }
00311                      nsCRT::free( pData);
00312               }
00313        }
00314 
00315        return( NS_OK);
00316 }
00317 
00318 
00319 NS_IMETHODIMP nsImportGenericAddressBooks::SetData( const char *dataId, nsISupports *item)
00320 {
00321        NS_PRECONDITION(dataId != nsnull, "null ptr");
00322     if (!dataId)
00323         return NS_ERROR_NULL_POINTER;
00324 
00325        if (!nsCRT::strcasecmp( dataId, "addressInterface")) {
00326               NS_IF_RELEASE( m_pInterface);
00327               if (item)
00328                      item->QueryInterface( NS_GET_IID(nsIImportAddressBooks), (void **) &m_pInterface);
00329        }
00330        if (!nsCRT::strcasecmp( dataId, "addressBooks")) {
00331               NS_IF_RELEASE( m_pBooks);
00332               if (item)
00333                      item->QueryInterface( NS_GET_IID(nsISupportsArray), (void **) &m_pBooks);
00334        }
00335        
00336        if (!nsCRT::strcasecmp( dataId, "addressLocation")) {
00337               m_pLocation = nsnull;
00338 
00339     if (item) {
00340       nsresult rv;
00341       nsCOMPtr <nsILocalFile> location = do_QueryInterface(item, &rv);
00342       NS_ENSURE_SUCCESS(rv,rv);
00343       
00344       rv = NS_NewFileSpecFromIFile(location, getter_AddRefs(m_pLocation));
00345       NS_ENSURE_SUCCESS(rv,rv);
00346     }
00347 
00348     if (m_pInterface)
00349                      m_pInterface->SetSampleLocation(m_pLocation);
00350        }
00351 
00352        if (!nsCRT::strcasecmp( dataId, "addressDestination")) {
00353               if (item) {
00354                      nsCOMPtr<nsISupportsCString> abString;
00355                      item->QueryInterface( NS_GET_IID(nsISupportsCString), getter_AddRefs( abString));
00356                      if (abString) {
00357                             if (m_pDestinationUri)
00358                                    nsCRT::free( m_pDestinationUri);
00359                             m_pDestinationUri = nsnull;
00360                 nsCAutoString tempUri;
00361                 abString->GetData(tempUri);
00362                 m_pDestinationUri = ToNewCString(tempUri);
00363                      }
00364               }
00365        }
00366 
00367        if (!nsCRT::strcasecmp( dataId, "fieldMap")) {
00368               NS_IF_RELEASE( m_pFieldMap);
00369               if (item)
00370                      item->QueryInterface( NS_GET_IID(nsIImportFieldMap), (void **) &m_pFieldMap);
00371        }
00372        
00373        return( NS_OK);
00374 }
00375 
00376 NS_IMETHODIMP nsImportGenericAddressBooks::GetStatus( const char *statusKind, PRInt32 *_retval)
00377 {
00378        NS_PRECONDITION(statusKind != nsnull, "null ptr");
00379        NS_PRECONDITION(_retval != nsnull, "null ptr");
00380        if (!statusKind || !_retval)
00381               return( NS_ERROR_NULL_POINTER);
00382        
00383        *_retval = 0;
00384 
00385        if (!nsCRT::strcasecmp( statusKind, "isInstalled")) {
00386               GetDefaultLocation();
00387               *_retval = (PRInt32) m_found;
00388        }
00389 
00390        if (!nsCRT::strcasecmp( statusKind, "canUserSetLocation")) {
00391               GetDefaultLocation();
00392               *_retval = (PRInt32) m_userVerify;
00393        }
00394        
00395        if (!nsCRT::strcasecmp( statusKind, "autoFind")) {
00396               GetDefaultLocation();
00397               *_retval = (PRInt32) m_autoFind;
00398        }
00399 
00400        if (!nsCRT::strcasecmp( statusKind, "supportsMultiple")) {
00401               PRBool        multi = PR_FALSE;
00402               if (m_pInterface)
00403                      m_pInterface->GetSupportsMultiple( &multi);
00404               *_retval = (PRInt32) multi;
00405        }
00406        
00407        if (!nsCRT::strcasecmp( statusKind, "needsFieldMap")) {
00408               PRBool        needs = PR_FALSE;
00409               if (m_pInterface && m_pLocation)
00410                      m_pInterface->GetNeedsFieldMap( m_pLocation, &needs);
00411               *_retval = (PRInt32) needs;
00412        }
00413 
00414        return( NS_OK);
00415 }
00416 
00417 void nsImportGenericAddressBooks::GetDefaultLocation( void)
00418 {
00419        if (!m_pInterface)
00420               return;
00421        
00422        if ((m_pLocation && m_gotLocation) || m_autoFind)
00423               return;
00424        
00425        if (m_description)
00426               nsCRT::free( m_description);
00427        m_description = nsnull;
00428        m_pInterface->GetAutoFind( &m_description, &m_autoFind);
00429        m_gotLocation = PR_TRUE;
00430        if (m_autoFind) {
00431               m_found = PR_TRUE;
00432               m_userVerify = PR_FALSE;
00433               return;
00434        }
00435 
00436        nsIFileSpec * pLoc = nsnull;
00437        m_pInterface->GetDefaultLocation( &pLoc, &m_found, &m_userVerify);
00438        if (!m_pLocation)
00439               m_pLocation = pLoc;
00440        else {
00441               NS_IF_RELEASE( pLoc);
00442        }
00443 }
00444 
00445 void nsImportGenericAddressBooks::GetDefaultBooks( void)
00446 {
00447        if (!m_pInterface || m_pBooks)
00448               return;
00449        
00450        if (!m_pLocation && !m_autoFind)
00451               return;
00452 
00453        nsresult rv = m_pInterface->FindAddressBooks( m_pLocation, &m_pBooks);
00454        if (NS_FAILED( rv)) {
00455               IMPORT_LOG0( "*** Error: FindAddressBooks failed\n");
00456        }
00457 }
00458 
00459 void nsImportGenericAddressBooks::GetDefaultFieldMap( void)
00460 {
00461        if (!m_pInterface || !m_pLocation)
00462               return;
00463        
00464        NS_IF_RELEASE( m_pFieldMap);
00465        
00466        nsresult      rv;
00467        nsCOMPtr<nsIImportService> impSvc(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv));
00468        if (NS_FAILED(rv)) {
00469               IMPORT_LOG0( "*** Unable to get nsIImportService.\n");
00470               return;
00471        }
00472 
00473        rv = impSvc->CreateNewFieldMap( &m_pFieldMap);
00474        if (NS_FAILED( rv))
00475               return;
00476        
00477        PRInt32       sz = 0;
00478        rv = m_pFieldMap->GetNumMozFields( &sz);
00479        if (NS_SUCCEEDED( rv))
00480               rv = m_pFieldMap->DefaultFieldMap( sz);
00481        if (NS_SUCCEEDED( rv))
00482               rv = m_pInterface->InitFieldMap( m_pLocation, m_pFieldMap);
00483        if (NS_FAILED( rv)) {
00484               IMPORT_LOG0( "*** Error: Unable to initialize field map\n");
00485               NS_IF_RELEASE( m_pFieldMap);
00486        }
00487 }
00488 
00489 
00490 NS_IMETHODIMP nsImportGenericAddressBooks::WantsProgress(PRBool *_retval)
00491 {
00492        NS_PRECONDITION(_retval != nsnull, "null ptr");
00493     if (!_retval)
00494         return NS_ERROR_NULL_POINTER;
00495        
00496        if (m_pThreadData) {
00497               m_pThreadData->DriverAbort();
00498               m_pThreadData = nsnull;
00499        }
00500 
00501        GetDefaultLocation();
00502        GetDefaultBooks();
00503 
00504        PRUint32             totalSize = 0;
00505        PRBool               result = PR_FALSE;
00506 
00507        if (m_pBooks) {
00508               PRUint32             count = 0;
00509               nsresult             rv = m_pBooks->Count( &count);
00510               PRUint32             i;
00511               PRBool               import;
00512               PRUint32             size;
00513               
00514               for (i = 0; i < count; i++) {
00515                      nsCOMPtr<nsIImportABDescriptor> book =
00516                             do_QueryElementAt(m_pBooks, i);
00517                      if (book) {
00518                             import = PR_FALSE;
00519                             size = 0;
00520                             rv = book->GetImport( &import);
00521                             if (import) {
00522                                    rv = book->GetSize( &size);
00523                                    result = PR_TRUE;
00524                             }
00525                             totalSize += size;
00526                      }
00527               }
00528 
00529               m_totalSize = totalSize;
00530        }
00531        
00532        m_doImport = result;
00533 
00534        *_retval = result;   
00535 
00536        return( NS_OK);
00537 }
00538 
00539 void nsImportGenericAddressBooks::SetLogs( nsString& success, nsString& error, nsISupportsString *pSuccess, nsISupportsString *pError)
00540 {
00541        nsAutoString str;
00542        if (pSuccess) {
00543               pSuccess->GetData(str);
00544         str.Append(success);
00545         pSuccess->SetData(success);
00546        }
00547        if (pError) {
00548               pError->GetData(str);
00549         str.Append(error);
00550         pError->SetData(error);
00551        }      
00552 }
00553 
00554 NS_IMETHODIMP nsImportGenericAddressBooks::BeginImport(nsISupportsString *successLog, nsISupportsString *errorLog, PRBool isAddrLocHome, PRBool *_retval)
00555 {
00556        NS_PRECONDITION(_retval != nsnull, "null ptr");
00557     if (!_retval)
00558         return NS_ERROR_NULL_POINTER;
00559 
00560        nsString      success;
00561        nsString      error;
00562        
00563        if (!m_doImport) {
00564               *_retval = PR_TRUE;
00565               nsImportStringBundle::GetStringByID( IMPORT_NO_ADDRBOOKS, success);
00566               SetLogs( success, error, successLog, errorLog);
00567               return( NS_OK);             
00568        }
00569        
00570        if (!m_pInterface || !m_pBooks) {
00571               nsImportStringBundle::GetStringByID( IMPORT_ERROR_AB_NOTINITIALIZED, error);
00572               SetLogs( success, error, successLog, errorLog);
00573               *_retval = PR_FALSE;
00574               return( NS_OK);
00575        }
00576 
00577        if (m_pThreadData) {
00578               m_pThreadData->DriverAbort();
00579               m_pThreadData = nsnull;
00580        }
00581 
00582        NS_IF_RELEASE( m_pSuccessLog);
00583        NS_IF_RELEASE( m_pErrorLog);
00584        m_pSuccessLog = successLog;
00585        m_pErrorLog = errorLog;
00586        NS_IF_ADDREF( m_pSuccessLog);
00587        NS_IF_ADDREF( m_pErrorLog);
00588        
00589        
00590        // kick off the thread to do the import!!!!
00591        m_pThreadData = new AddressThreadData();
00592        m_pThreadData->books = m_pBooks;
00593        NS_ADDREF( m_pBooks);
00594        m_pThreadData->addressImport = m_pInterface;
00595        NS_ADDREF( m_pInterface);
00596        m_pThreadData->fieldMap = m_pFieldMap;
00597        NS_IF_ADDREF( m_pFieldMap);
00598        m_pThreadData->errorLog = m_pErrorLog;
00599        NS_IF_ADDREF( m_pErrorLog);
00600        m_pThreadData->successLog = m_pSuccessLog;
00601        NS_IF_ADDREF( m_pSuccessLog);
00602        if (m_pDestinationUri)
00603               m_pThreadData->pDestinationUri = nsCRT::strdup( m_pDestinationUri);
00604        m_pThreadData->bAddrLocInput = isAddrLocHome ;
00605                             
00606        PRThread *pThread = PR_CreateThread( PR_USER_THREAD, &ImportAddressThread, m_pThreadData, 
00607                                                                PR_PRIORITY_NORMAL, 
00608                                                                PR_LOCAL_THREAD, 
00609                                                                PR_UNJOINABLE_THREAD,
00610                                                                0);
00611        if (!pThread) {
00612               m_pThreadData->ThreadDelete();
00613               m_pThreadData->DriverDelete();
00614               m_pThreadData = nsnull;
00615               *_retval = PR_FALSE;
00616               nsImportStringBundle::GetStringByID( IMPORT_ERROR_AB_NOTHREAD, error);
00617               SetLogs( success, error, successLog, errorLog);
00618        }
00619        else
00620               *_retval = PR_TRUE;
00621                                    
00622        return( NS_OK);
00623 
00624 }
00625 
00626 
00627 NS_IMETHODIMP nsImportGenericAddressBooks::ContinueImport(PRBool *_retval)
00628 {
00629     NS_PRECONDITION(_retval != nsnull, "null ptr");
00630     if (!_retval)
00631         return NS_ERROR_NULL_POINTER;
00632        
00633        *_retval = PR_TRUE;
00634        if (m_pThreadData) {
00635               if (m_pThreadData->fatalError)
00636                      *_retval = PR_FALSE;
00637        }
00638 
00639        return( NS_OK);
00640 }
00641 
00642 
00643 NS_IMETHODIMP nsImportGenericAddressBooks::GetProgress(PRInt32 *_retval)
00644 {
00645        // This returns the progress from the the currently
00646        // running import mail or import address book thread.
00647     NS_PRECONDITION(_retval != nsnull, "null ptr");
00648     if (!_retval)
00649         return NS_ERROR_NULL_POINTER;
00650 
00651        if (!m_pThreadData || !(m_pThreadData->threadAlive)) {
00652               *_retval = 100;                           
00653               return( NS_OK);      
00654        }
00655        
00656        PRUint32 sz = 0;
00657        if (m_pThreadData->currentSize && m_pInterface) {
00658               if (NS_FAILED( m_pInterface->GetImportProgress( &sz)))
00659                      sz = 0;
00660        }
00661        
00662        if (m_totalSize)
00663               *_retval = ((m_pThreadData->currentTotal + sz) * 100) / m_totalSize;
00664        else
00665               *_retval = 0;
00666        
00667        // never return less than 5 so it looks like we are doing something!
00668        if (*_retval < 5)
00669               *_retval = 5;
00670 
00671        // as long as the thread is alive don't return completely
00672        // done.
00673        if (*_retval > 99)
00674               *_retval = 99;
00675 
00676        return( NS_OK);
00677 }
00678 
00679 
00680 NS_IMETHODIMP nsImportGenericAddressBooks::CancelImport(void)
00681 {
00682        if (m_pThreadData) {
00683               m_pThreadData->abort = PR_TRUE;
00684               m_pThreadData->DriverAbort();
00685               m_pThreadData = nsnull;
00686        }
00687 
00688        return( NS_OK);
00689 }
00690 
00691 
00692 AddressThreadData::AddressThreadData()
00693 {
00694        fatalError = PR_FALSE;
00695        driverAlive = PR_TRUE;
00696        threadAlive = PR_TRUE;
00697        abort = PR_FALSE;
00698        currentTotal = 0;
00699        currentSize = 0;
00700        books = nsnull;
00701        addressImport = nsnull;
00702        successLog = nsnull;
00703        errorLog = nsnull;
00704        pDestinationUri = nsnull;
00705        fieldMap = nsnull;
00706 }
00707 
00708 AddressThreadData::~AddressThreadData()
00709 {
00710        if (pDestinationUri)
00711               nsCRT::free( pDestinationUri);
00712 
00713        NS_IF_RELEASE( books);
00714        NS_IF_RELEASE( addressImport);
00715        NS_IF_RELEASE( errorLog);
00716        NS_IF_RELEASE( successLog);
00717        NS_IF_RELEASE( fieldMap);
00718 }
00719 
00720 void AddressThreadData::DriverDelete( void)
00721 {
00722        driverAlive = PR_FALSE;
00723        if (!driverAlive && !threadAlive)
00724               delete this;
00725 }
00726 
00727 void AddressThreadData::ThreadDelete()
00728 {
00729        threadAlive = PR_FALSE;
00730        if (!driverAlive && !threadAlive)
00731               delete this;
00732 }
00733 
00734 void AddressThreadData::DriverAbort()
00735 {
00736        if (abort && !threadAlive) {
00737               // FIXME: Do whatever is necessary to abort what has already been imported!
00738        }
00739        else
00740               abort = PR_TRUE;
00741        DriverDelete();
00742 }
00743 
00744 
00745 nsIAddrDatabase *GetAddressBookFromUri( const char *pUri)
00746 {
00747     nsIAddrDatabase *       pDatabase = nsnull;
00748     if (pUri) {
00749         nsresult rv = NS_OK;
00750         NS_WITH_PROXIED_SERVICE(nsIAddressBook, addressBook, NS_ADDRESSBOOK_CONTRACTID, NS_UI_THREAD_EVENTQ, &rv); 
00751         if (addressBook)
00752             rv = addressBook->GetAbDatabaseFromURI(pUri, &pDatabase);
00753     }
00754 
00755        return pDatabase;
00756 }
00757 
00758 nsIAddrDatabase *GetAddressBook( const PRUnichar *name, PRBool makeNew)
00759 {
00760        nsresult                    rv = NS_OK;
00761 
00762        if (!makeNew) {
00763               // FIXME: How do I get the list of address books and look for a
00764               // specific name.  Major bogosity!
00765               // For now, assume we didn't find anything with that name
00766        }
00767        
00768        IMPORT_LOG0( "In GetAddressBook\n");
00769 
00770        nsCOMPtr<nsIProxyObjectManager> proxyMgr = 
00771                 do_GetService(kProxyObjectManagerCID, &rv);
00772        if (NS_FAILED( rv)) {
00773               IMPORT_LOG0( "*** Error: Unable to get proxy manager\n");
00774               return( nsnull);
00775        }
00776 
00777        nsIAddrDatabase *    pDatabase = nsnull;
00778 
00779        /* Get the profile directory */
00780        nsCOMPtr<nsILocalFile> dbPath;
00781 
00782        NS_WITH_PROXIED_SERVICE(nsIAddrBookSession, abSession, NS_ADDRBOOKSESSION_CONTRACTID, NS_UI_THREAD_EVENTQ, &rv); 
00783        
00784        if (NS_SUCCEEDED(rv))
00785               rv = abSession->GetUserProfileDirectory(getter_AddRefs(dbPath));
00786        if (NS_SUCCEEDED(rv)) {
00787               // Create a new address book file - we don't care what the file
00788               // name is, as long as it's unique
00789               rv = dbPath->Append(NS_LITERAL_STRING("impab.mab"));
00790         if (NS_SUCCEEDED(rv)) {
00791           rv = dbPath->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
00792               
00793           if (NS_SUCCEEDED(rv)) {
00794             IMPORT_LOG0( "Getting the address database factory\n");
00795 
00796             NS_WITH_PROXIED_SERVICE(nsIAddrDatabase, addrDBFactory, NS_ADDRDATABASE_CONTRACTID, NS_UI_THREAD_EVENTQ, &rv);
00797             if (NS_SUCCEEDED(rv) && addrDBFactory) {
00798                        IMPORT_LOG0( "Opening the new address book\n");
00799                        rv = addrDBFactory->Open( dbPath, PR_TRUE, PR_TRUE, &pDatabase);
00800             }
00801           }
00802         }
00803        }
00804        if (NS_FAILED(rv)) {
00805               IMPORT_LOG0( "Failed to get the user profile directory from the address book session\n");
00806        }
00807 
00808        
00809        if (pDatabase) {
00810               // We made a database, add it to the UI?!?!?!?!?!?!
00811               // This is major bogosity again!  Why doesn't the address book
00812               // just handle this properly for me?  Uggggg...
00813               
00814               NS_WITH_PROXIED_SERVICE(nsIRDFService, rdfService, kRDFServiceCID, NS_UI_THREAD_EVENTQ, &rv);
00815               if (NS_SUCCEEDED(rv)) {
00816                      nsCOMPtr<nsIRDFResource>    parentResource;
00817                      rv = rdfService->GetResource(NS_LITERAL_CSTRING(kAllDirectoryRoot),
00818                                    getter_AddRefs(parentResource));
00819                      nsCOMPtr<nsIAbDirectory> parentDir;
00820                      /*
00821                       * TODO
00822                       * This may not be required in the future since the 
00823                       * primary listeners of the nsIAbDirectory will be
00824                       * RDF directory datasource which propagates events to
00825                       * RDF Observers. In the future the RDF directory datasource
00826                       * will proxy the observers because asynchronous directory
00827                       * implementations, such as LDAP, will assert results from
00828                       * a thread other than the UI thread.
00829                       *
00830                       */
00831                      rv = proxyMgr->GetProxyForObject( NS_UI_THREAD_EVENTQ, NS_GET_IID( nsIAbDirectory),
00832                             parentResource, PROXY_SYNC | PROXY_ALWAYS, getter_AddRefs( parentDir));
00833                      if (parentDir)
00834                      {
00835                             nsCAutoString URI("moz-abmdbdirectory://");
00836                             nsCAutoString leafName;
00837                             rv = dbPath->GetNativeLeafName(leafName);
00838                             if (NS_FAILED(rv)) {
00839                               IMPORT_LOG0( "*** Error: Unable to get name of database file\n");
00840                             }
00841                             else {
00842                               URI.Append(leafName);
00843                               rv = parentDir->CreateDirectoryByURI(name, URI.get (), PR_FALSE);
00844                               if (NS_FAILED(rv))
00845                                 IMPORT_LOG0( "*** Error: Unable to create address book directory\n");
00846                             }
00847                      }
00848 
00849                      if (NS_SUCCEEDED(rv))
00850                        IMPORT_LOG0( "Added new address book to the UI\n");
00851                      else
00852                        IMPORT_LOG0( "*** Error: An error occurred while adding the address book to the UI\n");
00853               }
00854        }
00855        
00856        return( pDatabase);
00857 }
00858 
00859 void nsImportGenericAddressBooks::ReportError( PRUnichar *pName, nsString *pStream)
00860 {
00861        if (!pStream)
00862               return;
00863        // load the error string
00864        PRUnichar *pFmt = nsImportStringBundle::GetStringByID( IMPORT_ERROR_GETABOOK);
00865        PRUnichar *pText = nsTextFormatter::smprintf( pFmt, pName);
00866        pStream->Append( pText);
00867        nsTextFormatter::smprintf_free( pText);
00868        nsImportStringBundle::FreeString( pFmt);
00869        pStream->AppendWithConversion( NS_LINEBREAK);
00870 }
00871 
00872 PR_STATIC_CALLBACK( void) ImportAddressThread( void *stuff)
00873 {
00874        IMPORT_LOG0( "In Begin ImportAddressThread\n");
00875 
00876        AddressThreadData *pData = (AddressThreadData *)stuff;
00877        PRUint32      count = 0;
00878        nsresult      rv = pData->books->Count( &count);
00879        
00880        PRUint32                                  i;
00881        PRBool                                    import;
00882        PRUint32                                  size;
00883        nsCOMPtr<nsIAddrDatabase>   destDB( getter_AddRefs( GetAddressBookFromUri( pData->pDestinationUri)));
00884        nsCOMPtr<nsIAddrDatabase> pDestDB;
00885   
00886        nsString                                  success;
00887        nsString                                  error;
00888 
00889        for (i = 0; (i < count) && !(pData->abort); i++) {
00890               nsCOMPtr<nsIImportABDescriptor> book =
00891                      do_QueryElementAt(pData->books, i);
00892               if (book) {
00893                      import = PR_FALSE;
00894                      size = 0;
00895                      rv = book->GetImport( &import);
00896                      if (import)
00897                             rv = book->GetSize( &size);
00898                      
00899                      if (size && import) {
00900                             PRUnichar *pName;
00901                             book->GetPreferredName( &pName);
00902                             if (destDB) {
00903                                    pDestDB = destDB;
00904                             }
00905                             else {
00906                                    pDestDB = GetAddressBook( pName, PR_TRUE);
00907                             }
00908 
00909                             nsCOMPtr<nsIAddrDatabase> proxyAddrDatabase;
00910                             rv = NS_GetProxyForObject(NS_UI_THREAD_EVENTQ,
00911                                           NS_GET_IID(nsIAddrDatabase),
00912                                           pDestDB,
00913                                           PROXY_SYNC | PROXY_ALWAYS,
00914                                           getter_AddRefs(proxyAddrDatabase));
00915                             if (NS_FAILED(rv))
00916                                    return;
00917 
00918                             PRBool fatalError = PR_FALSE;
00919                             pData->currentSize = size;
00920                             if (proxyAddrDatabase) {
00921                                    PRUnichar *pSuccess = nsnull;
00922                                    PRUnichar *pError = nsnull;
00923 
00924                                    /*
00925                                    if (pData->fieldMap) {
00926                                           PRInt32              sz = 0;
00927                                           PRInt32              mapIndex;
00928                                           PRBool        active;
00929                                           pData->fieldMap->GetMapSize( &sz);
00930                                           IMPORT_LOG1( "**** Field Map Size: %d\n", (int) sz);
00931                                           for (PRInt32 i = 0; i < sz; i++) {
00932                                                  pData->fieldMap->GetFieldMap( i, &mapIndex);
00933                                                  pData->fieldMap->GetFieldActive( i, &active);
00934                                                  IMPORT_LOG3( "Field map #%d: index=%d, active=%d\n", (int) i, (int) mapIndex, (int) active);
00935                                           }
00936                                    }
00937                                    */
00938 
00939                                    rv = pData->addressImport->ImportAddressBook(    book, 
00940                                                                                                                 proxyAddrDatabase, // destination
00941                                                                                                                 pData->fieldMap, // fieldmap
00942                                                                                                                 pData->bAddrLocInput,
00943                                                                                                                 &pError,
00944                                                                                                                 &pSuccess,
00945                                                                                                                 &fatalError);
00946                                    if (pSuccess) {
00947                                           success.Append( pSuccess);
00948                                           nsCRT::free( pSuccess);
00949                                    }
00950                                    if (pError) {
00951                                           error.Append( pError);
00952                                           nsCRT::free( pError);
00953                                    }
00954                             }
00955                             else {
00956                                    nsImportGenericAddressBooks::ReportError( pName, &error);
00957                             }
00958 
00959                             nsCRT::free( pName);
00960 
00961                             pData->currentSize = 0;
00962                             pData->currentTotal += size;
00963                                    
00964                             if (!proxyAddrDatabase) {
00965                                    proxyAddrDatabase->Close( PR_TRUE);
00966                             }
00967 
00968                             if (fatalError) {
00969                                    pData->fatalError = PR_TRUE;
00970                                    break;
00971                             }
00972                      }
00973               }
00974 
00975               if (destDB) {
00976                      destDB->Close( PR_TRUE);
00977               }
00978        }
00979 
00980        
00981        nsImportGenericAddressBooks::SetLogs( success, error, pData->successLog, pData->errorLog);
00982 
00983        if (pData->abort || pData->fatalError) {
00984               // FIXME: do what is necessary to get rid of what has been imported so far.
00985               // Nothing if we went into an existing address book!  Otherwise, delete
00986               // the ones we created?
00987        }
00988 
00989        pData->ThreadDelete();      
00990 }