Back to index

lightning-sunbird  0.9+nobinonly
nsAbPalmSync.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is mozilla.org code.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation
00018  *
00019  * Portions created by the Initial Developer are Copyright (C) 2002
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *       Rajiv Dayal <rdayal@netscape.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * 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 "nsRDFResource.h"
00040 #include "nsAbPalmSync.h"
00041 #include "nsIAddrBookSession.h"
00042 #include "nsAbBaseCID.h"
00043 #include "nsMsgI18N.h"
00044 #include "nsIRDFService.h"
00045 #include "nsRDFCID.h"
00046 #include "nsUnicharUtils.h"
00047 #include "nsIAbMDBCard.h"
00048 #include "nsAbCardProperty.h"
00049 #include "prdtoa.h"
00050 #include "nsMsgUtils.h"
00051 
00052 #define  PREVIOUS_EXTENSION ".prev"
00053 #define  kPABDirectory  2 // defined in nsDirPrefs.h
00054 #define  kMAPIDirectory 3 // defined in nsDirPrefs.h
00055 
00056 #define PERSONAL_ADDRBOOK_URL   "moz-abmdbdirectory://abook.mab" // defined in MozABConduitSync.h
00057 
00058 #ifdef DEBUG_bienvenu
00059    PRBool PalmDataDisplayed = PR_FALSE;
00060    void DisplayTestData(nsABCOMCardStruct * aIPCCard, PRBool IsUnicode)
00061    {
00062        if (IsUnicode) {
00063            if(aIPCCard->displayName)
00064                printf("\n Card Data For : %S:", aIPCCard->displayName);
00065            if(aIPCCard->firstName)
00066                printf("\n First Name : %S", aIPCCard->firstName);
00067            if(aIPCCard->lastName)
00068                printf("\n Last Name : %S", aIPCCard->lastName);
00069            if(aIPCCard->primaryEmail)
00070                printf("\n Email : %S", aIPCCard->primaryEmail);
00071            if(aIPCCard->workPhone)
00072                printf("\n Work Phone : %S", aIPCCard->workPhone);
00073            if(aIPCCard->homePhone)
00074                printf("\n Home Phone : %S", aIPCCard->homePhone);
00075            if(aIPCCard->faxNumber)
00076                printf("\n Fax Number : %S", aIPCCard->faxNumber);
00077            if(aIPCCard->company)
00078                printf("\n Company : %S", aIPCCard->company);
00079            if(aIPCCard->jobTitle)
00080                printf("\n Job Title : %S", aIPCCard->jobTitle);
00081            if(aIPCCard->homeAddress)
00082                printf("\n Home Address : %S", aIPCCard->homeAddress);
00083            if(aIPCCard->homeCity)
00084                printf("\n Home City : %S", aIPCCard->homeCity);
00085            if(aIPCCard->homeState)
00086                printf("\n Home State : %S", aIPCCard->homeState);
00087            printf("\n");
00088        }
00089        else {
00090            if(aIPCCard->displayName)
00091                printf("\n Card Data For : %s:", (char *) aIPCCard->displayName);
00092            if(aIPCCard->firstName)
00093                printf("\n First Name : %s", (char *) aIPCCard->firstName);
00094            if(aIPCCard->lastName)
00095                printf("\n Last Name : %s", (char *) aIPCCard->lastName);
00096            if(aIPCCard->primaryEmail)
00097                printf("\n Email : %s", (char *) aIPCCard->primaryEmail);
00098            if(aIPCCard->workPhone)
00099                printf("\n Work Phone : %s", (char *) aIPCCard->workPhone);
00100            if(aIPCCard->homePhone)
00101                printf("\n Home Phone : %s", (char *) aIPCCard->homePhone);
00102            if(aIPCCard->faxNumber)
00103                printf("\n Fax Number : %s", (char *) aIPCCard->faxNumber);
00104            if(aIPCCard->company)
00105                printf("\n Company :   %s", (char *) aIPCCard->company);
00106            if(aIPCCard->jobTitle)
00107                printf("\n Job Title : %s", (char *) aIPCCard->jobTitle);
00108            if(aIPCCard->homeAddress)
00109                printf("\n Home Address : %s", (char *) aIPCCard->homeAddress);
00110            if(aIPCCard->homeCity)
00111                printf("\n Home City : %s", (char *) aIPCCard->homeCity);
00112            if(aIPCCard->homeState)
00113                printf("\n Home State : %s", (char *) aIPCCard->homeState);
00114            printf("\n");
00115        }
00116    }
00117 #endif
00118 
00119 nsAbPalmHotSync::nsAbPalmHotSync(PRBool aIsUnicode, PRUnichar * aAbDescUnicode, const char * aAbDesc, PRInt32 aPalmCatIndex, PRInt32 aPalmCatId)
00120 {
00121     mTotalCardCount=0;
00122 
00123     mCardForPalmCount = 0;
00124     mCardListForPalm = nsnull;
00125     
00126     mInitialized = PR_FALSE;
00127     mDBOpen = PR_FALSE;
00128     
00129     if(aIsUnicode)
00130         mAbName.Assign(aAbDescUnicode);
00131     else
00132         mAbName.AssignASCII(aAbDesc);
00133     mAbName.Trim(" ");
00134 
00135     mPalmCategoryIndex = aPalmCatIndex;
00136     mPalmCategoryId    = aPalmCatId;
00137 
00138     mIsPalmDataUnicode = aIsUnicode;
00139 
00140     mNewCardCount = 0;
00141     NS_NewISupportsArray(getter_AddRefs(mNewCardsArray));
00142     mIsNewCardForPalm = PR_FALSE;
00143 }
00144 
00145 nsAbPalmHotSync::~nsAbPalmHotSync()
00146 {
00147     // clear the nsVoidArray, don't free the stored pointers since they are freed by calling app (Conduit)
00148     mPalmRecords.Clear();
00149 
00150     if(mDBOpen && mABDB)
00151         mABDB->Close(PR_FALSE);
00152 }
00153 
00154 // this is a utility function
00155 void nsAbPalmHotSync::ConvertAssignPalmIDAttrib(PRUint32 id, nsIAbMDBCard * card)  
00156 { 
00157     PRInt64 l;
00158     LL_UI2L(l, id);
00159     PRFloat64 f;
00160     LL_L2F(f, l);
00161     char buf[128];
00162     PR_cnvtf(buf, 128, 0, f);
00163     card->SetAbDatabase(mABDB);
00164     card->SetStringAttribute(CARD_ATTRIB_PALMID,NS_ConvertASCIItoUCS2(buf).get());
00165 }
00166 
00167 nsresult nsAbPalmHotSync::GetABInterface()
00168 {
00169   // Use GetChildNodes() call here.
00170   nsresult rv;
00171   nsCOMPtr<nsIRDFService> rdfService = do_GetService (NS_RDF_CONTRACTID "/rdf-service;1", &rv);
00172   if(NS_FAILED(rv)) return E_FAIL;
00173     
00174   // Parent nsIABDirectory is "moz-abdirectory://".
00175   nsCOMPtr <nsIRDFResource> resource;
00176   rv = rdfService->GetResource(NS_LITERAL_CSTRING("moz-abdirectory://"), getter_AddRefs(resource));
00177   if(NS_FAILED(rv)) return E_FAIL;
00178 
00179   nsCOMPtr <nsIAbDirectory> directory = do_QueryInterface(resource, &rv);
00180   if(NS_FAILED(rv)) return E_FAIL;
00181 
00182   nsXPIDLCString fileName, uri, prefName;
00183   nsAutoString description;
00184   PRUint32 dirType, palmSyncTimeStamp;
00185   PRInt32 palmCategoryIndex;
00186   nsCOMPtr<nsISimpleEnumerator> subDirectories;
00187   if (NS_FAILED(directory->GetChildNodes(getter_AddRefs(subDirectories))) || !subDirectories)
00188     return E_FAIL;
00189 
00190   // Check each valid addrbook.
00191   nsCOMPtr<nsISupports> item;
00192   PRBool hasMore;
00193   while (NS_SUCCEEDED(rv = subDirectories->HasMoreElements(&hasMore)) && hasMore)
00194   {
00195     if (NS_SUCCEEDED(subDirectories->GetNext(getter_AddRefs(item))))
00196     {
00197       directory = do_QueryInterface(item, &rv);
00198       if (NS_SUCCEEDED(rv))
00199       {
00200         // TODO: may need to skip mailing list?? but maybe not since there's no mailing list on the top level.
00201         nsCOMPtr <nsIAbDirectoryProperties> properties;
00202         rv = directory->GetDirectoryProperties(getter_AddRefs(properties));
00203         if(NS_FAILED(rv)) return E_FAIL;
00204 
00205         rv = properties->GetDescription(description);
00206         if(NS_FAILED(rv)) return E_FAIL;
00207         rv = properties->GetFileName(getter_Copies(fileName));
00208         if(NS_FAILED(rv)) return E_FAIL;
00209         rv = properties->GetURI(getter_Copies(uri));
00210         if(NS_FAILED(rv)) return E_FAIL;
00211         rv = properties->GetDirType(&dirType);
00212         if(NS_FAILED(rv)) return E_FAIL;
00213         rv = properties->GetSyncTimeStamp(&palmSyncTimeStamp);
00214         if(NS_FAILED(rv)) return E_FAIL;
00215         rv = properties->GetCategoryId(&palmCategoryIndex);
00216         if(NS_FAILED(rv)) return E_FAIL;
00217         rv = properties->GetPrefName(getter_Copies(prefName));
00218 
00219         // Skip/Ignore 4.X addrbooks (ie, with ".na2" extension).
00220         if (((fileName.Length() > kABFileName_PreviousSuffixLen) && 
00221             strcmp(fileName.get() + fileName.Length() - kABFileName_PreviousSuffixLen, kABFileName_PreviousSuffix) == 0) ||
00222             (dirType != kPABDirectory && dirType != kMAPIDirectory))
00223           continue;
00224 
00225         // If Palm category is already assigned to AB then just check that (ie, was synced before).
00226         if((palmCategoryIndex > -1) && (mPalmCategoryIndex == palmCategoryIndex))
00227           break;
00228 
00229         // If Palm category is not already assigned check the AB name (ie, never
00230         // synced before). Note that Palm category name is only 15 chars max.
00231         if (description.Length() > 15 && mAbName.Length() <= 15)
00232           description.Cut(15, description.Length()-15);
00233 
00234         // check for matching AB+Category, and special case personal address book
00235         // to match "Personal" category.
00236         if(description == mAbName || 
00237             (prefName.Equals("ldap_2.servers.pab", nsCaseInsensitiveCStringComparator())
00238              && mAbName.LowerCaseEqualsLiteral("personal")))
00239           break;
00240         directory = nsnull;
00241       }
00242     }
00243   }
00244 
00245   // If not found return error.
00246   if(!directory)
00247     return NS_ERROR_FILE_NOT_FOUND;
00248 
00249   mDirectory = directory;
00250   mFileName = fileName;
00251   mUri = uri;
00252   mDescription = description;
00253   mDirType = dirType;
00254   mPalmSyncTimeStamp = palmSyncTimeStamp;
00255 
00256   return NS_OK;
00257 }
00258 
00259 nsresult nsAbPalmHotSync::Initialize()
00260 {
00261   // Use GetChildNodes() call here.
00262   if(mInitialized)
00263       return NS_OK;
00264 
00265   nsresult rv = GetABInterface();
00266   NS_ENSURE_SUCCESS(rv, rv);
00267   mInitialized = TRUE;
00268     return NS_OK;
00269 }
00270 
00271 nsresult nsAbPalmHotSync::AddAllRecordsToAB(PRBool existingAB, PRInt32 aCount, lpnsABCOMCardStruct aPalmRecords)
00272 {
00273     NS_ENSURE_ARG_POINTER(aPalmRecords);
00274     nsresult rv;
00275     // Create the new AB dir before adding cards/records.
00276     if (existingAB)
00277     {
00278       rv = Initialize();  
00279       NS_ENSURE_SUCCESS(rv, rv); 
00280       rv = OpenABDBForHotSync(PR_FALSE);
00281       NS_ENSURE_SUCCESS(rv, rv);
00282       // lets try deleting the db out from under ourselves. 
00283       nsFileSpec *abFileSpec;
00284       rv = mABDB->GetDbPath(&abFileSpec);
00285       NS_ENSURE_SUCCESS(rv, rv);
00286       mABDB->ForceClosed();
00287       mDBOpen = PR_FALSE;
00288       mABDB = nsnull;
00289       abFileSpec->Delete(PR_FALSE);
00290       delete abFileSpec;
00291     }
00292     else
00293     {
00294       nsresult rv = NewAB(mAbName);
00295       NS_ENSURE_SUCCESS(rv, rv);
00296 
00297       rv = Initialize(); // Find the new AB and and init some vars (set mDirectory etc).
00298       NS_ENSURE_SUCCESS(rv, rv);
00299     }
00300 
00301     // open the Moz AB database
00302     rv = OpenABDBForHotSync(PR_TRUE);
00303     NS_ENSURE_SUCCESS(rv, rv);
00304     // we are just storing the pointer array here not record arrays
00305     for (PRInt32 i=0; i < aCount; i++)
00306         mPalmRecords.AppendElement(&aPalmRecords[i]);
00307 
00308     // new DB here so no need to backup
00309     rv = UpdateMozABWithPalmRecords();
00310  
00311     rv = mABDB->Close(NS_SUCCEEDED(rv));
00312 
00313     if(NS_SUCCEEDED(rv)) {
00314         mDBOpen = PR_FALSE;
00315         PRUint32 modTimeInSec;
00316         PRTime2Seconds(PR_Now(), &modTimeInSec);
00317         rv = UpdateABInfo(modTimeInSec, mPalmCategoryIndex);
00318     }
00319     else { // get back the previous file
00320         rv = mABDB->ForceClosed();
00321         if(NS_SUCCEEDED(rv)) {
00322             nsCAutoString leafName;
00323             mABFile->GetNativeLeafName(leafName);
00324             PRBool bExists=PR_FALSE;
00325             mPreviousABFile->Exists(&bExists);
00326             if(bExists) {
00327                 nsCOMPtr<nsIFile> parent;
00328                 rv = mABFile->GetParent(getter_AddRefs(parent));
00329                 if (NS_SUCCEEDED(rv)) {
00330                     mABFile->Remove(PR_FALSE);
00331                     mPreviousABFile->CopyToNative(parent, leafName);
00332                 }
00333             }
00334             mDBOpen = PR_FALSE;
00335         }
00336     }
00337 
00338     return rv;
00339 }
00340 
00341 nsresult nsAbPalmHotSync::GetAllCards(PRInt32 * aCount, lpnsABCOMCardStruct * aCardList)
00342 {
00343     NS_ENSURE_ARG_POINTER(aCount);
00344     NS_ENSURE_ARG_POINTER(aCardList);
00345 
00346     if(!mInitialized) 
00347         return NS_ERROR_NOT_INITIALIZED;
00348 
00349     // open the Moz AB database
00350     nsresult rv = OpenABDBForHotSync(PR_FALSE); 
00351     if(NS_FAILED(rv))
00352         return rv;
00353 
00354     // create the list to be sent back to Palm
00355     mABDB->GetCardCount(&mTotalCardCount);
00356     *aCount = mTotalCardCount;
00357     if(!mTotalCardCount) {
00358         mABDB->Close(PR_FALSE);
00359         return NS_OK;
00360     }
00361 
00362     mCardListForPalm = (lpnsABCOMCardStruct) CoTaskMemAlloc(sizeof(nsABCOMCardStruct) * mTotalCardCount);
00363     if(!mCardListForPalm) {
00364         mABDB->Close(PR_FALSE);
00365         return NS_ERROR_OUT_OF_MEMORY;
00366     }
00367 
00368     nsCOMPtr<nsIEnumerator> cardsEnumerator;
00369     rv = mABDB->EnumerateCards(mDirectory, getter_AddRefs(cardsEnumerator));
00370     if (NS_FAILED(rv) || !cardsEnumerator) {
00371         mABDB->Close(PR_FALSE);
00372         return rv;
00373     }
00374 
00375     nsCOMPtr<nsISupports> item;
00376     nsCOMPtr<nsIAbCard> card;
00377     for (rv = cardsEnumerator->First(); NS_SUCCEEDED(rv); rv = cardsEnumerator->Next()) {
00378         rv = cardsEnumerator->CurrentItem(getter_AddRefs(item));
00379         if (NS_FAILED(rv)) 
00380             continue;
00381 
00382         card = do_QueryInterface(item, &rv);
00383         if (NS_FAILED(rv)) // can this be anything but a card?
00384             continue;
00385 
00386         PRBool isMailingList=PR_FALSE;
00387         rv = card->GetIsMailList(&isMailingList);
00388         if (NS_FAILED(rv) || isMailingList) // if mailing list go to cards
00389             continue;
00390 
00391         nsAbIPCCard  ipcCard(card);
00392         ipcCard.SetStatus(ATTR_NEW);
00393 
00394         rv = AddToListForPalm(ipcCard);
00395         if(NS_FAILED(rv))
00396             break;
00397 
00398         mNewCardsArray->AppendElement(card);
00399         mNewCardCount++;
00400     }
00401 
00402 
00403     *aCount = mCardForPalmCount;
00404     *aCardList = mCardListForPalm;
00405 
00406     // Don't close the DB yet, it will be closed when Done is called
00407 
00408     return NS_OK;
00409 }
00410 
00411 nsresult nsAbPalmHotSync::DoSyncAndGetUpdatedCards(PRInt32 aPalmCount, lpnsABCOMCardStruct aPalmRecords, 
00412                                                     PRInt32 * aMozCount, lpnsABCOMCardStruct * aMozCards)
00413 {
00414     NS_ENSURE_ARG_POINTER(aPalmRecords);
00415     NS_ENSURE_ARG_POINTER(aMozCount);
00416     NS_ENSURE_ARG_POINTER(aMozCards);
00417 
00418     if(!mInitialized) 
00419         return NS_ERROR_NOT_INITIALIZED;
00420 
00421     // open the Moz AB database
00422     nsresult rv = OpenABDBForHotSync(PR_FALSE); 
00423     if(NS_FAILED(rv))
00424         return rv;
00425 
00426     // we are just storing the pointer array here, not record arrays
00427     for (PRInt32 i=0; i < aPalmCount; i++) 
00428     {
00429         mPalmRecords.AppendElement(&aPalmRecords[i]);
00430 #ifdef DEBUG_bienvenu        
00431         DisplayTestData(&aPalmRecords[i],PR_FALSE);
00432 #endif
00433     }
00434 
00435     // create the list to be sent back to Palm
00436     mABDB->GetCardCount(&mTotalCardCount);
00437     PRUint32  deletedCardCount=0;
00438     mABDB->GetDeletedCardCount(&deletedCardCount);
00439     mTotalCardCount += deletedCardCount;
00440     if(mTotalCardCount) 
00441     {
00442         mCardListForPalm = (lpnsABCOMCardStruct) CoTaskMemAlloc(sizeof(nsABCOMCardStruct) * mTotalCardCount);
00443         if(!mCardListForPalm) 
00444         {
00445             mABDB->Close(PR_FALSE);
00446             return NS_ERROR_OUT_OF_MEMORY;
00447         }
00448     }
00449 
00450     // initialize the flag for any new Moz cards to be added to Palm
00451     mIsNewCardForPalm = PR_FALSE;
00452 
00453     // deal with new / modified or first time sync
00454     rv = LoadNewModifiedCardsSinceLastSync();
00455     if(NS_SUCCEEDED(rv))
00456         // deal with deleted
00457         rv = LoadDeletedCardsSinceLastSync();
00458     if(NS_SUCCEEDED(rv))
00459         // first backup the existing DB as Previous
00460         rv = KeepCurrentStateAsPrevious();
00461     if(NS_SUCCEEDED(rv))
00462         // update local DB for sync
00463         rv = UpdateMozABWithPalmRecords();
00464 
00465     // if there are no new cards to be added in Palm close DB
00466     // else wait for Done to be called.
00467     if(!mIsNewCardForPalm) 
00468     {
00469         rv = mABDB->Close(NS_SUCCEEDED(rv) && mPalmRecords.Count());
00470 
00471         if(NS_SUCCEEDED(rv)) 
00472         {
00473             mDBOpen = PR_FALSE;
00474             PRUint32 modTimeInSec;
00475             PRTime2Seconds(PR_Now(), &modTimeInSec);
00476             rv = UpdateABInfo(modTimeInSec, mPalmCategoryIndex);
00477         }
00478         else
00479         { // get back the previous file
00480             rv = mABDB->ForceClosed();
00481             if(NS_SUCCEEDED(rv)) 
00482             {
00483                 nsCAutoString leafName;
00484                 mABFile->GetNativeLeafName(leafName);
00485                 PRBool bExists=PR_FALSE;
00486                 mPreviousABFile->Exists(&bExists);
00487                 if(bExists) 
00488                 {
00489                     nsCOMPtr<nsIFile> parent;
00490                     rv = mABFile->GetParent(getter_AddRefs(parent));
00491                     if (NS_SUCCEEDED(rv)) 
00492                     {
00493                         mABFile->Remove(PR_FALSE);
00494                         mPreviousABFile->CopyToNative(parent, leafName);
00495                     }
00496                 }
00497                 mDBOpen = PR_FALSE;
00498             }
00499         }
00500     }
00501 
00502     *aMozCount = mCardForPalmCount;
00503     *aMozCards = mCardListForPalm;
00504 
00505     return rv;
00506 }
00507 
00508 // this takes care of the cases when the state is deleted
00509 nsresult nsAbPalmHotSync::LoadDeletedCardsSinceLastSync()
00510 {
00511     if(!mDBOpen || !mABDB || !mInitialized) 
00512         return NS_ERROR_NOT_INITIALIZED;
00513     
00514     nsISupportsArray * deletedCardArray;
00515     PRUint32  deletedCardCount;
00516     nsresult rv = mABDB->GetDeletedCardList(&deletedCardCount, &deletedCardArray);
00517     if(NS_FAILED(rv))
00518         return rv;
00519 
00520     for(PRUint32 i=0; i < deletedCardCount; i++) 
00521     {
00522         nsCOMPtr<nsIAbCard> card; 
00523         rv = deletedCardArray->QueryElementAt(i, NS_GET_IID(nsIAbCard), getter_AddRefs(card));
00524         if (NS_FAILED(rv)) // can this be anything but a card?
00525             continue;
00526         
00527         PRBool isMailingList=PR_FALSE;
00528         rv = card->GetIsMailList(&isMailingList);
00529         if (NS_FAILED(rv) || isMailingList)
00530             continue;
00531 
00532         PRUint32 lastModifiedDate = 0;
00533         rv = card->GetLastModifiedDate(&lastModifiedDate);
00534         if (NS_FAILED(rv) || !lastModifiedDate)
00535             continue;
00536 
00537         if(lastModifiedDate > mPalmSyncTimeStamp)
00538         {
00539             nsAbIPCCard  ipcCard(card);
00540             // check in the list of Palm records
00541             for(PRInt32 i=mPalmRecords.Count()-1; i >=0;  i--) 
00542             {
00543                 nsABCOMCardStruct * palmRec = (nsABCOMCardStruct *) mPalmRecords.ElementAt(i);
00544                 // if same record exists in palm list, donot delete it from Palm
00545                 if(ipcCard.Same(palmRec, mIsPalmDataUnicode))
00546                     continue;
00547             }
00548             ipcCard.SetStatus(ATTR_DELETED);
00549 
00550             rv = AddToListForPalm(ipcCard);
00551             if(NS_FAILED(rv))
00552                 break;
00553         }
00554     }
00555     return rv;
00556 }
00557 
00558 
00559 nsresult nsAbPalmHotSync::LoadNewModifiedCardsSinceLastSync()
00560 {
00561     if(!mDBOpen || !mABDB || !mInitialized) 
00562         return NS_ERROR_NOT_INITIALIZED;
00563 
00564     nsCOMPtr<nsIEnumerator> cardsEnumerator;
00565     nsresult rv = mABDB->EnumerateCards(mDirectory, getter_AddRefs(cardsEnumerator));
00566     if (NS_FAILED(rv) || !cardsEnumerator) 
00567         return NS_ERROR_NOT_AVAILABLE; // no cards available
00568 
00569     // create the list of cards to be sent to Palm
00570     nsCOMPtr<nsISupports> item;
00571     nsCOMPtr<nsIAbCard> card;
00572     for (rv = cardsEnumerator->First(); NS_SUCCEEDED(rv); rv = cardsEnumerator->Next()) 
00573     {
00574         rv = cardsEnumerator->CurrentItem(getter_AddRefs(item));
00575         if (NS_FAILED(rv)) 
00576             return rv;
00577 
00578         card = do_QueryInterface(item, &rv);
00579         if (NS_FAILED(rv)) // can this be anything but a card?
00580             continue;
00581 
00582         PRBool isMailingList=PR_FALSE;
00583         rv = card->GetIsMailList(&isMailingList);
00584         if (NS_FAILED(rv) || isMailingList) // if mailing list go to cards
00585             continue;
00586 
00587         PRUint32 lastModifiedDate = 0;
00588         rv = card->GetLastModifiedDate(&lastModifiedDate);
00589         if (NS_FAILED(rv))
00590             continue;
00591 
00592         if(lastModifiedDate > mPalmSyncTimeStamp  // take care of modified
00593             || !lastModifiedDate || !mPalmSyncTimeStamp) 
00594         {  // take care of new or never before sync
00595             
00596             //create nsAbIPCCard and assign its status based on lastModifiedDate
00597             nsAbIPCCard ipcCard(card);
00598             ipcCard.AddRef(); // someone needs a reference to this, since we
00599             // pass it around as an interface pointer
00600             ipcCard.SetStatus((lastModifiedDate) ? ATTR_MODIFIED : ATTR_NEW);
00601 
00602             // Check with the palm list (merging is done if required)
00603             if (CardExistsInPalmList(&ipcCard)) 
00604                 continue;
00605 
00606             rv = AddToListForPalm(ipcCard);
00607             if(NS_FAILED(rv))
00608                 break;
00609 
00610             if(ipcCard.GetStatus() == ATTR_NEW) 
00611             {
00612                 mNewCardsArray->AppendElement(card);
00613                 mNewCardCount++;
00614                 mIsNewCardForPalm = PR_TRUE;
00615             }
00616         }
00617     }
00618 
00619     return NS_OK;
00620 }
00621 
00622 
00623 // this take care of the all cases when the state is either modified or new
00624 PRBool nsAbPalmHotSync::CardExistsInPalmList(nsAbIPCCard  * aIPCCard)
00625 {
00626     NS_ENSURE_ARG_POINTER(aIPCCard);
00627 
00628     if(!mInitialized) 
00629         return PR_FALSE;
00630 
00631     PRBool exists = PR_FALSE;
00632 
00633     for(PRInt32 i=mPalmRecords.Count()-1; i >=0;  i--) 
00634     {
00635         nsABCOMCardStruct * palmRec = (nsABCOMCardStruct *) mPalmRecords.ElementAt(i);
00636         
00637         // if same record is in palm list also
00638         if(aIPCCard->Same(palmRec, mIsPalmDataUnicode)) 
00639         {
00640             // if the state deleted on both sides no need to do anything
00641             if ((palmRec->dwStatus & ATTR_DELETED || palmRec->dwStatus & ATTR_ARCHIVED) &&
00642                 (aIPCCard->GetStatus() == ATTR_DELETED)) 
00643             {
00644                 mPalmRecords.RemoveElementAt(i);
00645                 return PR_TRUE;
00646             }
00647             // if deleted on Palm and added or modified on Moz, don't delete on Moz
00648             if ( (palmRec->dwStatus & ATTR_DELETED || palmRec->dwStatus & ATTR_ARCHIVED) && 
00649                  ((aIPCCard->GetStatus() == ATTR_NEW) || (aIPCCard->GetStatus() == ATTR_MODIFIED)) ) 
00650             {
00651                 mPalmRecords.RemoveElementAt(i);
00652                 return PR_FALSE;
00653             }
00654 
00655             // set the palm record ID in the card if not already set
00656             if(!aIPCCard->GetRecordId()) 
00657             {
00658                 ConvertAssignPalmIDAttrib(palmRec->dwRecordId, aIPCCard);
00659                 mABDB->EditCard(aIPCCard, PR_FALSE);
00660                 aIPCCard->SetRecordId(palmRec->dwRecordId);
00661             }
00662 
00663             // if deleted in Moz and added or modified on Palm, don't delete on Palm
00664             if ( (aIPCCard->GetStatus() == ATTR_DELETED) && 
00665                  ((palmRec->dwStatus == ATTR_NEW) 
00666                    ||(palmRec->dwStatus == ATTR_MODIFIED)) ) 
00667                 return PR_TRUE;
00668 
00669             // for rest of the cases with state as either mod or new:
00670             nsStringArray diffAttrs;
00671             PRBool fieldsMatch = PR_FALSE;
00672             if(mIsPalmDataUnicode)
00673                 fieldsMatch = aIPCCard->Equals(palmRec, diffAttrs);
00674             else
00675                 fieldsMatch = aIPCCard->EqualsAfterUnicodeConversion(palmRec, diffAttrs);
00676 
00677             // if fields match, no need to keep it for sync
00678             if(fieldsMatch) 
00679             {
00680                 exists = PR_TRUE;
00681                 // since the fields match, no need to update Moz AB with palm record
00682                 mPalmRecords.RemoveElementAt(i); 
00683             }
00684             else 
00685             {
00686                 // we add an additional record on both sides alike Palm Desktop sync
00687                 palmRec->dwStatus = ATTR_NONE;
00688                 aIPCCard->SetStatus(ATTR_NEW);
00689                 exists = PR_FALSE;
00690             }
00691             // since we found the same record in palm sync list
00692             // no need to go thru the rest of the mPalmRecords list
00693             break;
00694         }
00695     }
00696 
00697     return exists;
00698 }
00699 
00700 // utility function
00701 nsresult nsAbPalmHotSync::AddToListForPalm(nsAbIPCCard & ipcCard)
00702 {
00703     // this should never happen but check for crossing array index
00704     if(mCardForPalmCount >= mTotalCardCount)
00705         return NS_ERROR_UNEXPECTED;
00706 
00707     nsresult rv = ipcCard.GetABCOMCardStruct(mIsPalmDataUnicode, &mCardListForPalm[mCardForPalmCount]);
00708     if(NS_SUCCEEDED(rv)) 
00709     {
00710         mCardListForPalm[mCardForPalmCount].dwCategoryId = mPalmCategoryId;
00711         mCardForPalmCount++;
00712     }
00713 
00714     return rv;
00715 }
00716 
00717 nsresult nsAbPalmHotSync::OpenABDBForHotSync(PRBool aCreate)
00718 {
00719     if(!mInitialized) 
00720         return NS_ERROR_NOT_INITIALIZED;
00721 
00722     // if already open
00723     if(mDBOpen && mABDB && mDirectory)
00724         return NS_OK;
00725 
00726     if(mFileName.IsEmpty())
00727         return NS_ERROR_FILE_INVALID_PATH;
00728 
00729     nsresult rv;
00730     nsCOMPtr<nsIAddrBookSession> abSession = do_GetService(NS_ADDRBOOKSESSION_CONTRACTID, &rv);
00731     if(NS_FAILED(rv)) 
00732         return rv;
00733 
00734     rv = abSession->GetUserProfileDirectory(getter_AddRefs(mABFile));
00735     if(NS_FAILED(rv)) 
00736         return rv;
00737 
00738               mABFile->AppendNative(mFileName);
00739 
00740     nsCOMPtr<nsIAddrDatabase> addrDBFactory = 
00741              do_GetService(NS_ADDRDATABASE_CONTRACTID, &rv);
00742     if(NS_FAILED(rv)) 
00743     {
00744         return rv;
00745     }
00746     
00747     rv = addrDBFactory->Open(mABFile, aCreate, PR_TRUE, getter_AddRefs(mABDB));
00748     NS_ENSURE_SUCCESS(rv, rv);
00749     mDBOpen = PR_TRUE;  // Moz AB DB is now Open
00750 
00751     return rv;
00752 }
00753 
00754 nsresult nsAbPalmHotSync::KeepCurrentStateAsPrevious()
00755 {
00756     if(!mInitialized) 
00757         return NS_ERROR_NOT_INITIALIZED;
00758 
00759     nsresult rv = NS_OK;
00760 
00761     nsCAutoString previousLeafName(mFileName);
00762     previousLeafName += PREVIOUS_EXTENSION;
00763 
00764     if(!mPreviousABFile) 
00765     {
00766         nsCOMPtr<nsIAddrBookSession> abSession = do_GetService(NS_ADDRBOOKSESSION_CONTRACTID, &rv);
00767         if(NS_FAILED(rv)) 
00768             return rv;
00769         rv = abSession->GetUserProfileDirectory(getter_AddRefs(mPreviousABFile));
00770         if(NS_SUCCEEDED(rv)) 
00771         {
00772             mPreviousABFile->AppendNative(previousLeafName);
00773             if(NS_FAILED(rv))
00774                 return rv;
00775         }
00776     }
00777 
00778     PRBool bExists=PR_FALSE;
00779     mABFile->Exists(&bExists);
00780     if(bExists) 
00781     {
00782         mPreviousABFile->Exists(&bExists);
00783         if(bExists)
00784             rv = mPreviousABFile->Remove(PR_FALSE);
00785         nsCOMPtr<nsIFile> parent;
00786         rv = mABFile->GetParent(getter_AddRefs(parent));
00787         if (NS_SUCCEEDED(rv))
00788             rv = mABFile->CopyToNative(parent, previousLeafName);
00789     }        
00790     return rv;
00791 }
00792 
00793 
00794 nsresult nsAbPalmHotSync::UpdateMozABWithPalmRecords()
00795 {
00796     if(!mInitialized || !mABDB || !mDBOpen)
00797         return NS_ERROR_NOT_INITIALIZED;
00798 
00799     nsresult rv = NS_OK;
00800 
00801     for(PRInt32 i=mPalmRecords.Count()-1; i >=0;  i--) 
00802     {
00803         nsABCOMCardStruct * palmRec = (nsABCOMCardStruct *)mPalmRecords.ElementAt(i);
00804         nsAbIPCCard ipcCard(palmRec, PR_FALSE);
00805 
00806         char recordIDBuf[128]; 
00807         PRInt64 l;
00808         LL_UI2L(l, palmRec->dwRecordId);
00809         PRFloat64 f;
00810         LL_L2F(f, l);
00811         PR_cnvtf(recordIDBuf, 128, 0, f);
00812 
00813         // if the card already exists
00814         nsCOMPtr<nsIAbCard> existingCard;
00815         rv = mABDB->GetCardFromAttribute(nsnull, CARD_ATTRIB_PALMID, recordIDBuf,
00816                                              PR_FALSE, getter_AddRefs(existingCard));
00817         if (!existingCard)
00818         {
00819           rv = mABDB->GetCardFromAttribute(nsnull, CARD_ATTRIB_DISPLAY, (const char *) palmRec->displayName,
00820                                              PR_FALSE, getter_AddRefs(existingCard));
00821           // if card with this display name exists, just continue; But, we should make sure
00822           // it's associated with the palm card going forward, so set the palmid.
00823           if (NS_SUCCEEDED(rv) && existingCard)
00824           {
00825             nsCOMPtr<nsIAbMDBCard> dbCard = do_QueryInterface(existingCard);
00826 
00827             dbCard->SetStringAttribute(CARD_ATTRIB_PALMID, NS_ConvertASCIItoUCS2(recordIDBuf).get());
00828             continue;
00829           }
00830 
00831         }
00832         if(NS_SUCCEEDED(rv) && existingCard) 
00833         {
00834             // Archived is the same as deleted in palm.
00835             if(palmRec->dwStatus & ATTR_DELETED || palmRec->dwStatus & ATTR_ARCHIVED) 
00836             {
00837                 mABDB->DeleteCard(existingCard, PR_FALSE);
00838                 continue;
00839             }
00840             if(palmRec->dwStatus & ATTR_NEW)
00841                 continue;
00842             if(palmRec->dwStatus & ATTR_MODIFIED) 
00843             {
00844                 PRBool isEqual=PR_FALSE;
00845                 ipcCard.Equals(existingCard, &isEqual);
00846                 if(isEqual)
00847                     continue;
00848                 else 
00849                 {
00850                     existingCard->Copy(&ipcCard);
00851                     rv = mABDB->EditCard(existingCard, PR_FALSE);
00852                     continue;
00853                 }
00854             }
00855         }
00856 
00857         nsCOMPtr<nsIAbMDBCard> dbCard;
00858         dbCard = do_CreateInstance(NS_ABMDBCARD_CONTRACTID, &rv);
00859         if(NS_FAILED(rv))
00860             continue;
00861 
00862         nsCOMPtr<nsIAbCard> newCard;
00863         newCard = do_QueryInterface(dbCard, &rv);
00864         if(NS_FAILED(rv)) 
00865             continue;
00866 
00867         rv = newCard->Copy(&ipcCard);
00868         if(NS_FAILED(rv)) 
00869             continue;
00870 
00871         // if the card does not exist
00872         if((ipcCard.GetStatus() == ATTR_NEW)
00873             ||(ipcCard.GetStatus() == ATTR_MODIFIED)
00874             || (ipcCard.GetStatus() == ATTR_NONE)) 
00875         {
00876             PRUint32 modTimeInSec;
00877             PRTime2Seconds(PR_Now(), &modTimeInSec);
00878             ipcCard.SetLastModifiedDate(modTimeInSec);
00879             rv = mABDB->CreateNewCardAndAddToDB(newCard, PR_FALSE);
00880             if(NS_SUCCEEDED(rv)) 
00881             {
00882                 // now set the attribute for the PalmRecID in the card in the DB
00883                 dbCard->SetAbDatabase(mABDB);
00884                 dbCard->SetStringAttribute(CARD_ATTRIB_PALMID, NS_ConvertASCIItoUCS2(recordIDBuf).get());
00885                 newCard = do_QueryInterface(dbCard, &rv);
00886                 if(NS_SUCCEEDED(rv))
00887                     rv = mABDB->EditCard(newCard, PR_FALSE);
00888             }
00889         }
00890     }
00891 
00892     return rv;
00893 }
00894 
00895 
00896 nsresult nsAbPalmHotSync::Done(PRBool aSuccess, PRInt32 aPalmCatIndex, PRUint32 aPalmRecIDListCount, unsigned long * aPalmRecordIDList)
00897 {
00898     if(!mInitialized) 
00899         return NS_ERROR_NOT_INITIALIZED;
00900 
00901     nsresult rv=NS_ERROR_UNEXPECTED;
00902 
00903     if(aPalmRecIDListCount == mNewCardCount) 
00904     {
00905         for(PRUint32 i=0; i<aPalmRecIDListCount; i++) 
00906         {
00907             nsCOMPtr<nsIAbMDBCard> dbCard;
00908             rv = mNewCardsArray->QueryElementAt(i, NS_GET_IID(nsIAbMDBCard), getter_AddRefs(dbCard));
00909             if(NS_SUCCEEDED(rv) && dbCard) 
00910             {
00911                 ConvertAssignPalmIDAttrib(aPalmRecordIDList[i], dbCard);
00912                 nsCOMPtr<nsIAbCard> newCard;
00913                 newCard = do_QueryInterface(dbCard, &rv);
00914                 if(NS_SUCCEEDED(rv))
00915                     mABDB->EditCard(newCard, PR_FALSE);
00916             }
00917         }
00918     }
00919 
00920     if(mABDB && mDBOpen) 
00921     {
00922         if(aSuccess) 
00923         {
00924             rv = mABDB->Close(PR_TRUE);
00925             if(NS_SUCCEEDED(rv)) 
00926             {
00927                 mDBOpen = PR_FALSE;
00928                 PRUint32 modTimeInSec;
00929                 PRTime2Seconds(PR_Now(), &modTimeInSec);
00930                 rv = UpdateABInfo(modTimeInSec, aPalmCatIndex);
00931             }
00932         }
00933         if(NS_FAILED(rv) || !aSuccess) 
00934         { // get back the previous file
00935             rv = mABDB->ForceClosed();
00936             if(NS_SUCCEEDED(rv)) 
00937             {
00938                 nsCAutoString leafName;
00939                 mABFile->GetNativeLeafName(leafName);
00940                 PRBool bExists=PR_FALSE;
00941                 mPreviousABFile->Exists(&bExists);
00942                 if(bExists) 
00943                 {
00944                     nsCOMPtr<nsIFile> parent;
00945                     rv = mABFile->GetParent(getter_AddRefs(parent));
00946                     if (NS_SUCCEEDED(rv)) 
00947                     {
00948                         mABFile->Remove(PR_FALSE);
00949                         mPreviousABFile->CopyToNative(parent, leafName);
00950                     }
00951                 }
00952                 mDBOpen = PR_FALSE;
00953             }
00954         }
00955     }
00956     
00957     return rv;
00958 }
00959 
00960 nsresult nsAbPalmHotSync::UpdateSyncInfo(long aCategoryIndex)
00961 {
00962   // aCategoryIndex = -1 means that callers want to reset the mod time as well. 
00963   mDBOpen = PR_FALSE;
00964   PRUint32 modTimeInSec;
00965   PRTime2Seconds(PR_Now(), &modTimeInSec);
00966   if (aCategoryIndex >= 0)
00967     return(UpdateABInfo(modTimeInSec, aCategoryIndex));
00968   else
00969     return(UpdateABInfo(0, aCategoryIndex)); // Reset mod time.
00970 }
00971 
00972 nsresult nsAbPalmHotSync::DeleteAB(long aCategoryIndex, const char * aABUrl)
00973 {
00974   nsresult rv;
00975   nsCOMPtr<nsISupportsArray> parentArray(do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID, &rv));
00976   NS_ENSURE_SUCCESS(rv, rv);
00977   nsCOMPtr<nsISupportsArray> selectedArray(do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID, &rv));
00978   NS_ENSURE_SUCCESS(rv, rv);
00979 
00980   nsCOMPtr<nsIRDFService> rdfService = do_GetService (NS_RDF_CONTRACTID "/rdf-service;1", &rv);
00981   NS_ENSURE_SUCCESS(rv, rv);
00982 
00983   // Parent nsIABDirectory: like "moz-abdirectory://".
00984   nsCOMPtr <nsIRDFResource> resource;
00985   rv = rdfService->GetResource(NS_LITERAL_CSTRING("moz-abdirectory://"),
00986                                getter_AddRefs(resource));
00987   NS_ENSURE_SUCCESS(rv, rv);
00988 
00989   nsCOMPtr <nsIAbDirectory> parentDirectory = do_QueryInterface(resource, &rv);
00990   NS_ENSURE_SUCCESS(rv, rv);
00991 
00992   parentArray->AppendElement(parentDirectory);
00993 
00994   // Selected folder nsIABDirectory: like "moz-abmdbdirectory://abook-1.mab"
00995   nsCOMPtr <nsIRDFResource> childResource;
00996   rv = rdfService->GetResource(nsDependentCString(aABUrl), getter_AddRefs(childResource));
00997   NS_ENSURE_SUCCESS(rv, rv);
00998   nsCOMPtr <nsIAbDirectory> selectedDirectory = do_QueryInterface(childResource, &rv);
00999   NS_ENSURE_SUCCESS(rv, rv);
01000 
01001   selectedArray->AppendElement(selectedDirectory);
01002 
01003   nsCOMPtr<nsIRDFDataSource> ds;
01004   rv = rdfService->GetDataSource("rdf:addressdirectory", getter_AddRefs(ds));
01005   NS_ENSURE_SUCCESS(rv, rv);
01006 
01007   nsCOMPtr <nsIAddressBook> ab = do_CreateInstance(NS_ADDRESSBOOK_CONTRACTID, &rv);
01008   NS_ENSURE_SUCCESS(rv, rv);
01009 
01010   return(ab->DeleteAddressBooks(ds, parentArray, selectedArray));
01011 }
01012 
01013 nsresult nsAbPalmHotSync::RenameAB(long aCategoryIndex, const char * aABUrl)
01014 {
01015   // Fill in property info and call ModifyAB().
01016   nsresult rv;
01017   nsCOMPtr <nsIAbDirectoryProperties> properties(do_CreateInstance(NS_ABDIRECTORYPROPERTIES_CONTRACTID, &rv));
01018   NS_ENSURE_SUCCESS(rv,rv);
01019 
01020   // For modify to work, we only need to set description, uri and dir type.
01021   rv = properties->SetDescription(mAbName);
01022   NS_ENSURE_SUCCESS(rv,rv);
01023   rv = properties->SetURI(aABUrl);
01024   NS_ENSURE_SUCCESS(rv,rv);
01025   rv = properties->SetDirType(kPABDirectory); // pab dir type for PalmSync
01026   NS_ENSURE_SUCCESS(rv,rv);
01027   rv = properties->SetCategoryId(aCategoryIndex);
01028   NS_ENSURE_SUCCESS(rv,rv);
01029   PRUint32 modTimeInSec;
01030   PRTime2Seconds(PR_Now(), &modTimeInSec);
01031   rv = properties->SetSyncTimeStamp(modTimeInSec);
01032   NS_ENSURE_SUCCESS(rv,rv);
01033 
01034   return(ModifyAB(aABUrl, properties));
01035 }
01036 
01037 nsresult nsAbPalmHotSync::NewAB(const nsString& aAbName)
01038 {
01039   nsresult rv;
01040   nsCOMPtr <nsIAddressBook> ab = do_CreateInstance(NS_ADDRESSBOOK_CONTRACTID, &rv);
01041   NS_ENSURE_SUCCESS(rv, rv);
01042 
01043   nsCOMPtr <nsIAbDirectoryProperties> properties = do_CreateInstance(NS_ABDIRECTORYPROPERTIES_CONTRACTID, &rv);
01044   NS_ENSURE_SUCCESS(rv, rv);
01045   properties->SetDirType(kPABDirectory);  
01046   properties->SetDescription(aAbName);
01047 
01048   return(ab->NewAddressBook(properties));
01049 }
01050 
01051 nsresult nsAbPalmHotSync::UpdateABInfo(PRUint32 aModTime, PRInt32 aCategoryIndex)
01052 {
01053   // Fill in property info and call ModifyAB().
01054   nsresult rv;
01055   nsCOMPtr <nsIAbDirectoryProperties> properties(do_CreateInstance(NS_ABDIRECTORYPROPERTIES_CONTRACTID, &rv));
01056   NS_ENSURE_SUCCESS(rv,rv);
01057 
01058   // For modify to work, we only need to set description, uri and 
01059   // dir type. Then add mod time and category id we want to modify.
01060   rv = properties->SetDescription(mDescription);
01061   NS_ENSURE_SUCCESS(rv,rv);
01062   rv = properties->SetURI(mUri.get());
01063   NS_ENSURE_SUCCESS(rv,rv);
01064   rv = properties->SetDirType(mDirType);
01065   NS_ENSURE_SUCCESS(rv,rv);
01066   rv = properties->SetCategoryId(aCategoryIndex);
01067   NS_ENSURE_SUCCESS(rv,rv);
01068   rv = properties->SetSyncTimeStamp(aModTime);
01069   NS_ENSURE_SUCCESS(rv,rv);
01070 
01071   return(ModifyAB(mUri.get(), properties));
01072 }
01073 
01074 nsresult nsAbPalmHotSync::ModifyAB(const char * aABUrl, nsIAbDirectoryProperties *aProperties)
01075 {
01076   nsresult rv;
01077 
01078   nsCOMPtr<nsIRDFService> rdfService = do_GetService (NS_RDF_CONTRACTID "/rdf-service;1", &rv);
01079   NS_ENSURE_SUCCESS(rv, rv);
01080 
01081   // Parent nsIABDirectory: like "moz-abdirectory://".
01082   nsCOMPtr <nsIRDFResource> resource;
01083   rv = rdfService->GetResource(NS_LITERAL_CSTRING("moz-abdirectory://"), getter_AddRefs(resource));
01084   NS_ENSURE_SUCCESS(rv, rv);
01085 
01086   nsCOMPtr <nsIAbDirectory> parentDirectory = do_QueryInterface(resource, &rv);
01087   NS_ENSURE_SUCCESS(rv, rv);
01088 
01089   // Selected folder nsIABDirectory: like "moz-abmdbdirectory://abook-1.mab"
01090   nsCOMPtr <nsIRDFResource> childResource;
01091   rv = rdfService->GetResource(nsDependentCString(aABUrl), getter_AddRefs(childResource));
01092   NS_ENSURE_SUCCESS(rv, rv);
01093   nsCOMPtr <nsIAbDirectory> selectedDirectory = do_QueryInterface(childResource, &rv);
01094   NS_ENSURE_SUCCESS(rv, rv);
01095 
01096   // RDF data source for addrbook
01097   nsCOMPtr<nsIRDFDataSource> ds;
01098   rv = rdfService->GetDataSource("rdf:addressdirectory", getter_AddRefs(ds));
01099   NS_ENSURE_SUCCESS(rv, rv);
01100 
01101   nsCOMPtr <nsIAddressBook> ab = do_CreateInstance(NS_ADDRESSBOOK_CONTRACTID, &rv);
01102   NS_ENSURE_SUCCESS(rv, rv);
01103 
01104   return(ab->ModifyAddressBook(ds, parentDirectory, selectedDirectory, aProperties));
01105 }